diff options
author | Orgad Shaneh <orgad.shaneh@audiocodes.com> | 2013-01-02 22:12:06 +0200 |
---|---|---|
committer | hjk <qthjk@ovi.com> | 2013-01-07 13:43:23 +0100 |
commit | 34db64c752a46942f43daf77263e27e124d932b2 (patch) | |
tree | 25955b8e9edb814fddec1c6e9ca610c95190b5ad /src/plugins/vcsbase/submitfieldwidget.cpp | |
parent | e174e24d582985dbdbf3421ab74ab52eb4589fb6 (diff) | |
download | qt-creator-34db64c752a46942f43daf77263e27e124d932b2.tar.gz |
Move SubmitEditorWidget from Utils to VcsBase
It belongs there
Change-Id: I4b4cdacf32b0eab299d4b2d5258cd4d91a759907
Reviewed-by: hjk <qthjk@ovi.com>
Diffstat (limited to 'src/plugins/vcsbase/submitfieldwidget.cpp')
-rw-r--r-- | src/plugins/vcsbase/submitfieldwidget.cpp | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/src/plugins/vcsbase/submitfieldwidget.cpp b/src/plugins/vcsbase/submitfieldwidget.cpp new file mode 100644 index 0000000000..3bd9f004c9 --- /dev/null +++ b/src/plugins/vcsbase/submitfieldwidget.cpp @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "submitfieldwidget.h" + +#include <QComboBox> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QLineEdit> +#include <QToolButton> +#include <QCompleter> +#include <QIcon> +#include <QToolBar> + +#include <QList> +#include <QDebug> + +enum { debug = 0 }; +enum { spacing = 2 }; + +static void inline setComboBlocked(QComboBox *cb, int index) +{ + const bool blocked = cb->blockSignals(true); + cb->setCurrentIndex(index); + cb->blockSignals(blocked); +} + +/*! + \class VcsBase::SubmitFieldWidget + \brief A widget for editing submit message fields like "reviewed-by:", + "signed-off-by:". + + It displays them in a vertical row of combo/line edit fields + that is modeled after the target address controls of mail clients. + When choosing a different field in the combo, a new row is opened if text + has been entered for the current field. Optionally, a "Browse..." button and + completer can be added. +*/ + +namespace VcsBase { + +// Field/Row entry +struct FieldEntry { + FieldEntry(); + void createGui(const QIcon &removeIcon); + void deleteGuiLater(); + + QComboBox *combo; + QHBoxLayout *layout; + QLineEdit *lineEdit; + QToolBar *toolBar; + QToolButton *clearButton; + QToolButton *browseButton; + int comboIndex; +}; + +FieldEntry::FieldEntry() : + combo(0), + layout(0), + lineEdit(0), + toolBar(0), + clearButton(0), + browseButton(0), + comboIndex(0) +{ +} + +void FieldEntry::createGui(const QIcon &removeIcon) +{ + layout = new QHBoxLayout; + layout->setMargin(0); + layout ->setSpacing(spacing); + combo = new QComboBox; + layout->addWidget(combo); + lineEdit = new QLineEdit; + layout->addWidget(lineEdit); + toolBar = new QToolBar; + toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); + layout->addWidget(toolBar); + clearButton = new QToolButton; + clearButton->setIcon(removeIcon); + toolBar->addWidget(clearButton); + browseButton = new QToolButton; + browseButton->setText(QLatin1String("...")); + toolBar->addWidget(browseButton); +} + +void FieldEntry::deleteGuiLater() +{ + clearButton->deleteLater(); + browseButton->deleteLater(); + toolBar->deleteLater(); + lineEdit->deleteLater(); + combo->deleteLater(); + layout->deleteLater(); +} + +// ------- SubmitFieldWidgetPrivate +struct SubmitFieldWidgetPrivate { + SubmitFieldWidgetPrivate(); + + int findSender(const QObject *o) const; + int findField(const QString &f, int excluded = -1) const; + inline QString fieldText(int) const; + inline QString fieldValue(int) const; + inline void focusField(int); + + const QIcon removeFieldIcon; + QStringList fields; + QCompleter *completer; + bool hasBrowseButton; + bool allowDuplicateFields; + + QList <FieldEntry> fieldEntries; + QVBoxLayout *layout; +}; + +SubmitFieldWidgetPrivate::SubmitFieldWidgetPrivate() : + removeFieldIcon(QLatin1String(":/vcsbase/images/removesubmitfield.png")), + completer(0), + hasBrowseButton(false), + allowDuplicateFields(false), + layout(0) +{ +} + +int SubmitFieldWidgetPrivate::findSender(const QObject *o) const +{ + const int count = fieldEntries.size(); + for (int i = 0; i < count; i++) { + const FieldEntry &fe = fieldEntries.at(i); + if (fe.combo == o || fe.browseButton == o || fe.clearButton == o || fe.lineEdit == o) + return i; + } + return -1; +} + +int SubmitFieldWidgetPrivate::findField(const QString &ft, int excluded) const +{ + const int count = fieldEntries.size(); + for (int i = 0; i < count; i++) + if (i != excluded && fieldText(i) == ft) + return i; + return -1; +} + +QString SubmitFieldWidgetPrivate::fieldText(int pos) const +{ + return fieldEntries.at(pos).combo->currentText(); +} + +QString SubmitFieldWidgetPrivate::fieldValue(int pos) const +{ + return fieldEntries.at(pos).lineEdit->text(); +} + +void SubmitFieldWidgetPrivate::focusField(int pos) +{ + fieldEntries.at(pos).lineEdit->setFocus(Qt::TabFocusReason); +} + +// SubmitFieldWidget +SubmitFieldWidget::SubmitFieldWidget(QWidget *parent) : + QWidget(parent), + d(new SubmitFieldWidgetPrivate) +{ + d->layout = new QVBoxLayout; + d->layout->setMargin(0); + d->layout->setSpacing(spacing); + setLayout(d->layout); +} + +SubmitFieldWidget::~SubmitFieldWidget() +{ + delete d; +} + +void SubmitFieldWidget::setFields(const QStringList & f) +{ + // remove old fields + for (int i = d->fieldEntries.size() - 1 ; i >= 0 ; i--) + removeField(i); + + d->fields = f; + if (!f.empty()) + createField(f.front()); +} + +QStringList SubmitFieldWidget::fields() const +{ + return d->fields; +} + +bool SubmitFieldWidget::hasBrowseButton() const +{ + return d->hasBrowseButton; +} + +void SubmitFieldWidget::setHasBrowseButton(bool on) +{ + if (d->hasBrowseButton == on) + return; + d->hasBrowseButton = on; + foreach (const FieldEntry &fe, d->fieldEntries) + fe.browseButton->setVisible(on); +} + +bool SubmitFieldWidget::allowDuplicateFields() const +{ + return d->allowDuplicateFields; +} + +void SubmitFieldWidget::setAllowDuplicateFields(bool v) +{ + d->allowDuplicateFields = v; +} + +QCompleter *SubmitFieldWidget::completer() const +{ + return d->completer; +} + +void SubmitFieldWidget::setCompleter(QCompleter *c) +{ + if (c == d->completer) + return; + d->completer = c; + foreach (const FieldEntry &fe, d->fieldEntries) + fe.lineEdit->setCompleter(c); +} + +QString SubmitFieldWidget::fieldValue(int pos) const +{ + return d->fieldValue(pos); +} + +void SubmitFieldWidget::setFieldValue(int pos, const QString &value) +{ + d->fieldEntries.at(pos).lineEdit->setText(value); +} + +QString SubmitFieldWidget::fieldValues() const +{ + const QChar blank = QLatin1Char(' '); + const QChar newLine = QLatin1Char('\n'); + // Format as "RevBy: value\nSigned-Off: value\n" + QString rc; + foreach (const FieldEntry &fe, d->fieldEntries) { + const QString value = fe.lineEdit->text().trimmed(); + if (!value.isEmpty()) { + rc += fe.combo->currentText(); + rc += blank; + rc += value; + rc += newLine; + } + } + return rc; +} + +void SubmitFieldWidget::createField(const QString &f) +{ + FieldEntry fe; + fe.createGui(d->removeFieldIcon); + fe.combo->addItems(d->fields); + if (!f.isEmpty()) { + const int index = fe.combo->findText(f); + if (index != -1) { + setComboBlocked(fe.combo, index); + fe.comboIndex = index; + } + } + + connect(fe.browseButton, SIGNAL(clicked()), this, SLOT(slotBrowseButtonClicked())); + if (!d->hasBrowseButton) + fe.browseButton->setVisible(false); + + if (d->completer) + fe.lineEdit->setCompleter(d->completer); + + connect(fe.combo, SIGNAL(currentIndexChanged(int)), + this, SLOT(slotComboIndexChanged(int))); + connect(fe.clearButton, SIGNAL(clicked()), + this, SLOT(slotRemove())); + d->layout->addLayout(fe.layout); + d->fieldEntries.push_back(fe); +} + +void SubmitFieldWidget::slotRemove() +{ + // Never remove first entry + const int index = d->findSender(sender()); + switch (index) { + case -1: + break; + case 0: + d->fieldEntries.front().lineEdit->clear(); + break; + default: + removeField(index); + break; + } +} + +void SubmitFieldWidget::removeField(int index) +{ + FieldEntry fe = d->fieldEntries.takeAt(index); + QLayoutItem * item = d->layout->takeAt(index); + fe.deleteGuiLater(); + delete item; +} + +void SubmitFieldWidget::slotComboIndexChanged(int comboIndex) +{ + const int pos = d->findSender(sender()); + if (debug) + qDebug() << '>' << Q_FUNC_INFO << pos; + if (pos == -1) + return; + // Accept new index or reset combo to previous value? + int &previousIndex = d->fieldEntries[pos].comboIndex; + if (comboIndexChange(pos, comboIndex)) { + previousIndex = comboIndex; + } else { + setComboBlocked(d->fieldEntries.at(pos).combo, previousIndex); + } + if (debug) + qDebug() << '<' << Q_FUNC_INFO << pos; +} + +// Handle change of a combo. Return "false" if the combo +// is to be reset (refuse new field). +bool SubmitFieldWidget::comboIndexChange(int pos, int index) +{ + const QString newField = d->fieldEntries.at(pos).combo->itemText(index); + // If the field is visible elsewhere: focus the existing one and refuse + if (!d->allowDuplicateFields) { + const int existingFieldIndex = d->findField(newField, pos); + if (existingFieldIndex != -1) { + d->focusField(existingFieldIndex); + return false; + } + } + // Empty value: just change the field + if (d->fieldValue(pos).isEmpty()) + return true; + // Non-empty: Create a new field and reset the triggering combo + createField(newField); + return false; +} + +void SubmitFieldWidget::slotBrowseButtonClicked() +{ + const int pos = d->findSender(sender()); + emit browseButtonClicked(pos, d->fieldText(pos)); +} + +} |