Commit 2193915c authored by Friedemann Kleint's avatar Friedemann Kleint

Start on a gerrit plugin as a sub-plugin of git.

- Add a gerrit window that shows a list of changes
  and buttons to display, apply or check out
  a change.
- Uses the new Qt 5 Json API or the utils/json
  classes for Qt 4.
Tested-by: default avatarTobias Hunger <tobias.hunger@nokia.com>
Tested-by: Orgad Shaneh's avatarOrgad Shaneh <orgads@gmail.com>

Change-Id: I14c6c2c2de8f95fb785752c7319be8638b386a1e
Reviewed-by: default avatarEike Ziller <eike.ziller@nokia.com>
Reviewed-by: default avatarTobias Hunger <tobias.hunger@nokia.com>
parent 2b88fedc
......@@ -262,6 +262,15 @@ IVersionControl* VcsManager::findVersionControlForDirectory(const QString &input
return allThatCanManage.first().second;
}
QStringList VcsManager::repositories(const IVersionControl *vc) const
{
QStringList result;
foreach (const VcsManagerPrivate::VcsInfo *vi, d->m_vcsInfoList)
if (vi->versionControl == vc)
result.push_back(vi->topLevel);
return result;
}
bool VcsManager::promptToDelete(const QString &fileName)
{
if (IVersionControl *vc = findVersionControlForDirectory(QFileInfo(fileName).absolutePath()))
......
......@@ -68,6 +68,9 @@ public:
void resetVersionControlForDirectory(const QString &inputDirectory);
IVersionControl *findVersionControlForDirectory(const QString &directory,
QString *topLevelDirectory = 0);
QStringList repositories(const IVersionControl *) const;
IVersionControl *checkout(const QString &versionControlType,
const QString &directory,
const QByteArray &url);
......
INCLUDEPATH += $$PWD
SOURCES += $$PWD/gerritdialog.cpp \
$$PWD/gerritmodel.cpp \
$$PWD/gerritparameters.cpp \
$$PWD/gerritplugin.cpp \
$$PWD/gerritoptionspage.cpp
HEADERS += $$PWD/gerritdialog.h \
$$PWD/gerritmodel.h \
$$PWD/gerritparameters.h \
$$PWD/gerritplugin.h \
$$PWD/gerritoptionspage.h
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "gerritdialog.h"
#include "gerritmodel.h"
#include "gerritparameters.h"
#include <utils/filterlineedit.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSpacerItem>
#include <QTreeView>
#include <QHeaderView>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QDesktopServices>
#include <QSortFilterProxyModel>
#include <QUrl>
#include <QClipboard>
#include <QApplication>
#include <QProcess>
namespace Gerrit {
namespace Internal {
GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
QWidget *parent)
: QDialog(parent)
, m_parameters(p)
, m_filterModel(new QSortFilterProxyModel(this))
, m_model(new GerritModel(p, this))
, m_treeView(new QTreeView)
, m_filterLineEdit(new Utils::FilterLineEdit)
, m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Close))
{
setWindowTitle(tr("Gerrit %1@%2").arg(p->user, p->host));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QVBoxLayout *l = new QVBoxLayout(this);
QHBoxLayout *hl = new QHBoxLayout;
hl->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
m_filterLineEdit->setFixedWidth(300);
hl->addWidget(m_filterLineEdit);
connect(m_filterLineEdit, SIGNAL(filterChanged(QString)),
m_filterModel, SLOT(setFilterFixedString(QString)));
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
l->addLayout(hl);
l->addWidget(m_treeView);
m_filterModel->setSourceModel(m_model);
m_filterModel->setFilterRole(GerritModel::FilterRole);
m_treeView->setModel(m_filterModel);
m_treeView->setMinimumWidth(600);
m_treeView->setUniformRowHeights(true);
m_treeView->setRootIsDecorated(false);
m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
QItemSelectionModel *selectionModel = m_treeView->selectionModel();
connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this, SLOT(slotEnableButtons()));
connect(m_treeView, SIGNAL(doubleClicked(QModelIndex)),
this, SLOT(slotDoubleClicked(QModelIndex)));
m_openButton = addActionButton(tr("Open"), SLOT(slotOpenBrowser()));
m_copyUrlButton = addActionButton(tr("Copy URL"), SLOT(slotCopyUrl()));
m_displayButton = addActionButton(tr("Diff..."), SLOT(slotFetchDisplay()));
m_applyButton = addActionButton(tr("Apply..."), SLOT(slotFetchApply()));
m_checkoutButton = addActionButton(tr("Checkout..."), SLOT(slotFetchCheckout()));
m_refreshButton = addActionButton(tr("Refresh"), SLOT(slotRefresh()));
connect(m_model, SIGNAL(refreshStateChanged(bool)),
m_refreshButton, SLOT(setDisabled(bool)));
connect(m_model, SIGNAL(refreshStateChanged(bool)),
this, SLOT(slotRefreshStateChanged(bool)));
l->addWidget(m_buttonBox);
connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
slotEnableButtons();
m_model->refresh();
resize(QSize(1200, 400));
}
QPushButton *GerritDialog::addActionButton(const QString &text, const char *buttonSlot)
{
QPushButton *button = m_buttonBox->addButton(text, QDialogButtonBox::ActionRole);
connect(button, SIGNAL(clicked()), this, buttonSlot);
return button;
}
GerritDialog::~GerritDialog()
{
}
void GerritDialog::slotDoubleClicked(const QModelIndex &i)
{
if (const QStandardItem *item = itemAt(i))
openUrl(item->row());
}
void GerritDialog::slotRefreshStateChanged(bool v)
{
if (!v && m_model->rowCount())
for (int c = 0; c < GerritModel::ColumnCount; ++c)
m_treeView->resizeColumnToContents(c);
}
void GerritDialog::slotOpenBrowser()
{
if (const QStandardItem *item = currentItem())
openUrl(item->row());
}
void GerritDialog::slotFetchDisplay()
{
if (const QStandardItem *item = currentItem())
emit fetchDisplay(m_model->change(item->row()));
}
void GerritDialog::slotFetchApply()
{
if (const QStandardItem *item = currentItem())
emit fetchApply(m_model->change(item->row()));
}
void GerritDialog::slotFetchCheckout()
{
if (const QStandardItem *item = currentItem())
emit fetchCheckout(m_model->change(item->row()));
}
void GerritDialog::slotCopyUrl()
{
if (const QStandardItem *item = currentItem())
QApplication::clipboard()->setText(m_model->change(item->row())->url);
}
void GerritDialog::slotRefresh()
{
m_model->refresh();
}
void GerritDialog::openUrl(int row) const
{
QDesktopServices::openUrl(QUrl(m_model->change(row)->url));
}
const QStandardItem *GerritDialog::itemAt(const QModelIndex &i, int column) const
{
if (i.isValid()) {
const QModelIndex source = m_filterModel->mapToSource(i);
if (source.isValid())
return m_model->item(source.row(), column);
}
return 0;
}
const QStandardItem *GerritDialog::currentItem(int column) const
{
const QModelIndex index = m_treeView->selectionModel()->currentIndex();
if (index.isValid())
return itemAt(index, column);
return 0;
}
void GerritDialog::slotEnableButtons()
{
const bool valid = m_treeView->selectionModel()->currentIndex().isValid();
m_openButton->setEnabled(valid);
m_displayButton->setEnabled(valid);
m_copyUrlButton->setEnabled(valid);
m_applyButton->setEnabled(valid);
m_checkoutButton->setEnabled(valid);
}
} // namespace Internal
} // namespace Gerrit
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef GERRIT_INTERNAL_GERRITDIALOG_H
#define GERRIT_INTERNAL_GERRITDIALOG_H
#include <QDialog>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
class QTreeView;
class QModelIndex;
class QSortFilterProxyModel;
class QStandardItem;
class QPushButton;
class QDialogButtonBox;
QT_END_NAMESPACE
namespace Utils {
class FilterLineEdit;
}
namespace Gerrit {
namespace Internal {
class GerritParameters;
class GerritModel;
class GerritChange;
class GerritDialog : public QDialog
{
Q_OBJECT
public:
explicit GerritDialog(const QSharedPointer<GerritParameters> &p,
QWidget *parent = 0);
~GerritDialog();
signals:
void fetchDisplay(const QSharedPointer<Gerrit::Internal::GerritChange> &);
void fetchApply(const QSharedPointer<Gerrit::Internal::GerritChange> &);
void fetchCheckout(const QSharedPointer<Gerrit::Internal::GerritChange> &);
private slots:
void slotEnableButtons();
void slotDoubleClicked(const QModelIndex &);
void slotRefreshStateChanged(bool);
void slotOpenBrowser();
void slotFetchDisplay();
void slotFetchApply();
void slotFetchCheckout();
void slotCopyUrl();
void slotRefresh();
private:
inline void openUrl(int row) const;
const QStandardItem *itemAt(const QModelIndex &i, int column = 0) const;
const QStandardItem *currentItem(int column = 0) const;
QPushButton *addActionButton(const QString &text, const char *buttonSlot);
const QSharedPointer<GerritParameters> m_parameters;
QSortFilterProxyModel *m_filterModel;
GerritModel *m_model;
QTreeView *m_treeView;
Utils::FilterLineEdit *m_filterLineEdit;
QDialogButtonBox *m_buttonBox;
QPushButton *m_openButton;
QPushButton *m_displayButton;
QPushButton *m_applyButton;
QPushButton *m_checkoutButton;
QPushButton *m_copyUrlButton;
QPushButton *m_refreshButton;
};
} // namespace Internal
} // namespace Gerrit
#endif // GERRIT_INTERNAL_GERRITDIALOG_H
This diff is collapsed.
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef GERRIT_INTERNAL_GERRITMODEL_H
#define GERRIT_INTERNAL_GERRITMODEL_H
#include <QStandardItemModel>
#include <QSharedPointer>
#include <QMetaType>
#include <QPair>
#include <QDateTime>
QT_BEGIN_NAMESPACE
class QUrl;
QT_END_NAMESPACE
namespace Gerrit {
namespace Internal {
class GerritParameters;
class QueryContext;
class GerritPatchSet {
public:
typedef QPair<QString, int> Approval;
GerritPatchSet() : patchSetNumber(1) {}
QString approvalsToolTip() const;
QString ref;
int patchSetNumber;
QList<Approval> approvals;
};
class GerritChange
{
public:
typedef QPair<QString, int> Approval;
GerritChange() : number(0) {}
bool isValid() const { return number && !url.isEmpty() && !project.isEmpty(); }
QString toolTip() const;
QString filterString() const;
QStringList gitFetchArguments(const QSharedPointer<GerritParameters> &p) const;
QString url;
int number;
QString id;
QString title;
QString owner;
QString email;
QString project;
QString branch;
QString status;
QDateTime lastUpdated;
GerritPatchSet currentPatchSet;
};
typedef QSharedPointer<GerritChange> GerritChangePtr;
class GerritModel : public QStandardItemModel
{
Q_OBJECT
public:
enum Columns {
NumberColumn,
TitleColumn,
OwnerColumn,
DateColumn,
ProjectColumn,
ApprovalsColumn,
StatusColumn,
ColumnCount
};
enum CustomModelRoles {
FilterRole = Qt::UserRole + 1,
GerritChangeRole = Qt::UserRole + 2
};
GerritModel(const QSharedPointer<GerritParameters> &, QObject *parent = 0);
~GerritModel();
GerritChangePtr change(int row) const;
int indexOf(int gerritNumber) const;
public slots:
void refresh();
signals:
void refreshStateChanged(bool isRefreshing); // For disabling the "Refresh" button.
private slots:
void queryFinished(const QByteArray &);
void queriesFinished();
void clearData();
private:
inline bool evaluateQuery(QString *errorMessage);
const QSharedPointer<GerritParameters> m_parameters;
QueryContext *m_query;
};
} // namespace Internal
} // namespace Gerrit
Q_DECLARE_METATYPE(Gerrit::Internal::GerritChangePtr)
#endif // GERRIT_INTERNAL_GERRITMODEL_H
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "gerritoptionspage.h"
#include "gerritparameters.h"
#include <coreplugin/icore.h>
#include <utils/pathchooser.h>
#include <QLineEdit>
#include <QSpinBox>
#include <QCheckBox>
#include <QFormLayout>
#include <QVBoxLayout>
namespace Gerrit {
namespace Internal {
GerritOptionsPage::GerritOptionsPage(const QSharedPointer<GerritParameters> &p,
QObject *parent)
: VcsBase::VcsBaseOptionsPage(parent)
, m_parameters(p)
{
}
QString GerritOptionsPage::displayName() const
{
return tr("Gerrit");
}
QWidget *GerritOptionsPage::createPage(QWidget *parent)
{
GerritOptionsWidget *gow = new GerritOptionsWidget(parent);
gow->setParameters(*m_parameters);
m_widget = gow;
return gow;
}
void GerritOptionsPage::apply()
{
if (GerritOptionsWidget *w = m_widget.data()) {
const GerritParameters newParameters = w->parameters();
if (newParameters != *m_parameters) {
*m_parameters = newParameters;
m_parameters->toSettings(Core::ICore::instance()->settings());
}
}
}
bool GerritOptionsPage::matches(const QString &s) const
{
return s.contains(QLatin1String("gerrit"), Qt::CaseInsensitive);
}
GerritOptionsWidget::GerritOptionsWidget(QWidget *parent)
: QWidget(parent)
, m_hostLineEdit(new QLineEdit(this))
, m_userLineEdit(new QLineEdit(this))
, m_sshChooser(new Utils::PathChooser)
, m_portSpinBox(new QSpinBox(this))
, m_additionalQueriesLineEdit(new QLineEdit(this))
, m_httpsCheckBox(new QCheckBox(tr("HTTPS")))
{
QFormLayout *formLayout = new QFormLayout(this);
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
formLayout->addRow(tr("&Host: "), m_hostLineEdit);
formLayout->addRow(tr("&User: "), m_userLineEdit);
m_sshChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_sshChooser->setCommandVersionArguments(QStringList(QLatin1String("-V")));
formLayout->addRow(tr("&ssh: "), m_sshChooser);
m_portSpinBox->setMinimum(1);
m_portSpinBox->setMaximum(65535);
formLayout->addRow(tr("&Port: "), m_portSpinBox);
formLayout->addRow(tr("&Additional queries: "), m_additionalQueriesLineEdit);
m_additionalQueriesLineEdit->setToolTip(tr(
"A comma-separated list of additional queries.\n"
"For example \"status:staged,status:integrating\""
" can be used to show the status of the Continuous Integration\n"
"of the Qt project."));
formLayout->addRow(tr("P&rotocol:"), m_httpsCheckBox);
m_httpsCheckBox->setToolTip(tr(