OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / libs / utils / submitfieldwidget.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "submitfieldwidget.h"
35
36 #include <QtGui/QComboBox>
37 #include <QtGui/QHBoxLayout>
38 #include <QtGui/QVBoxLayout>
39 #include <QtGui/QLineEdit>
40 #include <QtGui/QToolButton>
41 #include <QtGui/QCompleter>
42 #include <QtGui/QIcon>
43 #include <QtGui/QToolBar>
44
45 #include <QtCore/QList>
46 #include <QtCore/QDebug>
47
48 enum { debug = 0 };
49 enum { spacing = 2 };
50
51 static void inline setComboBlocked(QComboBox *cb, int index)
52 {
53     const bool blocked = cb->blockSignals(true);
54     cb->setCurrentIndex(index);
55     cb->blockSignals(blocked);
56 }
57
58 namespace Utils {
59
60 // Field/Row entry
61 struct FieldEntry {
62     FieldEntry();
63     void createGui(const QIcon &removeIcon);
64     void deleteGuiLater();
65
66     QComboBox *combo;
67     QHBoxLayout *layout;
68     QLineEdit *lineEdit;
69     QToolBar *toolBar;
70     QToolButton *clearButton;
71     QToolButton *browseButton;
72     int comboIndex;
73 };
74
75 FieldEntry::FieldEntry() :
76     combo(0),
77     layout(0),
78     lineEdit(0),
79     toolBar(0),
80     clearButton(0),
81     browseButton(0),
82     comboIndex(0)
83 {
84 }
85
86 void FieldEntry::createGui(const QIcon &removeIcon)
87 {
88     layout = new QHBoxLayout;
89     layout->setMargin(0);
90     layout ->setSpacing(spacing);
91     combo = new QComboBox;
92     layout->addWidget(combo);
93     lineEdit = new QLineEdit;
94     layout->addWidget(lineEdit);
95     toolBar = new QToolBar;
96     toolBar->setProperty("_q_custom_style_disabled", QVariant(true));
97     layout->addWidget(toolBar);
98     clearButton = new QToolButton;
99     clearButton->setIcon(removeIcon);
100     toolBar->addWidget(clearButton);
101     browseButton = new QToolButton;
102     browseButton->setText(QLatin1String("..."));
103     toolBar->addWidget(browseButton);
104 }
105
106 void FieldEntry::deleteGuiLater()
107 {
108     clearButton->deleteLater();
109     browseButton->deleteLater();
110     toolBar->deleteLater();
111     lineEdit->deleteLater();
112     combo->deleteLater();
113     layout->deleteLater();
114 }
115
116 // ------- SubmitFieldWidgetPrivate
117 struct SubmitFieldWidgetPrivate {
118     SubmitFieldWidgetPrivate();
119
120     int findSender(const QObject *o) const;
121     int findField(const QString &f, int excluded = -1) const;
122     inline QString fieldText(int) const;
123     inline QString fieldValue(int) const;
124     inline void focusField(int);
125
126     const QIcon removeFieldIcon;
127     QStringList fields;
128     QCompleter *completer;
129     bool hasBrowseButton;
130     bool allowDuplicateFields;
131
132     QList <FieldEntry> fieldEntries;
133     QVBoxLayout *layout;
134 };
135
136 SubmitFieldWidgetPrivate::SubmitFieldWidgetPrivate() :
137         removeFieldIcon(QLatin1String(":/utils/images/removesubmitfield.png")),
138         completer(0),
139         hasBrowseButton(false),
140         allowDuplicateFields(false),
141         layout(0)
142 {
143 }
144
145 int SubmitFieldWidgetPrivate::findSender(const QObject *o) const
146 {
147     const int count = fieldEntries.size();
148     for (int i = 0; i < count; i++) {
149         const FieldEntry &fe = fieldEntries.at(i);
150         if (fe.combo == o || fe.browseButton == o || fe.clearButton == o || fe.lineEdit == o)
151             return i;
152     }
153     return -1;
154 }
155
156 int SubmitFieldWidgetPrivate::findField(const QString &ft, int excluded) const
157 {
158     const int count = fieldEntries.size();
159     for (int i = 0; i < count; i++)
160         if (i != excluded && fieldText(i) == ft)
161             return i;
162     return -1;
163 }
164
165 QString SubmitFieldWidgetPrivate::fieldText(int pos) const
166 {
167     return fieldEntries.at(pos).combo->currentText();
168 }
169
170 QString SubmitFieldWidgetPrivate::fieldValue(int pos) const
171 {
172     return fieldEntries.at(pos).lineEdit->text();
173 }
174
175 void SubmitFieldWidgetPrivate::focusField(int pos)
176 {
177     fieldEntries.at(pos).lineEdit->setFocus(Qt::TabFocusReason);
178 }
179
180 // SubmitFieldWidget
181 SubmitFieldWidget::SubmitFieldWidget(QWidget *parent) :
182         QWidget(parent),
183         m_d(new SubmitFieldWidgetPrivate)
184 {
185     m_d->layout = new QVBoxLayout;
186     m_d->layout->setMargin(0);
187     m_d->layout->setSpacing(spacing);
188     setLayout(m_d->layout);
189 }
190
191 SubmitFieldWidget::~SubmitFieldWidget()
192 {
193     delete m_d;
194 }
195
196 void SubmitFieldWidget::setFields(const QStringList & f)
197 {
198     // remove old fields
199     for (int i = m_d->fieldEntries.size() - 1 ; i >= 0 ; i--)
200         removeField(i);
201
202     m_d->fields = f;
203     if (!f.empty())
204         createField(f.front());
205 }
206
207 QStringList SubmitFieldWidget::fields() const
208 {
209     return m_d->fields;
210 }
211
212 bool SubmitFieldWidget::hasBrowseButton() const
213 {
214     return m_d->hasBrowseButton;
215 }
216
217 void SubmitFieldWidget::setHasBrowseButton(bool d)
218 {
219     if (m_d->hasBrowseButton == d)
220         return;
221     m_d->hasBrowseButton = d;
222     foreach(const FieldEntry &fe, m_d->fieldEntries)
223         fe.browseButton->setVisible(d);
224 }
225
226 bool SubmitFieldWidget::allowDuplicateFields() const
227 {
228     return m_d->allowDuplicateFields;
229 }
230
231 void SubmitFieldWidget::setAllowDuplicateFields(bool v)
232 {
233     m_d->allowDuplicateFields = v;
234 }
235
236 QCompleter *SubmitFieldWidget::completer() const
237 {
238     return m_d->completer;
239 }
240
241 void SubmitFieldWidget::setCompleter(QCompleter *c)
242 {
243     if (c == m_d->completer)
244         return;
245     m_d->completer = c;
246     foreach(const FieldEntry &fe, m_d->fieldEntries)
247         fe.lineEdit->setCompleter(c);
248 }
249
250 QString SubmitFieldWidget::fieldValue(int pos) const
251 {
252     return m_d->fieldValue(pos);
253 }
254
255 void SubmitFieldWidget::setFieldValue(int pos, const QString &value)
256 {
257     m_d->fieldEntries.at(pos).lineEdit->setText(value);
258 }
259
260 QString SubmitFieldWidget::fieldValues() const
261 {
262     const QChar blank = QLatin1Char(' ');
263     const QChar newLine = QLatin1Char('\n');
264     // Format as "RevBy: value\nSigned-Off: value\n"
265     QString rc;
266     foreach(const FieldEntry &fe, m_d->fieldEntries) {
267         const QString value = fe.lineEdit->text().trimmed();
268         if (!value.isEmpty()) {
269             rc += fe.combo->currentText();
270             rc += blank;
271             rc += value;
272             rc += newLine;
273         }
274     }
275     return rc;
276 }
277
278 void SubmitFieldWidget::createField(const QString &f)
279 {
280     FieldEntry fe;
281     fe.createGui(m_d->removeFieldIcon);
282     fe.combo->addItems(m_d->fields);
283     if (!f.isEmpty()) {
284         const int index = fe.combo->findText(f);
285         if (index != -1) {
286             setComboBlocked(fe.combo, index);
287             fe.comboIndex = index;
288         }
289     }
290
291     connect(fe.browseButton, SIGNAL(clicked()), this, SLOT(slotBrowseButtonClicked()));
292     if (!m_d->hasBrowseButton)
293         fe.browseButton->setVisible(false);
294
295     if (m_d->completer)
296         fe.lineEdit->setCompleter(m_d->completer);
297
298     connect(fe.combo, SIGNAL(currentIndexChanged(int)),
299             this, SLOT(slotComboIndexChanged(int)));
300     connect(fe.clearButton, SIGNAL(clicked()),
301             this, SLOT(slotRemove()));
302     m_d->layout->addLayout(fe.layout);
303     m_d->fieldEntries.push_back(fe);
304 }
305
306 void SubmitFieldWidget::slotRemove()
307 {
308     // Never remove first entry
309     const int index = m_d->findSender(sender());
310     switch (index) {
311     case -1:
312         break;
313     case 0:
314         m_d->fieldEntries.front().lineEdit->clear();
315         break;
316     default:
317         removeField(index);
318         break;
319     }
320 }
321
322 void SubmitFieldWidget::removeField(int index)
323 {
324     FieldEntry fe = m_d->fieldEntries.takeAt(index);
325     QLayoutItem * item = m_d->layout->takeAt(index);
326     fe.deleteGuiLater();
327     delete item;
328 }
329
330 void SubmitFieldWidget::slotComboIndexChanged(int comboIndex)
331 {
332     const int pos = m_d->findSender(sender());
333     if (debug)
334         qDebug() << '>' << Q_FUNC_INFO << pos;
335     if (pos == -1)
336         return;
337     // Accept new index or reset combo to previous value?
338     int &previousIndex = m_d->fieldEntries[pos].comboIndex;
339     if (comboIndexChange(pos, comboIndex)) {
340         previousIndex = comboIndex;
341     } else {
342         setComboBlocked(m_d->fieldEntries.at(pos).combo, previousIndex);
343     }
344     if (debug)
345         qDebug() << '<' << Q_FUNC_INFO << pos;
346 }
347
348 // Handle change of a combo. Return "false" if the combo
349 // is to be reset (refuse new field).
350 bool SubmitFieldWidget::comboIndexChange(int pos, int index)
351 {
352     const QString newField = m_d->fieldEntries.at(pos).combo->itemText(index);
353     // If the field is visible elsewhere: focus the existing one and refuse
354     if (!m_d->allowDuplicateFields) {
355         const int existingFieldIndex = m_d->findField(newField, pos);
356         if (existingFieldIndex != -1) {
357             m_d->focusField(existingFieldIndex);
358             return false;
359         }
360     }
361     // Empty value: just change the field
362     if (m_d->fieldValue(pos).isEmpty())
363         return true;
364     // Non-empty: Create a new field and reset the triggering combo
365     createField(newField);
366     return false;
367 }
368
369 void SubmitFieldWidget::slotBrowseButtonClicked()
370 {
371     const int pos = m_d->findSender(sender());
372     emit browseButtonClicked(pos, m_d->fieldText(pos));
373 }
374
375 }