Fixes: Add common configuration to the VCSA base plugin; submit message check script and user name configuration. Details: Extend submit editor widget by configureable fields. Use them in the VCS base submit editor to specify users, provide completion and selection dialog for them.

This commit is contained in:
Friedemann Kleint
2009-03-19 17:40:01 +01:00
parent 40eab8980b
commit 27cb595bbb
19 changed files with 1303 additions and 27 deletions

View File

@@ -28,10 +28,14 @@
**************************************************************************/
#include "vcsbasesubmiteditor.h"
#include "vcsbasesettings.h"
#include "vcsbaseplugin.h"
#include "nicknamedialog.h"
#include "submiteditorfile.h"
#include <aggregation/aggregate.h>
#include <coreplugin/ifile.h>
#include <coreplugin/icore.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <utils/submiteditorwidget.h>
@@ -42,18 +46,31 @@
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QTemporaryFile>
#include <QtCore/QProcess>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QPointer>
#include <QtCore/QTextStream>
#include <QtGui/QStyle>
#include <QtGui/QToolBar>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QMessageBox>
#include <QtGui/QMainWindow>
#include <QtGui/QCompleter>
#include <QtGui/QLineEdit>
enum { debug = 0 };
enum { wantToolBar = 0 };
namespace VCSBase {
static inline QString submitMessageCheckScript()
{
return Internal::VCSBasePlugin::instance()->settings().submitMessageCheckScript;
}
struct VCSBaseSubmitEditorPrivate
{
VCSBaseSubmitEditorPrivate(const VCSBaseSubmitEditorParameters *parameters,
@@ -69,6 +86,8 @@ struct VCSBaseSubmitEditorPrivate
QPointer<QAction> m_diffAction;
QPointer<QAction> m_submitAction;
Internal::NickNameDialog *m_nickNameDialog;
};
VCSBaseSubmitEditorPrivate::VCSBaseSubmitEditorPrivate(const VCSBaseSubmitEditorParameters *parameters,
@@ -77,7 +96,8 @@ VCSBaseSubmitEditorPrivate::VCSBaseSubmitEditorPrivate(const VCSBaseSubmitEditor
m_widget(editorWidget),
m_toolWidget(0),
m_parameters(parameters),
m_file(new VCSBase::Internal::SubmitEditorFile(QLatin1String(m_parameters->mimeType), q))
m_file(new VCSBase::Internal::SubmitEditorFile(QLatin1String(m_parameters->mimeType), q)),
m_nickNameDialog(0)
{
m_contexts << Core::UniqueIDManager::instance()->uniqueIdentifier(m_parameters->context);
}
@@ -93,6 +113,29 @@ VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *pa
connect(m_d->m_widget, SIGNAL(diffSelected(QStringList)), this, SLOT(slotDiffSelectedVCSFiles(QStringList)));
connect(m_d->m_widget->descriptionEdit(), SIGNAL(textChanged()), this, SLOT(slotDescriptionChanged()));
const Internal::VCSBaseSettings settings = Internal::VCSBasePlugin::instance()->settings();
// Add additional context menu settings
if (!settings.submitMessageCheckScript.isEmpty() || !settings.nickNameFieldListFile.isEmpty()) {
QAction *sep = new QAction(this);
sep->setSeparator(true);
m_d->m_widget->addDescriptionEditContextMenuAction(sep);
// Run check action
if (!settings.submitMessageCheckScript.isEmpty()) {
QAction *checkAction = new QAction(tr("Check message"), this);
connect(checkAction, SIGNAL(triggered()), this, SLOT(slotCheckSubmitMessage()));
m_d->m_widget->addDescriptionEditContextMenuAction(checkAction);
}
// Insert nick
if (!settings.nickNameFieldListFile.isEmpty()) {
QAction *insertAction = new QAction(tr("Insert name..."), this);
connect(insertAction, SIGNAL(triggered()), this, SLOT(slotInsertNickName()));
m_d->m_widget->addDescriptionEditContextMenuAction(insertAction);
}
}
// Do we have user fields?
if (!settings.nickNameFieldListFile.isEmpty())
createUserFields(settings.nickNameFieldListFile);
connect(m_d->m_widget, SIGNAL(fieldDialogRequested(int)), this, SLOT(slotSetFieldNickName(int)));
Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
aggregate->add(new Find::BaseTextFind(m_d->m_widget->descriptionEdit()));
aggregate->add(this);
@@ -105,6 +148,26 @@ VCSBaseSubmitEditor::~VCSBaseSubmitEditor()
delete m_d;
}
void VCSBaseSubmitEditor::createUserFields(const QString &fieldConfigFile)
{
QFile fieldFile(fieldConfigFile);
if (!fieldFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
qWarning("%s: Unable to open %s: %s", Q_FUNC_INFO, qPrintable(fieldConfigFile), qPrintable(fieldFile.errorString()));
return;
}
// Parse into fields
const QStringList fields = QString::fromUtf8(fieldFile.readAll()).trimmed().split(QLatin1Char('\n'));
if (fields.empty())
return;
// Create a completer on user names
QCompleter *completer = new QCompleter(Internal::NickNameDialog::nickNameList(), this);
foreach(const QString &field, fields) {
const QString trimmedField = field.trimmed();
if (!trimmedField.isEmpty())
m_d->m_widget->addField(trimmedField, true)->setCompleter(completer);
}
}
void VCSBaseSubmitEditor::registerActions(QAction *editorUndoAction, QAction *editorRedoAction,
QAction *submitAction, QAction *diffAction)\
{
@@ -139,7 +202,6 @@ void VCSBaseSubmitEditor::setFileListSelectionMode(QAbstractItemView::SelectionM
m_d->m_widget->setFileListSelectionMode(sm);
}
void VCSBaseSubmitEditor::slotDescriptionChanged()
{
}
@@ -304,6 +366,118 @@ bool VCSBaseSubmitEditor::setFileContents(const QString &contents)
return true;
}
enum { checkDialogMinimumWidth = 500 };
VCSBaseSubmitEditor::PromptSubmitResult
VCSBaseSubmitEditor::promptSubmit(const QString &title, const QString &question, const QString &checkFailureQuestion) const
{
QString errorMessage;
QMessageBox::StandardButton answer = QMessageBox::Yes;
QWidget *parent = Core::ICore::instance()->mainWindow();
// Pop up a message depending on whether the check succeeded and the
// user wants to be prompted
if (checkSubmitMessage(&errorMessage)) {
// Check ok, do prompt?
if (Internal::VCSBasePlugin::instance()->settings().promptForSubmit) {
answer = QMessageBox::question(parent, title, question,
QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
QMessageBox::Yes);
}
} else {
// Check failed.
QMessageBox msgBox(QMessageBox::Question, title, checkFailureQuestion,
QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, parent);
msgBox.setDefaultButton(QMessageBox::Cancel);
msgBox.setInformativeText(errorMessage);
msgBox.setMinimumWidth(checkDialogMinimumWidth);
answer = static_cast<QMessageBox::StandardButton>(msgBox.exec());
}
switch (answer) {
case QMessageBox::Cancel:
return SubmitCanceled;
case QMessageBox::No:
return SubmitDiscarded;
default:
break;
}
return SubmitConfirmed;
}
QString VCSBaseSubmitEditor::promptForNickName()
{
if (!m_d->m_nickNameDialog)
m_d->m_nickNameDialog = new Internal::NickNameDialog(m_d->m_widget);
if (m_d->m_nickNameDialog->exec() == QDialog::Accepted)
return m_d->m_nickNameDialog->nickName();
return QString();
}
void VCSBaseSubmitEditor::slotInsertNickName()
{
const QString nick = promptForNickName();
if (!nick.isEmpty())
m_d->m_widget->descriptionEdit()->textCursor().insertText(nick);
}
void VCSBaseSubmitEditor::slotSetFieldNickName(int i)
{
const QString nick = promptForNickName();
if (!nick.isEmpty())
m_d->m_widget->fieldLineEdit(i)->setText(nick);
}
void VCSBaseSubmitEditor::slotCheckSubmitMessage()
{
QString errorMessage;
if (!checkSubmitMessage(&errorMessage)) {
QMessageBox msgBox(QMessageBox::Warning, tr("Submit Message Check failed"),
errorMessage, QMessageBox::Ok, m_d->m_widget);
msgBox.setMinimumWidth(checkDialogMinimumWidth);
msgBox.exec();
}
}
bool VCSBaseSubmitEditor::checkSubmitMessage(QString *errorMessage) const
{
const QString checkScript = submitMessageCheckScript();
if (checkScript.isEmpty())
return true;
// Write out message
QString tempFilePattern = QDir::tempPath();
if (!tempFilePattern.endsWith(QDir::separator()))
tempFilePattern += QDir::separator();
tempFilePattern += QLatin1String("msgXXXXXX.txt");
QTemporaryFile messageFile(tempFilePattern);
messageFile.setAutoRemove(true);
if (!messageFile.open()) {
*errorMessage = tr("Unable to open '%1': %2").arg(messageFile.fileName(), messageFile.errorString());
return false;
}
const QString messageFileName = messageFile.fileName();
messageFile.write(fileContents().toUtf8());
messageFile.close();
// Run check process
QProcess checkProcess;
checkProcess.start(checkScript, QStringList(messageFileName));
if (!checkProcess.waitForStarted()) {
*errorMessage = tr("The check script '%1' could not be started: %2").arg(checkScript, checkProcess.errorString());
return false;
}
if (!checkProcess.waitForFinished()) {
*errorMessage = tr("The check script '%1' could not be run: %2").arg(checkScript, checkProcess.errorString());
return false;
}
const int exitCode = checkProcess.exitCode();
if (exitCode != 0) {
*errorMessage = QString::fromLocal8Bit(checkProcess.readAllStandardError());
if (errorMessage->isEmpty())
*errorMessage = tr("The check script returned exit code %1.").arg(exitCode);
return false;
}
return true;
}
QIcon VCSBaseSubmitEditor::diffIcon()
{
return QIcon(QLatin1String(":/vcsbase/images/diff.png"));