1 #include "inputdialog.h"
8 #include <QDialogButtonBox>
12 #include <QStringListModel>
16 struct InputDialog::WidgetItem
{
17 WidgetItem() : widget(NULL
) {}
18 void init(QWidget
* w
, const char *name
) {
23 const char *prop_name
; // property name
28 QString
parseString(const QString
&value
, const InputDialog::VariableMap
&vars
) {
29 if (value
.startsWith('$')) return vars
.value(value
.mid(1), QString()).toString();
32 QStringList
parseStringList(const QString
&value
, const InputDialog::VariableMap
&vars
) {
33 QStringList values
= value
.split(',');
35 for (QStringList::iterator it
=values
.begin(), end
=values
.end(); it
!=end
; ++it
) {
36 if (it
->startsWith('$')) result
.append(vars
.value(value
.mid(1), QStringList()).toStringList());
37 else result
.append(*it
);
42 class RefNameValidator
: public QValidator
{
44 RefNameValidator(bool allowEmpty
=false, QObject
*parent
=0)
46 , invalid("[ ~^:\?*[]")
47 , allowEmpty(allowEmpty
)
50 void fixup(QString
& input
) const;
51 State
validate(QString
& input
, int & pos
) const;
53 const QRegExp invalid
;
57 void RefNameValidator::fixup(QString
&input
) const
59 // remove invalid chars
60 input
.replace(invalid
, "");
61 input
.replace("/.","/"); // no dot after slash
62 input
.replace("..","."); // no two dots in a row
63 input
.replace("//","/"); // no two slashes in a row
64 input
.replace("@{", "@"); // no sequence @{
67 QValidator::State
RefNameValidator::validate(QString
&input
, int &pos
) const
69 // https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
70 // automatically remove invalid chars
71 QString front
= input
.left(pos
); fixup(front
);
72 QString rear
= input
.mid(pos
); fixup(rear
);
74 // keep cursor were it was
77 QString
fixed(input
); fixup(fixed
);
78 if (fixed
!= input
) return Invalid
;
80 // empty string or single @ are not allowed
81 if ((input
.isEmpty() && !allowEmpty
) || input
== "@")
87 InputDialog::InputDialog(const QString
&cmd
, const VariableMap
&variables
,
88 const QString
&title
, QWidget
*parent
, Qt::WindowFlags f
)
92 this->setWindowTitle(title
);
93 QGridLayout
*layout
= new QGridLayout(this);
95 QRegExp
re("%(([a-z_]+)([[]([a-z ,]+)[]])?:)?([^%=]+)(=[^%]+)?%");
98 while ((start
= re
.indexIn(cmd
, start
)) != -1) {
99 const QString type
= re
.cap(2);
100 const QStringList opts
= re
.cap(4).split(',', QString::SkipEmptyParts
);
101 const QString name
= re
.cap(5);
102 const QString value
= re
.cap(6).mid(1);
103 if (widgets
.count(name
)) { // widget already created
104 if (!type
.isEmpty()) dbs("token must not be redefined: " + name
);
108 WidgetItemPtr
item (new WidgetItem());
110 item
->end
= start
= start
+ re
.matchedLength();
112 if (type
== "combobox") {
113 QComboBox
*w
= new QComboBox(this);
114 w
->addItems(parseStringList(value
, variables
));
115 if (opts
.contains("editable")) w
->setEditable(true);
116 w
->setMinimumWidth(100);
117 if (opts
.contains("ref")) {
118 w
->setValidator(new RefNameValidator(opts
.contains("empty")));
119 validators
.insert(name
, w
->validator());
120 connect(w
, SIGNAL(editTextChanged(QString
)), this, SLOT(validate()));
122 item
->init(w
, "currentText");
123 } else if (type
== "listbox") {
124 QListView
*w
= new QListView(this);
125 w
->setModel(new QStringListModel(parseStringList(value
, variables
)));
127 } else if (type
== "lineedit" || type
== "") {
128 QLineEdit
*w
= new QLineEdit(this);
129 w
->setText(parseString(value
, variables
));
130 QStringList values
= parseStringList(value
, variables
);
131 if (!values
.isEmpty()) // use default string list as
132 w
->setCompleter(new QCompleter(values
));
133 if (opts
.contains("ref")) {
134 w
->setValidator(new RefNameValidator(opts
.contains("empty")));
135 validators
.insert(name
, w
->validator());
136 connect(w
, SIGNAL(textEdited(QString
)), this, SLOT(validate()));
138 item
->init(w
, "text");
139 } else if (type
== "textedit") {
140 QTextEdit
*w
= new QTextEdit(this);
141 w
->setText(parseString(value
, variables
));
142 item
->init(w
, "plainText");
144 dbs("unknown widget type: " + type
);
147 widgets
.insert(name
, item
);
148 if (name
.startsWith('_')) { // _name triggers hiding of label
149 layout
->addWidget(item
->widget
, row
, 1);
151 layout
->addWidget(new QLabel(name
+ ":"), row
, 0);
152 layout
->addWidget(item
->widget
, row
, 1);
156 QDialogButtonBox
*buttons
= new QDialogButtonBox(QDialogButtonBox::Ok
| QDialogButtonBox::Cancel
);
157 layout
->addWidget(buttons
, row
, 0, 1, 2);
158 okButton
= buttons
->button(QDialogButtonBox::Ok
);
160 connect(okButton
, SIGNAL(pressed()), this, SLOT(accept()));
161 connect(buttons
->button(QDialogButtonBox::Cancel
), SIGNAL(pressed()), this, SLOT(reject()));
165 QWidget
*InputDialog::widget(const QString
&token
)
167 WidgetItemPtr item
= widgets
.value(token
);
168 return item
? item
->widget
: NULL
;
171 QVariant
InputDialog::value(const QString
&token
) const
173 WidgetItemPtr item
= widgets
.value(token
);
175 dbs("unknown token: " + token
);
178 return item
->widget
->property(item
->prop_name
);
181 bool InputDialog::validate()
184 for (QMap
<QString
, const QValidator
*>::const_iterator
185 it
=validators
.begin(), end
=validators
.end(); result
&& it
!= end
; ++it
) {
186 QString val
= value(it
.key()).toString();
188 if (it
.value()->validate(val
, pos
) != QValidator::Acceptable
)
191 okButton
->setEnabled(result
);
195 QString
InputDialog::replace(const VariableMap
&variables
) const
197 QString result
= cmd
;
198 for (WidgetMap::const_iterator it
= widgets
.begin(), end
= widgets
.end(); it
!= end
; ++it
) {
199 QString token
= "%" + it
.key() + "%";
200 WidgetItemPtr item
= it
.value();
201 QString value
= item
->widget
->property(item
->prop_name
).toString();
202 result
.replace(item
->start
, item
->end
- item
->start
, value
); // replace main token
203 result
.replace(token
, value
); // replace all other occurences of %name%
205 for (VariableMap::const_iterator it
=variables
.begin(), end
=variables
.end(); it
!= end
; ++it
) {
206 QString token
= "$" + it
.key();
207 QString val
= it
.value().type() == QVariant::StringList
? it
.value().toStringList().join(" ")
208 : it
.value().toString();
209 result
.replace(token
, val
);