2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2010-01-07 14:33:28 +01:00
|
|
|
|
2009-03-23 12:03:20 +01:00
|
|
|
#include "submitfieldwidget.h"
|
|
|
|
|
|
2022-07-21 13:03:09 +02:00
|
|
|
#include <utils/algorithm.h>
|
2017-10-06 17:58:08 +02:00
|
|
|
#include <utils/utilsicons.h>
|
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
#include <QLineEdit>
|
|
|
|
|
#include <QToolButton>
|
|
|
|
|
#include <QCompleter>
|
|
|
|
|
#include <QIcon>
|
|
|
|
|
#include <QToolBar>
|
2009-03-23 12:03:20 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QList>
|
|
|
|
|
#include <QDebug>
|
2009-03-23 12:03:20 +01:00
|
|
|
|
|
|
|
|
enum { debug = 0 };
|
|
|
|
|
enum { spacing = 2 };
|
|
|
|
|
|
|
|
|
|
static void inline setComboBlocked(QComboBox *cb, int index)
|
|
|
|
|
{
|
2017-09-30 07:12:57 +02:00
|
|
|
QSignalBlocker blocker(cb);
|
2009-03-23 12:03:20 +01:00
|
|
|
cb->setCurrentIndex(index);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-02 17:13:33 +01:00
|
|
|
/*!
|
2013-01-02 22:12:06 +02:00
|
|
|
\class VcsBase::SubmitFieldWidget
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The SubmitFieldWidget class is a widget for editing submit message
|
|
|
|
|
fields like "reviewed-by:",
|
2011-03-02 17:13:33 +01:00
|
|
|
"signed-off-by:".
|
|
|
|
|
|
2013-09-10 15:46:58 +02:00
|
|
|
The widget displays the fields in a vertical row of combo boxes or line edit fields
|
2011-03-02 17:13:33 +01:00
|
|
|
that is modeled after the target address controls of mail clients.
|
2013-09-10 15:46:58 +02:00
|
|
|
When choosing a different field in the combo box, a new row is opened if text
|
|
|
|
|
has been entered for the current field. Optionally, a \gui Browse button and
|
2011-03-02 17:13:33 +01:00
|
|
|
completer can be added.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-01-02 22:12:06 +02:00
|
|
|
namespace VcsBase {
|
2009-03-23 12:03:20 +01:00
|
|
|
|
|
|
|
|
// Field/Row entry
|
|
|
|
|
struct FieldEntry {
|
|
|
|
|
void createGui(const QIcon &removeIcon);
|
|
|
|
|
void deleteGuiLater();
|
|
|
|
|
|
2018-09-20 01:32:36 +03:00
|
|
|
QComboBox *combo = nullptr;
|
|
|
|
|
QHBoxLayout *layout = nullptr;
|
|
|
|
|
QLineEdit *lineEdit = nullptr;
|
|
|
|
|
QToolBar *toolBar = nullptr;
|
|
|
|
|
QToolButton *clearButton = nullptr;
|
|
|
|
|
QToolButton *browseButton = nullptr;
|
|
|
|
|
int comboIndex = 0;
|
2009-03-23 12:03:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void FieldEntry::createGui(const QIcon &removeIcon)
|
|
|
|
|
{
|
|
|
|
|
layout = new QHBoxLayout;
|
2019-08-29 10:36:01 +02:00
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
2009-03-23 12:03:20 +01:00
|
|
|
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();
|
2010-01-29 21:33:57 +01:00
|
|
|
lineEdit->deleteLater();
|
2009-03-23 12:03:20 +01:00
|
|
|
combo->deleteLater();
|
|
|
|
|
layout->deleteLater();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------- SubmitFieldWidgetPrivate
|
|
|
|
|
struct SubmitFieldWidgetPrivate {
|
|
|
|
|
SubmitFieldWidgetPrivate();
|
|
|
|
|
|
2022-07-21 13:03:09 +02:00
|
|
|
int indexOf(const QWidget *w) const;
|
2009-03-23 12:03:20 +01:00
|
|
|
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;
|
2018-09-20 01:32:36 +03:00
|
|
|
QCompleter *completer = nullptr;
|
2009-03-23 12:03:20 +01:00
|
|
|
|
|
|
|
|
QList <FieldEntry> fieldEntries;
|
2018-09-20 01:32:36 +03:00
|
|
|
QVBoxLayout *layout = nullptr;
|
|
|
|
|
|
|
|
|
|
bool hasBrowseButton = false;
|
|
|
|
|
bool allowDuplicateFields = false;
|
2009-03-23 12:03:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SubmitFieldWidgetPrivate::SubmitFieldWidgetPrivate() :
|
2018-09-20 01:32:36 +03:00
|
|
|
removeFieldIcon(Utils::Icons::BROKEN.icon())
|
2009-03-23 12:03:20 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-21 13:03:09 +02:00
|
|
|
int SubmitFieldWidgetPrivate::indexOf(const QWidget *w) const
|
2009-03-23 12:03:20 +01:00
|
|
|
{
|
2022-07-21 13:03:09 +02:00
|
|
|
return Utils::indexOf(fieldEntries, [w](const FieldEntry &fe) {
|
|
|
|
|
return fe.combo == w || fe.browseButton == w || fe.clearButton == w || fe.lineEdit == w;
|
|
|
|
|
});
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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),
|
2011-09-07 14:26:11 +02:00
|
|
|
d(new SubmitFieldWidgetPrivate)
|
2009-03-23 12:03:20 +01:00
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
d->layout = new QVBoxLayout;
|
2019-08-29 10:36:01 +02:00
|
|
|
d->layout->setContentsMargins(0, 0, 0, 0);
|
2011-09-07 14:26:11 +02:00
|
|
|
d->layout->setSpacing(spacing);
|
|
|
|
|
setLayout(d->layout);
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SubmitFieldWidget::~SubmitFieldWidget()
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
delete d;
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SubmitFieldWidget::setFields(const QStringList & f)
|
|
|
|
|
{
|
|
|
|
|
// remove old fields
|
2011-09-07 14:26:11 +02:00
|
|
|
for (int i = d->fieldEntries.size() - 1 ; i >= 0 ; i--)
|
2010-01-29 21:33:57 +01:00
|
|
|
removeField(i);
|
2009-03-23 12:03:20 +01:00
|
|
|
|
2011-09-07 14:26:11 +02:00
|
|
|
d->fields = f;
|
2009-03-23 12:03:20 +01:00
|
|
|
if (!f.empty())
|
|
|
|
|
createField(f.front());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList SubmitFieldWidget::fields() const
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
return d->fields;
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SubmitFieldWidget::hasBrowseButton() const
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
return d->hasBrowseButton;
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
2011-09-07 14:26:11 +02:00
|
|
|
void SubmitFieldWidget::setHasBrowseButton(bool on)
|
2009-03-23 12:03:20 +01:00
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
if (d->hasBrowseButton == on)
|
2009-03-23 12:03:20 +01:00
|
|
|
return;
|
2011-09-07 14:26:11 +02:00
|
|
|
d->hasBrowseButton = on;
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const FieldEntry &fe : std::as_const(d->fieldEntries))
|
2011-09-07 14:26:11 +02:00
|
|
|
fe.browseButton->setVisible(on);
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SubmitFieldWidget::allowDuplicateFields() const
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
return d->allowDuplicateFields;
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SubmitFieldWidget::setAllowDuplicateFields(bool v)
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
d->allowDuplicateFields = v;
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QCompleter *SubmitFieldWidget::completer() const
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
return d->completer;
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SubmitFieldWidget::setCompleter(QCompleter *c)
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
if (c == d->completer)
|
2009-03-23 12:03:20 +01:00
|
|
|
return;
|
2011-09-07 14:26:11 +02:00
|
|
|
d->completer = c;
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const FieldEntry &fe : std::as_const(d->fieldEntries))
|
2009-03-23 12:03:20 +01:00
|
|
|
fe.lineEdit->setCompleter(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SubmitFieldWidget::fieldValue(int pos) const
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
return d->fieldValue(pos);
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SubmitFieldWidget::setFieldValue(int pos, const QString &value)
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
d->fieldEntries.at(pos).lineEdit->setText(value);
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SubmitFieldWidget::fieldValues() const
|
|
|
|
|
{
|
|
|
|
|
const QChar blank = QLatin1Char(' ');
|
|
|
|
|
const QChar newLine = QLatin1Char('\n');
|
|
|
|
|
// Format as "RevBy: value\nSigned-Off: value\n"
|
|
|
|
|
QString rc;
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const FieldEntry &fe : std::as_const(d->fieldEntries)) {
|
2009-03-23 12:03:20 +01:00
|
|
|
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;
|
2011-09-07 14:26:11 +02:00
|
|
|
fe.createGui(d->removeFieldIcon);
|
|
|
|
|
fe.combo->addItems(d->fields);
|
2009-03-23 12:03:20 +01:00
|
|
|
if (!f.isEmpty()) {
|
|
|
|
|
const int index = fe.combo->findText(f);
|
|
|
|
|
if (index != -1) {
|
|
|
|
|
setComboBlocked(fe.combo, index);
|
|
|
|
|
fe.comboIndex = index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-21 13:03:09 +02:00
|
|
|
connect(fe.browseButton, &QAbstractButton::clicked, this, [this, button = fe.browseButton] {
|
|
|
|
|
const int pos = d->indexOf(button);
|
|
|
|
|
emit browseButtonClicked(pos, d->fieldText(pos));
|
|
|
|
|
});
|
2011-09-07 14:26:11 +02:00
|
|
|
if (!d->hasBrowseButton)
|
2009-03-23 12:03:20 +01:00
|
|
|
fe.browseButton->setVisible(false);
|
|
|
|
|
|
2011-09-07 14:26:11 +02:00
|
|
|
if (d->completer)
|
|
|
|
|
fe.lineEdit->setCompleter(d->completer);
|
2009-03-23 12:03:20 +01:00
|
|
|
|
2022-07-21 13:03:09 +02:00
|
|
|
connect(fe.combo, &QComboBox::currentIndexChanged, this, [this, combo = fe.combo](int index) {
|
|
|
|
|
slotComboIndexChanged(d->indexOf(combo), index);
|
|
|
|
|
});
|
|
|
|
|
connect(fe.clearButton, &QAbstractButton::clicked, this, [this, button = fe.clearButton] {
|
|
|
|
|
slotRemove(d->indexOf(button));
|
|
|
|
|
});
|
2011-09-07 14:26:11 +02:00
|
|
|
d->layout->addLayout(fe.layout);
|
|
|
|
|
d->fieldEntries.push_back(fe);
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-21 13:03:09 +02:00
|
|
|
void SubmitFieldWidget::slotRemove(int pos)
|
2009-03-23 12:03:20 +01:00
|
|
|
{
|
2022-07-21 13:03:09 +02:00
|
|
|
if (pos < 0)
|
|
|
|
|
return;
|
|
|
|
|
if (pos == 0)
|
2011-09-07 14:26:11 +02:00
|
|
|
d->fieldEntries.front().lineEdit->clear();
|
2022-07-21 13:03:09 +02:00
|
|
|
else
|
|
|
|
|
removeField(pos);
|
2009-03-23 12:03:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SubmitFieldWidget::removeField(int index)
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
FieldEntry fe = d->fieldEntries.takeAt(index);
|
|
|
|
|
QLayoutItem * item = d->layout->takeAt(index);
|
2009-03-23 12:03:20 +01:00
|
|
|
fe.deleteGuiLater();
|
|
|
|
|
delete item;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-21 13:03:09 +02:00
|
|
|
void SubmitFieldWidget::slotComboIndexChanged(int pos, int comboIndex)
|
2009-03-23 12:03:20 +01:00
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << '>' << Q_FUNC_INFO << pos;
|
2022-07-21 13:03:09 +02:00
|
|
|
if (pos < 0)
|
2009-03-23 12:03:20 +01:00
|
|
|
return;
|
|
|
|
|
// Accept new index or reset combo to previous value?
|
2011-09-07 14:26:11 +02:00
|
|
|
int &previousIndex = d->fieldEntries[pos].comboIndex;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (comboIndexChange(pos, comboIndex))
|
2009-03-23 12:03:20 +01:00
|
|
|
previousIndex = comboIndex;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else
|
2011-09-07 14:26:11 +02:00
|
|
|
setComboBlocked(d->fieldEntries.at(pos).combo, previousIndex);
|
2009-03-23 12:03:20 +01:00
|
|
|
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)
|
|
|
|
|
{
|
2011-09-07 14:26:11 +02:00
|
|
|
const QString newField = d->fieldEntries.at(pos).combo->itemText(index);
|
2009-03-23 12:03:20 +01:00
|
|
|
// If the field is visible elsewhere: focus the existing one and refuse
|
2011-09-07 14:26:11 +02:00
|
|
|
if (!d->allowDuplicateFields) {
|
|
|
|
|
const int existingFieldIndex = d->findField(newField, pos);
|
2009-03-23 12:03:20 +01:00
|
|
|
if (existingFieldIndex != -1) {
|
2011-09-07 14:26:11 +02:00
|
|
|
d->focusField(existingFieldIndex);
|
2009-03-23 12:03:20 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Empty value: just change the field
|
2011-09-07 14:26:11 +02:00
|
|
|
if (d->fieldValue(pos).isEmpty())
|
2009-03-23 12:03:20 +01:00
|
|
|
return true;
|
|
|
|
|
// Non-empty: Create a new field and reset the triggering combo
|
|
|
|
|
createField(newField);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|