forked from qt-creator/qt-creator
Template-CustomWizard: Make QComboBox parameters more flexible.
Separate value and display text for the entries, use in ListModel example. Rubber-stamped-by: aportale <alessandro.portale@trolltech.com>
This commit is contained in:
@@ -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 {
|
||||
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 {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user