forked from qt-creator/qt-creator
Added a gitorious clone wizard.
... based on the git clone wizard. Provide a wizard for browsing gitorious hosts. Task-number: 44831
This commit is contained in:
304
src/plugins/git/gitorious/gitoriousprojectwidget.cpp
Normal file
304
src/plugins/git/gitorious/gitoriousprojectwidget.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://www.qtsoftware.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "gitoriousprojectwidget.h"
|
||||
#include "gitorioushostwizardpage.h"
|
||||
#include "gitorious.h"
|
||||
#include "ui_gitoriousprojectwidget.h"
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QRegExp>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <QtGui/QStandardItemModel>
|
||||
#include <QtGui/QSortFilterProxyModel>
|
||||
#include <QtGui/QStandardItem>
|
||||
#include <QtGui/QItemSelectionModel>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtGui/QIcon>
|
||||
#include <QtGui/QStyle>
|
||||
|
||||
enum {
|
||||
urlRole = Qt::UserRole + 1 // Project has a URL in the description
|
||||
};
|
||||
|
||||
enum { debug = 1 };
|
||||
|
||||
namespace Gitorious {
|
||||
namespace Internal {
|
||||
|
||||
enum { ProjectColumn, DescriptionColumn, ColumnCount };
|
||||
|
||||
GitoriousProjectWidget::GitoriousProjectWidget(int hostIndex,
|
||||
QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_hostName(Gitorious::instance().hostName(hostIndex)),
|
||||
ui(new Ui::GitoriousProjectWidget),
|
||||
m_model(new QStandardItemModel(0, ColumnCount, this)),
|
||||
m_filterModel(new QSortFilterProxyModel),
|
||||
m_valid(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->infoToolButton->setIcon(style()->standardIcon(QStyle::SP_MessageBoxInformation));
|
||||
ui->infoToolButton->setEnabled(false);
|
||||
connect(ui->infoToolButton, SIGNAL(clicked()), this, SLOT(slotInfo()));
|
||||
// Filter
|
||||
connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), m_filterModel, SLOT(setFilterFixedString(QString)));
|
||||
ui->filterClearButton->setIcon(QIcon(Core::Constants::ICON_RESET));
|
||||
connect(ui->filterClearButton, SIGNAL(clicked()), ui->filterLineEdit, SLOT(clear()));
|
||||
// Updater
|
||||
ui->updateCheckBox->setChecked(true);
|
||||
if (Gitorious::instance().hostState(hostIndex) != GitoriousHost::ProjectsQueryRunning)
|
||||
ui->updateCheckBox->setVisible(false);
|
||||
connect(ui->updateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotUpdateCheckBoxChanged(int)));
|
||||
// Model
|
||||
QStringList headers;
|
||||
headers << tr("Project") << tr("Description");
|
||||
m_model->setHorizontalHeaderLabels(headers);
|
||||
// Populate the model
|
||||
slotUpdateProjects(hostIndex);
|
||||
// Filter on all columns
|
||||
m_filterModel->setSourceModel(m_model);
|
||||
m_filterModel->setFilterKeyColumn(-1);
|
||||
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
ui->projectTreeView->setModel(m_filterModel);
|
||||
// View
|
||||
ui->projectTreeView->setAlternatingRowColors(true);
|
||||
ui->projectTreeView->setRootIsDecorated(false);
|
||||
ui->projectTreeView->setUniformRowHeights(true);
|
||||
ui->projectTreeView->setSortingEnabled(true);
|
||||
connect(ui->projectTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
|
||||
this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)));
|
||||
ui->projectTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
// Select first, resize columns
|
||||
if (Gitorious::instance().projectCount(hostIndex)) {
|
||||
for (int r = 0; r < ColumnCount; r++)
|
||||
ui->projectTreeView->resizeColumnToContents(r);
|
||||
// Select first
|
||||
const QModelIndex index = m_filterModel->index(0, 0);
|
||||
ui->projectTreeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select|QItemSelectionModel::Current|QItemSelectionModel::Rows);
|
||||
}
|
||||
|
||||
// Continuous update
|
||||
Gitorious *gitorious = &Gitorious::instance();
|
||||
connect(gitorious, SIGNAL(projectListPageReceived(int,int)), this, SLOT(slotUpdateProjects(int)));
|
||||
connect(gitorious, SIGNAL(projectListReceived(int)), this, SLOT(slotUpdateProjects(int)));
|
||||
}
|
||||
|
||||
GitoriousProjectWidget::~GitoriousProjectWidget()
|
||||
{
|
||||
Gitorious *gitorious = &Gitorious::instance();
|
||||
disconnect(gitorious, SIGNAL(projectListPageReceived(int,int)), this, SLOT(slotUpdateProjects(int)));
|
||||
disconnect(gitorious, SIGNAL(projectListReceived(int)), this, SLOT(slotUpdateProjects(int)));
|
||||
delete ui;
|
||||
}
|
||||
|
||||
// Map indexes back via filter
|
||||
QStandardItem *GitoriousProjectWidget::itemFromIndex(const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid())
|
||||
return m_model->itemFromIndex(m_filterModel->mapToSource(index));
|
||||
return 0;
|
||||
}
|
||||
|
||||
QStandardItem *GitoriousProjectWidget::currentItem() const
|
||||
{
|
||||
return itemFromIndex(ui->projectTreeView->selectionModel()->currentIndex());
|
||||
}
|
||||
|
||||
void GitoriousProjectWidget::slotCurrentChanged(const QModelIndex ¤t, const QModelIndex & /* previous */)
|
||||
{
|
||||
// Any info URL to show?
|
||||
QString url;
|
||||
if (current.isValid())
|
||||
if (QStandardItem *item = itemFromIndex(current)) {
|
||||
// Project: URL in description?
|
||||
const QVariant urlV = item->data(urlRole);
|
||||
if (urlV.isValid())
|
||||
url = urlV.toString();
|
||||
}
|
||||
|
||||
ui->infoToolButton->setEnabled(!url.isEmpty());
|
||||
ui->infoToolButton->setToolTip(url);
|
||||
|
||||
const bool isValid = current.isValid();
|
||||
if (isValid != m_valid) {
|
||||
m_valid = isValid;
|
||||
emit validChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void GitoriousProjectWidget::slotInfo()
|
||||
{
|
||||
if (const QStandardItem *item = currentItem()) {
|
||||
const QVariant url = item->data(urlRole);
|
||||
if (url.isValid())
|
||||
QDesktopServices::openUrl(QUrl(url.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// Create a model row for a project
|
||||
static inline QList<QStandardItem *> projectEntry(const GitoriousProject &p)
|
||||
{
|
||||
enum { maxNameLength = 30 };
|
||||
// Truncate names with colons
|
||||
QString name = p.name;
|
||||
const int colonPos = name.indexOf(QLatin1Char(':'));
|
||||
if (colonPos != -1)
|
||||
name.truncate(colonPos);
|
||||
if (name.size() > maxNameLength) {
|
||||
name.truncate(maxNameLength);
|
||||
name += QLatin1String("...");
|
||||
}
|
||||
QStandardItem *nameItem = new QStandardItem(name);
|
||||
nameItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
|
||||
// Description
|
||||
QStandardItem *descriptionItem = new QStandardItem;
|
||||
descriptionItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
|
||||
QList<QStandardItem *> rc;
|
||||
rc << nameItem << descriptionItem;
|
||||
// Should the text contain an URL, store it under 'urlRole' for the info button
|
||||
QString url;
|
||||
GitoriousProjectWidget::setDescription(p.description, DescriptionColumn, &rc, &url);
|
||||
if (!url.isEmpty()) {
|
||||
const QVariant urlV = QVariant(url);
|
||||
nameItem->setData(urlV, urlRole);
|
||||
descriptionItem->setData(urlV, urlRole);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Utility to set description column and tooltip for a row from a free
|
||||
// format/HTMLish gitorious description. Make sure the description is just one
|
||||
// row for the item and set a tooltip with full contents. If desired, extract
|
||||
// an URL.
|
||||
|
||||
void GitoriousProjectWidget::setDescription(const QString &description,
|
||||
int descriptionColumn,
|
||||
QList<QStandardItem *> *items,
|
||||
QString *url /* =0 */)
|
||||
{
|
||||
enum { MaxDescriptionLineLength = 70 };
|
||||
// Trim description to 1 sensibly long line for the item view
|
||||
QString descLine = description;
|
||||
const int newLinePos = descLine.indexOf(QLatin1Char('\n'));
|
||||
if (newLinePos != -1)
|
||||
descLine.truncate(newLinePos);
|
||||
if (descLine.size() > MaxDescriptionLineLength) {
|
||||
const int dotPos = descLine.lastIndexOf(QLatin1Char('.'), MaxDescriptionLineLength);
|
||||
if (dotPos != -1) {
|
||||
descLine.truncate(dotPos);
|
||||
} else {
|
||||
descLine.truncate(MaxDescriptionLineLength);
|
||||
}
|
||||
descLine += QLatin1String("...");
|
||||
}
|
||||
items->at(descriptionColumn)->setText(descLine);
|
||||
// Set a HTML tooltip to make lines wrap and the markup sprinkled within work
|
||||
const QString htmlTip = QLatin1String("<html><body>") + description + QLatin1String("</body></html>");
|
||||
const int size = items->size();
|
||||
for (int i = 0; i < size; i++)
|
||||
items->at(i)->setToolTip(htmlTip);
|
||||
if (url) {
|
||||
// Should the text contain an URL, extract
|
||||
// Do not fall for "(http://XX)", strip special characters
|
||||
static const QRegExp urlRegExp(QLatin1String("(http://[\\w\\.-]+/[a-zA-Z0-9/\\-&]*)"));
|
||||
Q_ASSERT(urlRegExp.isValid());
|
||||
if (urlRegExp.indexIn(description) != -1) {
|
||||
*url= urlRegExp.cap(1);
|
||||
} else {
|
||||
url->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GitoriousProjectWidget::grabFocus()
|
||||
{
|
||||
ui->projectTreeView->setFocus();
|
||||
}
|
||||
|
||||
void GitoriousProjectWidget::slotUpdateCheckBoxChanged(int state)
|
||||
{
|
||||
if (state == Qt::Checked)
|
||||
slotUpdateProjects(Gitorious::instance().findByHostName(m_hostName));
|
||||
}
|
||||
|
||||
void GitoriousProjectWidget::slotUpdateProjects(int hostIndex)
|
||||
{
|
||||
if (!ui->updateCheckBox->isChecked())
|
||||
return;
|
||||
const Gitorious &gitorious = Gitorious::instance();
|
||||
// Complete list of projects
|
||||
if (m_hostName != gitorious.hostName(hostIndex))
|
||||
return;
|
||||
// Fill in missing projects
|
||||
const GitoriousHost::ProjectList &projects = gitorious.hosts().at(hostIndex).projects;
|
||||
const int size = projects.size();
|
||||
for (int i = m_model->rowCount(); i < size; i++)
|
||||
m_model->appendRow(projectEntry(*projects.at(i)));
|
||||
if (gitorious.hostState(hostIndex) == GitoriousHost::ProjectsComplete)
|
||||
ui->updateCheckBox->setVisible(false);
|
||||
}
|
||||
|
||||
bool GitoriousProjectWidget::isValid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
int GitoriousProjectWidget::hostIndex() const
|
||||
{
|
||||
return Gitorious::instance().findByHostName(m_hostName);
|
||||
}
|
||||
|
||||
QSharedPointer<GitoriousProject> GitoriousProjectWidget::project() const
|
||||
{
|
||||
if (const QStandardItem *item = currentItem()) {
|
||||
const int projectIndex = item->row();
|
||||
return Gitorious::instance().hosts().at(hostIndex()).projects.at(projectIndex);
|
||||
}
|
||||
return QSharedPointer<GitoriousProject>(new GitoriousProject);
|
||||
}
|
||||
|
||||
void GitoriousProjectWidget::changeEvent(QEvent *e)
|
||||
{
|
||||
QWidget::changeEvent(e);
|
||||
switch (e->type()) {
|
||||
case QEvent::LanguageChange:
|
||||
ui->retranslateUi(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Gitorious
|
||||
Reference in New Issue
Block a user