merge master

actorid
mrcheko 11 years ago
commit 6a3dddfb9a

@ -41,4 +41,4 @@ notifications:
- "chat.freenode.net#openmw"
on_success: change
on_failure: always
use_notice: true

@ -24,7 +24,7 @@ opencs_units (model/world
opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection
)
opencs_hdrs_noqt (model/world
@ -60,7 +60,7 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
scenetoolmode infocreator scriptedit dialoguesubview previewsubview
scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap
)
opencs_units (view/render
@ -88,34 +88,29 @@ opencs_units_noqt (view/tools
)
opencs_units (view/settings
abstractblock
proxyblock
abstractwidget
usersettingsdialog
datadisplayformatpage
windowpage
settingwindow
dialog
page
view
booleanview
textview
listview
resizeablestackedwidget
)
opencs_units_noqt (view/settings
abstractpage
blankpage
groupblock
customblock
groupbox
itemblock
settingwidget
toggleblock
support
frame
)
opencs_units (model/settings
usersettings
settingcontainer
settingmanager
setting
connector
)
opencs_units_noqt (model/settings
opencs_hdrs_noqt (model/settings
support
settingsitem
)
opencs_units_noqt (model/filter

@ -28,6 +28,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
setupDataFiles (config.first);
CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg");
mSettings.setModel (CSMSettings::UserSettings::instance());
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
@ -117,6 +118,18 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
//iterate the data directories and add them to the file dialog for loading
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
QString path = QString::fromStdString(iter->string());
mFileDialog.addFiles(path);
}
/*
//load the settings into the userSettings instance.
const QString settingFileName = "opencs.cfg";
CSMSettings::UserSettings::instance().loadSettings(settingFileName);
*/
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string> >());
}

@ -24,7 +24,7 @@
#include "view/doc/filedialog.hpp"
#include "view/doc/newgame.hpp"
#include "view/settings/usersettingsdialog.hpp"
#include "view/settings/dialog.hpp"
namespace OgreInit
{
@ -43,7 +43,7 @@ namespace CS
CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;
CSVDoc::NewGameDialogue mNewGame;
CSVSettings::UserSettingsDialog mSettings;
CSVSettings::Dialog mSettings;
CSVDoc::FileDialog mFileDialog;
boost::filesystem::path mLocal;
boost::filesystem::path mResources;

@ -0,0 +1,127 @@
#include "connector.hpp"
#include "../../view/settings/view.hpp"
#include "../../view/settings/page.hpp"
CSMSettings::Connector::Connector(CSVSettings::View *master,
QObject *parent)
: mMasterView (master), QObject(parent)
{}
void CSMSettings::Connector::addSlaveView (CSVSettings::View *view,
QList <QStringList> &masterProxyValues)
{
mSlaveViews.append (view);
mProxyListMap[view->viewKey()].append (masterProxyValues);
}
QList <QStringList> CSMSettings::Connector::getSlaveViewValues() const
{
QList <QStringList> list;
foreach (const CSVSettings::View *view, mSlaveViews)
list.append (view->selectedValues());
return list;
}
bool CSMSettings::Connector::proxyListsMatch (
const QList <QStringList> &list1,
const QList <QStringList> &list2) const
{
bool success = true;
for (int i = 0; i < list1.size(); i++)
{
success = stringListsMatch (list1.at(i), list2.at(i));
if (!success)
break;
}
return success;
}
void CSMSettings::Connector::slotUpdateMaster() const
{
//list of the current values for each slave.
QList <QStringList> slaveValueList = getSlaveViewValues();
int masterColumn = -1;
/*
* A row in the master view is one of the values in the
* master view's data model. This corresponds directly to the number of
* values in a proxy list contained in the ProxyListMap member.
* Thus, we iterate each "column" in the master proxy list
* (one for each vlaue in the master. Each column represents
* one master value's corresponding list of slave values. We examine
* each master value's list, comparing it to the current slave value list,
* stopping when we find a match using proxyListsMatch().
*
* If no match is found, clear the master view's value
*/
for (int i = 0; i < mMasterView->rowCount(); i++)
{
QList <QStringList> proxyValueList;
foreach (const QString &settingKey, mProxyListMap.keys())
{
// append the proxy value list stored in the i'th column
// for each setting key. A setting key is the id of the setting
// in page.name format.
proxyValueList.append (mProxyListMap.value(settingKey).at(i));
}
if (proxyListsMatch (slaveValueList, proxyValueList))
{
masterColumn = i;
break;
}
}
QString masterValue = mMasterView->value (masterColumn);
mMasterView->setSelectedValue (masterValue);
}
void CSMSettings::Connector::slotUpdateSlaves() const
{
int row = mMasterView->currentIndex();
if (row == -1)
return;
//iterate the proxy lists for the chosen master index
//and pass the list to each slave for updating
for (int i = 0; i < mSlaveViews.size(); i++)
{
QList <QStringList> proxyList =
mProxyListMap.value(mSlaveViews.at(i)->viewKey());
mSlaveViews.at(i)->setSelectedValues (proxyList.at(row));
}
}
bool CSMSettings::Connector::stringListsMatch (
const QStringList &list1,
const QStringList &list2) const
{
//returns a "sloppy" match, verifying that each list contains all the same
//items, though not necessarily in the same order.
if (list1.size() != list2.size())
return false;
QStringList tempList(list2);
//iterate each value in the list, removing one occurrence of the value in
//the other list. If no corresponding value is found, test fails
foreach (const QString &value, list1)
{
if (!tempList.contains(value))
return false;
tempList.removeOne(value);
}
return true;
}

@ -0,0 +1,55 @@
#ifndef CSMSETTINGS_CONNECTOR_HPP
#define CSMSETTINGS_CONNECTOR_HPP
#include <QObject>
#include <QList>
#include <QMap>
#include <QStringList>
#include "support.hpp"
namespace CSVSettings {
class View;
}
namespace CSMSettings {
class Connector : public QObject
{
Q_OBJECT
CSVSettings::View *mMasterView;
//map using the view pointer as a key to it's index value
QList <CSVSettings::View *> mSlaveViews;
//list of proxy values for each master value.
//value list order is indexed to the master value index.
QMap < QString, QList <QStringList> > mProxyListMap;
public:
explicit Connector(CSVSettings::View *master,
QObject *parent = 0);
void setMasterView (CSVSettings::View *view);
void addSlaveView (CSVSettings::View *view,
QList <QStringList> &masterProxyValues);
private:
bool proxyListsMatch (const QList <QStringList> &list1,
const QList <QStringList> &list2) const;
bool stringListsMatch (const QStringList &list1,
const QStringList &list2) const;
QList <QStringList> getSlaveViewValues() const;
public slots:
void slotUpdateSlaves() const;
void slotUpdateMaster() const;
};
}
#endif // CSMSETTINGS_CONNECTOR_HPP

@ -0,0 +1,281 @@
#include "setting.hpp"
#include "support.hpp"
CSMSettings::Setting::Setting()
{
buildDefaultSetting();
}
CSMSettings::Setting::Setting(SettingType typ, const QString &settingName,
const QString &pageName, const QStringList &values)
: mIsEditorSetting (false)
{
buildDefaultSetting();
int vType = static_cast <int> (typ);
if ((vType % 2) == 0)
setProperty (Property_IsMultiValue,
QVariant(true).toString());
else
vType--;
setProperty (Property_ViewType, QVariant (vType / 2).toString());
setProperty (Property_Page, pageName);
setProperty (Property_Name, settingName);
setProperty (Property_DeclaredValues, values);
}
void CSMSettings::Setting::buildDefaultSetting()
{
int arrLen = sizeof(sPropertyDefaults) / sizeof (*sPropertyDefaults);
for (int i = 0; i < arrLen; i++)
{
QStringList propertyList;
if (i <Property_DefaultValues)
propertyList.append (sPropertyDefaults[i]);
mProperties.append (propertyList);
}
}
void CSMSettings::Setting::addProxy (const Setting *setting,
const QStringList &vals)
{
if (serializable())
setSerializable (false);
QList <QStringList> list;
foreach (const QString &val, vals)
list << (QStringList() << val);
mProxies [setting->page() + '.' + setting->name()] = list;
}
void CSMSettings::Setting::addProxy (const Setting *setting,
const QList <QStringList> &list)
{
if (serializable())
setProperty (Property_Serializable, false);
mProxies [setting->page() + '.' + setting->name()] = list;
}
void CSMSettings::Setting::setColumnSpan (int value)
{
setProperty (Property_ColumnSpan, value);
}
int CSMSettings::Setting::columnSpan() const
{
return property (Property_ColumnSpan).at(0).toInt();
}
QStringList CSMSettings::Setting::declaredValues() const
{
return property (Property_DeclaredValues);
}
void CSMSettings::Setting::setDefinedValues (QStringList list)
{
setProperty (Property_DefinedValues, list);
}
QStringList CSMSettings::Setting::definedValues() const
{
return property (Property_DefinedValues);
}
QStringList CSMSettings::Setting::property (SettingProperty prop) const
{
if (prop >= mProperties.size())
return QStringList();
return mProperties.at(prop);
}
void CSMSettings::Setting::setDefaultValue (const QString &value)
{
setDefaultValues (QStringList() << value);
}
void CSMSettings::Setting::setDefaultValues (const QStringList &values)
{
setProperty (Property_DefaultValues, values);
}
QStringList CSMSettings::Setting::defaultValues() const
{
return property (Property_DefaultValues);
}
void CSMSettings::Setting::setDelimiter (const QString &value)
{
setProperty (Property_Delimiter, value);
}
QString CSMSettings::Setting::delimiter() const
{
return property (Property_Delimiter).at(0);
}
void CSMSettings::Setting::setEditorSetting(bool state)
{
mIsEditorSetting = true;
}
bool CSMSettings::Setting::isEditorSetting() const
{
return mIsEditorSetting;
}
void CSMSettings::Setting::setIsMultiLine (bool state)
{
setProperty (Property_IsMultiLine, state);
}
bool CSMSettings::Setting::isMultiLine() const
{
return (property (Property_IsMultiLine).at(0) == "true");
}
void CSMSettings::Setting::setIsMultiValue (bool state)
{
setProperty (Property_IsMultiValue, state);
}
bool CSMSettings::Setting::isMultiValue() const
{
return (property (Property_IsMultiValue).at(0) == "true");
}
const CSMSettings::ProxyValueMap &CSMSettings::Setting::proxyLists() const
{
return mProxies;
}
void CSMSettings::Setting::setSerializable (bool state)
{
setProperty (Property_Serializable, state);
}
bool CSMSettings::Setting::serializable() const
{
return (property (Property_Serializable).at(0) == "true");
}
void CSMSettings::Setting::setName (const QString &value)
{
setProperty (Property_Name, value);
}
QString CSMSettings::Setting::name() const
{
return property (Property_Name).at(0);
}
void CSMSettings::Setting::setPage (const QString &value)
{
setProperty (Property_Page, value);
}
QString CSMSettings::Setting::page() const
{
return property (Property_Page).at(0);
}
void CSMSettings::Setting::setRowSpan (const int value)
{
setProperty (Property_RowSpan, value);
}
int CSMSettings::Setting::rowSpan () const
{
return property (Property_RowSpan).at(0).toInt();
}
void CSMSettings::Setting::setViewType (int vType)
{
setProperty (Property_ViewType, vType);
}
CSVSettings::ViewType CSMSettings::Setting::viewType() const
{
return static_cast <CSVSettings::ViewType>
(property(Property_ViewType).at(0).toInt());
}
void CSMSettings::Setting::setViewColumn (int value)
{
setProperty (Property_ViewColumn, value);
}
int CSMSettings::Setting::viewColumn() const
{
return property (Property_ViewColumn).at(0).toInt();
}
void CSMSettings::Setting::setViewLocation (int row, int column)
{
setViewRow (row);
setViewColumn (column);
}
void CSMSettings::Setting::setViewRow (int value)
{
setProperty (Property_ViewRow, value);
}
int CSMSettings::Setting::viewRow() const
{
return property (Property_ViewRow).at(0).toInt();
}
void CSMSettings::Setting::setWidgetWidth (int value)
{
setProperty (Property_WidgetWidth, value);
}
int CSMSettings::Setting::widgetWidth() const
{
return property (Property_WidgetWidth).at(0).toInt();
}
void CSMSettings::Setting::setProperty (SettingProperty prop, bool value)
{
setProperty (prop, QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setProperty (SettingProperty prop, int value)
{
setProperty (prop, QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setProperty (SettingProperty prop,
const QString &value)
{
setProperty (prop, QStringList() << value);
}
void CSMSettings::Setting::setProperty (SettingProperty prop,
const QStringList &value)
{
if (prop < mProperties.size())
mProperties.replace (prop, value);
}
QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting)
{
stream << setting.properties();
stream << setting.proxies();
return stream;
}
QDataStream &operator >>(QDataStream& stream, CSMSettings::Setting& setting)
{
// stream >> setting.properties();
// stream >> setting.proxies();
return stream;
}

@ -0,0 +1,119 @@
#ifndef CSMSETTINGS_SETTING_HPP
#define CSMSETTINGS_SETTING_HPP
#include <QStringList>
#include <QMap>
#include "support.hpp"
namespace CSMSettings
{
//Maps setting id ("page.name") to a list of corresponding proxy values.
//Order of proxy value stringlists corresponds to order of master proxy's
//values in it's declared value list
typedef QMap <QString, QList <QStringList> > ProxyValueMap;
class Setting
{
QList <QStringList> mProperties;
QStringList mDefaults;
bool mIsEditorSetting;
//QString is the setting id in the form of "page.name"
//QList is a list of stringlists of proxy values.
//Order is important! Proxy stringlists are matched against
//master values by their position in the QList.
ProxyValueMap mProxies;
public:
explicit Setting();
explicit Setting(SettingType typ, const QString &settingName,
const QString &pageName,
const QStringList &values = QStringList());
void addProxy (const Setting *setting, const QStringList &vals);
void addProxy (const Setting *setting, const QList <QStringList> &list);
const QList <QStringList> &properties() const { return mProperties; }
const ProxyValueMap &proxies() const { return mProxies; }
void setColumnSpan (int value);
int columnSpan() const;
void setDeclaredValues (QStringList list);
QStringList declaredValues() const;
void setDefinedValues (QStringList list);
QStringList definedValues() const;
void setDefaultValue (const QString &value);
void setDefaultValues (const QStringList &values);
QStringList defaultValues() const;
void setDelimiter (const QString &value);
QString delimiter() const;
void setEditorSetting (bool state);
bool isEditorSetting() const;
void setIsMultiLine (bool state);
bool isMultiLine() const;
void setIsMultiValue (bool state);
bool isMultiValue() const;
void setName (const QString &value);
QString name() const;
void setPage (const QString &value);
QString page() const;
void setRowSpan (const int value);
int rowSpan() const;
const ProxyValueMap &proxyLists() const;
void setSerializable (bool state);
bool serializable() const;
void setViewColumn (int value);
int viewColumn() const;
void setViewLocation (int row = -1, int column = -1);
void setViewRow (int value);
int viewRow() const;
void setViewType (int vType);
CSVSettings::ViewType viewType() const;
void setWidgetWidth (int value);
int widgetWidth() const;
///returns the specified property value
QStringList property (SettingProperty prop) const;
///boilerplate code to convert setting values of common types
void setProperty (SettingProperty prop, bool value);
void setProperty (SettingProperty prop, int value);
void setProperty (SettingProperty prop, const QString &value);
void setProperty (SettingProperty prop, const QStringList &value);
void addProxy (Setting* setting,
QMap <QString, QStringList> &proxyMap);
protected:
void buildDefaultSetting();
};
}
Q_DECLARE_METATYPE(CSMSettings::Setting)
QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting);
QDataStream &operator >>(QDataStream &stream, CSMSettings::Setting& setting);
#endif // CSMSETTINGS_SETTING_HPP

@ -1,82 +0,0 @@
#include "settingcontainer.hpp"
#include <QStringList>
CSMSettings::SettingContainer::SettingContainer(QObject *parent) :
QObject(parent), mValue (0), mValues (0)
{
}
CSMSettings::SettingContainer::SettingContainer(const QString &value, QObject *parent) :
QObject(parent), mValue (new QString (value)), mValues (0)
{
}
void CSMSettings::SettingContainer::insert (const QString &value)
{
if (mValue)
{
mValues = new QStringList;
mValues->push_back (*mValue);
mValues->push_back (value);
delete mValue;
mValue = 0;
}
else
{
delete mValue;
mValue = new QString (value);
}
}
void CSMSettings::SettingContainer::update (const QString &value, int index)
{
if (isEmpty())
mValue = new QString(value);
else if (mValue)
*mValue = value;
else if (mValues)
mValues->replace(index, value);
}
QString CSMSettings::SettingContainer::getValue (int index) const
{
QString retVal("");
//if mValue is valid, it's a single-value property.
//ignore the index and return the value
if (mValue)
retVal = *mValue;
//otherwise, if it's a multivalued property
//return the appropriate value at the index
else if (mValues)
{
if (index == -1)
retVal = mValues->at(0);
else if (index < mValues->size())
retVal = mValues->at(index);
}
return retVal;
}
int CSMSettings::SettingContainer::count () const
{
int retVal = 0;
if (!isEmpty())
{
if (mValues)
retVal = mValues->size();
else
retVal = 1;
}
return retVal;
}

@ -1,47 +0,0 @@
#ifndef SETTINGCONTAINER_HPP
#define SETTINGCONTAINER_HPP
#include <QObject>
class QStringList;
namespace CSMSettings
{
class SettingContainer : public QObject
{
Q_OBJECT
QString *mValue;
QStringList *mValues;
public:
explicit SettingContainer (QObject *parent = 0);
explicit SettingContainer (const QString &value, QObject *parent = 0);
/// add a value to the container
/// multiple values supported
void insert (const QString &value);
/// update an existing value
/// index specifies multiple values
void update (const QString &value, int index = 0);
/// return value at specified index
QString getValue (int index = -1) const;
/// retrieve list of all values
inline QStringList *getValues() const { return mValues; }
/// return size of list
int count() const;
/// test for empty container
/// useful for default-constructed containers returned by QMap when invalid key is passed
inline bool isEmpty() const { return (!mValue && !mValues); }
inline bool isMultiValue() const { return (mValues); }
};
}
#endif // SETTINGCONTAINER_HPP

@ -0,0 +1,342 @@
#include <QFile>
#include <QTextCodec>
#include <QMessageBox>
#include <QDebug>
#include <QList>
#include "setting.hpp"
#include "settingmanager.hpp"
CSMSettings::SettingManager::SettingManager(QObject *parent) :
QObject(parent)
{
mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for \
writing</b><br><br> Please make sure you have the right\
permissions and try again.<br>");
mReadOnlyMessage = QObject::tr("<br><b>Could not open file for \
reading</b><br><br> Please make sure you have the \
right permissions and try again.<br>");
}
void CSMSettings::SettingManager::dumpModel()
{
foreach (Setting *setting, mSettings)
{
if (setting->proxyLists().isEmpty())
continue;
}
}
CSMSettings::Setting *CSMSettings::SettingManager::createSetting
(CSMSettings::SettingType typ, const QString &page, const QString &name,
const QStringList &values)
{
//get list of all settings for the current setting name
if (findSetting (page, name))
{
qWarning() << "Duplicate declaration encountered: "
<< (name + '.' + page);
return 0;
}
Setting *setting = new Setting (typ, name, page, values);
//add declaration to the model
mSettings.append (setting);
return setting;
}
CSMSettings::DefinitionPageMap
CSMSettings::SettingManager::readFilestream (QTextStream *stream)
{
//regEx's for page names and keys / values
QRegExp pageRegEx ("^\\[([^]]+)\\]");
QRegExp keyRegEx ("^([^=]+)\\s*=\\s*(.+)$");
QString currPage = "Unassigned";
DefinitionPageMap pageMap;
if (!stream)
{
displayFileErrorMessage(mReadWriteMessage, false);
return pageMap;
}
if (stream->atEnd())
return pageMap;
DefinitionMap *settingMap = new DefinitionMap();
pageMap[currPage] = settingMap;
while (!stream->atEnd())
{
QString line = stream->readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
//page name found
if (pageRegEx.exactMatch(line))
{
currPage = pageRegEx.cap(1).simplified().trimmed();
settingMap = new DefinitionMap();
pageMap[currPage] = settingMap;
continue;
}
//setting definition found
if ( (keyRegEx.indexIn(line) != -1))
{
QString settingName = keyRegEx.cap(1).simplified();
QString settingValue = keyRegEx.cap(2).simplified();
if (!settingMap->contains (settingName))
settingMap->insert (settingName, new QStringList());
settingMap->value(settingName)->append(settingValue);
}
}
//return empty map if no settings were ever added to
if (pageMap.size() == 1)
{
QString pageKey = pageMap.keys().at(0);
if (pageMap[pageKey]->size() == 0)
pageMap.clear();
}
return pageMap;
}
bool CSMSettings::SettingManager::writeFilestream(QTextStream *stream,
const QMap <QString, QStringList > &settingListMap)
{
if (!stream)
{
displayFileErrorMessage(mReadWriteMessage, false);
return false;
}
//disabled after rolling selector class into view. Need to
//iterate views to get setting definitions before writing to file
QStringList sectionKeys;
foreach (const QString &key, settingListMap.keys())
{
QStringList names = key.split('.');
QString section = names.at(0);
if (!sectionKeys.contains(section))
if (!settingListMap.value(key).isEmpty())
sectionKeys.append (section);
}
foreach (const QString &section, sectionKeys)
{
*stream << '[' << section << "]\n";
foreach (const QString &key, settingListMap.keys())
{
QStringList names = key.split('.');
if (names.at(0) != section)
continue;
QStringList list = settingListMap.value(key);
if (list.isEmpty())
continue;
QString name = names.at(1);
foreach (const QString value, list)
{
if (value.isEmpty())
continue;
*stream << name << " = " << value << '\n';
}
}
}
destroyStream (stream);
return true;
}
void CSMSettings::SettingManager::mergeSettings(DefinitionPageMap &destMap, DefinitionPageMap &srcMap)
{
if (srcMap.isEmpty())
return;
foreach (const QString &pageKey, srcMap.keys())
{
DefinitionMap *srcSetting = srcMap.value(pageKey);
//Unique Page:
//insertfrom the source map
if (!destMap.keys().contains (pageKey))
{
destMap.insert (pageKey, srcSetting);
continue;
}
DefinitionMap *destSetting = destMap.value(pageKey);
//Duplicate Page:
//iterate the settings in the source and check for duplicates in the
//destination
foreach (const QString &srcKey, srcSetting->keys())
{
//insert into destination if unique
if (!destSetting->keys().contains (srcKey))
destSetting->insert(srcKey, srcSetting->value (srcKey));
}
}
}
QTextStream *CSMSettings::SettingManager::openFilestream (const QString &filePath,
bool isReadOnly) const
{
QIODevice::OpenMode openFlags = QIODevice::Text;
if (isReadOnly)
openFlags = QIODevice::ReadOnly | openFlags;
else
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
QFile *file = new QFile(filePath);
QTextStream *stream = 0;
if (file->open(openFlags))
stream = new QTextStream(file);
if (stream)
stream->setCodec(QTextCodec::codecForName("UTF-8"));
return stream;
}
void CSMSettings::SettingManager::destroyStream(QTextStream *stream) const
{
stream->device()->close();
delete stream;
}
void CSMSettings::SettingManager::displayFileErrorMessage(const QString &message,
bool isReadOnly) const
{
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
if (!isReadOnly)
msgBox.setText (mReadWriteMessage + message);
else
msgBox.setText (message);
msgBox.exec();
}
void CSMSettings::SettingManager::addDefinitions (DefinitionPageMap &pageMap)
{
foreach (QString pageName, pageMap.keys())
{
DefinitionMap *settingMap = pageMap.value (pageName);
foreach (QString settingName, (*settingMap).keys())
{
QStringList *values = settingMap->value (settingName);
Setting *setting = findSetting (pageName, settingName);
if (!setting)
{
qWarning() << "Found definitions for undeclared setting "
<< pageName << "." << settingName;
continue;
}
if (values->size() == 0)
values->append (setting->defaultValues());
setting->setDefinedValues (*values);
}
}
}
QList <CSMSettings::Setting *> CSMSettings::SettingManager::findSettings
(const QStringList &list)
{
QList <CSMSettings::Setting *> settings;
foreach (const QString &value, list)
{
QStringList names = value.split(".", QString::SkipEmptyParts);
if (names.size() != 2)
continue;
Setting *setting = findSetting (names.at(0), names.at(1));
if (!setting)
continue;
settings.append (setting);
}
return settings;
}
CSMSettings::Setting *CSMSettings::SettingManager::findSetting
(const QString &pageName, const QString &settingName)
{
foreach (Setting *setting, mSettings)
{
if (setting->name() == settingName)
{
if (setting->page() == pageName)
return setting;
}
}
return 0;
}
QList <CSMSettings::Setting *> CSMSettings::SettingManager::findSettings
(const QString &pageName)
{
QList <CSMSettings::Setting *> settings;
foreach (Setting *setting, mSettings)
{
if (setting->page() == pageName)
settings.append (setting);
}
return settings;
}
CSMSettings::SettingPageMap CSMSettings::SettingManager::settingPageMap() const
{
SettingPageMap pageMap;
foreach (Setting *setting, mSettings)
pageMap[setting->page()].append (setting);
return pageMap;
}
void CSMSettings::SettingManager::updateUserSetting(const QString &settingKey,
const QStringList &list)
{
QStringList names = settingKey.split('.');
Setting *setting = findSetting (names.at(0), names.at(1));
setting->setDefinedValues (list);
emit userSettingUpdated (settingKey, list);
}

@ -0,0 +1,85 @@
#ifndef CSMSETTINGS_SETTINGMANAGER_HPP
#define CSMSETTINGS_SETTINGMANAGER_HPP
#include <QObject>
#include <QMap>
#include <QStringList>
#include <QTextStream>
#include "support.hpp"
#include "setting.hpp"
namespace CSMSettings
{
typedef QMap <QString, QStringList *> DefinitionMap;
typedef QMap <QString, DefinitionMap *> DefinitionPageMap;
typedef QMap <QString, QList <Setting *> > SettingPageMap;
class SettingManager : public QObject
{
Q_OBJECT
QString mReadOnlyMessage;
QString mReadWriteMessage;
QList <Setting *> mSettings;
public:
explicit SettingManager(QObject *parent = 0);
///retrieve a setting object from a given page and setting name
Setting *findSetting
(const QString &pageName, const QString &settingName);
///retrieve all settings for a specified page
QList <Setting *> findSettings (const QString &pageName);
///retrieve all settings named in the attached list.
///Setting names are specified in "PageName.SettingName" format.
QList <Setting *> findSettings (const QStringList &list);
///Retreive a map of the settings, keyed by page name
SettingPageMap settingPageMap() const;
protected:
///add a new setting to the model and return it
Setting *createSetting (CSMSettings::SettingType typ,
const QString &page, const QString &name,
const QStringList &values = QStringList());
///add definitions to the settings specified in the page map
void addDefinitions (DefinitionPageMap &pageMap);
///read setting definitions from file
DefinitionPageMap readFilestream(QTextStream *stream);
///write setting definitions to file
bool writeFilestream (QTextStream *stream,
const QMap <QString, QStringList > &settingMap);
///merge PageMaps of settings when loading from multiple files
void mergeSettings (DefinitionPageMap &destMap, DefinitionPageMap &srcMap);
QTextStream *openFilestream (const QString &filePath,
bool isReadOnly) const;
void destroyStream(QTextStream *stream) const;
void displayFileErrorMessage(const QString &message,
bool isReadOnly) const;
QList <Setting *> settings() const { return mSettings; }
void dumpModel();
signals:
void userSettingUpdated (const QString &, const QStringList &);
public slots:
void updateUserSetting (const QString &, const QStringList &);
};
}
#endif // CSMSETTINGS_SETTINGMANAGER_HPP

@ -1,104 +0,0 @@
#include "settingsitem.hpp"
#include <QStringList>
bool CSMSettings::SettingsItem::updateItem (const QStringList *values)
{
QStringList::ConstIterator it = values->begin();
//if the item is not multivalued,
//save the last value passed in the container
if (!mIsMultiValue)
{
it = values->end();
it--;
}
bool isValid = true;
QString value ("");
for (; it != values->end(); ++it)
{
value = *it;
isValid = validate(value);
//skip only the invalid values
if (!isValid)
continue;
insert(value);
}
return isValid;
}
bool CSMSettings::SettingsItem::updateItem (const QString &value)
{
//takes a value or a SettingsContainer and updates itself accordingly
//after validating the data against it's own definition
QString newValue = value;
if (!validate (newValue))
newValue = mDefaultValue;
bool success = (getValue() != newValue);
if (success)
{
if (mIsMultiValue)
insert (newValue);
else
update (newValue);
}
return success;
}
bool CSMSettings::SettingsItem::updateItem(int valueListIndex)
{
bool success = false;
if (mValueList)
{
if (mValueList->size() > valueListIndex)
success = updateItem (mValueList->at(valueListIndex));
}
return success;
}
bool CSMSettings::SettingsItem::validate (const QString &value)
{
//if there is no value list or value pair, there is no validation to do
bool isValid = !(!mValueList->isEmpty() || mValuePair);
if (!isValid && !mValueList->isEmpty())
{
for (QStringList::Iterator it = mValueList->begin(); it != mValueList->end(); ++it)
// foreach (QString listItem, *mValueList)
{
isValid = (value == *it);
if (isValid)
break;
}
}
else if (!isValid && mValuePair)
{
int numVal = value.toInt();
isValid = (numVal > mValuePair->left.toInt() && numVal < mValuePair->right.toInt());
}
return isValid;
}
void CSMSettings::SettingsItem::setDefaultValue (const QString &value)
{
mDefaultValue = value;
update (value);
}
QString CSMSettings::SettingsItem::getDefaultValue() const
{
return mDefaultValue;
}

@ -1,67 +0,0 @@
#ifndef SETTINGSITEM_HPP
#define SETTINGSITEM_HPP
#include <QObject>
#include "support.hpp"
#include "settingcontainer.hpp"
namespace CSMSettings
{
/// Represents a setting including metadata
/// (valid values, ranges, defaults, and multivalue status
class SettingsItem : public SettingContainer
{
QStringPair *mValuePair;
QStringList *mValueList;
bool mIsMultiValue;
QString mDefaultValue;
public:
explicit SettingsItem(QString name, bool isMultiValue,
const QString& defaultValue, QObject *parent = 0)
: SettingContainer(defaultValue, parent),
mIsMultiValue (isMultiValue), mValueList (0),
mValuePair (0), mDefaultValue (defaultValue)
{
QObject::setObjectName(name);
}
/// updateItem overloads for updating setting value
/// provided a list of values (multi-valued),
/// a specific value
/// or an index value corresponding to the mValueList
bool updateItem (const QStringList *values);
bool updateItem (const QString &value);
bool updateItem (int valueListIndex);
/// retrieve list of valid values for setting
inline QStringList *getValueList() { return mValueList; }
/// write list of valid values for setting
inline void setValueList (QStringList *valueList) { mValueList = valueList; }
/// valuePair used for spin boxes (max / min)
inline QStringPair *getValuePair() { return mValuePair; }
/// set value range (spinbox / integer use)
inline void setValuePair (QStringPair valuePair)
{
delete mValuePair;
mValuePair = new QStringPair(valuePair);
}
inline bool isMultivalue () { return mIsMultiValue; }
void setDefaultValue (const QString &value);
QString getDefaultValue () const;
private:
/// Verifies that the supplied value is one of the following:
/// 1. Within the limits of the value pair (min / max)
/// 2. One of the values indicated in the value list
bool validate (const QString &value);
};
}
#endif // SETTINGSITEM_HPP

@ -1 +0,0 @@
#include "support.hpp"

@ -1,39 +1,126 @@
#ifndef MODEL_SUPPORT_HPP
#define MODEL_SUPPORT_HPP
#ifndef SETTING_SUPPORT_HPP
#define SETTING_SUPPORT_HPP
#include <QObject>
#include <Qt>
#include <QPair>
#include <QList>
#include <QVariant>
#include <QStringList>
class QLayout;
class QWidget;
class QListWidgetItem;
//Typedefs
namespace CSMSettings
{
// Definition / Declaration model typedefs
// "Pair" = Setting name and specific data
// "ListItem" = Page name and associated setting pair
typedef QPair <QString, QString> StringPair;
typedef QPair <QString, QStringList> StringListPair;
typedef QList <StringListPair> StringListPairs;
}
//Enums
namespace CSMSettings
{
class SettingContainer;
enum SettingProperty
{
Property_Name = 0,
Property_Page = 1,
Property_ViewType = 2,
Property_IsMultiValue = 3,
Property_IsMultiLine = 4,
Property_WidgetWidth = 5,
Property_ViewRow = 6,
Property_ViewColumn = 7,
Property_Delimiter = 8,
Property_Serializable = 9,
Property_ColumnSpan = 10,
Property_RowSpan = 11,
typedef QList<SettingContainer *> SettingList;
typedef QMap<QString, SettingContainer *> SettingMap;
typedef QMap<QString, SettingMap *> SectionMap;
//Stringlists should always be the last items
Property_DefaultValues = 12,
Property_DeclaredValues = 13,
Property_DefinedValues = 14,
Property_Proxies = 15
};
struct QStringPair
enum SettingType
{
QStringPair(): left (""), right ("")
{}
Type_MultiBool = 0,
Type_SingleBool = 1,
Type_MultiList = 2,
Type_SingleList = 3,
Type_MultiRange = 4,
Type_SingleRange = 5,
Type_MultiText = 6,
Type_SingleText = 7
};
QStringPair (const QString &leftValue, const QString &rightValue)
: left (leftValue), right(rightValue)
{}
enum MergeMethod
{
Merge_Accept,
Merge_Ignore,
Merge_Overwrite
};
}
QStringPair (const QStringPair &pair)
: left (pair.left), right (pair.right)
{}
namespace CSVSettings
{
enum ViewType
{
ViewType_Boolean = 0,
ViewType_List = 1,
ViewType_Range = 2,
ViewType_Text = 3,
ViewType_Undefined = 4
};
QString left;
QString right;
enum Alignment
{
Align_Left = Qt::AlignLeft,
Align_Center = Qt::AlignHCenter,
Align_Right = Qt::AlignRight
};
}
bool isEmpty() const
{ return (left.isEmpty() && right.isEmpty()); }
//
namespace CSMSettings
{
struct PropertyDefaultValues
{
int id;
QString name;
QVariant value;
};
const QString sPropertyNames[] =
{
"name", "page", "view_type", "is_multi_value",
"is_multi_line", "widget_width", "view_row", "view_column", "delimiter",
"is_serializable","column_span", "row_span",
"defaults", "declarations", "definitions", "proxies"
};
const QString sPropertyDefaults[] =
{
"", //name
"", //page
"0", //view type
"false", //multivalue
"false", //multiline
"0", //widget width
"-1", //view row
"-1", //view column
",", //delimiter
"true", //serialized
"1", //column span
"1", //row span
"", //default values
"", //declared values
"", //defined values
"" //proxy values
};
}
#endif // MODEL_SUPPORT_HPP
#endif // VIEW_SUPPORT_HPP

@ -9,11 +9,14 @@
#include <QTextCodec>
#include <QFile>
#include <QSortFilterProxyModel>
#include <components/files/configurationmanager.hpp>
#include "settingcontainer.hpp"
#include <boost/version.hpp>
#include "setting.hpp"
#include "support.hpp"
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
@ -37,269 +40,236 @@ CSMSettings::UserSettings::UserSettings()
assert(!mUserSettingsInstance);
mUserSettingsInstance = this;
mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for writing</b><br><br> \
Please make sure you have the right permissions and try again.<br>");
mReadOnlyMessage = QObject::tr("<br><b>Could not open file for reading</b><br><br> \
Please make sure you have the right permissions and try again.<br>");
buildEditorSettingDefaults();
buildSettingModelDefaults();
}
void CSMSettings::UserSettings::buildEditorSettingDefaults()
void CSMSettings::UserSettings::buildSettingModelDefaults()
{
SettingContainer *windowHeight = new SettingContainer("768", this);
SettingContainer *windowWidth = new SettingContainer("1024", this);
SettingContainer *rsDelegate = new SettingContainer("Icon and Text", this);
SettingContainer *refIdTypeDelegate = new SettingContainer("Icon and Text", this);
windowHeight->setObjectName ("Height");
windowWidth->setObjectName ("Width");
rsDelegate->setObjectName ("Record Status Display");
refIdTypeDelegate->setObjectName ("Referenceable ID Type Display");
SettingMap *displayFormatMap = new SettingMap;
SettingMap *windowSizeMap = new SettingMap;
displayFormatMap->insert (rsDelegate->objectName(), rsDelegate );
displayFormatMap->insert (refIdTypeDelegate->objectName(), refIdTypeDelegate);
windowSizeMap->insert (windowWidth->objectName(), windowWidth );
windowSizeMap->insert (windowHeight->objectName(), windowHeight );
mEditorSettingDefaults.insert ("Display Format", displayFormatMap);
mEditorSettingDefaults.insert ("Window Size", windowSizeMap);
}
CSMSettings::UserSettings::~UserSettings()
{
mUserSettingsInstance = 0;
}
QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly) const
{
QIODevice::OpenMode openFlags = QIODevice::Text;
if (isReadOnly)
openFlags = QIODevice::ReadOnly | openFlags;
else
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
QFile *file = new QFile(filePath);
QTextStream *stream = 0;
if (file->open(openFlags))
QString section = "Window Size";
{
stream = new QTextStream(file);
stream->setCodec(QTextCodec::codecForName("UTF-8"));
Setting *width = createSetting (Type_SingleText, section, "Width");
Setting *height = createSetting (Type_SingleText, section, "Height");
width->setWidgetWidth (5);
height->setWidgetWidth (5);
width->setDefaultValues (QStringList() << "1024");
height->setDefaultValues (QStringList() << "768");
width->setEditorSetting (true);
height->setEditorSetting (true);
height->setViewLocation (2,2);
width->setViewLocation (2,1);
/*
*Create the proxy setting for predefined values
*/
Setting *preDefined = createSetting (Type_SingleList, section,
"Pre-Defined",
QStringList()
<< "640 x 480"
<< "800 x 600"
<< "1024 x 768"
<< "1440 x 900"
);
preDefined->setViewLocation (1, 1);
preDefined->setWidgetWidth (10);
preDefined->setColumnSpan (2);
preDefined->addProxy (width,
QStringList() << "640" << "800" << "1024" << "1440"
);
preDefined->addProxy (height,
QStringList() << "480" << "600" << "768" << "900"
);
}
return stream;
}
bool CSMSettings::UserSettings::writeSettings(QMap<QString, CSMSettings::SettingList *> &settings)
{
QTextStream *stream = openFileStream(mUserFilePath);
bool success = (stream);
if (success)
section = "Display Format";
{
QList<QString> keyList = settings.keys();
QString defaultValue = "Icon and Text";
foreach (QString key, keyList)
{
SettingList *sectionSettings = settings[key];
QStringList values = QStringList()
<< defaultValue << "Icon Only" << "Text Only";
*stream << "[" << key << "]" << '\n';
Setting *rsd = createSetting (Type_SingleBool,
section, "Record Status Display",
values);
foreach (SettingContainer *item, *sectionSettings)
*stream << item->objectName() << " = " << item->getValue() << '\n';
}
Setting *ritd = createSetting (Type_SingleBool,
section, "Referenceable ID Type Display",
values);
stream->device()->close();
delete stream;
stream = 0;
rsd->setEditorSetting (true);
ritd->setEditorSetting (true);
}
else
section = "Proxy Selection Test";
{
displayFileErrorMessage(mReadWriteMessage, false);
//create three setting objects, specifying the basic widget type,
//the setting view name, the page name, and the default value
Setting *masterBoolean = createSetting (Type_SingleBool, section,
"Master Proxy",
QStringList()
<< "Profile One" << "Profile Two"
<< "Profile Three" << "Profile Four"
);
Setting *slaveBoolean = createSetting (Type_MultiBool, section,
"Proxy Checkboxes",
QStringList() << "One" << "Two"
<< "Three" << "Four" << "Five"
);
Setting *slaveSingleText = createSetting (Type_SingleText, section,
"Proxy TextBox 1"
);
Setting *slaveMultiText = createSetting (Type_SingleText, section,
"ProxyTextBox 2"
);
// There are three types of values:
//
// Declared values - Pre-determined values, typically for
// combobox drop downs and boolean (radiobutton / checkbox) labels.
// These values represent the total possible list of values that may
// define a setting. No other values are allowed.
//
// Defined values - Values which represent the atual, current value of
// a setting. For settings with declared values, this must be one or
// several declared values, as appropriate.
//
// Proxy values - values the proxy master updates the proxy slave when
// it's own definition is set / changed. These are definitions for
// proxy slave settings, but must match any declared values the proxy
// slave has, if any.
masterBoolean->addProxy (slaveBoolean, QList <QStringList>()
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three" << "Five")
<< (QStringList() << "Two" << "Four")
);
masterBoolean->addProxy (slaveSingleText, QList <QStringList>()
<< (QStringList() << "Text A")
<< (QStringList() << "Text B")
<< (QStringList() << "Text A")
<< (QStringList() << "Text C")
);
masterBoolean->addProxy (slaveMultiText, QList <QStringList>()
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three" << "Five")
<< (QStringList() << "Two" << "Four")
);
//settings with proxies are not serialized by default
//other settings non-serialized for demo purposes
slaveBoolean->setSerializable (false);
slaveSingleText->setSerializable (false);
slaveMultiText->setSerializable (false);
slaveBoolean->setDefaultValues (QStringList()
<< "One" << "Three" << "Five");
slaveSingleText->setDefaultValue ("Text A");
slaveMultiText->setDefaultValues (QStringList()
<< "One" << "Three" << "Five");
slaveSingleText->setWidgetWidth (24);
slaveMultiText->setWidgetWidth (24);
}
return (success);
}
const CSMSettings::SectionMap &CSMSettings::UserSettings::getSectionMap() const
CSMSettings::UserSettings::~UserSettings()
{
return mSectionSettings;
mUserSettingsInstance = 0;
}
const CSMSettings::SettingMap *CSMSettings::UserSettings::getSettings(const QString &sectionName) const
void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{
return getValidSettings(sectionName);
}
mUserFilePath = QString::fromUtf8
(mCfgMgr.getUserConfigPath().c_str()) + fileName.toUtf8();
bool CSMSettings::UserSettings::loadFromFile(const QString &filePath)
{
if (filePath.isEmpty())
return false;
QString global = QString::fromUtf8
(mCfgMgr.getGlobalPath().c_str()) + fileName.toUtf8();
SectionMap loadedSettings;
QString local = QString::fromUtf8
(mCfgMgr.getLocalPath().c_str()) + fileName.toUtf8();
QTextStream *stream = openFileStream (filePath, true);
//open user and global streams
QTextStream *userStream = openFilestream (mUserFilePath, true);
QTextStream *otherStream = openFilestream (global, true);
bool success = (stream);
//failed stream, try for local
if (!otherStream)
otherStream = openFilestream (local, true);
if (success)
//error condition - notify and return
if (!otherStream || !userStream)
{
//looks for a square bracket, "'\\["
//that has one or more "not nothing" in it, "([^]]+)"
//and is closed with a square bracket, "\\]"
QRegExp sectionRe("^\\[([^]]+)\\]");
//Find any character(s) that is/are not equal sign(s), "[^=]+"
//followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
//and one or more periods, "(.+)"
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
CSMSettings::SettingMap *settings = 0;
QString section = "none";
while (!stream->atEnd())
{
QString line = stream->readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
//if a section is found, push it onto a new QStringList
//and push the QStringList onto
if (sectionRe.exactMatch(line))
{
//add the previous section's settings to the member map
if (settings)
loadedSettings.insert(section, settings);
//save new section and create a new list
section = sectionRe.cap(1);
settings = new SettingMap;
continue;
}
QString message = QObject::tr("<br><b>An error was encountered loading \
user settings files.</b><br><br> One or several files could not \
be read. This may be caused by a missing configuration file, \
incorrect file permissions or a corrupted installation of \
OpenCS.<br>");
if (keyRe.indexIn(line) != -1)
{
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified());
sc->setObjectName(keyRe.cap(1).simplified());
(*settings)[keyRe.cap(1).simplified()] = sc;
}
message += QObject::tr("<br>Global filepath: ") + global;
message += QObject::tr("<br>Local filepath: ") + local;
message += QObject::tr("<br>User filepath: ") + mUserFilePath;
}
loadedSettings.insert(section, settings);
stream->device()->close();
delete stream;
stream = 0;
displayFileErrorMessage ( message, true);
return;
}
mergeMap (loadedSettings);
//success condition - merge the two streams into a single map and save
DefinitionPageMap totalMap = readFilestream (userStream);
DefinitionPageMap otherMap = readFilestream(otherStream);
return success;
}
//merging other settings file in and ignore duplicate settings to
//avoid overwriting user-level settings
mergeSettings (totalMap, otherMap);
void CSMSettings::UserSettings::mergeMap (const CSMSettings::SectionMap &sectionSettings)
{
foreach (QString key, sectionSettings.uniqueKeys())
{
// insert entire section if it does not already exist in the loaded files
if (mSectionSettings.find(key) == mSectionSettings.end())
mSectionSettings.insert(key, sectionSettings.value(key));
else
{
SettingMap *passedSettings = sectionSettings.value(key);
SettingMap *settings = mSectionSettings.value(key);
foreach (QString key2, passedSettings->uniqueKeys())
{
//insert section settings individially if they do not already exist
if (settings->find(key2) == settings->end())
settings->insert(key2, passedSettings->value(key2));
else
{
settings->value(key2)->update(passedSettings->value(key2)->getValue());
}
}
}
}
if (!totalMap.isEmpty())
addDefinitions (totalMap);
}
void CSMSettings::UserSettings::loadSettings (const QString &fileName)
void CSMSettings::UserSettings::saveSettings
(const QMap <QString, QStringList> &settingMap)
{
mSectionSettings.clear();
//global
QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName;
bool globalOk = loadFromFile(globalFilePath);
//local
QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName;
bool localOk = loadFromFile(localFilePath);
//user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName;
loadFromFile(mUserFilePath);
if (!(localOk || globalOk))
for (int i = 0; i < settings().size(); i++)
{
QString message = QObject::tr("<br><b>Could not open user settings files for reading</b><br><br> \
Global and local settings files could not be read.\
You may have incorrect file permissions or the OpenCS installation may be corrupted.<br>");
Setting* setting = settings().at(i);
message += QObject::tr("<br>Global filepath: ") + globalFilePath;
message += QObject::tr("<br>Local filepath: ") + localFilePath;
QString key = setting->page() + '.' + setting->name();
displayFileErrorMessage ( message, true);
if (!settingMap.keys().contains(key))
continue;
setting->setDefinedValues (settingMap.value(key));
}
writeFilestream (openFilestream (mUserFilePath, false), settingMap);
}
void CSMSettings::UserSettings::updateSettings (const QString &sectionName, const QString &settingName)
QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
{
QStringList names = settingKey.split('.');
SettingMap *settings = getValidSettings(sectionName);
if (!settings)
return;
Setting *setting = findSetting(names.at(0), names.at(1));
if (settingName.isEmpty())
{
foreach (const SettingContainer *setting, *settings)
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
else
if (setting)
{
if (settings->find(settingName) != settings->end())
{
const SettingContainer *setting = settings->value(settingName);
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
if (!setting->definedValues().isEmpty())
return setting->definedValues().at(0);
}
}
QString CSMSettings::UserSettings::getSetting (const QString &section, const QString &setting) const
{
SettingMap *settings = getValidSettings(section);
QString retVal = "";
if (settings->find(setting) != settings->end())
retVal = settings->value(setting)->getValue();
return retVal;
return "";
}
CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
@ -307,49 +277,3 @@ CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
assert(mUserSettingsInstance);
return *mUserSettingsInstance;
}
void CSMSettings::UserSettings::displayFileErrorMessage(const QString &message, bool isReadOnly)
{
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
if (!isReadOnly)
msgBox.setText (mReadWriteMessage + message);
else
msgBox.setText (message);
msgBox.exec();
}
CSMSettings::SettingMap *
CSMSettings::UserSettings::getValidSettings (const QString &sectionName) const
{
SettingMap *settings = 0;
//copy the default values for the entire section if it's not found
if (mSectionSettings.find(sectionName) == mSectionSettings.end())
{
if (mEditorSettingDefaults.find(sectionName) != mEditorSettingDefaults.end())
settings = mEditorSettingDefaults.value (sectionName);
}
//otherwise, iterate the section's settings, looking for missing values and replacing them with defaults.
else
{
SettingMap *loadedSettings = mSectionSettings[sectionName];
SettingMap *defaultSettings = mEditorSettingDefaults[sectionName];
foreach (QString key, defaultSettings->uniqueKeys())
{
//write the default value to the loaded settings
if (loadedSettings->find((key))==loadedSettings->end())
loadedSettings->insert(key, defaultSettings->value(key));
}
settings = mSectionSettings.value (sectionName);
}
return settings;
}

@ -8,7 +8,7 @@
#include <boost/filesystem/path.hpp>
#include "support.hpp"
#include "settingmanager.hpp"
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
@ -21,17 +21,15 @@ class QFile;
namespace CSMSettings {
struct UserSettings: public QObject
class UserSettings: public SettingManager
{
Q_OBJECT
SectionMap mSectionSettings;
SectionMap mEditorSettingDefaults;
static UserSettings *mUserSettingsInstance;
QString mUserFilePath;
Files::ConfigurationManager mCfgMgr;
QString mReadOnlyMessage;
QString mReadWriteMessage;
@ -47,48 +45,19 @@ namespace CSMSettings {
void operator= (UserSettings const &); //not implemented
/// Writes settings to the last loaded settings file
bool writeSettings(QMap<QString, SettingList *> &sections);
/// Called from editor to trigger signal to update the specified setting.
/// If no setting name is specified, all settings found in the specified section are updated.
void updateSettings (const QString &sectionName, const QString &settingName = "");
bool writeSettings();
/// Retrieves the settings file at all three levels (global, local and user).
/// \todo Multi-valued settings are not fully implemented. Setting values
/// \todo loaded in later files will always overwrite previously loaded values.
void loadSettings (const QString &fileName);
/// Returns the entire map of settings across all sections
const SectionMap &getSectionMap () const;
/// Writes settings to the user's config file path
void saveSettings (const QMap <QString, QStringList > &settingMap);
const SettingMap *getSettings (const QString &sectionName) const;
/// Retrieves the value as a QString of the specified setting in the specified section
QString getSetting(const QString &section, const QString &setting) const;
QString settingValue (const QString &settingKey);
private:
/// Opens a QTextStream from the provided path as read-only or read-write.
QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const;
/// Parses a setting file specified in filePath from the provided text stream.
bool loadFromFile (const QString &filePath = "");
/// merge the passed map into mSectionSettings
void mergeMap (const SectionMap &);
void displayFileErrorMessage(const QString &message, bool isReadOnly);
void buildEditorSettingDefaults();
SettingMap *getValidSettings (const QString &sectionName) const;
signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
void buildSettingModelDefaults();
};
}
#endif // USERSETTINGS_HPP

@ -9,6 +9,9 @@
namespace CSMWorld
{
/// \brief Wrapper for Cell record
///
/// \attention The mData.mX and mData.mY fields of the ESM::Cell struct are not used.
/// Exterior cell coordinates are encoded in the cell ID.
struct Cell : public ESM::Cell
{
std::string mId;

@ -0,0 +1,60 @@
#include "cellcoordinates.hpp"
#include <ostream>
#include <sstream>
CSMWorld::CellCoordinates::CellCoordinates() : mX (0), mY (0) {}
CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {}
int CSMWorld::CellCoordinates::getX() const
{
return mX;
}
int CSMWorld::CellCoordinates::getY() const
{
return mY;
}
CSMWorld::CellCoordinates CSMWorld::CellCoordinates::move (int x, int y) const
{
return CellCoordinates (mX + x, mY + y);
}
std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) const
{
// we ignore the worldspace for now, since there is only one (will change in 1.1)
std::ostringstream stream;
stream << "#" << mX << " " << mY;
return stream.str();
}
bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right)
{
return left.getX()==right.getX() && left.getY()==right.getY();
}
bool CSMWorld::operator!= (const CellCoordinates& left, const CellCoordinates& right)
{
return !(left==right);
}
bool CSMWorld::operator< (const CellCoordinates& left, const CellCoordinates& right)
{
if (left.getX()<right.getX())
return true;
if (left.getX()>right.getX())
return false;
return left.getY()<right.getY();
}
std::ostream& CSMWorld::operator<< (std::ostream& stream, const CellCoordinates& coordiantes)
{
return stream << coordiantes.getX() << ", " << coordiantes.getY();
}

@ -0,0 +1,42 @@
#ifndef CSM_WOLRD_CELLCOORDINATES_H
#define CSM_WOLRD_CELLCOORDINATES_H
#include <iosfwd>
#include <string>
#include <QMetaType>
namespace CSMWorld
{
class CellCoordinates
{
int mX;
int mY;
public:
CellCoordinates();
CellCoordinates (int x, int y);
int getX() const;
int getY() const;
CellCoordinates move (int x, int y) const;
///< Return a copy of *this, moved by the given offset.
std::string getId (const std::string& worldspace) const;
///< Return the ID for the cell at these coordinates.
};
bool operator== (const CellCoordinates& left, const CellCoordinates& right);
bool operator!= (const CellCoordinates& left, const CellCoordinates& right);
bool operator< (const CellCoordinates& left, const CellCoordinates& right);
std::ostream& operator<< (std::ostream& stream, const CellCoordinates& coordiantes);
}
Q_DECLARE_METATYPE (CSMWorld::CellCoordinates)
#endif

@ -0,0 +1,83 @@
#include "cellselection.hpp"
#include <cmath>
#include <stdexcept>
#include <limits>
CSMWorld::CellSelection::Iterator CSMWorld::CellSelection::begin() const
{
return mCells.begin();
}
CSMWorld::CellSelection::Iterator CSMWorld::CellSelection::end() const
{
return mCells.end();
}
bool CSMWorld::CellSelection::add (const CellCoordinates& coordinates)
{
return mCells.insert (coordinates).second;
}
void CSMWorld::CellSelection::remove (const CellCoordinates& coordinates)
{
mCells.erase (coordinates);
}
bool CSMWorld::CellSelection::has (const CellCoordinates& coordinates) const
{
return mCells.find (coordinates)!=end();
}
int CSMWorld::CellSelection::getSize() const
{
return mCells.size();
}
CSMWorld::CellCoordinates CSMWorld::CellSelection::getCentre() const
{
if (mCells.empty())
throw std::logic_error ("call of getCentre on empty cell selection");
double x = 0;
double y = 0;
for (Iterator iter = begin(); iter!=end(); ++iter)
{
x += iter->getX();
y += iter->getY();
}
x /= mCells.size();
y /= mCells.size();
Iterator closest = begin();
double distance = std::numeric_limits<double>::max();
for (Iterator iter (begin()); iter!=end(); ++iter)
{
double deltaX = x - iter->getX();
double deltaY = y - iter->getY();
double delta = std::sqrt (deltaX * deltaX + deltaY * deltaY);
if (delta<distance)
{
distance = delta;
closest = iter;
}
}
return *closest;
}
void CSMWorld::CellSelection::move (int x, int y)
{
Container moved;
for (Iterator iter = begin(); iter!=end(); ++iter)
moved.insert (iter->move (x, y));
mCells.swap (moved);
}

@ -0,0 +1,57 @@
#ifndef CSM_WOLRD_CELLSELECTION_H
#define CSM_WOLRD_CELLSELECTION_H
#include <set>
#include <QMetaType>
#include "cellcoordinates.hpp"
namespace CSMWorld
{
/// \brief Selection of cells in a paged worldspace
///
/// \note The CellSelection does not specify the worldspace it applies to.
class CellSelection
{
public:
typedef std::set<CellCoordinates> Container;
typedef Container::const_iterator Iterator;
private:
Container mCells;
public:
Iterator begin() const;
Iterator end() const;
bool add (const CellCoordinates& coordinates);
///< Ignored if the cell specified by \a coordinates is already part of the selection.
///
/// \return Was a cell added to the collection?
void remove (const CellCoordinates& coordinates);
///< ignored if the cell specified by \a coordinates is not part of the selection.
bool has (const CellCoordinates& coordinates) const;
///< \return Is the cell specified by \a coordinates part of the selection?
int getSize() const;
///< Return number of cells.
CellCoordinates getCentre() const;
///< Return the selected cell that is closest to the geometric centre of the selection.
///
/// \attention This function must not be called on selections that are empty.
void move (int x, int y);
};
}
Q_DECLARE_METATYPE (CSMWorld::CellSelection)
#endif

@ -785,7 +785,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct RegionColumn : public Column<ESXRecordT>
{
RegionColumn() : Column<ESXRecordT> (Columns::ColumnId_Region, ColumnBase::Display_String) {}
RegionColumn() : Column<ESXRecordT> (Columns::ColumnId_Region, ColumnBase::Display_Region) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{

@ -38,14 +38,3 @@ std::string CSMWorld::RefCollection::getNewId()
stream << "ref#" << mNextId++;
return stream.str();
}
void CSMWorld::RefCollection::cloneRecord(const std::string& origin,
const std::string& destination,
const CSMWorld::UniversalId::Type type,
const CSMWorld::UniversalId::ArgumentType argumentType)
{
Record<CSMWorld::CellRef> clone(getRecord(origin));
clone.mState = CSMWorld::RecordBase::State_ModifiedOnly;
clone.get().mId = destination;
insertRecord(clone, getAppendIndex(destination, type), type);
}

@ -26,11 +26,6 @@ namespace CSMWorld
///< Load a sequence of references.
std::string getNewId();
void cloneRecord(const std::string& origin,
const std::string& destination,
const CSMWorld::UniversalId::Type type,
const CSMWorld::UniversalId::ArgumentType argumentType);
};
}

@ -1,6 +1,7 @@
#include "regionmap.hpp"
#include <cmath>
#include <algorithm>
#include <QBrush>
@ -25,17 +26,28 @@ CSMWorld::RegionMap::CellDescription::CellDescription (const Record<Cell>& cell)
mName = cell2.mName;
}
CSMWorld::RegionMap::CellIndex CSMWorld::RegionMap::getIndex (const QModelIndex& index) const
CSMWorld::CellCoordinates CSMWorld::RegionMap::getIndex (const QModelIndex& index) const
{
return CellIndex (index.column()+mMin.first,
(mMax.second-mMin.second - index.row()-1)+mMin.second);
return mMin.move (index.column(), mMax.getY()-mMin.getY() - index.row()-1);
}
QModelIndex CSMWorld::RegionMap::getIndex (const CellIndex& index) const
QModelIndex CSMWorld::RegionMap::getIndex (const CellCoordinates& index) const
{
// I hate you, Qt API naming scheme!
return QAbstractTableModel::index (mMax.second-mMin.second - (index.second-mMin.second)-1,
index.first-mMin.first);
return QAbstractTableModel::index (mMax.getY()-mMin.getY() - (index.getY()-mMin.getY())-1,
index.getX()-mMin.getX());
}
CSMWorld::CellCoordinates CSMWorld::RegionMap::getIndex (const Cell& cell) const
{
std::istringstream stream (cell.mId);
char ignore;
int x = 0;
int y = 0;
stream >> ignore >> x >> y;
return CellCoordinates (x, y);
}
void CSMWorld::RegionMap::buildRegions()
@ -70,21 +82,21 @@ void CSMWorld::RegionMap::buildMap()
{
CellDescription description (cell);
CellIndex index (cell2.mData.mX, cell2.mData.mY);
CellCoordinates index = getIndex (cell2);
mMap.insert (std::make_pair (index, description));
}
}
std::pair<CellIndex, CellIndex> mapSize = getSize();
std::pair<CellCoordinates, CellCoordinates> mapSize = getSize();
mMin = mapSize.first;
mMax = mapSize.second;
}
void CSMWorld::RegionMap::addCell (const CellIndex& index, const CellDescription& description)
void CSMWorld::RegionMap::addCell (const CellCoordinates& index, const CellDescription& description)
{
std::map<CellIndex, CellDescription>::iterator cell = mMap.find (index);
std::map<CellCoordinates, CellDescription>::iterator cell = mMap.find (index);
if (cell!=mMap.end())
{
@ -114,7 +126,7 @@ void CSMWorld::RegionMap::addCells (int start, int end)
if (cell2.isExterior())
{
CellIndex index (cell2.mData.mX, cell2.mData.mY);
CellCoordinates index = getIndex (cell2);
CellDescription description (cell);
@ -123,9 +135,9 @@ void CSMWorld::RegionMap::addCells (int start, int end)
}
}
void CSMWorld::RegionMap::removeCell (const CellIndex& index)
void CSMWorld::RegionMap::removeCell (const CellCoordinates& index)
{
std::map<CellIndex, CellDescription>::iterator cell = mMap.find (index);
std::map<CellCoordinates, CellDescription>::iterator cell = mMap.find (index);
if (cell!=mMap.end())
{
@ -160,7 +172,7 @@ void CSMWorld::RegionMap::updateRegions (const std::vector<std::string>& regions
std::for_each (regions2.begin(), regions2.end(), &Misc::StringUtils::lowerCase);
std::sort (regions2.begin(), regions2.end());
for (std::map<CellIndex, CellDescription>::const_iterator iter (mMap.begin());
for (std::map<CellCoordinates, CellDescription>::const_iterator iter (mMap.begin());
iter!=mMap.end(); ++iter)
{
if (!iter->second.mRegion.empty() &&
@ -176,90 +188,57 @@ void CSMWorld::RegionMap::updateRegions (const std::vector<std::string>& regions
void CSMWorld::RegionMap::updateSize()
{
std::pair<CellIndex, CellIndex> size = getSize();
std::pair<CellCoordinates, CellCoordinates> size = getSize();
if (int diff = size.first.getX() - mMin.getX())
{
int diff = size.first.first - mMin.first;
if (diff<0)
{
beginInsertColumns (QModelIndex(), 0, -diff-1);
mMin.first = size.first.first;
endInsertColumns();
}
else if (diff>0)
{
beginRemoveColumns (QModelIndex(), 0, diff-1);
mMin.first = size.first.first;
endRemoveColumns();
}
beginInsertColumns (QModelIndex(), 0, std::abs (diff)-1);
mMin = CellCoordinates (size.first.getX(), mMin.getY());
endInsertColumns();
}
if (int diff = size.first.getY() - mMin.getY())
{
int diff = size.first.second - mMin.second;
if (diff<0)
{
beginInsertRows (QModelIndex(), 0, -diff-1);
mMin.second = size.first.second;
endInsertRows();
}
else if (diff>0)
{
beginRemoveRows (QModelIndex(), 0, diff-1);
mMin.second = size.first.second;
endRemoveRows();
}
beginInsertRows (QModelIndex(), 0, std::abs (diff)-1);
mMin = CellCoordinates (mMin.getX(), size.first.getY());
endInsertRows();
}
if (int diff = size.second.getX() - mMax.getX())
{
int diff = size.second.first - mMax.first;
int columns = columnCount();
if (diff>0)
{
int columns = columnCount();
beginInsertColumns (QModelIndex(), columns, columns+diff-1);
mMax.first = size.second.first;
endInsertColumns();
}
else if (diff<0)
{
int columns = columnCount();
else
beginRemoveColumns (QModelIndex(), columns+diff, columns-1);
mMax.first = size.second.first;
endRemoveColumns();
}
mMax = CellCoordinates (size.second.getX(), mMax.getY());
endInsertColumns();
}
if (int diff = size.second.getY() - mMax.getY())
{
int diff = size.second.second - mMax.second;
int rows = rowCount();
if (diff>0)
{
int rows = rowCount();
beginInsertRows (QModelIndex(), rows, rows+diff-1);
mMax.second = size.second.second;
endInsertRows();
}
else if (diff<0)
{
int rows = rowCount();
else
beginRemoveRows (QModelIndex(), rows+diff, rows-1);
mMax.second = size.second.second;
endRemoveRows();
}
mMax = CellCoordinates (mMax.getX(), size.second.getY());
endInsertRows();
}
}
std::pair<CSMWorld::RegionMap::CellIndex, CSMWorld::RegionMap::CellIndex> CSMWorld::RegionMap::getSize()
const
std::pair<CSMWorld::CellCoordinates, CSMWorld::CellCoordinates> CSMWorld::RegionMap::getSize() const
{
const IdCollection<Cell>& cells = mData.getCells();
int size = cells.getSize();
CellIndex min (0, 0);
CellIndex max (0, 0);
CellCoordinates min (0, 0);
CellCoordinates max (0, 0);
for (int i=0; i<size; ++i)
{
@ -269,24 +248,24 @@ std::pair<CSMWorld::RegionMap::CellIndex, CSMWorld::RegionMap::CellIndex> CSMWor
if (cell2.isExterior())
{
CellIndex index (cell2.mData.mX, cell2.mData.mY);
CellCoordinates index = getIndex (cell2);
if (min==max)
{
min = index;
max = std::make_pair (min.first+1, min.second+1);
max = min.move (1, 1);
}
else
{
if (index.first<min.first)
min.first = index.first;
else if (index.first>=max.first)
max.first = index.first + 1;
if (index.second<min.second)
min.second = index.second;
else if (index.second>=max.second)
max.second = index.second + 1;
if (index.getX()<min.getX())
min = CellCoordinates (index.getX(), min.getY());
else if (index.getX()>=max.getX())
max = CellCoordinates (index.getX()+1, max.getY());
if (index.getY()<min.getY())
min = CellCoordinates (min.getX(), index.getY());
else if (index.getY()>=max.getY())
max = CellCoordinates (max.getX(), index.getY() + 1);
}
}
}
@ -323,7 +302,7 @@ int CSMWorld::RegionMap::rowCount (const QModelIndex& parent) const
if (parent.isValid())
return 0;
return mMax.second-mMin.second;
return mMax.getY()-mMin.getY();
}
int CSMWorld::RegionMap::columnCount (const QModelIndex& parent) const
@ -331,7 +310,7 @@ int CSMWorld::RegionMap::columnCount (const QModelIndex& parent) const
if (parent.isValid())
return 0;
return mMax.first-mMin.first;
return mMax.getX()-mMin.getX();
}
QVariant CSMWorld::RegionMap::data (const QModelIndex& index, int role) const
@ -343,7 +322,7 @@ QVariant CSMWorld::RegionMap::data (const QModelIndex& index, int role) const
{
/// \todo GUI class in non-GUI code. Needs to be addressed eventually.
std::map<CellIndex, CellDescription>::const_iterator cell =
std::map<CellCoordinates, CellDescription>::const_iterator cell =
mMap.find (getIndex (index));
if (cell!=mMap.end())
@ -370,13 +349,13 @@ QVariant CSMWorld::RegionMap::data (const QModelIndex& index, int role) const
if (role==Qt::ToolTipRole)
{
CellIndex cellIndex = getIndex (index);
CellCoordinates cellIndex = getIndex (index);
std::ostringstream stream;
stream << cellIndex.first << ", " << cellIndex.second;
stream << cellIndex;
std::map<CellIndex, CellDescription>::const_iterator cell =
std::map<CellCoordinates, CellDescription>::const_iterator cell =
mMap.find (cellIndex);
if (cell!=mMap.end())
@ -406,15 +385,33 @@ QVariant CSMWorld::RegionMap::data (const QModelIndex& index, int role) const
return QString::fromUtf8 (stream.str().c_str());
}
if (role==Role_Region)
{
CellCoordinates cellIndex = getIndex (index);
std::map<CellCoordinates, CellDescription>::const_iterator cell =
mMap.find (cellIndex);
if (cell!=mMap.end() && !cell->second.mRegion.empty())
return QString::fromUtf8 (Misc::StringUtils::lowerCase (cell->second.mRegion).c_str());
}
if (role==Role_CellId)
{
CellCoordinates cellIndex = getIndex (index);
std::ostringstream stream;
stream << "#" << cellIndex.getX() << " " << cellIndex.getY();
return QString::fromUtf8 (stream.str().c_str());
}
return QVariant();
}
Qt::ItemFlags CSMWorld::RegionMap::flags (const QModelIndex& index) const
{
if (mMap.find (getIndex (index))!=mMap.end())
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
return 0;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
void CSMWorld::RegionMap::regionsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
@ -491,11 +488,7 @@ void CSMWorld::RegionMap::cellsAboutToBeRemoved (const QModelIndex& parent, int
const Cell& cell2 = cell.get();
if (cell2.isExterior())
{
CellIndex index (cell2.mData.mX, cell2.mData.mY);
removeCell (index);
}
removeCell (getIndex (cell2));
}
}

@ -9,6 +9,7 @@
#include "record.hpp"
#include "cell.hpp"
#include "cellcoordinates.hpp"
namespace CSMWorld
{
@ -23,7 +24,11 @@ namespace CSMWorld
public:
typedef std::pair<int, int> CellIndex;
enum Role
{
Role_Region = Qt::UserRole,
Role_CellId = Qt::UserRole+1
};
private:
@ -39,27 +44,29 @@ namespace CSMWorld
};
Data& mData;
std::map<CellIndex, CellDescription> mMap;
CellIndex mMin; ///< inclusive
CellIndex mMax; ///< exclusive
std::map<CellCoordinates, CellDescription> mMap;
CellCoordinates mMin; ///< inclusive
CellCoordinates mMax; ///< exclusive
std::map<std::string, unsigned int> mColours; ///< region ID, colour (RGBA)
CellIndex getIndex (const QModelIndex& index) const;
CellCoordinates getIndex (const QModelIndex& index) const;
///< Translates a Qt model index into a cell index (which can contain negative components)
QModelIndex getIndex (const CellIndex& index) const;
QModelIndex getIndex (const CellCoordinates& index) const;
CellCoordinates getIndex (const Cell& cell) const;
void buildRegions();
void buildMap();
void addCell (const CellIndex& index, const CellDescription& description);
void addCell (const CellCoordinates& index, const CellDescription& description);
///< May be called on a cell that is already in the map (in which case an update is
// performed)
void addCells (int start, int end);
void removeCell (const CellIndex& index);
void removeCell (const CellCoordinates& index);
///< May be called on a cell that is not in the map (in which case the call is ignored)
void addRegion (const std::string& region, unsigned int colour);
@ -78,7 +85,7 @@ namespace CSMWorld
void updateSize();
std::pair<CellIndex, CellIndex> getSize() const;
std::pair<CellCoordinates, CellCoordinates> getSize() const;
public:
@ -89,6 +96,8 @@ namespace CSMWorld
virtual int columnCount (const QModelIndex& parent = QModelIndex()) const;
virtual QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const;
///< \note Calling this function with role==Role_CellId may return the ID of a cell
/// that does not exist.
virtual Qt::ItemFlags flags (const QModelIndex& index) const;

@ -12,16 +12,15 @@ CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
return mUniversalId;
}
void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
}
void CSVDoc::SubView::setStatusBar (bool show) {}
void CSVDoc::SubView::useHint (const std::string& hint) {}
void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &)
{}
void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id)
{
mUniversalId = id;
setWindowTitle (mUniversalId.toString().c_str());
}
}

@ -37,7 +37,6 @@ namespace CSVDoc
CSMWorld::UniversalId getUniversalId() const;
virtual void setEditLock (bool locked) = 0;
virtual void updateEditorSetting (const QString &, const QString &);
virtual void setStatusBar (bool show);
///< Default implementation: ignored
@ -48,6 +47,10 @@ namespace CSVDoc
signals:
void focusId (const CSMWorld::UniversalId& universalId, const std::string& hint);
public slots:
virtual void updateUserSetting
(const QString &, const QStringList &);
};
}

@ -12,7 +12,7 @@
#include "../../model/doc/document.hpp"
#include "../world/subviews.hpp"
#include "../tools/subviews.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "../../model/settings/usersettings.hpp"
#include "viewmanager.hpp"
#include "operations.hpp"
#include "subview.hpp"
@ -235,8 +235,11 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
mViewTotal (totalViews)
{
QString width = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Width"));
QString height = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Height"));
QString width = CSMSettings::UserSettings::instance().settingValue
("Window Size.Width");
QString height = CSMSettings::UserSettings::instance().settingValue
("Window Size.Height");
resize (width.toInt(), height.toInt());
@ -336,7 +339,10 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&)));
CSMSettings::UserSettings::instance().updateSettings("Display Format");
connect (&CSMSettings::UserSettings::instance(),
SIGNAL (userSettingUpdated (const QString &, const QStringList &)),
view,
SLOT (updateUserSetting (const QString &, const QStringList &)));
view->show();
}
@ -484,25 +490,9 @@ void CSVDoc::View::resizeViewHeight (int height)
resize (geometry().width(), height);
}
void CSVDoc::View::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
if ( (settingName == "Record Status Display") || (settingName == "Referenceable ID Type Display") )
{
foreach (QObject *view, mSubViewWindow.children())
{
// not all mSubviewWindow children are CSVDoc::Subview objects
CSVDoc::SubView *subview = dynamic_cast<CSVDoc::SubView *>(view);
if (subview)
subview->updateEditorSetting (settingName, settingValue);
}
}
else if (settingName == "Width")
resizeViewWidth (settingValue.toInt());
else if (settingName == "Height")
resizeViewHeight (settingValue.toInt());
}
void CSVDoc::View::updateUserSetting
(const QString &name, const QStringList &list)
{}
void CSVDoc::View::toggleShowStatusBar (bool show)
{

@ -126,6 +126,8 @@ namespace CSVDoc
void abortOperation (int type);
void updateUserSetting (const QString &, const QStringList &);
private slots:
void newView();

@ -15,7 +15,8 @@
#include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "../../model/settings/usersettings.hpp"
#include "view.hpp"
@ -83,9 +84,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
mDelegateFactories->add (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory (
CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone));
connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
}
CSVDoc::ViewManager::~ViewManager()
@ -119,6 +117,11 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest()));
connect (&CSMSettings::UserSettings::instance(),
SIGNAL (userSettingUpdated(const QString &, const QStringList &)),
view,
SLOT (updateUserSetting (const QString &, const QStringList &)));
updateIndices();
return view;
@ -313,9 +316,3 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
if (notifySaveOnClose (view))
QApplication::instance()->exit();
}
void CSVDoc::ViewManager::slotUpdateEditorSetting (const QString &settingName, const QString &settingValue)
{
foreach (CSVDoc::View *view, mViews)
view->updateEditorSetting (settingName, settingValue);
}

@ -76,9 +76,6 @@ namespace CSVDoc
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
void onExitWarningHandler(int state, CSMDoc::Document* document);
/// connected to update signal in UserSettings
void slotUpdateEditorSetting (const QString &, const QString &);
};
}

@ -193,11 +193,4 @@ std::string CSVFilter::EditWidget::generateFilter (std::pair< std::string, std::
}
return ss.str();
}
void CSVFilter::EditWidget::useFilterRequest (const std::string& idOfFilter)
{
clear();
insert(QString::fromUtf8(idOfFilter.c_str()));
}
}

@ -30,6 +30,9 @@ namespace CSVFilter
EditWidget (CSMWorld::Data& data, QWidget *parent = 0);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
signals:
void filterChanged (boost::shared_ptr<CSMFilter::Node> filter);
@ -47,10 +50,7 @@ namespace CSVFilter
void filterRowsInserted (const QModelIndex& parent, int start, int end);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
void useFilterRequest(const std::string& idOfFilter);
};
}

@ -15,23 +15,24 @@ CSVFilter::FilterBox::FilterBox (CSMWorld::Data& data, QWidget *parent)
layout->setContentsMargins (0, 0, 0, 0);
RecordFilterBox *recordFilterBox = new RecordFilterBox (data, this);
mRecordFilterBox = new RecordFilterBox (data, this);
layout->addWidget (recordFilterBox);
layout->addWidget (mRecordFilterBox);
setLayout (layout);
connect (recordFilterBox,
connect (mRecordFilterBox,
SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)),
this, SIGNAL (recordFilterChanged (boost::shared_ptr<CSMFilter::Node>)));
connect(this, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)),
recordFilterBox, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)));
connect(this, SIGNAL(useFilterRequest(const std::string&)), recordFilterBox, SIGNAL(useFilterRequest(const std::string&)));
setAcceptDrops(true);
}
void CSVFilter::FilterBox::setRecordFilter (const std::string& filter)
{
mRecordFilterBox->setFilter (filter);
}
void CSVFilter::FilterBox::dropEvent (QDropEvent* event)
{
std::vector<CSMWorld::UniversalId> data = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData())->getData();
@ -48,3 +49,9 @@ void CSVFilter::FilterBox::dragMoveEvent (QDragMoveEvent* event)
{
event->accept();
}
void CSVFilter::FilterBox::createFilterRequest (std::vector< std::pair< std::string, std::vector< std::string > > >& filterSource,
Qt::DropAction action)
{
mRecordFilterBox->createFilterRequest(filterSource, action);
}

@ -16,27 +16,33 @@ namespace CSMWorld
namespace CSVFilter
{
class RecordFilterBox;
class FilterBox : public QWidget
{
Q_OBJECT
RecordFilterBox *mRecordFilterBox;
public:
FilterBox (CSMWorld::Data& data, QWidget *parent = 0);
void setRecordFilter (const std::string& filter);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
private:
void dragEnterEvent (QDragEnterEvent* event);
void dropEvent (QDropEvent* event);
void dragMoveEvent(QDragMoveEvent *event);
public:
FilterBox (CSMWorld::Data& data, QWidget *parent = 0);
signals:
void recordFilterChanged (boost::shared_ptr<CSMFilter::Node> filter);
void recordDropped (std::vector<CSMWorld::UniversalId>& types, Qt::DropAction action);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
void useFilterRequest(const std::string& idOfFilter);
};
}

@ -15,18 +15,25 @@ CSVFilter::RecordFilterBox::RecordFilterBox (CSMWorld::Data& data, QWidget *pare
layout->addWidget (new QLabel ("Record Filter", this));
EditWidget *editWidget = new EditWidget (data, this);
mEdit = new EditWidget (data, this);
layout->addWidget (editWidget);
layout->addWidget (mEdit);
setLayout (layout);
connect (
editWidget, SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)),
mEdit, SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)),
this, SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)));
}
connect(this, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)),
editWidget, SLOT(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)));
void CSVFilter::RecordFilterBox::setFilter (const std::string& filter)
{
mEdit->clear();
mEdit->setText (QString::fromUtf8 (filter.c_str()));
}
connect(this, SIGNAL(useFilterRequest(const std::string&)), editWidget, SLOT(useFilterRequest(const std::string&)));
void CSVFilter::RecordFilterBox::createFilterRequest (std::vector< std::pair< std::string, std::vector< std::string > > >& filterSource,
Qt::DropAction action)
{
mEdit->createFilterRequest(filterSource, action);
}

@ -17,20 +17,28 @@ namespace CSMWorld
namespace CSVFilter
{
class EditWidget;
class RecordFilterBox : public QWidget
{
Q_OBJECT
EditWidget *mEdit;
public:
RecordFilterBox (CSMWorld::Data& data, QWidget *parent = 0);
signals:
void setFilter (const std::string& filter);
void useFilterRequest(const std::string& idOfFilter);
void filterChanged (boost::shared_ptr<CSMFilter::Node> filter);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
void useFilterRequest(const std::string& idOfFilter);
signals:
void filterChanged (boost::shared_ptr<CSMFilter::Node> filter);
};
}

@ -1,6 +1,47 @@
#include "pagedworldspacewidget.hpp"
#include <sstream>
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget *parent)
: WorldspaceWidget (parent)
{}
{}
void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
{
if (!hint.empty())
{
CSMWorld::CellSelection selection;
if (hint[0]=='c')
{
// syntax: c:#x1 y1; #x2 y2 (number of coordinate pairs can be 0 or larger)
char ignore;
std::istringstream stream (hint.c_str());
if (stream >> ignore)
{
char ignore1; // : or ;
char ignore2; // #
int x, y;
while (stream >> ignore1 >> ignore2 >> x >> y)
selection.add (CSMWorld::CellCoordinates (x, y));
/// \todo adjust camera position
}
}
else if (hint[0]=='r')
{
/// \todo implement 'r' type hints
}
setCellSelection (selection);
}
}
void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSelection& selection)
{
mSelection = selection;
emit cellSelectionChanged (mSelection);
}

@ -1,6 +1,8 @@
#ifndef OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
#define OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
#include "../../model/world/cellselection.hpp"
#include "worldspacewidget.hpp"
namespace CSVRender
@ -9,9 +11,22 @@ namespace CSVRender
{
Q_OBJECT
CSMWorld::CellSelection mSelection;
public:
PagedWorldspaceWidget (QWidget *parent);
///< \note Sets the cell area selection to an invalid value to indicate that currently
/// no cells are displayed. The cells to be displayed will be specified later through
/// hint system.
virtual void useViewHint (const std::string& hint);
void setCellSelection (const CSMWorld::CellSelection& selection);
signals:
void cellSelectionChanged (const CSMWorld::CellSelection& selection);
};
}

@ -26,6 +26,8 @@ void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
setNavigation (&mOrbit);
}
void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {}
void CSVRender::WorldspaceWidget::selectDefaultNavigationMode()
{
setNavigation (&m1st);

@ -33,6 +33,9 @@ namespace CSVRender
void selectDefaultNavigationMode();
virtual void useViewHint (const std::string& hint);
///< Default-implementation: ignored.
private slots:
void selectNavigationMode (const std::string& mode);

@ -1,112 +0,0 @@
#include "abstractblock.hpp"
CSVSettings::AbstractBlock::AbstractBlock(QWidget* parent)
: QObject (parent), mBox ( new GroupBox (parent) ), mWidgetParent (parent)
{}
CSVSettings::AbstractBlock::AbstractBlock(bool isVisible, QWidget* parent)
: QObject (parent), mBox ( new GroupBox (isVisible, parent)), mWidgetParent (parent)
{}
QLayout *CSVSettings::AbstractBlock::createLayout (Orientation direction,
bool isZeroMargin, QWidget* parent)
{
QLayout *layout = 0;
if (direction == Orient_Vertical)
layout = new QVBoxLayout (parent);
else
layout = new QHBoxLayout (parent);
if (isZeroMargin)
layout->setContentsMargins(0, 0, 0, 0);
return layout;
}
QGroupBox *CSVSettings::AbstractBlock::getGroupBox()
{
return mBox;
}
CSVSettings::AbstractWidget *CSVSettings::AbstractBlock::buildWidget (const QString& widgetName, WidgetDef &def,
QLayout *layout, bool isConnected) const
{
AbstractWidget *widg = 0;
switch (def.type)
{
case Widget_RadioButton:
widg = new SettingWidget<QRadioButton> (def, layout, mBox);
break;
case Widget_SpinBox:
widg = new SettingWidget<QSpinBox> (def, layout, mBox);
break;
case Widget_CheckBox:
widg = new SettingWidget<QCheckBox> (def, layout, mBox);
break;
case Widget_LineEdit:
widg = new SettingWidget<QLineEdit> (def, layout, mBox);
break;
case Widget_ListBox:
widg = new SettingWidget<QListWidget> (def, layout, mBox);
break;
case Widget_ComboBox:
widg = new SettingWidget<QComboBox> (def, layout, mBox);
break;
default:
break;
};
if (!mBox->layout())
mBox->setLayout(widg->getLayout());
widg->widget()->setObjectName(widgetName);
if (isConnected)
connect (widg, SIGNAL (signalUpdateItem (const QString &)), this, SLOT (slotUpdate (const QString &)));
connect (this, SIGNAL (signalUpdateWidget (const QString &)), widg, SLOT (slotUpdateWidget (const QString &) ));
return widg;
}
void CSVSettings::AbstractBlock::setVisible (bool isVisible)
{
mBox->setBorderVisibility (isVisible);
}
bool CSVSettings::AbstractBlock::isVisible () const
{
return mBox->borderVisibile();
}
QWidget *CSVSettings::AbstractBlock::getParent() const
{
return mWidgetParent;
}
void CSVSettings::AbstractBlock::slotUpdate (const QString &value)
{
slotUpdateSetting (objectName(), value);
}
void CSVSettings::AbstractBlock::slotSetEnabled(bool value)
{
mBox->setEnabled(value);
}
void CSVSettings::AbstractBlock::slotUpdateSetting (const QString &settingName, const QString &settingValue)
{
bool doEmit = true;
updateBySignal (settingName, settingValue, doEmit);
if (doEmit)
emit signalUpdateSetting (settingName, settingValue);
}

@ -1,82 +0,0 @@
#ifndef ABSTRACTBLOCK_HPP
#define ABSTRACTBLOCK_HPP
#include <QObject>
#include <QList>
#include "settingwidget.hpp"
#include "../../model/settings/settingsitem.hpp"
#include "groupbox.hpp"
namespace CSVSettings
{
/// Abstract base class for all blocks
class AbstractBlock : public QObject
{
Q_OBJECT
protected:
typedef QMap<QString, CSMSettings::SettingsItem*> SettingsItemMap;
GroupBox *mBox;
QWidget *mWidgetParent;
public:
explicit AbstractBlock (QWidget *parent = 0);
explicit AbstractBlock (bool isVisible, QWidget *parent = 0);
QGroupBox *getGroupBox();
void setVisible (bool isVisible);
bool isVisible() const;
virtual CSMSettings::SettingList *getSettings() = 0;
/// update settings found in the passed map and are encapsulated by the block
virtual bool updateSettings (const CSMSettings::SettingMap &settings) = 0;
/// update callback function called from update slot
/// used for updating application-level settings in the editor
virtual bool updateBySignal (const QString &name, const QString &value, bool &doEmit)
{ return false; }
protected:
/// Creates the layout for the block's QGroupBox
QLayout *createLayout (Orientation direction, bool isZeroMargin, QWidget* parent = 0);
/// Creates widgets that exist as direct children of the block
AbstractWidget *buildWidget (const QString &widgetName, WidgetDef &wDef,
QLayout *layout = 0, bool isConnected = true) const;
QWidget *getParent() const;
public slots:
/// enables / disables block-level widgets based on signals from other widgets
/// used in ToggleBlock
void slotSetEnabled (bool value);
/// receives updates to applicaion-level settings in the Editor
void slotUpdateSetting (const QString &settingName, const QString &settingValue);
private slots:
/// receives updates to a setting in the block pushed from the application level
void slotUpdate (const QString &value);
signals:
/// signal to UserSettings instance
void signalUpdateSetting (const QString &propertyName, const QString &propertyValue);
/// signal to widget for updating widget value
void signalUpdateWidget (const QString & value);
/// ProxyBlock use only.
/// Name and value correspond to settings for which the block is a proxy.
void signalUpdateProxySetting (const QString &propertyName, const QString &propertyValue);
};
}
#endif // ABSTRACTBLOCK_HPP

@ -1,44 +0,0 @@
#include "abstractpage.hpp"
#include <QGroupBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QRadioButton>
#include <QCheckBox>
#include <QSpinBox>
#include <QComboBox>
#include <QLineEdit>
#include <QMargins>
CSVSettings::AbstractPage::AbstractPage(QWidget *parent):
QWidget(parent)
{
QGridLayout *pageLayout = new QGridLayout(this);
setLayout (pageLayout);
}
CSVSettings::AbstractPage::AbstractPage(const QString &pageName, QWidget *parent):
QWidget(parent)
{
QWidget::setObjectName (pageName);
QGridLayout *pageLayout = new QGridLayout(this);
setLayout (pageLayout);
}
CSVSettings::AbstractPage::~AbstractPage()
{
}
CSMSettings::SettingList *CSVSettings::AbstractPage::getSettings()
{
CSMSettings::SettingList *settings = new CSMSettings::SettingList();
foreach (AbstractBlock *block, mAbstractBlocks)
{
CSMSettings::SettingList *groupSettings = block->getSettings();
settings->append (*groupSettings);
}
return settings;
}

@ -1,70 +0,0 @@
#ifndef ABSTRACTPAGE_HPP
#define ABSTRACTPAGE_HPP
#include <QWidget>
#include <QList>
#include <QLayout>
#include "abstractblock.hpp"
class SettingMap;
class SettingList;
namespace CSVSettings {
typedef QList<AbstractBlock *> AbstractBlockList;
/// Abstract base class for all setting pages in the dialog
/// \todo Scripted implementation of settings should eliminate the need
/// \todo derive page classes.
/// \todo AbstractPage should be replaced with a general page construction class.
class AbstractPage: public QWidget
{
protected:
AbstractBlockList mAbstractBlocks;
public:
AbstractPage(QWidget *parent = 0);
AbstractPage (const QString &pageName, QWidget* parent = 0);
~AbstractPage();
virtual void setupUi() = 0;
/// triggers widgiet initialization at the page level. All widgets updated to
/// current setting values
virtual void initializeWidgets (const CSMSettings::SettingMap &settings) = 0;
/// retrieve the list of settings local to the page.
CSMSettings::SettingList *getSettings();
void setObjectName();
protected:
/// Create a block for the page.
/// Block is constructed using passed definition struct
/// Page level-layout is created and assigned
template <typename S, typename T>
AbstractBlock *buildBlock (T *def)
{
S *block = new S (this);
int ret = block->build (def);
if (ret < 0)
return 0;
QGroupBox *box = block->getGroupBox();
QWidget::layout()->addWidget (box);
return block;
}
};
}
#endif // ABSTRACTPAGE_HPP

@ -1,78 +0,0 @@
#include "abstractwidget.hpp"
#include <QLayout>
#include <QLabel>
void CSVSettings::AbstractWidget::build(QWidget *widget, WidgetDef &def, bool noLabel)
{
if (!mLayout)
createLayout(def.orientation, true);
buildLabelAndWidget (widget, def, noLabel);
}
void CSVSettings::AbstractWidget::buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel)
{
if (def.widgetWidth > -1)
widget->setFixedWidth (def.widgetWidth);
if (!(def.caption.isEmpty() || noLabel) )
{
QLabel *label = new QLabel (def.caption, &dynamic_cast<QWidget &>( *parent()));
label->setBuddy (widget);
mLayout->addWidget (label);
if (def.labelWidth > -1)
label->setFixedWidth(def.labelWidth);
}
mLayout->addWidget (widget);
mLayout->setAlignment (widget, getAlignment (def.widgetAlignment));
}
void CSVSettings::AbstractWidget::createLayout
(Orientation direction, bool isZeroMargin)
{
if (direction == Orient_Vertical)
mLayout = new QVBoxLayout ();
else
mLayout = new QHBoxLayout ();
if (isZeroMargin)
mLayout->setContentsMargins(0, 0, 0, 0);
}
QFlags<Qt::AlignmentFlag> CSVSettings::AbstractWidget::getAlignment (CSVSettings::Alignment flag)
{
return QFlags<Qt::AlignmentFlag>(static_cast<int>(flag));
}
QLayout *CSVSettings::AbstractWidget::getLayout()
{
return mLayout;
}
void CSVSettings::AbstractWidget::slotUpdateWidget (const QString &value)
{
updateWidget (value);
}
void CSVSettings::AbstractWidget::slotUpdateItem(const QString &value)
{
emit signalUpdateItem (value);
}
void CSVSettings::AbstractWidget::slotUpdateItem(bool value)
{
if (value)
emit signalUpdateItem (widget()->objectName());
}
void CSVSettings::AbstractWidget::slotUpdateItem(int value)
{
emit signalUpdateItem (QString::number(value));
}
void CSVSettings::AbstractWidget::slotUpdateItem (QListWidgetItem* current, QListWidgetItem* previous)
{}

@ -1,69 +0,0 @@
#ifndef ABSTRACTWIDGET_HPP
#define ABSTRACTWIDGET_HPP
#include <QWidget>
#include "support.hpp"
class QLayout;
namespace CSVSettings
{
/// Abstract base class for widgets which are used in user preferences dialog
class AbstractWidget : public QObject
{
Q_OBJECT
QLayout *mLayout;
public:
/// Passed layout is assigned the constructed widget.
/// if no layout is passed, one is created.
explicit AbstractWidget (QLayout *layout = 0, QWidget* parent = 0)
: QObject (parent), mLayout (layout)
{}
/// retrieve layout for insertion into itemblock
QLayout *getLayout();
/// create the derived widget instance
void build (QWidget* widget, WidgetDef &def, bool noLabel = false);
/// reference to the derived widget instance
virtual QWidget *widget() = 0;
protected:
/// Callback called by receiving slot for widget udpates
virtual void updateWidget (const QString &value) = 0;
/// Converts user-defined enum to Qt equivalents
QFlags<Qt::AlignmentFlag> getAlignment (Alignment flag);
private:
/// Creates layout and assigns label and widget as appropriate
void createLayout (Orientation direction, bool isZeroMargin);
/// Creates label and widget according to passed definition
void buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel);
signals:
/// outbound update signal
void signalUpdateItem (const QString &value);
public slots:
/// receives inbound updates
void slotUpdateWidget (const QString &value);
/// Overloads for outbound updates from derived widget signal
void slotUpdateItem (const QString &value);
void slotUpdateItem (bool value);
void slotUpdateItem (int value);
void slotUpdateItem (QListWidgetItem* current, QListWidgetItem* previous);
};
}
#endif // ABSTRACTWIDGET_HPP

@ -1,50 +0,0 @@
#include "blankpage.hpp"
#include <QList>
#include <QListView>
#include <QGroupBox>
#include <QRadioButton>
#include <QDockWidget>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QStyle>
#ifdef Q_OS_MAC
#include <QPlastiqueStyle>
#endif
#include "../../model/settings/usersettings.hpp"
#include "groupblock.hpp"
#include "toggleblock.hpp"
CSVSettings::BlankPage::BlankPage(QWidget *parent):
AbstractPage("Blank", parent)
{
}
CSVSettings::BlankPage::BlankPage(const QString &title, QWidget *parent):
AbstractPage(title, parent)
{
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
QPlastiqueStyle *style = new QPlastiqueStyle;
//profilesComboBox->setStyle(style);
#endif
setupUi();
}
void CSVSettings::BlankPage::setupUi()
{
QGroupBox *pageBox = new QGroupBox(this);
layout()->addWidget(pageBox);
}
void CSVSettings::BlankPage::initializeWidgets (const CSMSettings::SettingMap &settings)
{
//iterate each item in each blocks in this section
//validate the corresponding setting against the defined valuelist if any.
foreach (AbstractBlock *block, mAbstractBlocks)
block->updateSettings (settings);
}

@ -1,28 +0,0 @@
#ifndef BLANKPAGE_HPP
#define BLANKPAGE_HPP
#include "abstractpage.hpp"
class QGroupBox;
namespace CSVSettings {
class UserSettings;
class AbstractBlock;
/// Derived page with no widgets
/// Reference use only.
class BlankPage : public AbstractPage
{
public:
BlankPage (QWidget *parent = 0);
BlankPage (const QString &title, QWidget *parent);
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings);
};
}
#endif // BLANKPAGE_HPP

@ -0,0 +1,91 @@
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QCheckBox>
#include <QRadioButton>
#include <QGroupBox>
#include <QAbstractButton>
#include "booleanview.hpp"
#include "../../model/settings/setting.hpp"
CSVSettings::BooleanView::BooleanView (CSMSettings::Setting *setting,
Page *parent)
: View (setting, parent)
{
foreach (const QString &value, setting->declaredValues())
{
QAbstractButton *button = 0;
if (isMultiValue())
button = new QCheckBox (value, this);
else
button = new QRadioButton (value, this);
connect (button, SIGNAL (clicked (bool)),
this, SLOT (slotToggled (bool)));
button->setObjectName (value);
addWidget (button);
mButtons[value] = button;
}
}
void CSVSettings::BooleanView::slotToggled (bool state)
{
//test only for true to avoid multiple selection updates with radiobuttons
if (!isMultiValue() && !state)
return;
QStringList values;
foreach (QString key, mButtons.keys())
{
if (mButtons.value(key)->isChecked())
values.append (key);
}
setSelectedValues (values, false);
View::updateView();
}
void CSVSettings::BooleanView::updateView (bool signalUpdate) const
{
QStringList values = selectedValues();
foreach (const QString &buttonName, mButtons.keys())
{
QAbstractButton *button = mButtons[buttonName];
//if the value is not found in the list, the widget is checked false
bool buttonValue = values.contains(buttonName);
//skip if the butotn value will not change
if (button->isChecked() == buttonValue)
continue;
//disable autoexclusive if it's enabled and we're setting
//the button value to false
bool switchExclusive = (!buttonValue && button->autoExclusive());
if (switchExclusive)
button->setAutoExclusive (false);
button->setChecked (buttonValue);
if (switchExclusive)
button->setAutoExclusive(true);
}
View::updateView (signalUpdate);
}
CSVSettings::BooleanView *CSVSettings::BooleanViewFactory::createView
(CSMSettings::Setting *setting,
Page *parent)
{
return new BooleanView (setting, parent);
}

@ -0,0 +1,44 @@
#ifndef CSVSETTINGS_BOOLEANVIEW_HPP
#define CSVSETTINGS_BOOELANVIEW_HPP
#include <QWidget>
#include <QAbstractButton>
#include "view.hpp"
#include "../../model/settings/support.hpp"
class QStringListModel;
namespace CSVSettings
{
class BooleanView : public View
{
Q_OBJECT
QMap <QString, QAbstractButton *> mButtons;
public:
explicit BooleanView (CSMSettings::Setting *setting,
Page *parent);
protected:
void updateView (bool signalUpdate = true) const;
private slots:
void slotToggled (bool state);
};
class BooleanViewFactory : public QObject, public IViewFactory
{
Q_OBJECT
public:
explicit BooleanViewFactory (QWidget *parent = 0)
: QObject (parent)
{}
BooleanView *createView (CSMSettings::Setting *setting,
Page *parent);
};
}
#endif // CSVSETTINGS_BOOLEANVIEW_HPP

@ -1,121 +0,0 @@
#include "customblock.hpp"
#include "groupblock.hpp"
#include "itemblock.hpp"
#include "proxyblock.hpp"
CSVSettings::CustomBlock::CustomBlock (QWidget *parent) : AbstractBlock (parent)
{
}
int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefList::iterator *it)
{
int retVal = 0;
GroupBlockDefList::iterator defaultIt;
GroupBlockDefList::iterator listIt = defList.begin();
GroupBlockDefList::iterator proxyIt = defaultIt;
if (it)
listIt = *it;
ProxyBlock *proxyBlock = new ProxyBlock(getParent());
for (; listIt != defList.end(); ++listIt)
{
if (!(*listIt)->isProxy)
retVal = buildGroupBlock (*listIt);
else
{
mGroupList << proxyBlock;
proxyIt = listIt;
}
}
if (proxyIt != defaultIt)
retVal = buildProxyBlock (*proxyIt, proxyBlock);
return retVal;
}
CSVSettings::GroupBox *CSVSettings::CustomBlock::buildGroupBox (Orientation orientation)
{
GroupBox *box = new GroupBox (false, mBox);
createLayout (orientation, true, box);
return box;
}
int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef *def)
{
GroupBlock *block = new GroupBlock (getParent());
mGroupList << block;
connect (block, SIGNAL (signalUpdateSetting(const QString &, const QString &)),
this, SLOT (slotUpdateSetting (const QString &, const QString &)));
return block->build(def);
}
int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef *def, ProxyBlock *block)
{
if (def->settingItems.size() != 1)
return -1;
int retVal = block->build(def);
if (retVal != 0)
return retVal;
// The first settingItem is the proxy setting, containing the list of settings bound to it.
foreach (QStringList *list, *(def->settingItems.at(0)->proxyList))
{
QString proxiedBlockName = list->at(0);
//iterate each group in the custom block, matching it to each proxied setting
//and connecting it appropriately
foreach (GroupBlock *groupBlock, mGroupList)
{
ItemBlock *proxiedBlock = groupBlock->getItemBlock (proxiedBlockName);
if (proxiedBlock)
{
block->addSetting(proxiedBlock, list);
//connect the proxy block's update signal to the custom block's slot
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SLOT (slotUpdateSetting (const QString &, const QString &)));
}
}
}
return 0;
}
CSMSettings::SettingList *CSVSettings::CustomBlock::getSettings()
{
CSMSettings::SettingList *settings = new CSMSettings::SettingList();
foreach (GroupBlock *block, mGroupList)
{
CSMSettings::SettingList *groupSettings = block->getSettings();
if (groupSettings)
settings->append(*groupSettings);
}
return settings;
}
bool CSVSettings::CustomBlock::updateSettings (const CSMSettings::SettingMap &settings)
{
bool success = true;
foreach (GroupBlock *block, mGroupList)
{
bool success2 = block->updateSettings (settings);
success = success && success2;
}
return success;
}

@ -1,47 +0,0 @@
#ifndef CUSTOMBLOCK_HPP
#define CUSTOMBLOCK_HPP
#include "abstractblock.hpp"
namespace CSVSettings
{
class ProxyBlock;
/// Base class for customized user preference setting blocks
/// Special block classes should be derived from CustomBlock
class CustomBlock : public AbstractBlock
{
protected:
GroupBlockList mGroupList;
public:
explicit CustomBlock (QWidget *parent = 0);
/// Update settings local to the block
bool updateSettings (const CSMSettings::SettingMap &settings);
/// Retrieve settings local to the block
CSMSettings::SettingList *getSettings();
/// construct the block using the passed definition
int build (GroupBlockDefList &defList, GroupBlockDefList::Iterator *it = 0);
protected:
/// construct the block groupbox
GroupBox *buildGroupBox (Orientation orientation);
private:
/// Construction function for creating a standard GroupBlock child
int buildGroupBlock(GroupBlockDef *def);
/// Construction function for creating a standard ProxyBlock child
int buildProxyBlock(GroupBlockDef *def, ProxyBlock *block);
};
}
#endif // CUSTOMBLOCK_HPP

@ -1,57 +0,0 @@
#include "datadisplayformatpage.hpp"
#include "groupblock.hpp"
#include "../../model/settings/usersettings.hpp"
CSVSettings::DataDisplayFormatPage::DataDisplayFormatPage(QWidget* parent) :
AbstractPage("Display Format", parent)
{
setupUi();
}
CSVSettings::GroupBlockDef *CSVSettings::DataDisplayFormatPage::setupDataDisplay( const QString &title)
{
GroupBlockDef *statusBlock = new GroupBlockDef(QString(title));
SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon Only");
*(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only");
WidgetDef statusWidget (Widget_RadioButton);
statusWidget.valueList = statusItem->valueList;
statusItem->widget = statusWidget;
statusBlock->settingItems << statusItem;
statusBlock->isZeroMargin = false;
return statusBlock;
}
void CSVSettings::DataDisplayFormatPage::setupUi()
{
mAbstractBlocks << buildBlock<GroupBlock> (setupDataDisplay ("Record Status Display"));
mAbstractBlocks << buildBlock<GroupBlock> (setupDataDisplay ("Referenceable ID Type Display"));
foreach (AbstractBlock *block, mAbstractBlocks)
{
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
}
connect ( this,
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()),
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::DataDisplayFormatPage::initializeWidgets (const CSMSettings::SettingMap &settings)
{
//iterate each item in each blocks in this section
//validate the corresponding setting against the defined valuelist if any.
for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin();
it_block != mAbstractBlocks.end(); ++it_block)
(*it_block)->updateSettings (settings);
}

@ -1,33 +0,0 @@
#ifndef EDITORPAGE_HPP
#define EDITORPAGE_HPP
#include "support.hpp"
#include "abstractpage.hpp"
namespace CSVSettings
{
class DataDisplayFormatPage : public AbstractPage
{
Q_OBJECT
public:
explicit DataDisplayFormatPage(QWidget *parent = 0);
void initializeWidgets (const CSMSettings::SettingMap &settings);
void setupUi();
private:
/// User preference view of the record status delegate's icon / text setting
GroupBlockDef *setupDataDisplay(const QString &);
signals:
/// Signals up for changes to editor application-level settings
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
public slots:
};
}
#endif // EDITORPAGE_HPP

@ -0,0 +1,132 @@
#include "dialog.hpp"
#include <QListWidgetItem>
#include <QApplication>
#include <QWidget>
#include <QStackedWidget>
#include <QtGui>
#include "../../model/settings/usersettings.hpp"
#include "page.hpp"
#include <QApplication>
#include <QSplitter>
#include <QTreeView>
#include <QListView>
#include <QTableView>
#include <QStandardItemModel>
#include <QStandardItem>
CSVSettings::Dialog::Dialog(QMainWindow *parent)
: mStackedWidget (0), mDebugMode (false), SettingWindow (parent)
{
setWindowTitle(QString::fromUtf8 ("User Settings"));
setupDialog();
connect (mPageListWidget,
SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this,
SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
}
void CSVSettings::Dialog::slotChangePage
(QListWidgetItem *cur, QListWidgetItem *prev)
{
mStackedWidget->changePage
(mPageListWidget->row (cur), mPageListWidget->row (prev));
layout()->activate();
setFixedSize(minimumSizeHint());
}
void CSVSettings::Dialog::setupDialog()
{
//create central widget with it's layout and immediate children
QWidget *centralWidget = new QGroupBox (this);
centralWidget->setLayout (new QHBoxLayout());
centralWidget->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Preferred);
setCentralWidget (centralWidget);
setDockOptions (QMainWindow::AllowNestedDocks);
buildPageListWidget (centralWidget);
buildStackedWidget (centralWidget);
}
void CSVSettings::Dialog::buildPages()
{
SettingWindow::createPages ();
QFontMetrics fm (QApplication::font());
foreach (Page *page, SettingWindow::pages())
{
QString pageName = page->objectName();
int textWidth = fm.width(pageName);
new QListWidgetItem (pageName, mPageListWidget);
mPageListWidget->setFixedWidth (textWidth + 50);
mStackedWidget->addWidget (&dynamic_cast<QWidget &>(*(page)));
}
addDebugPage();
resize (mStackedWidget->sizeHint());
}
void CSVSettings::Dialog::addDebugPage()
{
/*
QTreeView *tree = new QTreeView();
//tree->setModel( &CSMSettings::UserSettings::instance().model() );
mStackedWidget->addWidget(tree);
new QListWidgetItem ("Standard Item Model", mPageListWidget);*/
}
void CSVSettings::Dialog::buildPageListWidget (QWidget *centralWidget)
{
mPageListWidget = new QListWidget (centralWidget);
mPageListWidget->setMinimumWidth(50);
mPageListWidget->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Expanding);
mPageListWidget->setSelectionBehavior (QAbstractItemView::SelectItems);
centralWidget->layout()->addWidget(mPageListWidget);
}
void CSVSettings::Dialog::buildStackedWidget (QWidget *centralWidget)
{
mStackedWidget = new ResizeableStackedWidget (centralWidget);
centralWidget->layout()->addWidget (mStackedWidget);
}
void CSVSettings::Dialog::closeEvent (QCloseEvent *event)
{
//SettingWindow::closeEvent() must be called first to ensure
//model is updated
SettingWindow::closeEvent (event);
saveSettings();
}
void CSVSettings::Dialog::show()
{
if (pages().isEmpty())
buildPages();
QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move (screenCenter - geometry().center());
QWidget::show();
}

@ -0,0 +1,55 @@
#ifndef CSVSETTINGS_DIALOG_H
#define CSVSETTINGS_DIALOG_H
#include "settingwindow.hpp"
#include "resizeablestackedwidget.hpp"
#include <QStandardItem>
class QStackedWidget;
class QListWidget;
class QListWidgetItem;
namespace CSVSettings {
class Page;
class Dialog : public SettingWindow
{
Q_OBJECT
QListWidget *mPageListWidget;
ResizeableStackedWidget *mStackedWidget;
bool mDebugMode;
public:
explicit Dialog (QMainWindow *parent = 0);
///Enables setting debug mode. When the dialog opens, a page is created
///which displays the SettingModel's contents in a Tree view.
void enableDebugMode (bool state, QStandardItemModel *model = 0);
protected:
/// Settings are written on close
void closeEvent (QCloseEvent *event);
void setupDialog();
private:
void buildPages();
void buildPageListWidget (QWidget *centralWidget);
void buildStackedWidget (QWidget *centralWidget);
void addDebugPage();
public slots:
void show();
private slots:
void slotChangePage (QListWidgetItem *, QListWidgetItem *);
};
}
#endif // CSVSETTINGS_DIALOG_H

@ -1,53 +0,0 @@
#include "editorpage.hpp"
#include "groupblock.hpp"
#include "../../model/settings/usersettings.hpp"
CSVSettings::EditorPage::EditorPage(QWidget* parent) :
AbstractPage("Display Format", parent)
{
setupUi();
}
CSVSettings::GroupBlockDef *CSVSettings::EditorPage::setupRecordStatusDisplay()
{
GroupBlockDef *statusBlock = new GroupBlockDef(QString("Record Status Display"));
SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon and Text");
*(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only");
WidgetDef statusWidget (Widget_RadioButton);
statusWidget.valueList = statusItem->valueList;
statusItem->widget = statusWidget;
statusBlock->settingItems << statusItem;
return statusBlock;
}
void CSVSettings::EditorPage::setupUi()
{
mAbstractBlocks << buildBlock<GroupBlock>(setupRecordStatusDisplay());
foreach (AbstractBlock *block, mAbstractBlocks)
{
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
}
connect ( this,
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()),
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::EditorPage::initializeWidgets (const CSMSettings::SettingMap &settings)
{
//iterate each item in each blocks in this section
//validate the corresponding setting against the defined valuelist if any.
for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin();
it_block != mAbstractBlocks.end(); ++it_block)
(*it_block)->updateSettings (settings);
}

@ -1,33 +0,0 @@
#ifndef EDITORPAGE_HPP
#define EDITORPAGE_HPP
#include "support.hpp"
#include "abstractpage.hpp"
namespace CSVSettings
{
class EditorPage : public AbstractPage
{
Q_OBJECT
public:
explicit EditorPage(QWidget *parent = 0);
void initializeWidgets (const CSMSettings::SettingMap &settings);
void setupUi();
private:
/// User preference view of the record status delegate's icon / text setting
GroupBlockDef *setupRecordStatusDisplay();
signals:
/// Signals up for changes to editor application-level settings
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
public slots:
};
}
#endif // EDITORPAGE_HPP

@ -0,0 +1,103 @@
#include "frame.hpp"
#include <QWidget>
const QString CSVSettings::Frame::sInvisibleBoxStyle =
QString::fromUtf8("Frame { border:2px; padding 2px; margin: 2px;}");
CSVSettings::Frame::Frame (bool isVisible, const QString &title,
QWidget *parent)
: mIsHorizontal (true), mLayout (new SettingLayout()),
QGroupBox (title, parent)
{
setFlat (true);
mVisibleBoxStyle = styleSheet();
if (!isVisible)
setStyleSheet (sInvisibleBoxStyle);
setLayout (mLayout);
}
void CSVSettings::Frame::hideWidgets()
{
for (int i = 0; i < children().size(); i++)
{
QObject *obj = children().at(i);
Frame *widgFrame = dynamic_cast <Frame *> (obj);
if (widgFrame)
{
widgFrame->hideWidgets();
continue;
}
QWidget *widg = static_cast <QWidget *> (obj);
if (widg->property("sizePolicy").isValid())
widg->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored);
}
layout()->activate();
setFixedSize(minimumSizeHint());
}
void CSVSettings::Frame::showWidgets()
{
for (int i = 0; i < children().size(); i++)
{
QObject *obj = children().at(i);
Frame *widgFrame = dynamic_cast <Frame *> (obj);
if (widgFrame)
{
widgFrame->showWidgets();
continue;
}
QWidget *widg = static_cast <QWidget *> (obj);
if (widg->property("sizePolicy").isValid())
widg->setSizePolicy
(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
}
layout()->activate();
setFixedSize(minimumSizeHint());
}
void CSVSettings::Frame::addWidget (QWidget *widget, int row, int column,
int rowSpan, int columnSpan)
{
if (row == -1)
row = getNextRow();
if (column == -1)
column = getNextColumn();
mLayout->addWidget (widget, row, column, rowSpan, columnSpan);
//, Qt::AlignLeft | Qt::AlignTop);
widget->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored);
}
int CSVSettings::Frame::getNextRow () const
{
int row = mLayout->rowCount();
if (mIsHorizontal && row > 0)
row--;
return row;
}
int CSVSettings::Frame::getNextColumn () const
{
int column = 0;
if (mIsHorizontal)
column = mLayout->columnCount();
return column;
}

@ -0,0 +1,58 @@
#ifndef CSVSETTINGS_FRAME_HPP
#define CSVSETTINGS_FRAME_HPP
#include <QSizePolicy>
#include <QGroupBox>
#include <QGridLayout>
#include "../../model/settings/support.hpp"
namespace CSVSettings
{
class SettingLayout : public QGridLayout
{
public:
explicit SettingLayout (QWidget *parent = 0)
: QGridLayout (parent)
{
setContentsMargins(0,0,0,0);
setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
};
/// Custom implementation of QGroupBox to act as a base for view classes
class Frame : public QGroupBox
{
static const QString sInvisibleBoxStyle;
QString mVisibleBoxStyle;
bool mIsHorizontal;
SettingLayout *mLayout;
public:
explicit Frame (bool isVisible, const QString &title = "",
QWidget *parent = 0);
///Adds a widget to the grid layout, setting the position
///relative to the last added widgets, or absolutely for positive
///row / column values
void addWidget (QWidget *widget, int row = -1, int column = -1,
int rowSpan = 1, int columnSpan = 1);
///Force the grid to lay out in horizontal or vertical alignments
void setHLayout() { mIsHorizontal = true; }
void setVLayout() { mIsHorizontal = false; }
void showWidgets();
void hideWidgets();
private:
int getNextColumn() const;
int getNextRow() const;
};
}
#endif // CSVSETTINGS_FRAME_HPP

@ -1,108 +0,0 @@
#include "groupblock.hpp"
#include "itemblock.hpp"
CSVSettings::GroupBlock::GroupBlock (QWidget* parent)
: AbstractBlock (parent)
{}
CSVSettings::GroupBlock::GroupBlock (bool isVisible, QWidget *parent)
: AbstractBlock (isVisible, parent)
{}
int CSVSettings::GroupBlock::build (GroupBlockDef *def)
{
if (def->settingItems.size() == 0)
return -1;
int retVal = 0;
setVisible (def->isVisible);
mBox->setLayout(createLayout (def->widgetOrientation, def->isZeroMargin));
setObjectName (def->title);
mBox->setTitle (def->title);
foreach (SettingsItemDef *itemDef, def->settingItems)
{
ItemBlock *block = new ItemBlock (mBox);
if (block->build (*itemDef) < 0)
{
retVal = -2;
break;
}
mItemBlockList << block;
mBox->layout()->addWidget (block->getGroupBox());
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SLOT (slotUpdateSetting (const QString &, const QString &) ));
}
return retVal;
}
CSMSettings::SettingList *CSVSettings::GroupBlock::getSettings()
{
CSMSettings::SettingList *settings = 0;
foreach (ItemBlock *block, mItemBlockList)
{
if (!settings)
settings = new CSMSettings::SettingList();
settings->append(*(block->getSettings ()));
}
return settings;
}
CSVSettings::ItemBlock *CSVSettings::GroupBlock::getItemBlock (const QString &name, ItemBlockList *blockList)
{
ItemBlock *retBlock = 0;
if (!blockList)
blockList = &mItemBlockList;
foreach (ItemBlock *block, *blockList)
{
if (block->objectName() == name)
{
retBlock = block;
break;
}
}
return retBlock;
}
CSVSettings::ItemBlock *CSVSettings::GroupBlock::getItemBlock (int index)
{
ItemBlock *retBlock = 0;
if (mItemBlockList.size() > index)
retBlock = mItemBlockList.at(index);
return retBlock;
}
bool CSVSettings::GroupBlock::updateSettings (const CSMSettings::SettingMap &settings)
{
bool success = true;
//update all non-proxy settings
foreach (ItemBlock *block, mItemBlockList)
{
CSMSettings::SettingContainer *setting = settings[block->objectName()];
if (setting)
{
bool success2 = block->update (setting->getValue());
success = success && success2;
}
}
return success;
}

@ -1,43 +0,0 @@
#ifndef GROUPBLOCK_HPP
#define GROUPBLOCK_HPP
#include <QList>
#include "abstractblock.hpp"
namespace CSVSettings
{
class ItemBlock;
/// Base class for group blocks.
/// Derived block classes should use CustomBlock
class GroupBlock : public AbstractBlock
{
ItemBlockList mItemBlockList;
public:
GroupBlock (QWidget* parent = 0);
GroupBlock (bool isVisible, QWidget *parent = 0);
/// build the gorup block based on passed definition
int build (GroupBlockDef *def);
/// update settings local to the group block
bool updateSettings (const CSMSettings::SettingMap &settings);
/// retrieve setting list local to the group block
CSMSettings::SettingList *getSettings();
/// retrieve item block by name from the passed list or local list
ItemBlock *getItemBlock (const QString &name, ItemBlockList *blockList = 0);
/// retrieve the item block by index from the local list
ItemBlock *getItemBlock (int index);
protected:
/// create block layout based on passed definition
int buildLayout (GroupBlockDef &def);
};
}
#endif // GROUPBLOCK_HPP

@ -1,56 +0,0 @@
#include "groupbox.hpp"
const QString CSVSettings::GroupBox::INVISIBLE_BOX_STYLE =
QString::fromUtf8("QGroupBox { border: 0px; padding 0px; margin: 0px;}");
CSVSettings::GroupBox::GroupBox(QWidget *parent) :
QGroupBox (parent)
{
initBox();
}
CSVSettings::GroupBox::GroupBox (bool isVisible, QWidget *parent) :
QGroupBox (parent)
{
initBox(isVisible);
}
void CSVSettings::GroupBox::initBox(bool isVisible)
{
setFlat (true);
VISIBLE_BOX_STYLE = styleSheet();
if (!isVisible)
setStyleSheet (INVISIBLE_BOX_STYLE);
}
bool CSVSettings::GroupBox::borderVisibile() const
{
return (styleSheet() != INVISIBLE_BOX_STYLE);
}
void CSVSettings::GroupBox::setTitle (const QString &title)
{
if (borderVisibile() )
{
QGroupBox::setTitle (title);
setMinimumWidth();
}
}
void CSVSettings::GroupBox::setBorderVisibility (bool value)
{
if (value)
setStyleSheet(VISIBLE_BOX_STYLE);
else
setStyleSheet(INVISIBLE_BOX_STYLE);
}
void CSVSettings::GroupBox::setMinimumWidth()
{
//set minimum width to accommodate title, if needed
//1.5 multiplier to account for bold title.
QFontMetrics fm (font());
int minWidth = fm.width(title());
QGroupBox::setMinimumWidth (minWidth * 1.5);
}

@ -1,28 +0,0 @@
#ifndef GROUPBOX_HPP
#define GROUPBOX_HPP
#include <QGroupBox>
namespace CSVSettings
{
/// Custom implementation of QGroupBox to be used with block classes
class GroupBox : public QGroupBox
{
static const QString INVISIBLE_BOX_STYLE;
QString VISIBLE_BOX_STYLE; //not a const...
public:
explicit GroupBox (QWidget *parent = 0);
explicit GroupBox (bool isVisible, QWidget *parent = 0);
void setTitle (const QString &title);
void setBorderVisibility (bool value);
bool borderVisibile() const;
private:
void setMinimumWidth();
void initBox(bool isVisible = true);
};
}
#endif // GROUPBOX_HPP

@ -1,115 +0,0 @@
#include "itemblock.hpp"
#include <QFontMetrics>
CSVSettings::ItemBlock::ItemBlock (QWidget* parent)
: mSetting (0), AbstractBlock (false, parent)
{
}
int CSVSettings::ItemBlock::build(SettingsItemDef &iDef)
{
buildItemBlock (iDef);
buildItemBlockWidgets (iDef);
return 0;
}
void CSVSettings::ItemBlock::buildItemBlockWidgets (SettingsItemDef &iDef)
{
WidgetDef wDef = iDef.widget;
QLayout *blockLayout = 0;
QString defaultValue = iDef.defaultValue;
switch (wDef.type)
{
case Widget_CheckBox:
case Widget_RadioButton:
foreach (QString item, *(iDef.valueList))
{
wDef.caption = item;
wDef.isDefault = (item == defaultValue);
blockLayout = buildWidget (item, wDef, blockLayout)->getLayout();
}
break;
case Widget_ComboBox:
case Widget_ListBox:
//assign the item's value list to the widget's value list.
//pass through to default to finish widget construction.
if (!wDef.valueList)
wDef.valueList = iDef.valueList;
default:
//only one instance of this non-list widget type.
//Set it's value to the default value for the item and build the widget.
if (wDef.value.isEmpty())
wDef.value = iDef.defaultValue;
buildWidget (iDef.name, wDef);
}
}
void CSVSettings::ItemBlock::buildItemBlock (SettingsItemDef &iDef)
{
QString defaultValue = iDef.defaultValue;
setObjectName(iDef.name);
mSetting = new CSMSettings::SettingsItem (objectName(),
iDef.hasMultipleValues, iDef.defaultValue,
parent());
if (iDef.valueList)
mSetting->setValueList(iDef.valueList);
if (!iDef.minMax.isEmpty())
mSetting->setValuePair(iDef.minMax);
}
bool CSVSettings::ItemBlock::update (const QString &value)
{
bool success = updateItem (value);
if (success)
signalUpdateWidget (value);
return success;
}
bool CSVSettings::ItemBlock::updateItem (const QString &value)
{
return mSetting->updateItem(value);
}
bool CSVSettings::ItemBlock::updateBySignal(const QString &name, const QString &value, bool &doEmit)
{
bool success = (mSetting->getValue() != value);
if (success)
success = updateItem(value);
return success;
}
CSMSettings::SettingList *CSVSettings::ItemBlock::getSettings ()
{
CSMSettings::SettingList *list = new CSMSettings::SettingList();
list->push_back(mSetting);
return list;
}
QString CSVSettings::ItemBlock::getValue() const
{
return mSetting->getValue();
}

@ -1,48 +0,0 @@
#ifndef ITEMBLOCK_HPP
#define ITEMBLOCK_HPP
#include "abstractblock.hpp"
namespace CSVSettings
{
class ItemBlock : public AbstractBlock
{
CSMSettings::SettingsItem *mSetting;
WidgetList mWidgetList;
public:
ItemBlock (QWidget* parent = 0);
/// pure virtual function not implemented
bool updateSettings (const CSMSettings::SettingMap &settings) { return false; }
CSMSettings::SettingList *getSettings ();
QString getValue () const;
/// item blocks encapsulate only one setting
int getSettingCount();
/// update setting value and corresponding widget
bool update (const QString &value);
/// virtual construction function
int build(SettingsItemDef &iDef);
private:
/// custom construction function
void buildItemBlock (SettingsItemDef& iDef);
void buildItemBlockWidgets (SettingsItemDef& iDef);
/// update the setting value
bool updateItem (const QString &);
/// callback function triggered when update to application level is signalled
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
};
}
#endif // ITEMBLOCK_HPP

@ -0,0 +1,106 @@
#include "listview.hpp"
#include "../../model/settings/setting.hpp"
#include <QListView>
#include <QComboBox>
#include <QStringListModel>
CSVSettings::ListView::ListView(CSMSettings::Setting *setting,
Page *parent)
: mComboBox (0), mAbstractItemView (0), View(setting, parent)
{
QWidget *widget =
buildWidget(setting->isMultiLine(), setting->widgetWidth());
addWidget (widget, setting->viewRow(), setting->viewColumn());
if (mComboBox)
buildComboBoxModel();
else if (mAbstractItemView)
buildAbstractItemViewModel();
}
void CSVSettings::ListView::buildComboBoxModel()
{
mComboBox->setModel (dataModel());
mComboBox->setModelColumn (0);
mComboBox->view()->setSelectionModel (selectionModel());
int curIdx = -1;
if (!selectionModel()->selection().isEmpty())
curIdx = selectionModel()->selectedIndexes().at(0).row();
mComboBox->setCurrentIndex (curIdx);
connect (mComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(emitItemViewUpdate(int)));
}
void CSVSettings::ListView::buildAbstractItemViewModel()
{
mAbstractItemView->setModel (dataModel());
mAbstractItemView->setSelectionModel (selectionModel());
//connection needs to go here for list view update to signal to
//the outside
}
void CSVSettings::ListView::emitItemViewUpdate (int idx)
{
updateView();
}
QWidget *CSVSettings::ListView::buildWidget(bool isMultiLine, int width)
{
QWidget *widget = 0;
if (isMultiLine)
{
mAbstractItemView = new QListView (this);
widget = mAbstractItemView;
if (width > 0)
widget->setFixedWidth (widgetWidth (width));
}
else
{
mComboBox = new QComboBox (this);
widget = mComboBox;
if (width > 0)
mComboBox->setMinimumContentsLength (width);
}
return widget;
}
void CSVSettings::ListView::showEvent ( QShowEvent * event )
{
View::showEvent (event);
}
void CSVSettings::ListView::updateView (bool signalUpdate) const
{
QStringList values = selectedValues();
if (mComboBox)
{
int idx = -1;
if (values.size() > 0)
idx = (mComboBox->findText(values.at(0)));
mComboBox->setCurrentIndex (idx);
}
View::updateView (signalUpdate);
}
CSVSettings::ListView *CSVSettings::ListViewFactory::createView
(CSMSettings::Setting *setting,
Page *parent)
{
return new ListView(setting, parent);
}

@ -0,0 +1,63 @@
#ifndef CSVSETTINGS_LISTVIEW_HPP
#define CSVSETTINGS_LISTVIEW_HPP
#include "view.hpp"
class QStringListModel;
class QComboBox;
class QAbstractItemView;
namespace CSVSettings
{
class ListView : public View
{
Q_OBJECT
QAbstractItemView *mAbstractItemView;
QComboBox *mComboBox;
public:
explicit ListView (CSMSettings::Setting *setting,
Page *parent);
protected:
void updateView (bool signalUpdate = true) const;
void showEvent ( QShowEvent * event );
///Receives signal from widget and signals viwUpdated()
void slotTextEdited (QString value);
private:
///Helper function to construct a model for an AbstractItemView
void buildAbstractItemViewModel();
///Helper function to construct a model for a combobox
void buildComboBoxModel();
///Helper function to build the view widget
QWidget *buildWidget (bool isMultiLine, int width);
private slots:
///Receives updates from single-select widgets (like combobox) and
///signals viewUpdated with the selected values.
void emitItemViewUpdate (int idx);
};
class ListViewFactory : public QObject, public IViewFactory
{
Q_OBJECT
public:
explicit ListViewFactory (QWidget *parent = 0)
: QObject (parent)
{}
ListView *createView (CSMSettings::Setting *setting,
Page *parent);
};
}
#endif // CSVSETTINGS_LISTVIEW_HPP

@ -0,0 +1,88 @@
#include "page.hpp"
#include "view.hpp"
#include "booleanview.hpp"
#include "textview.hpp"
#include "listview.hpp"
#include "../../model/settings/usersettings.hpp"
#include "../../model/settings/connector.hpp"
#include "settingwindow.hpp"
QMap <CSVSettings::ViewType, CSVSettings::IViewFactory *>
CSVSettings::Page::mViewFactories;
CSVSettings::Page::Page(const QString &pageName,
QList <CSMSettings::Setting *> settingList,
SettingWindow *parent) :
mParent(parent), mIsEditorPage (false), Frame(false, "", parent)
{
setObjectName (pageName);
if (mViewFactories.size() == 0)
buildFactories();
setVLayout();
setupViews (settingList);
}
void CSVSettings::Page::setupViews
(QList <CSMSettings::Setting *> &settingList)
{
foreach (CSMSettings::Setting *setting, settingList)
addView (setting);
}
void CSVSettings::Page::addView (CSMSettings::Setting *setting)
{
if (setting->viewType() == ViewType_Undefined)
return;
View *view = mViewFactories[setting->viewType()]->createView(setting, this);
if (!view)
return;
mViews.append (view);
addWidget (view, setting->viewRow(), setting->viewColumn(),
setting->rowSpan(), setting->columnSpan() );
//if this page is an editor page, connect each of it's views up to the
//UserSettings singleton for signaling back to OpenCS
if (setting->isEditorSetting()) {
connect (view, SIGNAL (viewUpdated(const QString&, const QStringList&)),
&CSMSettings::UserSettings::instance(),
SLOT (updateUserSetting (const QString &, const QStringList &)));
}
}
CSVSettings::View *CSVSettings::Page::findView (const QString &page,
const QString &setting) const
{
//if this is not the page we're looking for,
//appeal to the parent setting window to find the appropriate view
if (page != objectName())
return mParent->findView (page, setting);
//otherwise, return the matching view
for (int i = 0; i < mViews.size(); i++)
{
View *view = mViews.at(i);
if (view->parentPage()->objectName() != page)
continue;
if (view->objectName() == setting)
return view;
}
return 0;
}
void CSVSettings::Page::buildFactories()
{
mViewFactories[ViewType_Boolean] = new BooleanViewFactory (this);
mViewFactories[ViewType_Text] = new TextViewFactory (this);
mViewFactories[ViewType_List] = new ListViewFactory (this);
}

@ -0,0 +1,54 @@
#ifndef CSVSETTINGS_PAGE_HPP
#define CSVSETTINGS_PAGE_HPP
#include <QSizePolicy>
#include <QWidget>
#include <QMap>
#include <QList>
#include "frame.hpp"
#include "../../model/settings/support.hpp"
namespace CSMSettings { class Setting; }
namespace CSVSettings
{
class View;
class IViewFactory;
class SettingWindow;
class Page : public Frame
{
Q_OBJECT
QList<View *> mViews;
SettingWindow *mParent;
static QMap <ViewType, IViewFactory *> mViewFactories;
bool mIsEditorPage;
public:
explicit Page(const QString &pageName,
QList <CSMSettings::Setting *> settingList,
SettingWindow *parent);
///Creates a new view based on the passed setting and adds it to
///the page.
void addView (CSMSettings::Setting *setting);
///Iterates the views created for this page based on the passed setting
///and returns it.
View *findView (const QString &page, const QString &setting) const;
const QList <View *> &views () const { return mViews; }
private:
///Creates views based on the passed setting list
void setupViews (QList <CSMSettings::Setting *> &settingList);
///Creates factory objects for view construction
void buildFactories();
};
}
#endif // CSVSETTINGS_PAGE_HPP

@ -1,152 +0,0 @@
#include "proxyblock.hpp"
#include "itemblock.hpp"
CSVSettings::ProxyBlock::ProxyBlock (QWidget *parent)
: GroupBlock (parent)
{
}
int CSVSettings::ProxyBlock::build (GroupBlockDef *proxyDef)
{
//get the list of pre-defined values for the proxy
mValueList = proxyDef->settingItems.at(0)->valueList;
bool success = GroupBlock::build(proxyDef);
//connect the item block of the proxy setting to the proxy-update slot
connect (getItemBlock(0), SIGNAL (signalUpdateSetting(const QString &, const QString &)),
this, SLOT (slotUpdateProxySetting (const QString &, const QString &)));
return success;
}
void CSVSettings::ProxyBlock::addSetting (ItemBlock *settingBlock, QStringList *proxyList)
{
//connect the item block of the proxied seting to the generic update slot
connect (settingBlock, SIGNAL (signalUpdateSetting(const QString &, const QString &)),
this, SLOT (slotUpdateProxySetting(const QString &, const QString &)));
mProxiedItemBlockList << settingBlock;
mProxyList << proxyList;
}
bool CSVSettings::ProxyBlock::updateSettings (const CSMSettings::SettingMap &settings)
{
return updateByProxiedSettings(&settings);
}
bool CSVSettings::ProxyBlock::updateBySignal(const QString &name, const QString &value, bool &doEmit)
{
doEmit = false;
return updateProxiedSettings();
}
void CSVSettings::ProxyBlock::slotUpdateProxySetting (const QString &name, const QString &value)
{
updateByProxiedSettings();
}
bool CSVSettings::ProxyBlock::updateProxiedSettings()
{
foreach (ItemBlock *block, mProxiedItemBlockList)
{
QString value = getItemBlock(0)->getValue();
bool success = false;
int i = 0;
//find the value index of the selected value in the proxy setting
for (; i < mValueList->size(); ++i)
{
success = (value == mValueList->at(i));
if (success)
break;
}
if (!success)
return false;
// update the containing the proxied item's name
foreach (QStringList *list, mProxyList)
{
if ( list->at(0) == block->objectName())
block->update (list->at(++i));
}
}
return true;
}
bool CSVSettings::ProxyBlock::updateByProxiedSettings(const CSMSettings::SettingMap *settings)
{
bool success = false;
int commonIndex = -1;
//update all proxy settings based on values from non-proxies
foreach (QStringList *list, mProxyList)
{
//Iterate each proxy item's proxied setting list, getting the current values
//Compare those value indices.
//If indices match, they correlate to one of the proxy's values in it's value list
//first value is always the name of the setting the proxy setting manages
QStringList::Iterator itProxyValue = list->begin();
QString proxiedSettingName = (*itProxyValue);
QString proxiedSettingValue = "";
itProxyValue++;
if (!settings)
{
//get the actual setting value
ItemBlock *block = getProxiedItemBlock (proxiedSettingName);
if (block)
proxiedSettingValue = block->getValue();
}
else
proxiedSettingValue = (*settings)[proxiedSettingName]->getValue();
int j = 0;
//iterate each value in the proxy string list
for (; itProxyValue != (list)->end(); ++itProxyValue)
{
success = ((*itProxyValue) == proxiedSettingValue);
if (success)
break;
j++;
}
//break if no match was found
if ( !success )
break;
if (commonIndex != -1)
success = (commonIndex == j);
else
commonIndex = j;
//break if indices were found, but mismatch
if (!success)
break;
}
//if successful, the proxied setting values match a pre-defined value in the
//proxy's value list. Set the proxy to that value index
if (success)
{
ItemBlock *block = getItemBlock(0);
if (block)
block->update (mValueList->at(commonIndex));
}
return success;
}
CSVSettings::ItemBlock *CSVSettings::ProxyBlock::getProxiedItemBlock (const QString &name)
{
return getItemBlock (name, &mProxiedItemBlockList);
}

@ -1,52 +0,0 @@
#ifndef PROXYBLOCK_HPP
#define PROXYBLOCK_HPP
#include "groupblock.hpp"
namespace CSVSettings
{
class ProxyBlock : public GroupBlock
{
Q_OBJECT
/// TODO: Combine mProxyItemBlockList and mProxyList.
ItemBlockList mProxiedItemBlockList;
ProxyList mProxyList;
QStringList *mValueList;
public:
explicit ProxyBlock (QWidget *parent = 0);
explicit ProxyBlock (ItemBlock *proxyItemBlock, QWidget *parent = 0);
/// Add a block that contains a proxied setting to the proxy block.
void addSetting (ItemBlock* settingBlock, QStringList *proxyList);
int build (GroupBlockDef *def);
CSMSettings::SettingList *getSettings() { return 0; }
/// Update settings local to the proxy block pushed from application level
bool updateSettings (const CSMSettings::SettingMap &settings);
/// callback function triggered when update to the application level is signaled.
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
private:
/// return the item block of a proxied setting
ItemBlock *getProxiedItemBlock (const QString &name);
/// update the proxy setting with data from the proxied settings
bool updateByProxiedSettings(const CSMSettings::SettingMap *settings = 0);
/// update proxied settings with data from the proxy setting
bool updateProxiedSettings();
private slots:
void slotUpdateProxySetting (const QString &name, const QString &value);
};
}
#endif // PROXYBLOCK_HPP

@ -0,0 +1,40 @@
#include "resizeablestackedwidget.hpp"
#include "page.hpp"
#include <QListWidgetItem>
CSVSettings::ResizeableStackedWidget::ResizeableStackedWidget(QWidget *parent) :
QStackedWidget(parent)
{}
void CSVSettings::ResizeableStackedWidget::addWidget(QWidget* pWidget)
{
QStackedWidget::addWidget(pWidget);
}
void CSVSettings::ResizeableStackedWidget::changePage
(int current, int previous)
{
if (current == previous)
return;
Page *prevPage = 0;
Page *curPage = 0;
if (previous > -1)
prevPage = static_cast <Page *> (widget (previous));
if (current > -1)
curPage = static_cast <Page *> (widget (current));
if (prevPage)
prevPage->hideWidgets();
if (curPage)
curPage->showWidgets();
layout()->activate();
setFixedSize(minimumSizeHint());
setCurrentIndex (current);
}

@ -0,0 +1,23 @@
#ifndef CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP
#define CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP
#include <QStackedWidget>
class QListWidgetItem;
namespace CSVSettings
{
class ResizeableStackedWidget : public QStackedWidget
{
Q_OBJECT
public:
explicit ResizeableStackedWidget(QWidget *parent = 0);
void addWidget(QWidget* pWidget);
void changePage (int, int);
};
}
#endif // CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP

@ -1 +0,0 @@
#include "settingwidget.hpp"

@ -1,214 +0,0 @@
#ifndef SETTINGWIDGET_HPP
#define SETTINGWIDGET_HPP
#include <QLabel>
#include <QCheckBox>
#include <QSpinBox>
#include <QLineEdit>
#include <QRadioButton>
#include <QComboBox>
#include <QListWidget>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "abstractwidget.hpp"
namespace CSVSettings
{
/// Generic template for radiobuttons / checkboxes
template <typename T1>
class SettingWidget : public AbstractWidget
{
T1 *mWidget;
public:
explicit SettingWidget (WidgetDef &def, QLayout *layout, QWidget* parent = 0)
: AbstractWidget (layout, parent), mWidget (new T1 (parent))
{
mWidget->setText(def.caption);
build (mWidget, def, true);
mWidget->setChecked(def.isDefault);
connect (mWidget, SIGNAL (toggled (bool)),
this, SLOT (slotUpdateItem (bool)));
}
QWidget *widget() { return mWidget; }
private:
void updateWidget (const QString &value)
{
if ( value == mWidget->objectName() && !mWidget->isChecked() )
mWidget->setChecked (true);
}
};
/// spin box template
template <>
class SettingWidget <QSpinBox>: public AbstractWidget
{
QSpinBox *mWidget;
public:
SettingWidget (WidgetDef &def, QLayout *layout, QWidget *parent = 0)
: AbstractWidget (layout, parent), mWidget (new QSpinBox (parent))
{
def.caption += tr(" (%1 to %2)").arg(def.minMax->left).arg(def.minMax->right);
mWidget->setMaximum (def.minMax->right.toInt());
mWidget->setMinimum (def.minMax->left.toInt());
mWidget->setValue (def.value.toInt());
build (mWidget, def);
connect (mWidget, SIGNAL (valueChanged (int)),
this, SLOT (slotUpdateItem (int)));
mWidget->setAlignment (getAlignment(def.valueAlignment));
}
QWidget *widget() { return mWidget; }
private:
void updateWidget (const QString &value)
{
int intVal = value.toInt();
if (intVal >= mWidget->minimum() && intVal <= mWidget->maximum() && intVal != mWidget->value())
mWidget->setValue (intVal);
}
signals:
};
/// combo box template
template <>
class SettingWidget <QComboBox>: public CSVSettings::AbstractWidget
{
QComboBox *mWidget;
public:
explicit SettingWidget(WidgetDef &def, QLayout *layout, QWidget *parent = 0)
: AbstractWidget (layout, parent), mWidget (new QComboBox (parent))
{
int i = 0;
foreach (QString item, *(def.valueList))
{
mWidget->addItem (item);
if (item == def.value)
mWidget->setCurrentIndex(i);
i++;
}
build (mWidget, def);
connect (mWidget, SIGNAL (currentIndexChanged (const QString &)),
this, SLOT (slotUpdateItem (const QString &)));
//center the combo box items
mWidget->setEditable (true);
mWidget->lineEdit()->setReadOnly (true);
mWidget->lineEdit()->setAlignment (getAlignment(def.valueAlignment));
QFlags<Qt::AlignmentFlag> alignment = mWidget->lineEdit()->alignment();
for (int j = 0; j < mWidget->count(); j++)
mWidget->setItemData (j, QVariant(alignment), Qt::TextAlignmentRole);
}
QWidget *widget() { return mWidget; }
private:
void updateWidget (const QString &value)
{
if (mWidget->currentText() != value)
mWidget->setCurrentIndex(mWidget->findText(value));
}
};
/// line edit template
template <>
class SettingWidget <QLineEdit>: public CSVSettings::AbstractWidget
{
QLineEdit *mWidget;
public:
explicit SettingWidget(WidgetDef &def, QLayout *layout, QWidget *parent = 0)
: AbstractWidget (layout, parent), mWidget (new QLineEdit (parent))
{
if (!def.inputMask.isEmpty())
mWidget->setInputMask (def.inputMask);
mWidget->setText (def.value);
build (mWidget, def);
connect (mWidget, SIGNAL (textChanged (const QString &)),
this, SLOT (slotUpdateItem (const QString &)));
mWidget->setAlignment (getAlignment(def.valueAlignment));
}
QWidget *widget() { return mWidget; }
void updateWidget (const QString &value)
{
if (mWidget->text() != value)
mWidget->setText(value);
}
};
/// list widget template
/// \todo Not fully implemented. Only widget supporting multi-valued settings
template <>
class SettingWidget <QListWidget>: public CSVSettings::AbstractWidget
{
QListWidget *mWidget;
public:
explicit SettingWidget(WidgetDef &def, QLayout *layout, QWidget *parent = 0 )
: AbstractWidget (layout, parent), mWidget (new QListWidget (parent))
{
int i = 0;
foreach (QString item, *(def.valueList))
{
mWidget->addItem (item);
if (item == def.value) {}
i++;
}
build (mWidget, def);
}
QWidget *widget() { return mWidget; }
private:
void updateWidget (const QString &value) {}
};
}
#endif // SETTINGWIDGET_HPP

@ -0,0 +1,114 @@
#include <QApplication>
#include <QDebug>
#include "../../model/settings/setting.hpp"
#include "../../model/settings/connector.hpp"
#include "../../model/settings/usersettings.hpp"
#include "settingwindow.hpp"
#include "page.hpp"
#include "view.hpp"
CSVSettings::SettingWindow::SettingWindow(QWidget *parent)
: QMainWindow(parent)
{}
void CSVSettings::SettingWindow::createPages()
{
CSMSettings::SettingPageMap pageMap = mModel->settingPageMap();
QList <CSMSettings::Setting *> connectedSettings;
foreach (const QString &pageName, pageMap.keys())
{
QList <CSMSettings::Setting *> pageSettings = pageMap.value (pageName);
mPages.append (new Page (pageName, pageSettings, this));
for (int i = 0; i < pageSettings.size(); i++)
{
CSMSettings::Setting *setting = pageSettings.at(i);
if (!setting->proxyLists().isEmpty())
connectedSettings.append (setting);
}
}
if (!connectedSettings.isEmpty())
createConnections(connectedSettings);
}
void CSVSettings::SettingWindow::createConnections
(const QList <CSMSettings::Setting *> &list)
{
foreach (const CSMSettings::Setting *setting, list)
{
View *masterView = findView (setting->page(), setting->name());
CSMSettings::Connector *connector =
new CSMSettings::Connector (masterView, this);
connect (masterView,
SIGNAL (viewUpdated(const QString &, const QStringList &)),
connector,
SLOT (slotUpdateSlaves())
);
const CSMSettings::ProxyValueMap &proxyMap = setting->proxyLists();
foreach (const QString &key, proxyMap.keys())
{
QStringList keyPair = key.split('.');
if (keyPair.size() != 2)
continue;
View *slaveView = findView (keyPair.at(0), keyPair.at(1));
if (!slaveView)
{
qWarning () << "Unable to create connection for view "
<< key;
continue;
}
QList <QStringList> proxyList = proxyMap.value (key);
connector->addSlaveView (slaveView, proxyList);
connect (slaveView,
SIGNAL (viewUpdated(const QString &, const QStringList &)),
connector,
SLOT (slotUpdateMaster()));
}
}
}
CSVSettings::View *CSVSettings::SettingWindow::findView
(const QString &pageName, const QString &setting)
{
foreach (const Page *page, mPages)
{
if (page->objectName() == pageName)
return page->findView (pageName, setting);
}
return 0;
}
void CSVSettings::SettingWindow::saveSettings()
{
QMap <QString, QStringList> settingMap;
foreach (const Page *page, mPages)
{
foreach (const View *view, page->views())
{
if (view->serializable())
settingMap[view->viewKey()] = view->selectedValues();
}
}
CSMSettings::UserSettings::instance().saveSettings (settingMap);
}
void CSVSettings::SettingWindow::closeEvent (QCloseEvent *event)
{
QApplication::focusWidget()->clearFocus();
}

@ -0,0 +1,49 @@
#ifndef CSVSETTINGS_SETTINGWINDOW_HPP
#define CSVSETTINGS_SETTINGWINDOW_HPP
#include <QMainWindow>
#include <QList>
#include "../../model/settings/support.hpp"
namespace CSMSettings {
class Setting;
class SettingManager;
}
namespace CSVSettings {
class Page;
class View;
typedef QList <Page *> PageList;
class SettingWindow : public QMainWindow
{
Q_OBJECT
PageList mPages;
CSMSettings::SettingManager *mModel;
public:
explicit SettingWindow(QWidget *parent = 0);
View *findView (const QString &pageName, const QString &setting);
void setModel (CSMSettings::SettingManager &model) { mModel = &model; }
protected:
virtual void closeEvent (QCloseEvent *event);
void createPages();
const PageList &pages() const { return mPages; }
void saveSettings();
private:
void createConnections (const QList <CSMSettings::Setting *> &list);
};
}
#endif // CSVSETTINGS_SETTINGWINDOW_HPP

@ -1 +0,0 @@
#include "support.hpp"

@ -1,206 +0,0 @@
#ifndef VIEW_SUPPORT_HPP
#define VIEW_SUPPORT_HPP
#include <QList>
#include <QStringList>
#include "../../model/settings/support.hpp"
namespace CSVSettings
{
struct WidgetDef;
class ItemBlock;
class GroupBlock;
struct GroupBlockDef;
typedef QList<GroupBlockDef *> GroupBlockDefList;
typedef QList<GroupBlock *> GroupBlockList;
typedef QList<ItemBlock *> ItemBlockList;
typedef QList<QStringList *> ProxyList;
typedef QList<WidgetDef *> WidgetList;
typedef QMap<QString, ItemBlock *> ItemBlockMap;
enum Orientation
{
Orient_Horizontal,
Orient_Vertical
};
enum WidgetType
{
Widget_CheckBox,
Widget_ComboBox,
Widget_LineEdit,
Widget_ListBox,
Widget_RadioButton,
Widget_SpinBox,
Widget_Undefined
};
enum Alignment
{
Align_Left = Qt::AlignLeft,
Align_Center = Qt::AlignHCenter,
Align_Right = Qt::AlignRight
};
/// definition struct for widgets
struct WidgetDef
{
/// type of widget providing input
WidgetType type;
/// width of caption label
int labelWidth;
/// width of input widget
int widgetWidth;
/// label / widget orientation (horizontal / vertical)
Orientation orientation;
/// input mask (line edit only)
QString inputMask;
/// label caption. Leave empty for multiple items. See BlockDef::captionList
QString caption;
/// widget value. Leave empty for multiple items. See BlockDef::valueList
QString value;
/// Min/Max QString value pair. If empty, assigned to property item value pair.
CSMSettings::QStringPair *minMax;
/// value list for list widgets. If left empty, is assigned to property item value list during block build().
QStringList *valueList;
/// determined at runtime
bool isDefault;
/// left / center / right-justify text in widget
Alignment valueAlignment;
/// left / center / right-justify widget in group box
Alignment widgetAlignment;
WidgetDef() : labelWidth (-1), widgetWidth (-1),
orientation (Orient_Horizontal),
isDefault (true), valueAlignment (Align_Center),
widgetAlignment (Align_Right),
inputMask (""), value (""),
caption (""), valueList (0)
{}
WidgetDef (WidgetType widgType)
: type (widgType), orientation (Orient_Horizontal),
caption (""), value (""), valueAlignment (Align_Center),
widgetAlignment (Align_Right),
labelWidth (-1), widgetWidth (-1),
valueList (0), isDefault (true)
{}
};
/// Defines the attributes of the setting as it is represented in the config file
/// as well as the UI elements (group box and widget) that serve it.
/// Only one widget may serve as the input widget for the setting.
struct SettingsItemDef
{
/// setting name
QString name;
/// list of valid values for the setting
QStringList *valueList;
/// Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value)
QString defaultValue;
/// flag indicating multi-valued setting
bool hasMultipleValues;
/// minimum / maximum value pair
CSMSettings::QStringPair minMax;
/// definition of the input widget for this setting
WidgetDef widget;
/// general orientation of the widget / label for this setting
Orientation orientation;
/// list of settings and corresponding default values for proxy widget
ProxyList *proxyList;
SettingsItemDef() : name (""), defaultValue (""), orientation (Orient_Vertical), hasMultipleValues (false)
{}
SettingsItemDef (QString propName, QString propDefault, Orientation propOrient = Orient_Vertical)
: name (propName), defaultValue (propDefault), orientation (propOrient),
hasMultipleValues(false), valueList (new QStringList), proxyList ( new ProxyList)
{}
};
/// Generic container block
struct GroupBlockDef
{
/// block title
QString title;
/// list of captions for widgets at the block level (not associated with any particular setting)
QStringList captions;
/// list of widgets at the block level (not associated with any particular setting)
WidgetList widgets;
/// list of the settings which are subordinate to the setting block.
QList<SettingsItemDef *> settingItems;
/// general orientation of widgets in group block
Orientation widgetOrientation;
/// determines whether or not box border/title are visible
bool isVisible;
/// indicates whether or not this block defines a proxy block
bool isProxy;
/// generic default value attribute
QString defaultValue;
/// shows / hides margins
bool isZeroMargin;
GroupBlockDef (): title(""), widgetOrientation (Orient_Vertical), isVisible (true), isProxy (false), defaultValue (""), isZeroMargin (true)
{}
GroupBlockDef (QString blockTitle)
: title (blockTitle), widgetOrientation (Orient_Vertical), isProxy (false), isVisible (true), defaultValue (""), isZeroMargin (true)
{}
};
/// used to create unique, complex blocks
struct CustomBlockDef
{
/// block title
QString title;
/// default value for widgets unique to the custom block
QString defaultValue;
/// list of settings groups that comprise the settings within the custom block
GroupBlockDefList blockDefList;
/// orientation of the widgets within the block
Orientation blockOrientation;
CustomBlockDef (): title (""), defaultValue (""), blockOrientation (Orient_Horizontal)
{}
CustomBlockDef (const QString &blockTitle)
: title (blockTitle), defaultValue (""), blockOrientation (Orient_Horizontal)
{}
};
}
#endif // VIEW_SUPPORT_HPP

@ -0,0 +1,73 @@
#include <QTextEdit>
#include <QLineEdit>
#include "textview.hpp"
#include "../../model/settings/setting.hpp"
CSVSettings::TextView::TextView(CSMSettings::Setting *setting, Page *parent)
: mDelimiter (setting->delimiter()), View (setting, parent)
{
if (setting->isMultiLine())
mTextWidget = new QTextEdit ("", this);
else
mTextWidget = new QLineEdit ("", this);
if (setting->widgetWidth() > 0)
mTextWidget->setFixedWidth (widgetWidth (setting->widgetWidth()));
connect (mTextWidget, SIGNAL (textEdited (QString)),
this, SLOT (slotTextEdited (QString)));
addWidget (mTextWidget, setting->viewRow(), setting->viewColumn());
}
bool CSVSettings::TextView::isEquivalent
(const QString &lhs, const QString &rhs) const
{
return (lhs.trimmed() == rhs.trimmed());
}
void CSVSettings::TextView::setWidgetText (const QString &value) const
{
mTextWidget->setProperty ("text", value);
}
void CSVSettings::TextView::slotTextEdited (QString value)
{
QStringList values = value.split (mDelimiter, QString::SkipEmptyParts);
QStringList returnValues;
foreach (const QString &splitValue, values)
returnValues.append (splitValue.trimmed());
setSelectedValues (returnValues, false);
View::updateView();
}
void CSVSettings::TextView::updateView(bool signalUpdate) const
{
QString values = selectedValues().join (mDelimiter);
if (isEquivalent (widgetText(), values))
return;
setWidgetText (values);
View::updateView (signalUpdate);
}
QString CSVSettings::TextView::widgetText() const
{
return mTextWidget->property("text").toString();
}
CSVSettings::TextView *CSVSettings::TextViewFactory::createView
(CSMSettings::Setting *setting,
Page *parent)
{
return new TextView (setting, parent);
}

@ -0,0 +1,56 @@
#ifndef CSVSETTINGS_TEXTVIEW_HPP
#define CSVSETTINGS_TEXTVIEW_HPP
#include "view.hpp"
#include "../../model/settings/setting.hpp"
namespace CSVSettings
{
class TextView : public View
{
Q_OBJECT
QWidget *mTextWidget;
QString mDelimiter;
public:
explicit TextView (CSMSettings::Setting *setting,
Page *parent = 0);
protected:
void updateView (bool signalUpdate = true) const;
protected slots:
///Receives updates to the widget for signalling
void slotTextEdited (QString value);
private:
///Comparison function that returns true if the trimmed() strings
///are equal
bool isEquivalent (const QString &lhs, const QString &rhs) const;
///Convenience function to return the text of the widget
QString widgetText() const;
///Convenience function to set the text of the widget
void setWidgetText (const QString &value) const;
};
class TextViewFactory : public QObject, public IViewFactory
{
Q_OBJECT
public:
explicit TextViewFactory (QWidget *parent = 0)
: QObject (parent)
{}
TextView *createView (CSMSettings::Setting *setting,
Page *parent);
};
}
#endif // CSVSETTINGS_TEXTVIEW_HPP

@ -1,80 +0,0 @@
#include "toggleblock.hpp"
#include "groupblock.hpp"
#include "groupbox.hpp"
#include "itemblock.hpp"
CSVSettings::ToggleBlock::ToggleBlock(QWidget *parent) :
CustomBlock(parent)
{}
int CSVSettings::ToggleBlock::build(CustomBlockDef *def)
{
if (def->blockDefList.size()==0)
return -1;
QList<GroupBlockDef *>::Iterator it = def->blockDefList.begin();
//first def in the list is the def for the toggle block
GroupBlockDef *toggleDef = *it++;
if (toggleDef->captions.size() != def->blockDefList.size()-1 )
return -2;
if (toggleDef->widgets.size() == 0)
return -3;
//create the toogle block UI structure
QLayout *blockLayout = createLayout (def->blockOrientation, true);
GroupBox *propertyBox = buildGroupBox (toggleDef->widgetOrientation);
mBox->setLayout(blockLayout);
mBox->setTitle (toggleDef->title);
//build the blocks contained in the def list
//this manages proxy block construction.
//Any settings managed by the proxy setting
//must be included in the blocks defined in the list.
CustomBlock::build (def->blockDefList, &it);
for (GroupBlockList::iterator it = mGroupList.begin(); it != mGroupList.end(); ++it)
propertyBox->layout()->addWidget ((*it)->getGroupBox());
//build togle widgets, linking them to the settings
GroupBox *toggleBox = buildToggleWidgets (toggleDef, def->defaultValue);
blockLayout->addWidget(toggleBox);
blockLayout->addWidget(propertyBox);
blockLayout->setAlignment (propertyBox, Qt::AlignRight);
return 0;
}
CSVSettings::GroupBox *CSVSettings::ToggleBlock::buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle)
{
GroupBox *box = new GroupBox (false, getParent());
QLayout *layout = createLayout (def->widgetOrientation, true, static_cast<QWidget *>(box));
for (int i = 0; i < def->widgets.size(); ++i)
{
QString caption = def->captions.at(i);
WidgetDef *wDef = def->widgets.at(i);
wDef->caption = caption;
wDef->widgetAlignment = Align_Left;
AbstractWidget *widg = buildWidget (caption, *wDef, layout, false);
GroupBlock *block = mGroupList.at(i);
//connect widget's update to the property block's enabled status
connect (widg->widget(), SIGNAL (toggled (bool)), block, SLOT (slotSetEnabled(bool)));
//enable the default toggle option
block->getGroupBox()->setEnabled( caption == defaultToggle );
layout = widg->getLayout();
}
return box;
}

@ -1,29 +0,0 @@
#ifndef TOGGLEBLOCK_HPP
#define TOGGLEBLOCK_HPP
#include <QObject>
#include "customblock.hpp"
namespace CSVSettings
{
class GroupBlock;
class GroupBox;
class ToggleWidget;
class ItemBlock;
class ToggleBlock : public CustomBlock
{
public:
explicit ToggleBlock(QWidget *parent = 0);
int build (CustomBlockDef *def);
private:
/// Constructor for toggle widgets that are specific to toggle block
/// Widgets are not a part of the user preference settings
GroupBox *buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle);
};
}
#endif // TOGGLEBLOCK_HPP

@ -1,119 +0,0 @@
#include "usersettingsdialog.hpp"
#include <boost/filesystem/path.hpp>
#include <QApplication>
#include <QDesktopWidget>
#include <QWidget>
#include <QTabWidget>
#include <QMessageBox>
#include <QTextCodec>
#include <QFile>
#include <QPushButton>
#include <QDockWidget>
#include <QGridLayout>
#include <QApplication>
#include <QDesktopWidget>
#include "../../model/settings/support.hpp"
#include "datadisplayformatpage.hpp"
#include "windowpage.hpp"
#include "settingwidget.hpp"
CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
QMainWindow (parent), mStackedWidget (0)
{
setWindowTitle(QString::fromUtf8 ("User Settings"));
buildPages();
setWidgetStates ();
connect (mListWidget,
SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this,
SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
QRect scr = QApplication::desktop()->screenGeometry();
QRect rect = geometry();
move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y());
}
CSVSettings::UserSettingsDialog::~UserSettingsDialog()
{
}
void CSVSettings::UserSettingsDialog::closeEvent (QCloseEvent *event)
{
writeSettings();
}
void CSVSettings::UserSettingsDialog::setWidgetStates ()
{
CSMSettings::UserSettings::instance().loadSettings("opencs.cfg");
//iterate the tabWidget's pages (sections)
for (int i = 0; i < mStackedWidget->count(); i++)
{
//get the settings defined for the entire section
//and update widget
QString pageName = mStackedWidget->widget(i)->objectName();
const CSMSettings::SettingMap *settings = CSMSettings::UserSettings::instance().getSettings(pageName);
AbstractPage &page = getAbstractPage (i);
page.initializeWidgets(*settings);
}
}
void CSVSettings::UserSettingsDialog::buildPages()
{
//craete central widget with it's layout and immediate children
QWidget *centralWidget = new QWidget (this);
mListWidget = new QListWidget (centralWidget);
mStackedWidget = new QStackedWidget (centralWidget);
QGridLayout* dialogLayout = new QGridLayout();
mListWidget->setMinimumWidth(0);
mListWidget->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding);
mStackedWidget->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
dialogLayout->addWidget (mListWidget,0,0);
dialogLayout->addWidget (mStackedWidget,0,1, Qt::AlignTop);
centralWidget->setLayout (dialogLayout);
setCentralWidget (centralWidget);
setDockOptions (QMainWindow::AllowNestedDocks);
createPage<WindowPage>();
createPage<DataDisplayFormatPage>();
}
void CSVSettings::UserSettingsDialog::writeSettings()
{
QMap<QString, CSMSettings::SettingList *> settings;
for (int i = 0; i < mStackedWidget->count(); ++i)
{
AbstractPage &page = getAbstractPage (i);
settings [page.objectName()] = page.getSettings();
}
CSMSettings::UserSettings::instance().writeSettings(settings);
}
CSVSettings::AbstractPage &CSVSettings::UserSettingsDialog::getAbstractPage (int index)
{
return dynamic_cast<AbstractPage &> (*(mStackedWidget->widget (index)));
}
void CSVSettings::UserSettingsDialog::slotChangePage(QListWidgetItem *current, QListWidgetItem *previous)
{
if (!current)
current = previous;
if (!(current == previous))
mStackedWidget->setCurrentIndex (mListWidget->row(current));
}

@ -1,71 +0,0 @@
#ifndef USERSETTINGSDIALOG_H
#define USERSETTINGSDIALOG_H
#include <QMainWindow>
#include <QStackedWidget>
#include <QListWidgetItem>
#include <QApplication>
#include "../../model/settings/usersettings.hpp"
#include "../../model/settings/support.hpp"
class QHBoxLayout;
class AbstractWidget;
class QStackedWidget;
class QListWidget;
namespace CSVSettings {
class AbstractPage;
class UserSettingsDialog : public QMainWindow
{
Q_OBJECT
QListWidget *mListWidget;
QStackedWidget *mStackedWidget;
public:
UserSettingsDialog(QMainWindow *parent = 0);
~UserSettingsDialog();
private:
/// Settings are written on close
void closeEvent (QCloseEvent *event);
/// return the setting page by name
/// performs dynamic cast to AbstractPage *
AbstractPage &getAbstractPage (int index);
void setWidgetStates ();
void buildPages();
void writeSettings();
/// Templated function to create a custom user preference page
template <typename T>
void createPage ()
{
T *page = new T(mStackedWidget);
mStackedWidget->addWidget (&dynamic_cast<QWidget &>(*page));
new QListWidgetItem (page->objectName(), mListWidget);
//finishing touches
QFontMetrics fm (QApplication::font());
int textWidth = fm.width(page->objectName());
if ((textWidth + 50) > mListWidget->minimumWidth())
mListWidget->setMinimumWidth(textWidth + 50);
resize (mStackedWidget->sizeHint());
}
public slots:
/// Called when a different page is selected in the left-hand list widget
void slotChangePage (QListWidgetItem*, QListWidgetItem*);
};
}
#endif // USERSETTINGSDIALOG_H

@ -0,0 +1,223 @@
#include <QStringListModel>
#include <QSortFilterProxyModel>
#include <QStandardItem>
#include <QApplication>
#include "view.hpp"
#include "../../model/settings/support.hpp"
#include "../../model/settings/setting.hpp"
#include "page.hpp"
CSVSettings::View::View(CSMSettings::Setting *setting,
Page *parent)
: mDataModel(0), mParentPage (parent),
mHasFixedValues (!setting->declaredValues().isEmpty()),
mIsMultiValue (setting->isMultiValue()),
mViewKey (setting->page() + '.' + setting->name()),
mSerializable (setting->serializable()),
Frame(true, setting->name(), parent)
{
setObjectName (setting->name());
buildView();
buildModel (setting);
}
void CSVSettings::View::buildModel (const CSMSettings::Setting *setting)
{
QStringList values = setting->definedValues();
if (values.isEmpty())
values.append (setting->defaultValues());
if (mHasFixedValues)
buildFixedValueModel (setting->declaredValues());
else
buildUpdatableValueModel (values);
mSelectionModel = new QItemSelectionModel (mDataModel, this);
setSelectedValues (values, false);
}
void CSVSettings::View::buildFixedValueModel (const QStringList &values)
{
mDataModel = new QStringListModel (values, this);
}
void CSVSettings::View::buildUpdatableValueModel (const QStringList &values)
{
QList <QStandardItem *> itemList;
foreach (const QString &value, values)
itemList.append (new QStandardItem(value));
// QSortFilterProxyModel *filter = new QSortFilterProxyModel (this);
QStandardItemModel *model = new QStandardItemModel (this);
model->appendColumn (itemList);
// filter->setSourceModel (model);
/* filter->setFilterRegExp ("*");
filter->setFilterKeyColumn (0);
filter->setFilterRole (Qt::DisplayRole);*/
mDataModel = model;
}
void CSVSettings::View::buildView()
{
setFlat (true);
setHLayout();
}
int CSVSettings::View::currentIndex () const
{
if (selectedValues().isEmpty())
return -1;
QString currentValue = selectedValues().at(0);
for (int i = 0; i < mDataModel->rowCount(); i++)
if (value(i) == currentValue)
return i;
return -1;
}
void CSVSettings::View::refresh() const
{
select (mSelectionModel->selection());
updateView();
}
int CSVSettings::View::rowCount() const
{
return mDataModel->rowCount();
}
void CSVSettings::View::select (const QItemSelection &selection) const
{
mSelectionModel->clear();
mSelectionModel->select(selection, QItemSelectionModel::Select);
}
QStringList CSVSettings::View::selectedValues() const
{
QStringList selValues;
foreach (const QModelIndex &idx, mSelectionModel->selectedIndexes())
selValues.append (value(idx.row()));
return selValues;
}
void CSVSettings::View::setSelectedValue (const QString &value,
bool doViewUpdate, bool signalUpdate)
{
setSelectedValues (QStringList() << value, doViewUpdate, signalUpdate);
}
void CSVSettings::View::setSelectedValues (const QStringList &list,
bool doViewUpdate, bool signalUpdate)
{
QItemSelection selection;
if (stringListsMatch (list, selectedValues()))
return;
if (!mHasFixedValues)
{
QStandardItemModel *model =
static_cast <QStandardItemModel *>(mDataModel);
model->clear();
model->appendColumn (toStandardItemList (list));
for (int i = 0; i < model->rowCount(); i++)
{
QModelIndex idx = model->index(i, 0);
selection.append (QItemSelectionRange (idx, idx));
}
}
else
{
for (int i = 0; i < mDataModel->rowCount(); i++)
{
if (list.contains(value(i)))
{
QModelIndex idx = mDataModel->index(i, 0);
selection.append(QItemSelectionRange (idx, idx));
}
}
}
select (selection);
//push changes to model side
//update the view if the selection was set from the model side, not by the
//user
if (doViewUpdate)
updateView (signalUpdate);
}
void CSVSettings::View::showEvent ( QShowEvent * event )
{
refresh();
}
bool CSVSettings::View::stringListsMatch (
const QStringList &list1,
const QStringList &list2) const
{
//returns a "sloppy" match, verifying that each list contains all the same
//items, though not necessarily in the same order.
if (list1.size() != list2.size())
return false;
QStringList tempList(list2);
//iterate each value in the list, removing one occurrence of the value in
//the other list. If no corresponding value is found, test fails
foreach (const QString &value, list1)
{
if (!tempList.contains(value))
return false;
tempList.removeOne(value);
}
return true;
}
QList <QStandardItem *> CSVSettings::View::toStandardItemList
(const QStringList &list) const
{
QList <QStandardItem *> itemList;
foreach (const QString &value, list)
itemList.append (new QStandardItem (value));
return itemList;
}
void CSVSettings::View::updateView (bool signalUpdate) const
{
if (signalUpdate)
emit viewUpdated(viewKey(), selectedValues());
}
QString CSVSettings::View::value (int row) const
{
if (row > -1 && row < mDataModel->rowCount())
return mDataModel->data (mDataModel->index(row, 0)).toString();
return "";
}
int CSVSettings::View::widgetWidth(int characterCount) const
{
QString widthToken = QString().fill ('P', characterCount);
QFontMetrics fm (QApplication::font());
return (fm.width (widthToken));
}

@ -0,0 +1,163 @@
#ifndef CSVSETTINGS_VIEW_HPP
#define CSVSETTINGS_VIEW_HPP
#include <QWidget>
#include <QList>
#include "frame.hpp"
#include "../../model/settings/support.hpp"
class QGroupBox;
class QStringList;
class QStandardItem;
class QItemSelection;
class QStringListModel;
class QStandardItemModel;
class QAbstractItemModel;
class QItemSelectionModel;
namespace CSMSettings { class Setting; }
namespace CSVSettings
{
class Page;
class View : public Frame
{
Q_OBJECT
///Pointer to the owning Page instance
Page *mParentPage;
///Pointer to the selection model for the view
QItemSelectionModel *mSelectionModel;
///Pointer to the data model for the view's selection model
QAbstractItemModel *mDataModel;
///State indicating whether or not the setting has a pre-defined list
///of values, limiting possible definitions
bool mHasFixedValues;
///State indicating whether the view will allow multiple values
bool mIsMultiValue;
QString mViewKey;
bool mSerializable;
public:
explicit View (CSMSettings::Setting *setting, Page *parent);
///Physical frame in which the view UI is contained
void addViewWidget (QWidget *widget, int row = -1, int col = -1) const;
///Returns the index / row of the passed value, -1 if not found.
int currentIndex () const;
///Returns the number of rows in the view's data model
int rowCount() const;
///Returns bool indicating the data in this view should / should not
///be serialized to a config file
bool serializable() const { return mSerializable; }
///Returns a pointer to the view's owning parent page
const Page *parentPage() const { return mParentPage; }
///Returns the selected items in the selection model as a QStringList
QStringList selectedValues() const;
///Sets the selected items in the selection model based on passed list.
///Bools allow opt-out of updating the view
///or signaling the view was updatedto avoid viscious cylcing.
void setSelectedValues (const QStringList &values,
bool updateView = true,
bool signalUpdate = true);
void setSelectedValue (const QString &value,
bool updateView = true,
bool signalUpdate = true);
///Returns the value of the data model at the specified row
QString value (int row) const;
QString viewKey() const { return mViewKey; }
protected:
/// Returns the model which provides data for the selection model
QAbstractItemModel *dataModel() { return mDataModel; }
///Accessor function for subclasses
bool isMultiValue() { return mIsMultiValue; }
///Returns the view selection model
QItemSelectionModel *selectionModel() { return mSelectionModel;}
///Global callback for basic view initialization
void showEvent ( QShowEvent * event );
///Virtual for updating a specific View subclass
///bool indicates whether a signal is emitted that the view was updated
virtual void updateView (bool signalUpdate = true) const;
///Returns the pixel width corresponding to the specified number of
///characters.
int widgetWidth(int characterCount) const;
private:
///Constructs the view layout
void buildView();
///Constructs the data and selection models
void buildModel (const CSMSettings::Setting *setting);
///In cases where the view has a pre-defined list of possible values,
///a QStringListModel is created using those values.
///View changes operate on the selection model only.
void buildFixedValueModel (const QStringList &definitions);
///In cases where the view does not have a pre-defined list of possible
///values, a QStandardItemModel is created, containing the actual
///setting definitions. View changes first update the data in the
///model to match the data in the view. The selection model always
///selects all values.
void buildUpdatableValueModel (const QStringList &definitions);
///Refreshes the view
void refresh() const;
///Convenince function for selection model's select() method. Also
///clears out the model beforehand to ensure complete selection.
void select (const QItemSelection &selection) const;
///Compares two string lists "loosely", ensuring that all values in
///one list are contained entirely in the other, and that neither list
///has more values than the other. List order is not considered.
bool stringListsMatch (const QStringList &list1,
const QStringList &list2) const;
///Converts a string list to a list of QStandardItem pointers.
QList <QStandardItem *> toStandardItemList(const QStringList &) const;
signals:
///Signals that the view has been changed.
void viewUpdated(const QString &, const QStringList &) const;
};
class IViewFactory
{
public:
///Creation interface for view factories
virtual View *createView (CSMSettings::Setting *setting,
Page *parent) = 0;
};
}
#endif // CSVSETTINGS_VIEW_HPP

@ -1,144 +0,0 @@
#include "windowpage.hpp"
#include <QList>
#include <QListView>
#include <QGroupBox>
#include <QRadioButton>
#include <QDockWidget>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QStyle>
#ifdef Q_OS_MAC
#include <QPlastiqueStyle>
#endif
#include "../../model/settings/usersettings.hpp"
#include "groupblock.hpp"
#include "toggleblock.hpp"
#include "../../view/settings/abstractblock.hpp"
CSVSettings::WindowPage::WindowPage(QWidget *parent):
AbstractPage("Window Size", parent)
{
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
QPlastiqueStyle *style = new QPlastiqueStyle;
//profilesComboBox->setStyle(style);
#endif
setupUi();
}
CSVSettings::GroupBlockDef * CSVSettings::WindowPage::buildDefinedWindowSize()
{
GroupBlockDef *block = new GroupBlockDef ( "Defined Size");
SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480");
WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox);
widthByHeightWidget.widgetWidth = 90;
*(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768" << "1440x900";
QStringList *widthProxy = new QStringList;
QStringList *heightProxy = new QStringList;
(*widthProxy) << "Width" << "640" << "800" << "1024" << "1440";
(*heightProxy) << "Height" << "480" << "600" << "768" << "900";
*(widthByHeightItem->proxyList) << widthProxy << heightProxy;
widthByHeightItem->widget = widthByHeightWidget;
block->settingItems << widthByHeightItem;
block->isProxy = true;
block->isVisible = false;
return block;
}
CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildCustomWindowSize()
{
GroupBlockDef *block = new GroupBlockDef ("Custom Size");
//custom width
SettingsItemDef *widthItem = new SettingsItemDef ("Width", "640");
widthItem->widget = WidgetDef (Widget_LineEdit);
widthItem->widget.widgetWidth = 45;
widthItem->widget.inputMask = "9999";
//custom height
SettingsItemDef *heightItem = new SettingsItemDef ("Height", "480");
heightItem->widget = WidgetDef (Widget_LineEdit);
heightItem->widget.widgetWidth = 45;
heightItem->widget.caption = "x";
heightItem->widget.inputMask = "9999";
block->settingItems << widthItem << heightItem;
block->widgetOrientation = Orient_Horizontal;
block->isVisible = false;
return block;
}
CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildWindowSizeToggle()
{
GroupBlockDef *block = new GroupBlockDef (objectName());
// window size toggle
block->captions << "Pre-Defined" << "Custom";
block->widgetOrientation = Orient_Vertical;
block->isVisible = false;
//define a widget for each group in the toggle
for (int i = 0; i < 2; i++)
block->widgets << new WidgetDef (Widget_RadioButton);
block->widgets.at(0)->isDefault = false;
return block;
}
CSVSettings::CustomBlockDef *CSVSettings::WindowPage::buildWindowSize(GroupBlockDef *toggle_def,
GroupBlockDef *defined_def,
GroupBlockDef *custom_def)
{
CustomBlockDef *block = new CustomBlockDef(QString ("Window Size"));
block->blockDefList << toggle_def << defined_def << custom_def;
block->defaultValue = "Custom";
return block;
}
void CSVSettings::WindowPage::setupUi()
{
CustomBlockDef *windowSize = buildWindowSize(buildWindowSizeToggle(),
buildDefinedWindowSize(),
buildCustomWindowSize()
);
mAbstractBlocks << buildBlock<ToggleBlock> (windowSize);
foreach (AbstractBlock *block, mAbstractBlocks)
{
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
}
connect ( this,
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()),
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::WindowPage::initializeWidgets (const CSMSettings::SettingMap &settings)
{
//iterate each item in each blocks in this section
//validate the corresponding setting against the defined valuelist if any.
for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin();
it_block != mAbstractBlocks.end(); ++it_block)
(*it_block)->updateSettings (settings);
}

@ -1,34 +0,0 @@
#ifndef WINDOWPAGE_H
#define WINDOWPAGE_H
#include "abstractpage.hpp"
class QGroupBox;
namespace CSVSettings {
class UserSettings;
class AbstractBlock;
class WindowPage : public AbstractPage
{
Q_OBJECT
public:
WindowPage(QWidget *parent = 0);
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings);
///
GroupBlockDef *buildCustomWindowSize();
GroupBlockDef *buildDefinedWindowSize();
GroupBlockDef *buildWindowSizeToggle();
CustomBlockDef *buildWindowSize (GroupBlockDef *, GroupBlockDef *, GroupBlockDef *);
signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
};
}
#endif //WINDOWPAGE_H

@ -33,12 +33,13 @@ void CSVTools::ReportSubView::setEditLock (bool locked)
// ignored. We don't change document state anyway.
}
void CSVTools::ReportSubView::updateEditorSetting (const QString& key, const QString& value)
void CSVTools::ReportSubView::updateUserSetting
(const QString &name, const QStringList &list)
{
mIdTypeDelegate->updateEditorSetting (key, value);
mIdTypeDelegate->updateUserSetting (name, list);
}
void CSVTools::ReportSubView::show (const QModelIndex& index)
{
focusId (mModel->getUniversalId (index.row()), "");
}
}

@ -39,7 +39,8 @@ namespace CSVTools
virtual void setEditLock (bool locked);
virtual void updateEditorSetting (const QString&, const QString&);
virtual void updateUserSetting
(const QString &, const QStringList &);
private slots:
@ -47,4 +48,4 @@ namespace CSVTools
};
}
#endif
#endif

@ -1,16 +1,26 @@
#include "datadisplaydelegate.hpp"
#include "../../model/settings/usersettings.hpp"
#include <QApplication>
#include <QPainter>
CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
const IconList &icons,
QUndoStack &undoStack, QObject *parent)
: EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly), mIcons (icons)
, mIconSize (QSize(16, 16)), mIconLeftOffset(3), mTextLeftOffset(8)
QUndoStack &undoStack,
const QString &settingKey,
QObject *parent)
: EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly),
mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3),
mTextLeftOffset(8), mSettingKey (settingKey)
{
mTextAlignment.setAlignment (Qt::AlignLeft | Qt::AlignVCenter );
buildPixmaps();
QString value =
CSMSettings::UserSettings::instance().settingValue (settingKey);
updateDisplayMode(value);
}
void CSVWorld::DataDisplayDelegate::buildPixmaps ()
@ -89,6 +99,30 @@ void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOp
painter->drawPixmap (iconRect, mPixmaps.at(index).second);
}
void CSVWorld::DataDisplayDelegate::updateUserSetting (const QString &name,
const QStringList &list)
{
if (list.isEmpty())
return;
QString value = list.at(0);
if (name == mSettingKey)
updateDisplayMode (value);
}
void CSVWorld::DataDisplayDelegate::updateDisplayMode (const QString &mode)
{
if (mode == "Icon and Text")
mDisplayMode = Mode_IconAndText;
else if (mode == "Icon Only")
mDisplayMode = Mode_IconOnly;
else if (mode == "Text Only")
mDisplayMode = Mode_TextOnly;
}
CSVWorld::DataDisplayDelegate::~DataDisplayDelegate()
{
mIcons.clear();
@ -106,5 +140,7 @@ CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (Q
QObject *parent) const
{
return new DataDisplayDelegate (mValues, mIcons, undoStack, parent);
return new DataDisplayDelegate (mValues, mIcons, undoStack, "", parent);
}

@ -35,10 +35,14 @@ namespace CSVWorld
int mIconLeftOffset;
int mTextLeftOffset;
QString mSettingKey;
public:
explicit DataDisplayDelegate (const ValueList & values,
const IconList & icons,
QUndoStack& undoStack, QObject *parent);
QUndoStack& undoStack,
const QString &settingKey,
QObject *parent);
~DataDisplayDelegate();
@ -53,8 +57,14 @@ namespace CSVWorld
/// offset the horizontal position of the text from the right edge of the icon. Default is 8 pixels.
void setTextLeftOffset (int offset);
///update the display mode for the delegate
void updateUserSetting (const QString &name, const QStringList &list);
private:
/// update the display mode based on a passed string
void updateDisplayMode (const QString &);
/// custom paint function for painting the icon. Mode_IconAndText and Mode_Icon only.
void paintIcon (QPainter *painter, const QStyleOptionViewItem &option, int i) const;

@ -4,30 +4,11 @@
CSVWorld::IdTypeDelegate::IdTypeDelegate
(const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent)
: DataDisplayDelegate (values, icons, undoStack, parent)
: DataDisplayDelegate (values, icons, undoStack,
"Display Format.Referenceable ID Type Display",
parent)
{}
bool CSVWorld::IdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
/// \todo make the setting key a member variable, that is initialised from a constructor argument
if (settingName == "Referenceable ID Type Display")
{
if (settingValue == "Icon and Text")
mDisplayMode = Mode_IconAndText;
else if (settingValue == "Icon Only")
mDisplayMode = Mode_IconOnly;
else if (settingValue == "Text Only")
mDisplayMode = Mode_TextOnly;
return true;
}
return false;
}
CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory()
{
for (int i=0; i<CSMWorld::UniversalId::NumberOfTypes; ++i)

@ -12,9 +12,6 @@ namespace CSVWorld
{
public:
IdTypeDelegate (const ValueList &mValues, const IconList &icons, QUndoStack& undoStack, QObject *parent);
virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue);
};
class IdTypeDelegateFactory : public DataDisplayDelegateFactory

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save