Commit 280541ae authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Template-CustomWizard: Make QComboBox parameters more flexible.



Separate value and display text for the entries, use
in ListModel example.
Rubber-stamped-by: default avataraportale <alessandro.portale@trolltech.com>
parent cdf7dbea
......@@ -51,7 +51,18 @@ Custom class wizard example configuration file. -->
<fielddescription xml:lang="de">Klassenname:</fielddescription>
</field>
<field name="Datatype">
<fieldcontrol class="QComboBox" combochoices="QString,int" defaultindex="0" />
<fieldcontrol class="QComboBox" defaultindex="0">
<comboentries>
<comboentry value="QString">
<comboentrytext>class QString</comboentrytext>
<comboentrytext xml:lang="de">Klasse QString</comboentrytext>
</comboentry>
<comboentry value="int">
<comboentrytext>Integer</comboentrytext>
<comboentrytext xml:lang="de">Ganzzahlwert</comboentrytext>
</comboentry>
</comboentries>
</fieldcontrol>
<fielddescription>Data type:</fielddescription>
<fielddescription xml:lang="de">Datentyp:</fielddescription>
</field>
......
......@@ -54,16 +54,43 @@ TextFieldComboBox::TextFieldComboBox(QWidget *parent) :
QComboBox(parent)
{
setEditable(false);
connect(this, SIGNAL(currentIndexChanged(QString)), this, SIGNAL(textChanged(QString)));
connect(this, SIGNAL(currentIndexChanged(int)),
this, SLOT(slotCurrentIndexChanged(int)));
}
QString TextFieldComboBox::text() const
{
return valueAt(currentIndex());
}
void TextFieldComboBox::setText(const QString &s)
{
const int index = findText(s);
const int index = findData(QVariant(s), Qt::UserRole);
if (index != -1 && index != currentIndex())
setCurrentIndex(index);
}
void TextFieldComboBox::slotCurrentIndexChanged(int i)
{
emit text4Changed(valueAt(i));
}
void TextFieldComboBox::setItems(const QStringList &displayTexts,
const QStringList &values)
{
QTC_ASSERT(displayTexts.size() == values.size(), return)
clear();
addItems(displayTexts);
const int count = values.count();
for (int i = 0; i < count; i++)
setItemData(i, QVariant(values.at(i)), Qt::UserRole);
}
QString TextFieldComboBox::valueAt(int i) const
{
return i >= 0 && i < count() ? itemData(i, Qt::UserRole).toString() : QString();
}
// -------------- TextCheckBox
TextFieldCheckBox::TextFieldCheckBox(const QString &text, QWidget *parent) :
QCheckBox(text, parent),
......@@ -154,15 +181,45 @@ void CustomWizardFieldPage::addField(const CustomWizardField &field)\
}
}
// Return the list of values and display texts for combo
static void comboChoices(const CustomWizardField::ControlAttributeMap &controlAttributes,
QStringList *values, QStringList *displayTexts)
{
typedef CustomWizardField::ControlAttributeMap::ConstIterator AttribMapConstIt;
values->clear();
displayTexts->clear();
// Pre 2.2 Legacy: "combochoices" attribute with a comma-separated list, for
// display == value.
const AttribMapConstIt attribConstEnd = controlAttributes.constEnd();
const AttribMapConstIt choicesIt = controlAttributes.constFind(QLatin1String("combochoices"));
if (choicesIt != attribConstEnd) {
const QString &choices = choicesIt.value();
if (!choices.isEmpty())
*values = *displayTexts = choices.split(QLatin1Char(','));
return;
}
// From 2.2 on: Separate lists of value and text. Add all values found.
for (int i = 0; ; i++) {
const QString valueKey = CustomWizardField::comboEntryValueKey(i);
const AttribMapConstIt valueIt = controlAttributes.constFind(valueKey);
if (valueIt == attribConstEnd)
break;
values->push_back(valueIt.value());
const QString textKey = CustomWizardField::comboEntryTextKey(i);
displayTexts->push_back(controlAttributes.value(textKey));
}
}
QWidget *CustomWizardFieldPage::registerComboBox(const QString &fieldName,
const CustomWizardField &field)
{
TextFieldComboBox *combo = new TextFieldComboBox;
do { // Set up items and current index
const QString choices = field.controlAttributes.value(QLatin1String("combochoices"));
if (choices.isEmpty())
break;
combo->addItems(choices.split(QLatin1Char(',')));
QStringList values;
QStringList displayTexts;
comboChoices(field.controlAttributes, &values, &displayTexts);
combo->setItems(displayTexts, values);
bool ok;
const QString currentIndexS = field.controlAttributes.value(QLatin1String("defaultindex"));
if (currentIndexS.isEmpty())
......@@ -201,6 +258,8 @@ QWidget *CustomWizardFieldPage::registerCheckBox(const QString &fieldName,
typedef CustomWizardField::ControlAttributeMap::const_iterator AttributeMapConstIt;
TextFieldCheckBox *checkBox = new TextFieldCheckBox(fieldDescription);
const bool defaultValue = field.controlAttributes.value(QLatin1String("defaultvalue")) == QLatin1String("true");
checkBox->setChecked(defaultValue);
const AttributeMapConstIt trueTextIt = field.controlAttributes.constFind(QLatin1String("truevalue"));
if (trueTextIt != field.controlAttributes.constEnd()) // Also set empty texts
checkBox->setTrueText(trueTextIt.value());
......
......@@ -54,17 +54,27 @@ struct CustomWizardContext;
// A non-editable combo for text editing purposes that plays
// with QWizard::registerField (providing a settable 'text' property).
// Allows for a separation of values to be used for wizard fields replacement
// and display texts.
class TextFieldComboBox : public QComboBox {
Q_PROPERTY(QString text READ text WRITE setText)
Q_OBJECT
public:
explicit TextFieldComboBox(QWidget *parent = 0);
QString text() const { return currentText(); }
QString text() const;
void setText(const QString &s);
void setItems(const QStringList &displayTexts, const QStringList &values);
signals:
void text4Changed(const QString &); // Do not conflict with Qt 3 compat signal.
private slots:
void slotCurrentIndexChanged(int);
private:
inline QString valueAt(int) const;
};
// A Checkbox that plays with QWizard::registerField (providing a settable
......
......@@ -58,6 +58,9 @@ static const char displayCategoryElementC[] = "displaycategory";
static const char fieldPageTitleElementC[] = "fieldpagetitle";
static const char fieldsElementC[] = "fields";
static const char fieldElementC[] = "field";
static const char comboEntriesElementC[] = "comboentries";
static const char comboEntryElementC[] = "comboentry";
static const char comboEntryTextElementC[] = "comboentrytext";
static const char fieldDescriptionElementC[] = "fielddescription";
static const char fieldNameAttributeC[] = "name";
......@@ -77,6 +80,11 @@ enum ParseState {
ParseWithinWizard,
ParseWithinFields,
ParseWithinField,
ParseWithinFieldDescription,
ParseWithinFieldControl,
ParseWithinComboEntries,
ParseWithinComboEntry,
ParseWithinComboEntryText,
ParseWithinFiles,
ParseWithinFile,
ParseError
......@@ -98,6 +106,17 @@ void CustomWizardField::clear()
controlAttributes.clear();
}
// Attribute map keys for combo entries
QString CustomWizardField::comboEntryValueKey(int i)
{
return QLatin1String("comboValue") + QString::number(i);
}
QString CustomWizardField::comboEntryTextKey(int i)
{
return QLatin1String("comboText") + QString::number(i);
}
CustomWizardFile::CustomWizardFile() :
openEditor(false), openProject(false)
{
......@@ -148,7 +167,7 @@ static inline bool skipOverElementText(QXmlStreamReader &reader)
// Assign the element text to the string passed on if the language matches,
// that is, the element has no language attribute or there is an exact match.
// If there is no match, skip over the element text.
static inline void assignLanguageElementText(QXmlStreamReader &reader,
static inline bool assignLanguageElementText(QXmlStreamReader &reader,
const QString &desiredLanguage,
QString *target)
{
......@@ -156,18 +175,21 @@ static inline void assignLanguageElementText(QXmlStreamReader &reader,
if (elementLanguage.isEmpty()) {
// Try to find a translation for our built-in Wizards
*target = QCoreApplication::translate("ProjectExplorer::CustomWizard", reader.readElementText().toLatin1().constData());
} else if (elementLanguage == desiredLanguage) {
return true;
}
if (elementLanguage == desiredLanguage) {
*target = reader.readElementText();
} else {
// Language mismatch: forward to end element.
skipOverElementText(reader);
return true;
}
// Language mismatch: forward to end element.
skipOverElementText(reader);
return false;
}
// Copy&paste from above to call a setter of BaseFileParameters.
// Implementation of a sophisticated mem_fun pattern is left
// as an exercise to the reader.
static inline void assignLanguageElementText(QXmlStreamReader &reader,
static inline bool assignLanguageElementText(QXmlStreamReader &reader,
const QString &desiredLanguage,
Core::BaseFileWizardParameters *bp,
void (Core::BaseFileWizardParameters::*setter)(const QString &))
......@@ -177,12 +199,15 @@ static inline void assignLanguageElementText(QXmlStreamReader &reader,
// Try to find a translation for our built-in Wizards
const QString translated = QCoreApplication::translate("ProjectExplorer::CustomWizard", reader.readElementText().toLatin1().constData());
(bp->*setter)(translated);
} else if (elementLanguage == desiredLanguage) {
return true;
}
if (elementLanguage == desiredLanguage) {
(bp->*setter)(reader.readElementText());
} else {
// Language mismatch: forward to end element.
skipOverElementText(reader);
return true;
}
// Language mismatch: forward to end element.
skipOverElementText(reader);
return false;
}
// Read level sub-elements of "wizard"
......@@ -226,24 +251,12 @@ static bool parseCustomProjectElement(QXmlStreamReader &reader,
return false;
}
// Read sub-elements of "fields"
static bool parseFieldElement(QXmlStreamReader &reader,
const QString &language,
CustomWizardField *m)
static inline QMap<QString, QString> attributesToStringMap(const QXmlStreamAttributes &attributes)
{
const QStringRef elementName = reader.name();
if (elementName == QLatin1String(fieldDescriptionElementC)) {
assignLanguageElementText(reader, language, &m->description);
return true;
}
// Copy widget control attributes
if (elementName == QLatin1String(fieldControlElementC)) {
foreach(const QXmlStreamAttribute &attribute, reader.attributes())
m->controlAttributes.insert(attribute.name().toString(), attribute.value().toString());
skipOverElementText(reader);
return true;
}
return false;
QMap<QString, QString> rc;
foreach(const QXmlStreamAttribute &attribute, attributes)
rc.insert(attribute.name().toString(), attribute.value().toString());
return rc;
}
// Switch parser state depending on opening element name.
......@@ -264,11 +277,30 @@ static ParseState nextOpeningState(ParseState in, const QStringRef &name)
if (name == QLatin1String(fieldElementC))
return ParseWithinField;
break;
case ParseWithinField:
if (name == QLatin1String(fieldDescriptionElementC))
return ParseWithinFieldDescription;
if (name == QLatin1String(fieldControlElementC))
return ParseWithinFieldControl;
break;
case ParseWithinFieldControl:
if (name == QLatin1String(comboEntriesElementC))
return ParseWithinComboEntries;
break;
case ParseWithinComboEntries:
if (name == QLatin1String(comboEntryElementC))
return ParseWithinComboEntry;
break;
case ParseWithinComboEntry:
if (name == QLatin1String(comboEntryTextElementC))
return ParseWithinComboEntryText;
break;
case ParseWithinFiles:
if (name == QLatin1String(fileElementC))
return ParseWithinFile;
break;
case ParseWithinField:
case ParseWithinFieldDescription: // No subelements
case ParseWithinComboEntryText:
case ParseWithinFile:
case ParseError:
break;
......@@ -302,6 +334,26 @@ static ParseState nextClosingState(ParseState in, const QStringRef &name)
if (name == QLatin1String(fileElementC))
return ParseWithinFiles;
break;
case ParseWithinFieldDescription:
if (name == QLatin1String(fieldDescriptionElementC))
return ParseWithinField;
break;
case ParseWithinFieldControl:
if (name == QLatin1String(fieldControlElementC))
return ParseWithinField;
break;
case ParseWithinComboEntries:
if (name == QLatin1String(comboEntriesElementC))
return ParseWithinFieldControl;
break;
case ParseWithinComboEntry:
if (name == QLatin1String(comboEntryElementC))
return ParseWithinComboEntries;
break;
case ParseWithinComboEntryText:
if (name == QLatin1String(comboEntryTextElementC))
return ParseWithinComboEntry;
break;
case ParseError:
break;
}
......@@ -373,6 +425,7 @@ bool CustomWizardParameters::parse(QIODevice &device,
Core::BaseFileWizardParameters *bp,
QString *errorMessage)
{
int comboEntryCount = 0;
QXmlStreamReader reader(&device);
QXmlStreamReader::TokenType token = QXmlStreamReader::EndDocument;
ParseState state = ParseBeginning;
......@@ -392,8 +445,6 @@ bool CustomWizardParameters::parse(QIODevice &device,
// Read out subelements applicable to current state
if (state == ParseWithinWizard && parseCustomProjectElement(reader, configFileFullPath, language, this, bp))
break;
if (state == ParseWithinField && parseFieldElement(reader, language, &field))
break;
// switch to next state
state = nextOpeningState(state, reader.name());
// Read attributes post state-switching
......@@ -413,6 +464,29 @@ bool CustomWizardParameters::parse(QIODevice &device,
field.name = attributeValue(reader, fieldNameAttributeC);
field.mandatory = booleanAttributeValue(reader, fieldMandatoryAttributeC);
break;
case ParseWithinFieldDescription:
assignLanguageElementText(reader, language, &field.description);
state = ParseWithinField; // The above reads away the end tag, set state.
break;
case ParseWithinFieldControl: // Copy widget control attributes
field.controlAttributes = attributesToStringMap(reader.attributes());
break;
case ParseWithinComboEntries:
break;
case ParseWithinComboEntry: // Combo entry with 'value' attribute
field.controlAttributes.insert(CustomWizardField::comboEntryValueKey(comboEntryCount),
attributeValue(reader, "value"));
break;
case ParseWithinComboEntryText: {
// This reads away the end tag, set state here.
QString text;
if (assignLanguageElementText(reader, language, &text))
field.controlAttributes.insert(CustomWizardField::comboEntryTextKey(comboEntryCount),
text);
state = ParseWithinComboEntry;
}
break;
case ParseWithinFile: { // file attribute
CustomWizardFile file;
file.source = attributeValue(reader, fileNameSourceAttributeC);
......@@ -435,14 +509,20 @@ bool CustomWizardParameters::parse(QIODevice &device,
break;
case QXmlStreamReader::EndElement:
state = nextClosingState(state, reader.name());
if (state == ParseError) {
switch (state) {
case ParseError:
*errorMessage = msgError(reader, configFileFullPath,
QString::fromLatin1("Unexpected end element %1").arg(reader.name().toString()));
return false;
}
if (state == ParseWithinFields) { // Leaving a field element
case ParseWithinFields: // Leaving a field element
fields.push_back(field);
field.clear();
break;
case ParseWithinComboEntries:
comboEntryCount++;
break;
default:
break;
}
break;
default:
......
......@@ -49,6 +49,10 @@ struct CustomWizardField {
CustomWizardField();
void clear();
// Attribute map keys for combo entries
static QString comboEntryValueKey(int i);
static QString comboEntryTextKey(int i);
QString description;
QString name;
ControlAttributeMap controlAttributes;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment