1 #include "inputdialog.h"
8 #include <QDialogButtonBox>
12 #include <QStringListModel>
16 InputDialog::WidgetItem::WidgetItem() : widget(NULL
)
20 void InputDialog::WidgetItem::init(QWidget
* w
, const char *name
) {
25 QString
parseString(const QString
&value
, const InputDialog::VariableMap
&vars
) {
26 if (value
.startsWith('$')) return vars
.value(value
.mid(1), QString()).toString();
29 QStringList
parseStringList(const QString
&value
, const InputDialog::VariableMap
&vars
) {
30 QStringList values
= value
.split(',');
32 for (QStringList::iterator it
=values
.begin(), end
=values
.end(); it
!=end
; ++it
) {
33 if (it
->startsWith('$')) result
.append(vars
.value(value
.mid(1), QStringList()).toStringList());
34 else result
.append(*it
);
39 class RefNameValidator
: public QValidator
{
41 RefNameValidator(bool allowEmpty
=false, QObject
*parent
=0)
43 , invalid("[ ~^:\?*[]")
44 , allowEmpty(allowEmpty
)
47 void fixup(QString
& input
) const;
48 State
validate(QString
& input
, int & pos
) const;
50 const QRegExp invalid
;
54 void RefNameValidator::fixup(QString
&input
) const
56 // remove invalid chars
57 input
.replace(invalid
, "");
58 input
.replace("/.","/"); // no dot after slash
59 input
.replace("..","."); // no two dots in a row
60 input
.replace("//","/"); // no two slashes in a row
61 input
.replace("@{", "@"); // no sequence @{
64 QValidator::State
RefNameValidator::validate(QString
&input
, int &pos
) const
66 // https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
67 // automatically remove invalid chars
68 QString front
= input
.left(pos
); fixup(front
);
69 QString rear
= input
.mid(pos
); fixup(rear
);
71 // keep cursor were it was
74 QString
fixed(input
); fixup(fixed
);
75 if (fixed
!= input
) return Invalid
;
77 // empty string or single @ are not allowed
78 if ((input
.isEmpty() && !allowEmpty
) || input
== "@")
84 InputDialog::InputDialog(const QString
&cmd
, const VariableMap
&variables
,
85 const QString
&title
, QWidget
*parent
, Qt::WindowFlags f
)
89 this->setWindowTitle(title
);
90 QGridLayout
*layout
= new QGridLayout(this);
92 QRegExp
re("%(([a-z_]+)([[]([a-z ,]+)[]])?:)?([^%=]+)(=[^%]+)?%");
95 while ((start
= re
.indexIn(cmd
, start
)) != -1) {
96 const QString type
= re
.cap(2);
97 const QStringList opts
= re
.cap(4).split(',', QGIT_SPLITBEHAVIOR(SkipEmptyParts
));
98 const QString name
= re
.cap(5);
99 const QString value
= re
.cap(6).mid(1);
100 if (widgets
.count(name
)) { // widget already created
101 if (!type
.isEmpty()) dbs("token must not be redefined: " + name
);
105 WidgetItemPtr
item (new WidgetItem());
107 item
->end
= start
= start
+ re
.matchedLength();
109 if (type
== "combobox") {
110 QComboBox
*w
= new QComboBox(this);
111 w
->addItems(parseStringList(value
, variables
));
112 if (opts
.contains("editable")) w
->setEditable(true);
113 w
->setMinimumWidth(100);
114 if (opts
.contains("ref")) {
115 w
->setValidator(new RefNameValidator(opts
.contains("empty")));
116 validators
.insert(name
, w
->validator());
117 connect(w
, SIGNAL(editTextChanged(QString
)), this, SLOT(validate()));
119 item
->init(w
, "currentText");
120 } else if (type
== "listbox") {
121 QListView
*w
= new QListView(this);
122 w
->setModel(new QStringListModel(parseStringList(value
, variables
)));
124 } else if (type
== "lineedit" || type
== "") {
125 QLineEdit
*w
= new QLineEdit(this);
126 w
->setText(parseString(value
, variables
));
127 QStringList values
= parseStringList(value
, variables
);
128 if (!values
.isEmpty()) // use default string list as
129 w
->setCompleter(new QCompleter(values
));
130 if (opts
.contains("ref")) {
131 w
->setValidator(new RefNameValidator(opts
.contains("empty")));
132 validators
.insert(name
, w
->validator());
133 connect(w
, SIGNAL(textEdited(QString
)), this, SLOT(validate()));
135 item
->init(w
, "text");
136 } else if (type
== "textedit") {
137 QTextEdit
*w
= new QTextEdit(this);
138 w
->setText(parseString(value
, variables
));
139 item
->init(w
, "plainText");
141 dbs("unknown widget type: " + type
);
144 widgets
.insert(name
, item
);
145 if (name
.startsWith('_')) { // _name triggers hiding of label
146 layout
->addWidget(item
->widget
, row
, 1);
148 layout
->addWidget(new QLabel(name
+ ":"), row
, 0);
149 layout
->addWidget(item
->widget
, row
, 1);
153 QDialogButtonBox
*buttons
= new QDialogButtonBox(QDialogButtonBox::Ok
| QDialogButtonBox::Cancel
);
154 layout
->addWidget(buttons
, row
, 0, 1, 2);
155 okButton
= buttons
->button(QDialogButtonBox::Ok
);
157 connect(okButton
, SIGNAL(pressed()), this, SLOT(accept()));
158 connect(buttons
->button(QDialogButtonBox::Cancel
), SIGNAL(pressed()), this, SLOT(reject()));
162 QWidget
*InputDialog::widget(const QString
&token
)
164 WidgetItemPtr item
= widgets
.value(token
);
165 return item
? item
->widget
: NULL
;
168 QVariant
InputDialog::value(const QString
&token
) const
170 WidgetItemPtr item
= widgets
.value(token
);
172 dbs("unknown token: " + token
);
175 return item
->widget
->property(item
->prop_name
);
178 bool InputDialog::validate()
181 for (QMap
<QString
, const QValidator
*>::const_iterator
182 it
=validators
.begin(), end
=validators
.end(); result
&& it
!= end
; ++it
) {
183 QString val
= value(it
.key()).toString();
185 if (it
.value()->validate(val
, pos
) != QValidator::Acceptable
)
188 okButton
->setEnabled(result
);
192 QString
InputDialog::replace(const VariableMap
&variables
) const
194 QString result
= cmd
;
195 int shift
= 0, start
= 0, len
= 0; // will keep track of position shifts during replacements
196 for (WidgetMap::const_iterator it
= widgets
.begin(), end
= widgets
.end(); it
!= end
; ++it
) {
197 QString token
= "%" + it
.key() + "%";
198 WidgetItemPtr item
= it
.value();
199 start
= item
->start
- shift
;
200 len
= item
->end
- item
->start
;
201 QString value
= item
->widget
->property(item
->prop_name
).toString();
202 result
.replace(start
, len
, value
); // replace main token
203 shift
+= len
- value
.length();
204 result
.replace(token
, value
); // replace all other occurences of %name%
206 for (VariableMap::const_iterator it
=variables
.begin(), end
=variables
.end(); it
!= end
; ++it
) {
207 QString token
= "$" + it
.key();
208 QString val
= it
.value().type() == QVariant::StringList
? it
.value().toStringList().join(" ")
209 : it
.value().toString();
210 result
.replace(token
, val
);