Merge remote-tracking branch 'zini/master' into animations

pull/16/head
Chris Robinson 12 years ago
commit 53d1c3939c

@ -48,6 +48,7 @@ public:
mCache.clear(); mCache.clear();
QString sectionPrefix; QString sectionPrefix;
QRegExp sectionRe("^\\[([^]]+)\\]"); QRegExp sectionRe("^\\[([^]]+)\\]");
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");

@ -2,6 +2,7 @@ set (OPENCS_SRC main.cpp)
opencs_units (. editor) opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc opencs_units (model/doc
document document
@ -71,6 +72,35 @@ opencs_units_noqt (view/tools
subviews subviews
) )
opencs_units (view/settings
abstractblock
proxyblock
abstractwidget
usersettingsdialog
editorpage
)
opencs_units_noqt (view/settings
abstractpage
blankpage
groupblock
customblock
groupbox
itemblock
settingwidget
toggleblock
support
)
opencs_units (model/settings
usersettings
settingcontainer
)
opencs_units_noqt (model/settings
support
settingsitem
)
set (OPENCS_US set (OPENCS_US
) )

@ -23,7 +23,6 @@ namespace CS
FileDialog mFileDialog; FileDialog mFileDialog;
Files::ConfigurationManager mCfgMgr; Files::ConfigurationManager mCfgMgr;
void setupDataFiles(); void setupDataFiles();
// not implemented // not implemented

@ -3,6 +3,7 @@
#include <cassert> #include <cassert>
#include <QDebug>
void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin, void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified) const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
{ {

@ -0,0 +1,82 @@
#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;
}

@ -0,0 +1,37 @@
#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);
virtual QString getName() const {return "";}
void insert (const QString &value);
void update (const QString &value, int index = 0);
QString getValue (int index = -1) const;
inline QStringList *getValues() const { return mValues; }
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,102 @@
#include "settingsitem.hpp"
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)
{
bool isValid = true;
//validation required only if a value list or min/max value pair has been provided
if (mValueList->size()>0)
{
for (QStringList::ConstIterator it = mValueList->begin(); it !=mValueList->end(); ++it)
{
isValid = ( value == *it);
if (isValid)
break;
}
}
else if (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;
}

@ -0,0 +1,47 @@
#ifndef SETTINGSITEM_HPP
#define SETTINGSITEM_HPP
#include <QObject>
#include "support.hpp"
#include "settingcontainer.hpp"
namespace CSMSettings
{
class SettingsItem : public SettingContainer
{
QStringPair *mValuePair;
QStringList *mValueList;
bool mIsMultiValue;
QString mName;
QString mDefaultValue;
public:
explicit SettingsItem(QString name, bool isMultiValue,
const QString& defaultValue, QObject *parent = 0)
: SettingContainer(defaultValue, parent),
mIsMultiValue (isMultiValue), mValueList (0),
mName (name), mValuePair (0), mDefaultValue (defaultValue)
{}
bool updateItem (const QStringList *values);
bool updateItem (const QString &value);
bool updateItem (int valueListIndex);
inline QStringList *getValueList() { return mValueList; }
inline void setValueList (QStringList *valueList) { mValueList = valueList; }
inline QStringPair *getValuePair() { return mValuePair; }
inline void setValuePair (QStringPair valuePair) { mValuePair = new QStringPair(valuePair); }
inline QString getName () const { return mName; }
inline bool isMultivalue () { return mIsMultiValue; }
void setDefaultValue (const QString &value);
QString getDefaultValue () const;
private:
bool validate (const QString &value);
};
}
#endif // SETTINGSITEM_HPP

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

@ -0,0 +1,39 @@
#ifndef MODEL_SUPPORT_HPP
#define MODEL_SUPPORT_HPP
#include <QObject>
#include <QStringList>
class QLayout;
class QWidget;
class QListWidgetItem;
namespace CSMSettings
{
class SettingContainer;
typedef QList<SettingContainer *> SettingList;
typedef QMap<QString, SettingContainer *> SettingMap;
typedef QMap<QString, SettingMap *> SectionMap;
struct QStringPair
{
QStringPair(): left (""), right ("")
{}
QStringPair (const QString &leftValue, const QString &rightValue)
: left (leftValue), right(rightValue)
{}
QStringPair (const QStringPair &pair)
: left (pair.left), right (pair.right)
{}
QString left;
QString right;
bool isEmpty() const
{ return (left.isEmpty() && right.isEmpty()); }
};
}
#endif // MODEL_SUPPORT_HPP

@ -0,0 +1,137 @@
#include "usersettings.hpp"
#include <QTextStream>
#include <QDir>
#include <QString>
#include <QRegExp>
#include <QMap>
#include <QMessageBox>
#include <QTextCodec>
#include <components/files/configurationmanager.hpp>
#include "settingcontainer.hpp"
#include <boost/version.hpp>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
#if (BOOST_VERSION <= 104600)
namespace boost
{
template<>
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
{
return boost::filesystem::path(arg);
}
} /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */
CSMSettings::UserSettings::UserSettings()
{
mUserSettingsInstance = this;
}
CSMSettings::UserSettings::~UserSettings()
{
}
QFile *CSMSettings::UserSettings::openFile (const QString &filename)
{
QFile *file = new QFile(filename);
bool success = (file->open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) ;
if (!success)
{
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("Error writing OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open or create %0 for writing</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(file->fileName()));
msgBox.exec();
delete file;
file = 0;
}
return file;
}
bool CSMSettings::UserSettings::writeFile(QFile *file, QMap<QString, CSMSettings::SettingList *> &settings)
{
if (!file)
return false;
QTextStream stream(file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
QList<QString> keyList = settings.keys();
foreach (QString key, keyList)
{
SettingList *sectionSettings = settings[key];
stream << "[" << key << "]" << '\n';
foreach (SettingContainer *item, *sectionSettings)
stream << item->getName() << " = " << item->getValue() << '\n';
}
file->close();
return true;
}
void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap &sections)
{
//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 whirespace, "\\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)
sections.insert(section, settings);
//save new section and create a new list
section = sectionRe.cap(1);
settings = new SettingMap;
continue;
}
if (keyRe.indexIn(line) != -1)
{
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified());
(*settings)[keyRe.cap(1).simplified()] = sc;
}
}
sections.insert(section, settings);
}

@ -0,0 +1,52 @@
#ifndef USERSETTINGS_HPP
#define USERSETTINGS_HPP
#include <QTextStream>
#include <QStringList>
#include <QString>
#include <QMap>
#include <boost/filesystem/path.hpp>
#include "support.hpp"
namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
struct ConfigurationManager;}
class QFile;
namespace CSMSettings {
struct UserSettings: public QObject
{
Q_OBJECT
public:
static UserSettings &instance()
{
static UserSettings instance;
return instance;
}
QFile *openFile (const QString &);
bool writeFile(QFile *file, QMap<QString, SettingList *> &sections);
void getSettings (QTextStream &stream, SectionMap &settings);
private:
UserSettings *mUserSettingsInstance;
UserSettings();
~UserSettings();
UserSettings (UserSettings const &); //not implemented
void operator= (UserSettings const &); //not implemented
signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
};
}
#endif // USERSETTINGS_HPP

@ -0,0 +1,6 @@
#include "ocspropertywidget.hpp"
OcsPropertyWidget::OcsPropertyWidget(QObject *parent) :
QObject(parent)
{
}

@ -0,0 +1,18 @@
#ifndef OCSPROPERTYWIDGET_HPP
#define OCSPROPERTYWIDGET_HPP
#include <QObject>
class OcsPropertyWidget : public QObject
{
Q_OBJECT
public:
explicit OcsPropertyWidget(QObject *parent = 0);
signals:
public slots:
};
#endif // OCSPROPERTYWIDGET_HPP

@ -1,8 +1,11 @@
#include "startup.hpp" #include "startup.hpp"
#include <QApplication>
#include <QDesktopWidget>
#include <QPushButton> #include <QPushButton>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QRect>
CSVDoc::StartupDialogue::StartupDialogue() CSVDoc::StartupDialogue::StartupDialogue()
{ {
@ -17,4 +20,8 @@ CSVDoc::StartupDialogue::StartupDialogue()
layout->addWidget (loadDocument); layout->addWidget (loadDocument);
setLayout (layout); setLayout (layout);
}
QRect scr = QApplication::desktop()->screenGeometry();
QRect rect = geometry();
move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y());
}

@ -10,11 +10,9 @@
#include <QtGui/QApplication> #include <QtGui/QApplication>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../world/subviews.hpp" #include "../world/subviews.hpp"
#include "../tools/subviews.hpp" #include "../tools/subviews.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "viewmanager.hpp" #include "viewmanager.hpp"
#include "operations.hpp" #include "operations.hpp"
#include "subview.hpp" #include "subview.hpp"
@ -67,6 +65,10 @@ void CSVDoc::View::setupEditMenu()
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo"));
mRedo->setShortcuts (QKeySequence::Redo); mRedo->setShortcuts (QKeySequence::Redo);
edit->addAction (mRedo); edit->addAction (mRedo);
QAction *userSettings = new QAction (tr ("&Preferences"), this);
connect (userSettings, SIGNAL (triggered()), this, SLOT (showUserSettings()));
edit->addAction (userSettings);
} }
void CSVDoc::View::setupViewMenu() void CSVDoc::View::setupViewMenu()
@ -349,3 +351,25 @@ void CSVDoc::View::exit()
{ {
emit exitApplicationRequest (this); emit exitApplicationRequest (this);
} }
void CSVDoc::View::showUserSettings()
{
CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this);
connect (&(CSMSettings::UserSettings::instance()), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)) );
settingsDialog->show();
}
void CSVDoc::View::slotUpdateEditorSetting(const QString &settingName, const QString &settingValue)
{
static QString lastValue = "";
if (lastValue != settingValue)
{
//evaluate settingName against tokens to determine which function to call to update Editor application.
lastValue = settingValue;
}
}

@ -102,6 +102,8 @@ namespace CSVDoc
void abortOperation (int type); void abortOperation (int type);
void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue);
private slots: private slots:
void newView(); void newView();
@ -135,6 +137,8 @@ namespace CSVDoc
void addSpellsSubView(); void addSpellsSubView();
void addCellsSubView(); void addCellsSubView();
void showUserSettings();
}; };
} }

@ -3,6 +3,9 @@
#include <map> #include <map>
#include <QApplication>
#include <QDesktopWidget>
#include "../../model/doc/documentmanager.hpp" #include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"

@ -0,0 +1,112 @@
#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 = createSettingWidget<QRadioButton> (def, layout);
break;
case Widget_SpinBox:
widg = createSettingWidget<QSpinBox> (def, layout);
break;
case Widget_CheckBox:
widg = createSettingWidget<QCheckBox> (def, layout);
break;
case Widget_LineEdit:
widg = createSettingWidget<QLineEdit> (def, layout);
break;
case Widget_ListBox:
widg = createSettingWidget<QListWidget> (def, layout);
break;
case Widget_ComboBox:
widg = createSettingWidget<QComboBox> (def, layout);
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);
}

@ -0,0 +1,71 @@
#ifndef ABSTRACTBLOCK_HPP
#define ABSTRACTBLOCK_HPP
#include <QObject>
#include <QList>
#include "settingwidget.hpp"
#include "../../model/settings/settingsitem.hpp"
#include "groupbox.hpp"
namespace CSVSettings
{
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;
virtual bool updateSettings (const CSMSettings::SettingMap &settings) = 0;
virtual bool updateBySignal (const QString &name, const QString &value, bool &doEmit)
{ return false; }
protected:
QLayout *createLayout (Orientation direction, bool isZeroMargin, QWidget* parent = 0);
AbstractWidget *buildWidget (const QString &widgetName, WidgetDef &wDef,
QLayout *layout = 0, bool isConnected = true) const;
template <typename T>
AbstractWidget *createSettingWidget (WidgetDef &wDef, QLayout *layout) const
{
return new SettingWidget<T> (wDef, layout, mBox);
}
QWidget *getParent() const;
public slots:
void slotSetEnabled (bool value);
void slotUpdateSetting (const QString &settingName, const QString &settingValue);
private slots:
void slotUpdate (const QString &value);
signals:
//signal to functions outside the settings tab widget
void signalUpdateSetting (const QString &propertyName, const QString &propertyValue);
void signalUpdateWidget (const QString & value);
//propertyName and propertyValue are for properties for which the updated setting acts as a proxy
void signalUpdateProxySetting (const QString &propertyName, const QString &propertyValue);
};
}
#endif // ABSTRACTBLOCK_HPP

@ -0,0 +1,39 @@
#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)
{
}
CSVSettings::AbstractPage::AbstractPage(const QString &pageName, QWidget *parent):
QWidget(parent)
{
QWidget::setObjectName (pageName);
}
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;
}

@ -0,0 +1,59 @@
#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;
class AbstractPage: public QWidget
{
protected:
AbstractBlockList mAbstractBlocks;
public:
AbstractPage(QWidget *parent = 0);
AbstractPage (const QString &pageName, QWidget* parent = 0);
~AbstractPage();
virtual void setupUi()=0;
virtual void initializeWidgets (const CSMSettings::SettingMap &settings) = 0;
CSMSettings::SettingList *getSettings();
void setObjectName();
protected:
template <typename S, typename T>
AbstractBlock *buildBlock (T &def)
{
S *block = new S (this);
int ret = block->build (def);
if (ret < 0)
return 0;
QWidget::layout()->addWidget (block->getGroupBox());
return block;
}
};
}
#endif // ABSTRACTPAGE_HPP

@ -0,0 +1,78 @@
#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)
{}

@ -0,0 +1,64 @@
#ifndef ABSTRACTWIDGET_HPP
#define ABSTRACTWIDGET_HPP
#include <QWidget>
#include "support.hpp"
class QLayout;
namespace CSVSettings
{
class AbstractWidget : public QObject
{
Q_OBJECT
QLayout *mLayout;
public:
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:
//called by inbound signal for type-specific widget udpates
virtual void updateWidget (const QString &value) = 0;
//converts user-defined enum to Qt equivalents
QFlags<Qt::AlignmentFlag> getAlignment (Alignment flag);
private:
//widget initialization utilities
void createLayout (Orientation direction, bool isZeroMargin);
void buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel);
signals:
//outbound update
void signalUpdateItem (const QString &value);
public slots:
//inbound updates
void slotUpdateWidget (const QString &value);
//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

@ -0,0 +1,58 @@
#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)
{
initPage();
}
CSVSettings::BlankPage::BlankPage(const QString &title, QWidget *parent):
AbstractPage(title, parent)
{
initPage();
}
void CSVSettings::BlankPage::initPage()
{
// 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);
QLayout* pageLayout = new QVBoxLayout();
setLayout(pageLayout);
pageLayout->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);
}

@ -0,0 +1,29 @@
#ifndef BLANKPAGE_HPP
#define BLANKPAGE_HPP
#include "abstractpage.hpp"
class QGroupBox;
namespace CSVSettings {
class UserSettings;
class AbstractBlock;
class BlankPage : public AbstractPage
{
public:
BlankPage (QWidget *parent = 0);
BlankPage (const QString &title, QWidget *parent);
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings);
private:
void initPage();
};
}
#endif // BLANKPAGE_HPP

@ -0,0 +1,120 @@
#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);
QLayout *layout = 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.properties.size() != 1)
return -1;
int retVal = block->build(def);
if (retVal != 0)
return retVal;
foreach (QStringList *list, *(def.properties.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;
}

@ -0,0 +1,36 @@
#ifndef CUSTOMBLOCK_HPP
#define CUSTOMBLOCK_HPP
#include "abstractblock.hpp"
namespace CSVSettings
{
class ProxyBlock;
class CustomBlock : public AbstractBlock
{
protected:
GroupBlockList mGroupList;
public:
explicit CustomBlock (QWidget *parent = 0);
bool updateSettings (const CSMSettings::SettingMap &settings);
CSMSettings::SettingList *getSettings();
int build (GroupBlockDefList &defList, GroupBlockDefList::Iterator *it = 0);
protected:
GroupBox *buildGroupBox (Orientation orientation);
private:
int buildGroupBlock(GroupBlockDef &def);
int buildProxyBlock(GroupBlockDef &def, ProxyBlock *block);
};
}
#endif // CUSTOMBLOCK_HPP

@ -0,0 +1,163 @@
#include "editorpage.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::EditorPage::EditorPage(QWidget *parent):
AbstractPage("Editor", parent)
{
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
QPlastiqueStyle *style = new QPlastiqueStyle;
//profilesComboBox->setStyle(style);
#endif
setupUi();
}
void CSVSettings::EditorPage::setupUi()
{
GroupBlockDef undoStack (QString("Undo Stack Size"));
GroupBlockDef topLevelWindowCount (QString("Maximum Top-Level Window Count"));
GroupBlockDef reuseSubwindow (QString("Reuse Subwindows"));
GroupBlockDef customWindowSize (QString ("Custom Window Size"));
GroupBlockDef definedWindowSize (QString ("Pre-Defined Window Size"));
GroupBlockDef windowSizeToggle (QString ("Window Size"));
CustomBlockDef windowSize (QString ("Window Size"));
////////////////////////////
//undo stack size property
///////////////////////////
SettingsItemDef *undoStackItem = new SettingsItemDef (undoStack.title, "32");
undoStack.properties << undoStackItem;
undoStackItem->minMax.left = "0";
undoStackItem->minMax.right = "64";
WidgetDef stackWidget (Widget_SpinBox);
stackWidget.minMax = &(undoStackItem->minMax);
stackWidget.widgetWidth = 50;
undoStackItem->widget = stackWidget;
//////////////////////////////////////
//number of top level windows property
/////////////////////////////////////
SettingsItemDef *topLevelItem = new SettingsItemDef (topLevelWindowCount.title, "100");
topLevelWindowCount.properties << topLevelItem;
topLevelItem->minMax.left = "1";
topLevelItem->minMax.right = "256";
WidgetDef topLvlWinWidget (Widget_SpinBox);
topLvlWinWidget.minMax = &(topLevelItem->minMax);
topLvlWinWidget.widgetWidth = 50;
topLevelItem->widget = topLvlWinWidget;
///////////////////////////
//reuse subwindows property
////////////////////////////
SettingsItemDef *reuseSubItem = new SettingsItemDef (reuseSubwindow.title, "Reuse Subwindows");
*(reuseSubItem->valueList) << "None" << "Top-Level" << "Document-Level";
WidgetDef reuseSubWidget (Widget_RadioButton);
reuseSubWidget.valueList = (reuseSubItem->valueList);
reuseSubWidget.widgetAlignment = Align_Left;
reuseSubwindow.properties << reuseSubItem;
reuseSubItem->widget = reuseSubWidget;
///////////////////////////////
//custom window size properties
///////////////////////////////
//custom width
SettingsItemDef *widthItem = new SettingsItemDef ("Window Width", "640");
widthItem->widget = WidgetDef (Widget_LineEdit);
widthItem->widget.widgetWidth = 45;
//custom height
SettingsItemDef *heightItem = new SettingsItemDef ("Window Height", "480");
heightItem->widget = WidgetDef (Widget_LineEdit);
heightItem->widget.widgetWidth = 45;
heightItem->widget.caption = "x";
customWindowSize.properties << widthItem << heightItem;
customWindowSize.widgetOrientation = Orient_Horizontal;
customWindowSize.isVisible = false;
//pre-defined
SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480");
WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox);
widthByHeightWidget.widgetWidth = 90;
*(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768";
QStringList *widthProxy = new QStringList;
QStringList *heightProxy = new QStringList;
(*widthProxy) << "Window Width" << "640" << "800" << "1024";
(*heightProxy) << "Window Height" << "480" << "600" << "768";
*(widthByHeightItem->proxyList) << widthProxy << heightProxy;
widthByHeightItem->widget = widthByHeightWidget;
definedWindowSize.properties << widthByHeightItem;
definedWindowSize.isProxy = true;
definedWindowSize.isVisible = false;
// window size toggle
windowSizeToggle.captions << "Pre-Defined" << "Custom";
windowSizeToggle.widgetOrientation = Orient_Vertical;
windowSizeToggle.isVisible = false;
//define a widget for each group in the toggle
for (int i = 0; i < 2; i++)
windowSizeToggle.widgets << new WidgetDef (Widget_RadioButton);
windowSizeToggle.widgets.at(0)->isDefault = false;
windowSize.blockDefList << &windowSizeToggle << &definedWindowSize << &customWindowSize;
windowSize.defaultValue = "Custom";
QGridLayout *pageLayout = new QGridLayout(this);
setLayout (pageLayout);
mAbstractBlocks << buildBlock<GroupBlock> (topLevelWindowCount)
<< buildBlock<GroupBlock> (reuseSubwindow)
<< buildBlock<ToggleBlock> (windowSize)
<< buildBlock<GroupBlock> (undoStack);
foreach (AbstractBlock *block, mAbstractBlocks)
{
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, 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);
}

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

@ -0,0 +1,108 @@
#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.properties.size() == 0)
return -1;
int retVal = 0;
setVisible (def.isVisible);
mBox->setLayout(createLayout (def.widgetOrientation, true));
setObjectName (def.title);
mBox->setTitle (def.title);
foreach (SettingsItemDef *itemDef, def.properties)
{
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;
}

@ -0,0 +1,32 @@
#ifndef GROUPBLOCK_HPP
#define GROUPBLOCK_HPP
#include <QList>
#include "abstractblock.hpp"
namespace CSVSettings
{
class ItemBlock;
class GroupBlock : public AbstractBlock
{
ItemBlockList mItemBlockList;
public:
GroupBlock (QWidget* parent = 0);
GroupBlock (bool isVisible, QWidget *parent = 0);
int build (GroupBlockDef &def);
bool updateSettings (const CSMSettings::SettingMap &settings);
CSMSettings::SettingList *getSettings();
ItemBlock *getItemBlock (const QString &name, ItemBlockList *blockList = 0);
ItemBlock *getItemBlock (int index);
protected:
int buildLayout (GroupBlockDef &def);
};
}
#endif // GROUPBLOCK_HPP

@ -0,0 +1,56 @@
#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);
}

@ -0,0 +1,27 @@
#ifndef GROUPBOX_HPP
#define GROUPBOX_HPP
#include <QGroupBox>
namespace CSVSettings
{
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

@ -0,0 +1,115 @@
#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();
}

@ -0,0 +1,38 @@
#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);
bool updateSettings (const CSMSettings::SettingMap &settings) { return false; }
CSMSettings::SettingList *getSettings ();
QString getValue () const;
int getSettingCount();
bool update (const QString &value);
int build(SettingsItemDef &iDef);
private:
void buildItemBlock (SettingsItemDef& iDef);
void buildItemBlockWidgets (SettingsItemDef& iDef);
bool updateItem (const QString &);
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
};
}
#endif // ITEMBLOCK_HPP

@ -0,0 +1,149 @@
#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.properties.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;
for (; i < mValueList->size(); ++i)
{
success = (value == mValueList->at(i));
if (success)
break;
}
if (!success)
return false;
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);
}

@ -0,0 +1,42 @@
#ifndef PROXYBLOCK_HPP
#define PROXYBLOCK_HPP
#include "groupblock.hpp"
namespace CSVSettings
{
class ProxyBlock : public GroupBlock
{
Q_OBJECT
//NOTE: mProxyItemBlockList and mProxyList
//should be combined into a value pair and stored in one list.
ItemBlockList mProxiedItemBlockList;
ProxyList mProxyList;
QStringList *mValueList;
public:
explicit ProxyBlock (QWidget *parent = 0);
explicit ProxyBlock (ItemBlock *proxyItemBlock, QWidget *parent = 0);
void addSetting (ItemBlock* settingBlock, QStringList *proxyList);
int build (GroupBlockDef &def);
CSMSettings::SettingList *getSettings() { return 0; }
bool updateSettings (const CSMSettings::SettingMap &settings);
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
private:
ItemBlock *getProxiedItemBlock (const QString &name);
bool updateByProxiedSettings(const CSMSettings::SettingMap *settings = 0);
bool updateProxiedSettings();
private slots:
void slotUpdateProxySetting (const QString &name, const QString &value);
};
}
#endif // PROXYBLOCK_HPP

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

@ -0,0 +1,208 @@
#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
{
//VALID FOR RADIOBUTTON / CHECKBOX (or other toggle widget with it's own label)
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);
}
};
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:
};
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));
}
};
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);
}
};
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 @@
#include "support.hpp"

@ -0,0 +1,144 @@
#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
};
//template for defining the widget of a property.
struct WidgetDef
{
WidgetType type; //type of widget providing input
int labelWidth; //width of caption label
int widgetWidth; //width of input widget
Orientation orientation; //label / widget orientation (horizontal / vertical)
QString inputMask; //input mask (line edit)
QString caption; //label caption. Leave empty for multiple items. See BlockDef::captionList
QString value; //widget value. Leave empty for multiple items. See BlockDef::valueList
CSMSettings::QStringPair *minMax; //Min/Max QString value pair. If empty, assigned to property item value pair.
QStringList *valueList; //value list for list widgets. If left empty, is assigned to property item value list during block build().
bool isDefault; //isDefault - determined at runtime.
Alignment valueAlignment; //left / center / right-justify text in widget
Alignment widgetAlignment; //left / center / right-justify widget in group box
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 property 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 property.
struct SettingsItemDef
{
QString name; //property name
QStringList *valueList; //list of valid values for the property.
//Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value)
QString defaultValue;
bool hasMultipleValues;
CSMSettings::QStringPair minMax; //minimum / maximum value pair
WidgetDef widget; //definition of the input widget for this setting
Orientation orientation; //general orientation of the widget / label for this property
ProxyList *proxyList; //list of property and corresponding default values for proxy widget
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)
{}
};
//Hierarchically, this is a "sub-section" of properties within a section, solely for UI organization.
//Does not correlate to config file structure.
struct GroupBlockDef
{
QString title; //title of the block containing the property or properties of this sub-section
QStringList captions; //list of captions for widgets at the block level (not associated with any particular property)
WidgetList widgets; //list of widgets at the block level (not associated with any particular property)
QList<SettingsItemDef *> properties; //list of the property(ies) which are subordinate to the property block.
Orientation widgetOrientation; //general orientation of widgets in group block
bool isVisible; //determines whether or not box border/title are visible
bool isProxy; //indicates whether or not this block defines a proxy block
QString defaultValue; //generic default value attribute
GroupBlockDef (): title(""), widgetOrientation (Orient_Vertical), isVisible (true), isProxy (false), defaultValue ("")
{}
GroupBlockDef (QString blockTitle)
: title (blockTitle), widgetOrientation (Orient_Vertical), isProxy (false), isVisible (true), defaultValue ("")
{}
};
struct CustomBlockDef
{
QString title;
QString defaultValue; //default value for widgets unique to the custom block
GroupBlockDefList blockDefList; //list of settings groups that comprise the settings within the custom 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,80 @@
#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;
}

@ -0,0 +1,27 @@
#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:
GroupBox *buildToggleWidgets (GroupBlockDef &def, QString &defaultToggle);
};
}
#endif // TOGGLEBLOCK_HPP

@ -0,0 +1,173 @@
#include "usersettingsdialog.hpp"
#include <QApplication>
#include <QDesktopWidget>
#include <QWidget>
#include <QTabWidget>
#include <QMessageBox>
#include <QTextCodec>
#include <QFile>
#include <QPushButton>
#include <QDockWidget>
#include "blankpage.hpp"
#include "editorpage.hpp"
#include "../../model/settings/support.hpp"
#include "settingwidget.hpp"
#include <QDebug>
CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
QMainWindow (parent), mStackedWidget (0)
{
setWindowTitle(QString::fromUtf8 ("User Settings"));
buildPages();
setWidgetStates (loadSettings());
positionWindow ();
connect (mListWidget,
SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this,
SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
}
CSVSettings::UserSettingsDialog::~UserSettingsDialog()
{
}
void CSVSettings::UserSettingsDialog::closeEvent (QCloseEvent *event)
{
writeSettings();
}
void CSVSettings::UserSettingsDialog::setWidgetStates (CSMSettings::SectionMap settingsMap)
{
//iterate the tabWidget's pages (sections)
for (int i = 0; i < mStackedWidget->count(); i++)
{
//get the settings defined for the entire section
CSMSettings::SettingMap *settings = settingsMap [mStackedWidget->widget(i)->objectName()];
//if found, initialize the page's widgets
if (settings)
{
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);
QLayout* dialogLayout = new QHBoxLayout();
dialogLayout->addWidget (mListWidget);
dialogLayout->addWidget (mStackedWidget);
centralWidget->setLayout (dialogLayout);
setCentralWidget (centralWidget);
setDockOptions (QMainWindow::AllowNestedDocks);
//uncomment to test with sample editor page.
//createSamplePage();
createPage<BlankPage>("Page1");
createPage<BlankPage>("Page2");
createPage<BlankPage>("Page3");
}
void CSVSettings::UserSettingsDialog::createSamplePage()
{
//add pages to stackedwidget and items to listwidget
CSVSettings::AbstractPage *page
= new CSVSettings::EditorPage(this);
mStackedWidget->addWidget (page);
new QListWidgetItem (page->objectName(), mListWidget);
connect ( page, SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()), SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::UserSettingsDialog::positionWindow ()
{
QRect scr = QApplication::desktop()->screenGeometry();
move(scr.center().x() - (width() / 2), scr.center().y() - (height() / 2));
}
CSMSettings::SectionMap CSVSettings::UserSettingsDialog::loadSettings ()
{
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
mPaths.append(QString("opencs.cfg"));
mPaths.append(userPath + QString("opencs.cfg"));
CSMSettings::SectionMap settingsMap;
foreach (const QString &path, mPaths)
{
qDebug() << "Loading config file:" << qPrintable(path);
QFile file(path);
if (file.exists())
{
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error opening OpenCS configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName()));
msgBox.exec();
return settingsMap;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
CSMSettings::UserSettings::instance().getSettings(stream, settingsMap);
}
file.close();
}
return settingsMap;
}
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().writeFile(CSMSettings::UserSettings::instance().openFile(mPaths.back()), 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));
}

@ -0,0 +1,71 @@
#ifndef USERSETTINGSDIALOG_H
#define USERSETTINGSDIALOG_H
#include <QMainWindow>
#include <QStackedWidget>
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
#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
QStringList mPaths;
QListWidget *mListWidget;
QStackedWidget *mStackedWidget;
Files::ConfigurationManager mCfgMgr;
public:
UserSettingsDialog(QMainWindow *parent = 0);
~UserSettingsDialog();
private:
void closeEvent (QCloseEvent *event);
AbstractPage *getAbstractPage (int index);
void setWidgetStates (CSMSettings::SectionMap settingsMap);
void buildPages();
void positionWindow ();
CSMSettings::SectionMap loadSettings();
void writeSettings();
void createSamplePage();
template <typename T>
void createPage (const QString &title)
{
T *page = new T(title, this);
mStackedWidget->addWidget (dynamic_cast<QWidget *>(page));
new QListWidgetItem (page->objectName(), mListWidget);
//finishing touches
if (mStackedWidget->sizeHint().width() < 640)
mStackedWidget->sizeHint().setWidth(640);
if (mStackedWidget->sizeHint().height() < 480)
mStackedWidget->sizeHint().setHeight(480);
resize (mStackedWidget->sizeHint());
}
public slots:
void slotChangePage (QListWidgetItem*, QListWidgetItem*);
};
}
#endif // USERSETTINGSDIALOG_H

@ -238,6 +238,7 @@ namespace MWBase
virtual void enableRest() = 0; virtual void enableRest() = 0;
virtual bool getRestEnabled() = 0; virtual bool getRestEnabled() = 0;
virtual bool getJournalAllowed() = 0;
virtual bool getPlayerSleeping() = 0; virtual bool getPlayerSleeping() = 0;
virtual void wakeUpPlayer() = 0; virtual void wakeUpPlayer() = 0;

@ -235,6 +235,12 @@ namespace MWClass
return 0; return 0;
} }
bool Creature::isPersistent(const MWWorld::Ptr &actor) const
{
MWWorld::LiveCellRef<ESM::Creature>* ref = actor.get<ESM::Creature>();
return ref->mBase->mPersistent;
}
MWWorld::Ptr MWWorld::Ptr
Creature::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const Creature::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
{ {

@ -64,6 +64,8 @@ namespace MWClass
virtual int getServices (const MWWorld::Ptr& actor) const; virtual int getServices (const MWWorld::Ptr& actor) const;
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
static void registerSelf(); static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;

@ -235,6 +235,12 @@ namespace MWClass
MWBase::Environment::get().getMechanicsManager()->add(ptr); MWBase::Environment::get().getMechanicsManager()->add(ptr);
} }
bool Npc::isPersistent(const MWWorld::Ptr &actor) const
{
MWWorld::LiveCellRef<ESM::NPC>* ref = actor.get<ESM::NPC>();
return ref->mBase->mPersistent;
}
std::string Npc::getModel(const MWWorld::Ptr &ptr) const std::string Npc::getModel(const MWWorld::Ptr &ptr) const
{ {
MWWorld::LiveCellRef<ESM::NPC> *ref = MWWorld::LiveCellRef<ESM::NPC> *ref =

@ -130,6 +130,8 @@ namespace MWClass
virtual int getServices (const MWWorld::Ptr& actor) const; virtual int getServices (const MWWorld::Ptr& actor) const;
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
static void registerSelf(); static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;

@ -404,8 +404,8 @@ namespace MWClass
{ {
return std::make_pair (2, ""); return std::make_pair (2, "");
} }
return std::make_pair (1, "");
} }
return std::make_pair(1, "");
} }
return std::make_pair (0, ""); return std::make_pair (0, "");
} }

@ -201,7 +201,7 @@ namespace MWGui
{ {
mPtr = container; mPtr = container;
if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot)
{ {
// we are stealing stuff // we are stealing stuff
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
@ -258,9 +258,9 @@ namespace MWGui
onTakeAllButtonClicked(mTakeButton); onTakeAllButtonClicked(mTakeButton);
/// \todo if corpse is non-disposable: messagebox #{sDisposeCorpseFail} /// \todo if corpse is non-disposable: messagebox #{sDisposeCorpseFail}
//if () if (MWWorld::Class::get(mPtr).isPersistent(mPtr))
// MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}");
//else else
MWBase::Environment::get().getWorld()->deleteObject(mPtr); MWBase::Environment::get().getWorld()->deleteObject(mPtr);
mPtr = MWWorld::Ptr(); mPtr = MWWorld::Ptr();

@ -18,6 +18,8 @@ namespace MWGui
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onOkButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onOkButtonClicked);
mItemEdit->eventEditTextChange += MyGUI::newDelegate(this, &CountDialog::onEditTextChange); mItemEdit->eventEditTextChange += MyGUI::newDelegate(this, &CountDialog::onEditTextChange);
mSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &CountDialog::onSliderMoved); mSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &CountDialog::onSliderMoved);
// make sure we read the enter key being pressed to accept multiple items
mItemEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &CountDialog::onEnterKeyPressed);
} }
void CountDialog::open(const std::string& item, const std::string& message, const int maxCount) void CountDialog::open(const std::string& item, const std::string& message, const int maxCount)
@ -37,6 +39,7 @@ namespace MWGui
width, width,
mMainWidget->getHeight()); mMainWidget->getHeight());
// by default, the text edit field has the focus of the keyboard
MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit); MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit);
mSlider->setScrollPosition(maxCount-1); mSlider->setScrollPosition(maxCount-1);
@ -54,7 +57,16 @@ namespace MWGui
setVisible(false); setVisible(false);
} }
// essentially duplicating what the OK button does if user presses
// Enter key
void CountDialog::onEnterKeyPressed(MyGUI::EditBox* _sender)
{
eventOkClicked(NULL, mSlider->getScrollPosition()+1);
setVisible(false);
}
void CountDialog::onEditTextChange(MyGUI::EditBox* _sender) void CountDialog::onEditTextChange(MyGUI::EditBox* _sender)
{ {
if (_sender->getCaption() == "") if (_sender->getCaption() == "")

@ -25,11 +25,12 @@ namespace MWGui
MyGUI::TextBox* mLabelText; MyGUI::TextBox* mLabelText;
MyGUI::Button* mOkButton; MyGUI::Button* mOkButton;
MyGUI::Button* mCancelButton; MyGUI::Button* mCancelButton;
void onCancelButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender);
void onOkButtonClicked(MyGUI::Widget* _sender); void onOkButtonClicked(MyGUI::Widget* _sender);
void onEditTextChange(MyGUI::EditBox* _sender); void onEditTextChange(MyGUI::EditBox* _sender);
void onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position); void onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position);
void onEnterKeyPressed(MyGUI::EditBox* _sender);
}; };
} }

@ -180,6 +180,10 @@ namespace
void open() void open()
{ {
if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ())
{
MWBase::Environment::get().getWindowManager()->popGuiMode ();
}
mModel->load (); mModel->load ();
setBookMode (); setBookMode ();

@ -226,6 +226,8 @@ namespace MWGui
virtual void enableRest() { mRestAllowed = true; } virtual void enableRest() { mRestAllowed = true; }
virtual bool getRestEnabled(); virtual bool getRestEnabled();
virtual bool getJournalAllowed() { return (mAllowed & GW_Magic); }
virtual bool getPlayerSleeping(); virtual bool getPlayerSleeping();
virtual void wakeUpPlayer(); virtual void wakeUpPlayer();

@ -220,6 +220,11 @@ namespace MWWorld
return get (ptr.getTypeName()); return get (ptr.getTypeName());
} }
bool Class::isPersistent(const Ptr &ptr) const
{
throw std::runtime_error ("class does not support persistence");
}
void Class::registerClass (const std::string& key, boost::shared_ptr<Class> instance) void Class::registerClass (const std::string& key, boost::shared_ptr<Class> instance)
{ {
sClasses.insert (std::make_pair (key, instance)); sClasses.insert (std::make_pair (key, instance));

@ -253,6 +253,8 @@ namespace MWWorld
virtual float getWeight (const MWWorld::Ptr& ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
virtual Ptr virtual Ptr
copyToCell(const Ptr &ptr, CellStore &cell) const; copyToCell(const Ptr &ptr, CellStore &cell) const;

@ -1245,7 +1245,7 @@ namespace MWWorld
{ {
--mPlayIntro; --mPlayIntro;
if (mPlayIntro == 0) if (mPlayIntro == 0)
mRendering->playVideo("mw_intro.bik", true); mRendering->playVideo(mFallback.getFallbackString("Movies_New_Game"), true);
} }
mWeatherManager->update (duration); mWeatherManager->update (duration);

@ -15,8 +15,9 @@ ESM_Context ESMReader::getContext()
return mCtx; return mCtx;
} }
ESMReader::ESMReader(): ESMReader::ESMReader()
mBuffer(50*1024) : mBuffer(50*1024)
, mRecordFlags(0)
{ {
} }

@ -216,7 +216,7 @@ public:
follows the header, ie beyond the entire record. You should use follows the header, ie beyond the entire record. You should use
leftRec to orient yourself inside the record itself. leftRec to orient yourself inside the record itself.
*/ */
void getRecHeader() { uint32_t u; getRecHeader(u); } void getRecHeader() { getRecHeader(mRecordFlags); }
void getRecHeader(uint32_t &flags); void getRecHeader(uint32_t &flags);
bool hasMoreRecs() const { return mCtx.leftFile > 0; } bool hasMoreRecs() const { return mCtx.leftFile > 0; }
@ -249,11 +249,16 @@ public:
/// Sets font encoder for ESM strings /// Sets font encoder for ESM strings
void setEncoder(ToUTF8::Utf8Encoder* encoder); void setEncoder(ToUTF8::Utf8Encoder* encoder);
/// Get record flags of last record
unsigned int getRecordFlags() { return mRecordFlags; }
private: private:
Ogre::DataStreamPtr mEsm; Ogre::DataStreamPtr mEsm;
ESM_Context mCtx; ESM_Context mCtx;
unsigned int mRecordFlags;
// Special file signifier (see SpecialFile enum above) // Special file signifier (see SpecialFile enum above)
// Buffer for ESM strings // Buffer for ESM strings

@ -7,6 +7,8 @@ namespace ESM {
void Creature::load(ESMReader &esm) void Creature::load(ESMReader &esm)
{ {
mPersistent = esm.getRecordFlags() & 0x0400;
mModel = esm.getHNString("MODL"); mModel = esm.getHNString("MODL");
mOriginal = esm.getHNOString("CNAM"); mOriginal = esm.getHNOString("CNAM");
mName = esm.getHNOString("FNAM"); mName = esm.getHNOString("FNAM");

@ -69,6 +69,9 @@ struct Creature
NPDTstruct mData; NPDTstruct mData;
int mFlags; int mFlags;
bool mPersistent;
float mScale; float mScale;
std::string mId, mModel, mName, mScript; std::string mId, mModel, mName, mScript;

@ -10,6 +10,8 @@ void NPC::load(ESMReader &esm)
{ {
mNpdt52.mGold = -10; mNpdt52.mGold = -10;
mPersistent = esm.getRecordFlags() & 0x0400;
mModel = esm.getHNOString("MODL"); mModel = esm.getHNOString("MODL");
mName = esm.getHNOString("FNAM"); mName = esm.getHNOString("FNAM");

@ -62,7 +62,7 @@ struct NPC
struct NPDTstruct52 struct NPDTstruct52
{ {
short mLevel; short mLevel;
char mStrength, unsigned char mStrength,
mIntelligence, mIntelligence,
mWillpower, mWillpower,
mAgility, mAgility,
@ -100,6 +100,8 @@ struct NPC
int mFlags; int mFlags;
bool mPersistent;
InventoryList mInventory; InventoryList mInventory;
SpellList mSpells; SpellList mSpells;

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>520</width> <width>518</width>
<height>256</height> <height>304</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
@ -112,7 +112,9 @@
</layout> </layout>
<action name="newProfileAction"> <action name="newProfileAction">
<property name="icon"> <property name="icon">
<iconset theme="document-new"/> <iconset theme="document-new">
<normaloff/>
</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>New Profile</string> <string>New Profile</string>
@ -126,7 +128,9 @@
</action> </action>
<action name="deleteProfileAction"> <action name="deleteProfileAction">
<property name="icon"> <property name="icon">
<iconset theme="edit-delete"/> <iconset theme="edit-delete">
<normaloff/>
</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Delete Profile</string> <string>Delete Profile</string>

Loading…
Cancel
Save