Mercurial plugin, merge request with suggested fixes.

This commit is contained in:
Brian McGillion
2009-09-15 13:03:13 +03:00
parent 0915342d15
commit 989e1b5acf
42 changed files with 3504 additions and 3 deletions

View File

@@ -0,0 +1,27 @@
<plugin name="Mercurial" version="1.2.91" compatVersion="1.2.91">
<vendor>Brian McGillion</vendor>
<copyright>(C) 2008-2009 Brian McGillion</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin 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 plugin may be used under the terms of the GNU Lesser
General Public License version 2.1 as published by the Free Software
Foundation. 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.</license>
<description>Mercurial integration.</description>
<url>http://www.qtsoftware.com</url>
<dependencyList>
<dependency name="TextEditor" version="1.2.91"/>
<dependency name="ProjectExplorer" version="1.2.91"/>
<dependency name="Core" version="1.2.91"/>
<dependency name="VCSBase" version="1.2.91"/>
</dependencyList>
</plugin>

View File

@@ -0,0 +1,19 @@
#include "annotationhighlighter.h"
#include "constants.h"
using namespace Mercurial::Internal;
using namespace Mercurial;
MercurialAnnotationHighlighter::MercurialAnnotationHighlighter(const ChangeNumbers &changeNumbers,
QTextDocument *document)
: VCSBase::BaseAnnotationHighlighter(changeNumbers, document),
changeset(Constants::CHANGESETID12)
{
}
QString MercurialAnnotationHighlighter::changeNumber(const QString &block) const
{
if (changeset.indexIn(block) != -1)
return changeset.cap(1);
return QString();
}

View File

@@ -0,0 +1,22 @@
#ifndef ANNOTATIONHIGHLIGHTER_H
#define ANNOTATIONHIGHLIGHTER_H
#include <vcsbase/baseannotationhighlighter.h>
namespace Mercurial {
namespace Internal {
class MercurialAnnotationHighlighter : public VCSBase::BaseAnnotationHighlighter
{
public:
explicit MercurialAnnotationHighlighter(const ChangeNumbers &changeNumbers,
QTextDocument *document = 0);
private:
virtual QString changeNumber(const QString &block) const;
QRegExp changeset;
};
} //namespace Internal
}// namespace Mercurial
#endif // ANNOTATIONHIGHLIGHTER_H

View File

@@ -0,0 +1,59 @@
#include "clonewizard.h"
#include "clonewizardpage.h"
#include "mercurialplugin.h"
#include "mercurialsettings.h"
#include <QtCore/QDebug>
using namespace Mercurial::Internal;
CloneWizard::CloneWizard(QObject *parent)
: VCSBase::BaseCheckoutWizard(parent),
m_icon(QIcon(":/mercurial/images/hg.png"))
{
}
QIcon CloneWizard::icon() const
{
return m_icon;
}
QString CloneWizard::description() const
{
return tr("Clone a Mercurial repository");
}
QString CloneWizard::name() const
{
return tr("Mercurial Clone");
}
QList<QWizardPage*> CloneWizard::createParameterPages(const QString &path)
{
QList<QWizardPage*> wizardPageList;
CloneWizardPage *page = new CloneWizardPage;
page->setPath(path);
wizardPageList.push_back(page);
return wizardPageList;
}
QSharedPointer<VCSBase::AbstractCheckoutJob> CloneWizard::createJob(const QList<QWizardPage *> &parameterPages,
QString *checkoutPath)
{
const CloneWizardPage *page = qobject_cast<const CloneWizardPage *>(parameterPages.front());
if (!page)
return QSharedPointer<VCSBase::AbstractCheckoutJob>();
MercurialSettings *settings = MercurialPlugin::instance()->settings();
QStringList args = settings->standardArguments();
QString path = page->path();
QString directory = page->directory();
args << "clone" << page->repository() << directory;
*checkoutPath = path + "/" + directory;
return QSharedPointer<VCSBase::AbstractCheckoutJob>(new VCSBase::ProcessCheckoutJob(settings->binary(),
args, path));
}

View File

@@ -0,0 +1,33 @@
#ifndef CLONEWIZARD_H
#define CLONEWIZARD_H
#include <vcsbase/basecheckoutwizard.h>
#include <vcsbase/checkoutjobs.h>
#include <QtGui/QIcon>
namespace Mercurial {
namespace Internal {
class CloneWizard : public VCSBase::BaseCheckoutWizard
{
public:
CloneWizard(QObject *parent = 0);
QIcon icon() const;
QString description() const;
QString name() const;
protected:
QList<QWizardPage *> createParameterPages(const QString &path);
QSharedPointer<VCSBase::AbstractCheckoutJob> createJob(const QList<QWizardPage *> &parameterPages,
QString *checkoutPath);
private:
QIcon m_icon;
};
} //namespace Internal
} //namespace Mercurial
#endif // CLONEWIZARD_H

View File

@@ -0,0 +1,21 @@
#include "clonewizardpage.h"
using namespace Mercurial::Internal;
CloneWizardPage::CloneWizardPage(QWidget *parent)
: VCSBase::BaseCheckoutWizardPage(parent)
{
setRepositoryLabel("Clone URL:");
}
QString CloneWizardPage::directoryFromRepository(const QString &repository) const
{
//mercruial repositories are generally of the form protocol://repositoryUrl/repository/
//we are just looking for repository.
QString repo = repository.trimmed();
if (repo.endsWith('/'))
repo = repo.remove(-1, 1);
//Take the basename or the repository url
return repo.mid(repo.lastIndexOf('/') + 1);
}

View File

@@ -0,0 +1,22 @@
#ifndef CLONEWIZARDPAGE_H
#define CLONEWIZARDPAGE_H
#include <vcsbase/basecheckoutwizardpage.h>
namespace Mercurial {
namespace Internal {
class CloneWizardPage : public VCSBase::BaseCheckoutWizardPage
{
Q_OBJECT
public:
CloneWizardPage(QWidget *parent = 0);
protected:
QString directoryFromRepository(const QString &rrepository) const;
};
} //namespace Internal
} //namespace Mercurial
#endif // CLONEWIZARDPAGE_H

View File

@@ -0,0 +1,68 @@
#include "commiteditor.h"
#include "mercurialcommitwidget.h"
#include <vcsbase/submitfilemodel.h>
#include <QtCore/QDebug>
#include <QDir> //TODO REMOVE WHEN BASE FILE CHANGES ARE PULLED
using namespace Mercurial::Internal;
CommitEditor::CommitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent)
: VCSBase::VCSBaseSubmitEditor(parameters, new MercurialCommitWidget(parent)),
fileModel(0)
{
setDisplayName(tr("Commit Editor"));
}
MercurialCommitWidget *CommitEditor::commitWidget()
{
return static_cast<MercurialCommitWidget *>(widget());
}
void CommitEditor::setFields(const QFileInfo &repositoryRoot, const QString &branch,
const QString &userName, const QString &email,
const QList<QPair<QString, QString> > &repoStatus)
{
MercurialCommitWidget *mercurialWidget = commitWidget();
if (!mercurialWidget)
return;
mercurialWidget->setFields(repositoryRoot.absoluteFilePath(), branch, userName, email);
fileModel = new VCSBase::SubmitFileModel(this);
//TODO Messy tidy this up
typedef QPair<QString, QString> PAIR;
QStringList shouldTrack;
foreach (PAIR status, repoStatus) {
if (status.first == "Untracked")
shouldTrack.append(status.second);
else
fileModel->addFile(status.second, status.first, false);
}
VCSBase::VCSBaseSubmitEditor::filterUntrackedFilesOfProject(repositoryRoot.absoluteFilePath(),
&shouldTrack);
foreach (QString track, shouldTrack) {
foreach (PAIR status, repoStatus) {
if (status.second == track)
fileModel->addFile(status.second, status.first, false);
}
}
setFileModel(fileModel);
}
QString CommitEditor::committerInfo()
{
return commitWidget()->committer();
}
QString CommitEditor::repoRoot()
{
return commitWidget()->repoRoot();
}

View File

@@ -0,0 +1,40 @@
#ifndef COMMITEDITOR_H
#define COMMITEDITOR_H
#include <vcsbase/vcsbasesubmiteditor.h>
#include <QtCore/QFileInfo>
namespace VCSBase {
class SubmitFileModel;
}
namespace Mercurial {
namespace Internal {
class MercurialCommitWidget;
class CommitEditor : public VCSBase::VCSBaseSubmitEditor
{
Q_OBJECT
public:
explicit CommitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters,
QWidget *parent);
void setFields(const QFileInfo &repositoryRoot, const QString &branch,
const QString &userName, const QString &email,
const QList<QPair<QString, QString> > &repoStatus);
QString committerInfo();
QString repoRoot();
private:
inline MercurialCommitWidget *commitWidget();
VCSBase::SubmitFileModel *fileModel;
};
}
}
#endif // COMMITEDITOR_H

View File

@@ -0,0 +1,103 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace Mercurial {
namespace Constants {
enum { debug = 1 };
const char * const MERCURIAL = "mercurial";
const char * const MECURIALREPO = ".hg";
const char * const MERCURIALDEFAULT = "hg";
//options page items
const char * const MERCURIALPATH = "Mercurial_Path";
const char * const MERCURIALUSERNAME = "Mercurial_Username";
const char * const MERCURIALEMAIL = "Mercurial_Email";
const char * const MERCURIALLOGCOUNT = "Mercurial_LogCount";
const char * const MERCURIALTIMEOUT = "Mercurial_Timeout";
const char * const MERCURIALPROMPTSUBMIT = "Mercurial_PromptOnSubmit";
//changeset identifiers
const char * const CHANGESETID12 = " ([a-f0-9]{12,12}) "; //match 12 hex chars and capture
const char * const CHANGESETID40 = " ([a-f0-9]{40,40}) ";
const char * const CHANGEIDEXACT12 = "[a-f0-9]{12,12}"; //match 12 hex chars a
const char * const CHANGEIDEXACT40 = "[a-f0-9]{40,40}";
const char * const DIFFIDENTIFIER = "^[-+]{3,3} [ab]{1,1}.*"; // match e.g. +++ b/filename
//Errors
const char * const ERRORSTARTING = "Unable to start Mercurial Process";
const char * const TIMEDOUT = "Timed out waiting for Mercurail Process to Finish";
//BaseEditorParameters
const char * const COMMANDLOG = "Mercurial Command Log Editor";
const char * const COMMANDAPP = "application/vnd.nokia.text.scs_mercurial_commandlog";
const char * const COMMANDEXT = "vcsMercurialCommand";
const char * const FILELOG = "Mercurial File Log Editor";
const char * const LOGAPP = "application/vnd.nokia.text.scs_mercurial_log";
const char * const LOGEXT = "vcsMercurialLog";
const char * const ANNOTATELOG = "Mercurial Annotation Editor";
const char * const ANNOTATEAPP = "application/vnd.nokia.text.scs_mercurial_annotatelog";
const char * const ANNOTATEEXT = "vcsMercurialAnnotate";
const char * const DIFFLOG = "Mercurial Diff Editor";
const char * const DIFFAPP = "text/x-patch";
const char * const DIFFEXT = "diff";
//SubmitEditorParameters
const char * const COMMITKIND = "Mercurial Commit Log Editor";
const char * const COMMITMIMETYPE = "application/vnd.nokia.text.scs_mercurial_commitlog";
#ifndef Q_WS_MAC
const char * const MODIFIER = "Alt+";
const char * const MENUKEY = "Alt+H, ";
#else
const char * const MODIFIER = "Meta+";
const char * const MENUKEY = "Meta+H, ";
#endif
//menu items
//File menu actions
const char * const ANNOTATE = "Mercurial.Annotate";
const char * const DIFF = "Mercurial.DiffSingleFile";
const char * const LOG = "Mercurial.LogSingleFile";
const char * const REVERT = "Mercurial.RevertSingleFile";
const char * const STATUS = "Mercurial.Status";
//directory menu Actions
const char * const DIFFMULTI = "Mercurial.Action.DiffMulti";
const char * const REVERTMULTI = "Mercurial.Action.RevertMulti";
const char * const STATUSMULTI = "Mercurial.Action.StatusMulti";
const char * const LOGMULTI = "Mercurial.Action.Logmulti";
//repository menu actions
const char * const PULL = "Mercurial.Action.Pull";
const char * const PUSH = "Mercurial.Action.Push";
const char * const UPDATE = "Mercurial.Action.Update";
const char * const IMPORT = "Mercurial.Action.Import";
const char * const INCOMING = "Mercurial.Action.Incoming";
const char * const OUTGOING = "Mercurial.Action.Outgoing";
const char * const COMMIT = "Mercurial.Action.Commit";
//Repository Management
const char * const MERGE = "Mercurial.Action.Merge";
const char * const BRANCH = "Mercurial.Action.Branch";
const char * const HEADS = "Mercurial.Action.Heads";
const char * const PARENTS = "Mercurial.Action.Parents";
const char * const TAGS = "Mercurial.Action.Tags";
const char * const TIP = "Mercurial.Action.TIP";
const char * const PATHS = "Mercurial.Action.Paths";
//Less commonly used menu actions
const char * const CLONE = "Mercurial.Action.Clone";
const char * const INIT = "Mercurial.Action.Init";
const char * const SERVE = "Mercurial.Action.Serve";
//submit editor actions
const char * const COMMITEDITOR = "Mercurial.Action.Editor.Commit";
const char * const DIFFEDITOR = "Mercurial.Action.Editor.Diff";
} // namespace Constants
} // namespace mercurial
#endif // CONSTANTS_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,41 @@
TARGET = Mercurial
TEMPLATE = lib
include(../../qtcreatorplugin.pri)
include(mercurial_dependencies.pri)
SOURCES += mercurialplugin.cpp \
optionspage.cpp \
mercurialoutputwindow.cpp \
mercurialcontrol.cpp \
mercurialclient.cpp \
mercurialjobrunner.cpp \
annotationhighlighter.cpp \
mercurialeditor.cpp \
revertdialog.cpp \
srcdestdialog.cpp \
mercurialcommitwidget.cpp \
commiteditor.cpp \
clonewizardpage.cpp \
clonewizard.cpp \
mercurialsettings.cpp
HEADERS += mercurialplugin.h \
constants.h \
optionspage.h \
mercurialoutputwindow.h \
mercurialcontrol.h \
mercurialclient.h \
mercurialjobrunner.h \
annotationhighlighter.h \
mercurialeditor.h \
revertdialog.h \
srcdestdialog.h \
mercurialcommitwidget.h \
commiteditor.h \
clonewizardpage.h \
clonewizard.h \
mercurialsettings.h
OTHER_FILES += Mercurial.pluginspec
FORMS += optionspage.ui \
revertdialog.ui \
srcdestdialog.ui \
mercurialcommitpanel.ui
RESOURCES += mercurial.qrc

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/mercurial" >
<file>images/hg.png</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,5 @@
include(../../plugins/projectexplorer/projectexplorer.pri)
include(../../plugins/texteditor/texteditor.pri)
include(../../plugins/coreplugin/coreplugin.pri)
include(../../plugins/vcsbase/vcsbase.pri)
include(../../libs/utils/utils.pri)

View File

@@ -0,0 +1,414 @@
#include "mercurialclient.h"
#include "mercurialjobrunner.h"
#include "constants.h"
#include "mercurialsettings.h"
#include "mercurialplugin.h"
#include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h>
#include <utils/qtcassert.h>
#include <vcsbase/vcsbaseeditor.h>
#include <QtCore/QStringList>
#include <QtCore/QSharedPointer>
#include <QtCore/QDir>
#include <QtCore/QProcess>
#include <QtCore/QTextCodec>
#include <QtCore/QtDebug>
using namespace Mercurial::Internal;
using namespace Mercurial;
inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property, const QString &entry)
{
foreach (Core::IEditor *ed, core->editorManager()->openedEditors())
if (ed->file()->property(property).toString() == entry)
return ed;
return 0;
}
MercurialClient::MercurialClient()
: core(Core::ICore::instance())
{
jobManager = new MercurialJobRunner();
jobManager->start();
}
MercurialClient::~MercurialClient()
{
if (jobManager) {
delete jobManager;
jobManager = 0;
}
}
bool MercurialClient::add(const QString &filename)
{
QFileInfo file(filename);
QStringList args;
args << "add" << file.absoluteFilePath();
return hgProcessSync(file, args);
}
bool MercurialClient::remove(const QString &filename)
{
QFileInfo file(filename);
QStringList args;
args << "remove" << file.absoluteFilePath();
return hgProcessSync(file, args);
}
bool MercurialClient::manifestSync(const QString &filename)
{
QFileInfo file(filename);
QStringList args("manifest");
QByteArray output;
hgProcessSync(file, args, &output);
QStringList files = QString::fromLocal8Bit(output).split('\n');
foreach (QString fileName, files) {
QFileInfo managedFile(filename);
if (file == managedFile)
return true;
}
return false;
}
bool MercurialClient::hgProcessSync(const QFileInfo &file, const QStringList &args,
QByteArray *output) const
{
QProcess hgProcess;
hgProcess.setWorkingDirectory(file.isDir() ? file.absoluteFilePath() : file.absolutePath());
MercurialSettings *settings = MercurialPlugin::instance()->settings();
QStringList arguments = settings->standardArguments();
arguments << args;
hgProcess.start(settings->binary(), arguments);
if (!hgProcess.waitForStarted())
return false;
hgProcess.closeWriteChannel();
if (!hgProcess.waitForFinished(settings->timeout())) {
hgProcess.terminate();
return false;
}
if ((hgProcess.exitStatus() == QProcess::NormalExit) && (hgProcess.exitCode() == 0)) {
if (output)
*output = hgProcess.readAllStandardOutput();
return true;
}
return false;
}
QString MercurialClient::branchQuerySync(const QFileInfo &repositoryRoot)
{
QByteArray output;
if (hgProcessSync(repositoryRoot, QStringList("branch"), &output))
return QTextCodec::codecForLocale()->toUnicode(output).trimmed();
return QString("Unknown Branch");
}
void MercurialClient::annotate(const QFileInfo &file)
{
QStringList args;
args << "annotate" << "-u" << "-c" << "-d" << file.absoluteFilePath();
const QString kind = Constants::ANNOTATELOG;
const QString title = tr("Hg Annotate %1").arg(file.fileName());
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, file.absolutePath(), true,
"annotate", file.absoluteFilePath());
QSharedPointer<HgTask> job(new HgTask(file.absolutePath(), args, editor));
jobManager->enqueueJob(job);
}
void MercurialClient::diff(const QFileInfo &fileOrDir)
{
QStringList args;
QString id;
QString workingPath;
args << "diff" << "-g" << "-p" << "-U 8";
if (!fileOrDir.isDir()) {
args.append(fileOrDir.absoluteFilePath());
id = fileOrDir.absoluteFilePath();
workingPath = fileOrDir.absolutePath();
} else {
id = MercurialPlugin::instance()->currentProjectName();
workingPath = fileOrDir.absoluteFilePath();
}
const QString kind = Constants::DIFFLOG;
const QString title = tr("Hg diff %1").arg(fileOrDir.isDir() ? id : fileOrDir.fileName());
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingPath, true,
"diff", id);
QSharedPointer<HgTask> job(new HgTask(workingPath, args, editor));
jobManager->enqueueJob(job);
}
void MercurialClient::log(const QFileInfo &fileOrDir)
{
QStringList args;
QString id;
QString workingDir;
args << "log";
if (!fileOrDir.isDir()) {
args.append(fileOrDir.absoluteFilePath());
id = fileOrDir.absoluteFilePath();
workingDir = fileOrDir.absolutePath();
} else {
id = MercurialPlugin::instance()->currentProjectName();
workingDir = fileOrDir.absoluteFilePath();
}
const QString kind = Constants::FILELOG;
const QString title = tr("Hg log %1").arg(fileOrDir.isDir() ? id : fileOrDir.fileName());
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingDir, true,
"log", id);
QSharedPointer<HgTask> job(new HgTask(workingDir, args, editor));
jobManager->enqueueJob(job);
}
void MercurialClient::revert(const QFileInfo &fileOrDir, const QString &revision)
{
QStringList args;
args << "revert";
if (!revision.isEmpty())
args << "-r" << revision;
if (!fileOrDir.isDir())
args.append(fileOrDir.absoluteFilePath());
else
args.append("--all");
QSharedPointer<HgTask> job(new HgTask(fileOrDir.isDir() ? fileOrDir.absoluteFilePath() :
fileOrDir.absolutePath(), args, false));
jobManager->enqueueJob(job);
}
void MercurialClient::status(const QFileInfo &fileOrDir)
{
QStringList args;
args << "status";
if (!fileOrDir.isDir())
args.append(fileOrDir.absoluteFilePath());
QSharedPointer<HgTask> job(new HgTask(fileOrDir.isDir() ? fileOrDir.absoluteFilePath() :
fileOrDir.absolutePath(), args, false));
jobManager->enqueueJob(job);
}
void MercurialClient::statusWithSignal(const QFileInfo &repositoryRoot)
{
QStringList args;
args << "status";
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, true));
connect(job.data(), SIGNAL(rawData(const QByteArray &)),
this, SLOT(statusParser(const QByteArray &)));
jobManager->enqueueJob(job);
}
void MercurialClient::statusParser(const QByteArray &data)
{
QList<QPair<QString, QString> > statusList;
QStringList rawStatusList = QTextCodec::codecForLocale()->toUnicode(data).split(QLatin1Char('\n'));
foreach (QString string, rawStatusList) {
QPair<QString, QString> status;
if (string.startsWith('M'))
status.first = "Modified";
else if (string.startsWith('A'))
status.first = "Added";
else if (string.startsWith('R'))
status.first = "Removed";
else if (string.startsWith('!'))
status.first = "Deleted";
else if (string.startsWith('?'))
status.first = "Untracked";
else
continue;
//the status string should be similar to "M file_with_Changes"
//so just should take the file name part and store it
status.second = string.mid(2);
statusList.append(status);
}
emit parsedStatus(statusList);
}
void MercurialClient::import(const QFileInfo &repositoryRoot, const QStringList &files)
{
QStringList args;
args << "import" << "--no-commit";
foreach (QString file, files)
args.append(file);
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
jobManager->enqueueJob(job);
}
void MercurialClient::pull(const QFileInfo &repositoryRoot, const QString &repository)
{
QStringList args;
args << "pull";
if (!repository.isEmpty())
args.append(repository);
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
jobManager->enqueueJob(job);
}
void MercurialClient::push(const QFileInfo &repositoryRoot, const QString &repository)
{
QStringList args;
args << "push";
if (!repository.isEmpty())
args.append(repository);
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
jobManager->enqueueJob(job);
}
void MercurialClient::incoming(const QFileInfo &repositoryRoot, const QString &repository)
{
QStringList args;
args << "incoming" << "-g" << "-p";
if (!repository.isEmpty())
args.append(repository);
QString id = MercurialPlugin::instance()->currentProjectName();
const QString kind = Constants::DIFFLOG;
const QString title = tr("Hg incoming %1").arg(id);
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, repositoryRoot.absoluteFilePath(),
true, "incoming", id);
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, editor));
jobManager->enqueueJob(job);
}
void MercurialClient::outgoing(const QFileInfo &repositoryRoot)
{
QStringList args;
args << "outgoing" << "-g" << "-p";
QString id = MercurialPlugin::instance()->currentProjectName();
const QString kind = Constants::DIFFLOG;
const QString title = tr("Hg outgoing %1").arg(id);
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, repositoryRoot.absoluteFilePath(), true,
"outgoing", id);
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, editor));
jobManager->enqueueJob(job);
}
void MercurialClient::view(const QString &source, const QString &id)
{
QStringList args;
args << "log" << "-p" << "-g" << "-r" << id;
const QString kind = Constants::DIFFLOG;
const QString title = tr("Hg log %1").arg(id);
VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source,
true, "view", id);
QSharedPointer<HgTask> job(new HgTask(source, args, editor));
jobManager->enqueueJob(job);
}
void MercurialClient::update(const QFileInfo &repositoryRoot, const QString &revision)
{
QStringList args;
args << "update";
if (!revision.isEmpty())
args << revision;
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
jobManager->enqueueJob(job);
}
void MercurialClient::commit(const QFileInfo &repositoryRoot, const QStringList &files,
const QString &commiterInfo, const QString &commitMessageFile)
{
QStringList args;
args << "commit" << "-u" << commiterInfo << "-l" << commitMessageFile << files;
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
jobManager->enqueueJob(job);
}
QString MercurialClient::findTopLevelForFile(const QFileInfo &file)
{
const QString repositoryTopDir = QLatin1String(Constants::MECURIALREPO);
QDir dir = file.isDir() ? QDir(file.absoluteFilePath()) : QDir(file.absolutePath());
do {
if (QFileInfo(dir, repositoryTopDir).exists())
return dir.absolutePath();
} while (dir.cdUp());
return QString();
}
void MercurialClient::settingsChanged()
{
if (jobManager)
jobManager->restart();
}
VCSBase::VCSBaseEditor *MercurialClient::createVCSEditor(const QString &kind, QString title,
const QString &source, bool setSourceCodec,
const char *registerDynamicProperty,
const QString &dynamicPropertyValue) const
{
VCSBase::VCSBaseEditor *baseEditor = 0;
Core::IEditor* outputEditor = locateEditor(core, registerDynamicProperty, dynamicPropertyValue);
if (outputEditor) {
// Exists already
outputEditor->createNew(tr("Working..."));
baseEditor = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
QTC_ASSERT(baseEditor, return 0);
} else {
outputEditor = core->editorManager()->openEditorWithContents(kind, &title, tr("Working..."));
outputEditor->file()->setProperty(registerDynamicProperty, dynamicPropertyValue);
baseEditor = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
QTC_ASSERT(baseEditor, return 0);
baseEditor->setSource(source);
if (setSourceCodec)
baseEditor->setCodec(VCSBase::VCSBaseEditor::getCodec(source));
}
core->editorManager()->activateEditor(outputEditor);
return baseEditor;
}

View File

@@ -0,0 +1,75 @@
#ifndef MERCURIALCLIENT_H
#define MERCURIALCLIENT_H
#include <QtCore/QObject>
#include <QtCore/QFileInfo>
#include <QtCore/QByteArray>
#include <QtCore/QPair>
namespace Core {
class ICore;
}
namespace VCSBase{
class VCSBaseEditor;
}
namespace Mercurial {
namespace Internal {
class MercurialJobRunner;
class MercurialClient : public QObject
{
Q_OBJECT
public:
MercurialClient();
~MercurialClient();
bool add(const QString &fileName);
bool remove(const QString &fileName);
bool manifestSync(const QString &filename);
QString branchQuerySync(const QFileInfo &repositoryRoot);
void annotate(const QFileInfo &file);
void diff(const QFileInfo &fileOrDir);
void log(const QFileInfo &fileOrDir);
void import(const QFileInfo &repositoryRoot, const QStringList &files);
void pull(const QFileInfo &repositoryRoot, const QString &repository);
void push(const QFileInfo &repositoryRoot, const QString &repository);
void incoming(const QFileInfo &repositoryRoot, const QString &repository);
void outgoing(const QFileInfo &repositoryRoot);
void status(const QFileInfo &fileOrDir);
void statusWithSignal(const QFileInfo &fileOrDir);
void revert(const QFileInfo &fileOrDir, const QString &revision);
void update(const QFileInfo &repositoryRoot, const QString &revision);
void commit(const QFileInfo &repositoryRoot, const QStringList &files,
const QString &commiterInfo, const QString &commitMessageFile);
static QString findTopLevelForFile(const QFileInfo &file);
signals:
void parsedStatus(const QList<QPair<QString, QString> > &statusList);
public slots:
void view(const QString &source, const QString &id);
void settingsChanged();
private slots:
void statusParser(const QByteArray &data);
private:
bool hgProcessSync(const QFileInfo &file, const QStringList &args,
QByteArray *output=0) const;
MercurialJobRunner *jobManager;
Core::ICore *core;
VCSBase::VCSBaseEditor *createVCSEditor(const QString &kind, QString title,
const QString &source, bool setSourceCodec,
const char *registerDynamicProperty,
const QString &dynamicPropertyValue) const;
};
} //namespace Internal
} //namespace Mercurial
#endif // MERCURIALCLIENT_H

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mercurial::Internal::MercurialCommitPanel</class>
<widget class="QWidget" name="Mercurial::Internal::MercurialCommitPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>374</width>
<height>229</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="infoGroup">
<property name="title">
<string>General Information</string>
</property>
<layout class="QFormLayout" name="infoFormLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="repositoryLabelLabel">
<property name="text">
<string>Repository:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="repositoryLabel">
<property name="text">
<string>repository</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="branchLabelLabel">
<property name="text">
<string>Branch:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="branchLabel">
<property name="text">
<string>branch</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="editGroup">
<property name="title">
<string>Commit Information</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="authorLabel">
<property name="text">
<string>Author:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="authorLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="emailLabel">
<property name="text">
<string>Email:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="emailLineEdit"/>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>161</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,117 @@
#include "mercurialcommitwidget.h"
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorconstants.h>
#include <QtGui/QSyntaxHighlighter>
#include <QtGui/QTextEdit>
#include <QtCore/QDebug>
#include <QtCore/QRegExp>
//see the git submit widget for details of the syntax Highlighter
//TODO Check to see when the Highlighter has been moved to a base class and use that instead
namespace Mercurial {
namespace Internal {
// Retrieve the comment char format from the text editor.
static QTextCharFormat commentFormat()
{
const TextEditor::FontSettings settings = TextEditor::TextEditorSettings::instance()->fontSettings();
return settings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_COMMENT));
}
// Highlighter for Mercurial submit messages. Make the first line bold, indicates
// comments as such (retrieving the format from the text editor) and marks up
// keywords (words in front of a colon as in 'Task: <bla>').
class MercurialSubmitHighlighter : QSyntaxHighlighter
{
public:
explicit MercurialSubmitHighlighter(QTextEdit *parent);
virtual void highlightBlock(const QString &text);
private:
enum State { Header, Comment, Other };
const QTextCharFormat m_commentFormat;
const QRegExp m_keywordPattern;
const QChar m_hashChar;
};
MercurialSubmitHighlighter::MercurialSubmitHighlighter(QTextEdit * parent) :
QSyntaxHighlighter(parent),
m_commentFormat(commentFormat()),
m_keywordPattern(QLatin1String("^\\w+:")),
m_hashChar(QLatin1Char('#'))
{
Q_ASSERT(m_keywordPattern.isValid());
}
void MercurialSubmitHighlighter::highlightBlock(const QString &text)
{
// figure out current state
State state = Other;
const QTextBlock block = currentBlock();
if (block.position() == 0) {
state = Header;
} else {
if (text.startsWith(m_hashChar))
state = Comment;
}
// Apply format.
switch (state) {
case Header: {
QTextCharFormat charFormat = format(0);
charFormat.setFontWeight(QFont::Bold);
setFormat(0, text.size(), charFormat);
}
break;
case Comment:
setFormat(0, text.size(), m_commentFormat);
break;
case Other:
// Format key words ("Task:") italic
if (m_keywordPattern.indexIn(text, 0, QRegExp::CaretAtZero) == 0) {
QTextCharFormat charFormat = format(0);
charFormat.setFontItalic(true);
setFormat(0, m_keywordPattern.matchedLength(), charFormat);
}
break;
}
}
MercurialCommitWidget::MercurialCommitWidget(QWidget *parent) :
Core::Utils::SubmitEditorWidget(parent),
mercurialCommitPanel(new QWidget)
{
mercurialCommitPanelUi.setupUi(mercurialCommitPanel);
insertTopWidget(mercurialCommitPanel);
new MercurialSubmitHighlighter(descriptionEdit());
}
void MercurialCommitWidget::setFields(const QString &repositoryRoot, const QString &branch,
const QString &userName, const QString &email)
{
mercurialCommitPanelUi.repositoryLabel->setText(repositoryRoot);
mercurialCommitPanelUi.branchLabel->setText(branch);
mercurialCommitPanelUi.authorLineEdit->setText(userName);
mercurialCommitPanelUi.emailLineEdit->setText(email);
}
QString MercurialCommitWidget::committer()
{
QString user = mercurialCommitPanelUi.authorLineEdit->text() + QLatin1String(" <") +
mercurialCommitPanelUi.emailLineEdit->text() + QLatin1String(">");
return user;
}
QString MercurialCommitWidget::repoRoot()
{
return mercurialCommitPanelUi.repositoryLabel->text();
}
} // namespace Internal
} // namespace Mercurial

View File

@@ -0,0 +1,35 @@
#ifndef MERCURIALCOMMITWIDGET_H
#define MERCURIALCOMMITWIDGET_H
#include "ui_mercurialcommitpanel.h"
#include <utils/submiteditorwidget.h>
namespace Mercurial {
namespace Internal {
/*submit editor widget based on git SubmitEditor
Some extra fields have been added to the standard SubmitEditorWidget,
to help to conform to the commit style that is used by both git and Mercurial*/
class MercurialCommitWidget : public Core::Utils::SubmitEditorWidget
{
public:
explicit MercurialCommitWidget(QWidget *parent = 0);
void setFields(const QString &repositoryRoot, const QString &branch,
const QString &userName, const QString &email);
QString committer();
QString repoRoot();
private:
QWidget *mercurialCommitPanel;
Ui::MercurialCommitPanel mercurialCommitPanelUi;
};
} // namespace Internal
} // namespace Mercurial
#endif // MERCURIALCOMMITWIDGET_H

View File

@@ -0,0 +1,80 @@
#include "mercurialcontrol.h"
#include "mercurialclient.h"
#include <QtCore/QFileInfo>
using namespace Mercurial::Internal;
MercurialControl::MercurialControl(MercurialClient *client)
: mercurialClient(client),
mercurialEnabled(true)
{
}
QString MercurialControl::name() const
{
return tr("Mercurial");
}
bool MercurialControl::isEnabled() const
{
return mercurialEnabled;
}
void MercurialControl::setEnabled(bool enabled)
{
if (mercurialEnabled != enabled) {
mercurialEnabled = enabled;
emit enabledChanged(mercurialEnabled);
}
}
bool MercurialControl::managesDirectory(const QString &directory) const
{
QFileInfo dir(directory);
return !mercurialClient->findTopLevelForFile(dir).isEmpty();
}
QString MercurialControl::findTopLevelForDirectory(const QString &directory) const
{
QFileInfo dir(directory);
return mercurialClient->findTopLevelForFile(dir);
}
bool MercurialControl::supportsOperation(Operation operation) const
{
bool supported = true;
switch (operation) {
case Core::IVersionControl::AddOperation:
case Core::IVersionControl::DeleteOperation:
break;
case Core::IVersionControl::OpenOperation:
default:
supported = false;
break;
}
return supported;
}
bool MercurialControl::vcsOpen(const QString &filename)
{
Q_UNUSED(filename)
return true;
}
bool MercurialControl::vcsAdd(const QString &filename)
{
return mercurialClient->add(filename);
}
bool MercurialControl::vcsDelete(const QString &filename)
{
return mercurialClient->remove(filename);
}
bool MercurialControl::sccManaged(const QString &filename)
{
return mercurialClient->manifestSync(filename);
}

View File

@@ -0,0 +1,41 @@
#ifndef MERCURIALCONTROL_H
#define MERCURIALCONTROL_H
#include <coreplugin/iversioncontrol.h>
namespace Mercurial {
namespace Internal {
class MercurialClient;
//Implements just the basics of the Version Control Interface
//MercurialClient handles all the work
class MercurialControl: public Core::IVersionControl
{
Q_OBJECT
public:
explicit MercurialControl(MercurialClient *mercurialClient);
QString name() const;
bool isEnabled() const;
void setEnabled(bool enabled);
bool managesDirectory(const QString &filename) const;
QString findTopLevelForDirectory(const QString &directory) const;
bool supportsOperation(Operation operation) const;
bool vcsOpen(const QString &fileName);
bool vcsAdd(const QString &filename);
bool vcsDelete(const QString &filename);
bool sccManaged(const QString &filename);
signals:
void enabledChanged(bool);
private:
MercurialClient *mercurialClient;
bool mercurialEnabled;
};
} //namespace Internal
} //namespace Mercurial
#endif // MERCURIALCONTROL_H

View File

@@ -0,0 +1,85 @@
#include "mercurialeditor.h"
#include "annotationhighlighter.h"
#include "constants.h"
#include "mercurialclient.h"
#include <coreplugin/editormanager/editormanager.h>
#include <vcsbase/diffhighlighter.h>
#include <QtCore/QSet>
#include <QtCore/QString>
#include <QtGui/QTextCursor>
#include <QtGui/QTextBlock>
#include <QtCore/QDir>
#include <QtCore/QDebug>
using namespace Mercurial::Internal;
using namespace Mercurial;
MercurialEditor::MercurialEditor(const VCSBase::VCSBaseEditorParameters *type, QWidget *parent)
: VCSBase::VCSBaseEditor(type, parent),
exactIdentifier12(Constants::CHANGEIDEXACT12),
exactIdentifier40(Constants::CHANGEIDEXACT40),
changesetIdentifier12(Constants::CHANGESETID12),
changesetIdentifier40(Constants::CHANGESETID40),
diffIdentifier(Constants::DIFFIDENTIFIER)
{
}
QSet<QString> MercurialEditor::annotationChanges() const
{
QSet<QString> changes;
const QString data = toPlainText();
if (data.isEmpty())
return changes;
int position = 0;
while ((position = changesetIdentifier12.indexIn(data, position)) != -1) {
changes.insert(changesetIdentifier12.cap(1));
position += changesetIdentifier12.matchedLength();
}
return changes;
}
QString MercurialEditor::changeUnderCursor(const QTextCursor &cursorIn) const
{
QTextCursor cursor = cursorIn;
cursor.select(QTextCursor::WordUnderCursor);
if (cursor.hasSelection()) {
const QString change = cursor.selectedText();
if (exactIdentifier12.exactMatch(change))
return change;
if (exactIdentifier40.exactMatch(change))
return change;
}
return QString();
}
VCSBase::DiffHighlighter *MercurialEditor::createDiffHighlighter() const
{
return new VCSBase::DiffHighlighter(diffIdentifier);
}
VCSBase::BaseAnnotationHighlighter *MercurialEditor::createAnnotationHighlighter(const QSet<QString> &changes) const
{
return new MercurialAnnotationHighlighter(changes);
}
QString MercurialEditor::fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const
{
QString filechangeId("+++ b/");
QTextBlock::iterator iterator;
for (iterator = diffFileSpec.begin(); !(iterator.atEnd()); iterator++) {
QTextFragment fragment = iterator.fragment();
if(fragment.isValid()) {
if (fragment.text().startsWith(filechangeId)) {
QFileInfo sourceFile(source());
QDir repository(MercurialClient::findTopLevelForFile(sourceFile));
QString filename = fragment.text().remove(0, filechangeId.size());
return repository.absoluteFilePath(filename);
}
}
}
return QString();
}

View File

@@ -0,0 +1,32 @@
#ifndef MERCURIALEDITOR_H
#define MERCURIALEDITOR_H
#include <vcsbase/vcsbaseeditor.h>
#include <QtCore/QRegExp>
namespace Mercurial {
namespace Internal {
class MercurialEditor : public VCSBase::VCSBaseEditor
{
public:
explicit MercurialEditor(const VCSBase::VCSBaseEditorParameters *type, QWidget *parent);
private:
virtual QSet<QString> annotationChanges() const;
virtual QString changeUnderCursor(const QTextCursor &cursor) const;
virtual VCSBase::DiffHighlighter *createDiffHighlighter() const;
virtual VCSBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const;
virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const;
const QRegExp exactIdentifier12;
const QRegExp exactIdentifier40;
const QRegExp changesetIdentifier12;
const QRegExp changesetIdentifier40;
const QRegExp diffIdentifier;
};
} // namespace Internal
} // namespace Mercurial
#endif // MERCURIALEDITOR_H

View File

@@ -0,0 +1,176 @@
#include "mercurialjobrunner.h"
#include "mercurialplugin.h"
#include "mercurialoutputwindow.h"
#include "constants.h"
#include "mercurialsettings.h"
#include <vcsbase/vcsbaseeditor.h>
#include <QtCore/QProcess>
#include <QtCore/QTime>
#include <QtCore/QString>
#include <QtCore/QSettings>
using namespace Mercurial::Internal;
using namespace Mercurial;
HgTask::HgTask(const QString &repositoryRoot, QStringList &arguments, bool emitRaw)
: m_repositoryRoot(repositoryRoot),
arguments(arguments),
emitRaw(emitRaw),
editor(0)
{
}
HgTask::HgTask(const QString &repositoryRoot, QStringList &arguments, VCSBase::VCSBaseEditor *editor)
: m_repositoryRoot(repositoryRoot),
arguments(arguments),
emitRaw(false),
editor(editor)
{
}
MercurialJobRunner::MercurialJobRunner()
: keepRunning(true)
{
plugin = MercurialPlugin::instance();
connect(this, SIGNAL(error(const QByteArray &)), plugin->outputPane(), SLOT(append(const QByteArray &)));
connect(this, SIGNAL(info(const QString &)), plugin->outputPane(), SLOT(append(const QString &)));
}
MercurialJobRunner::~MercurialJobRunner()
{
stop();
}
void MercurialJobRunner::stop()
{
mutex.lock();
keepRunning = false;
//Create a dummy task to break the cycle
QSharedPointer<HgTask> job(0);
jobs.enqueue(job);
waiter.wakeAll();
mutex.unlock();
wait();
}
void MercurialJobRunner::restart()
{
stop();
mutex.lock();
keepRunning = true;
mutex.unlock();
start();
}
void MercurialJobRunner::getSettings()
{
MercurialSettings *settings = MercurialPlugin::instance()->settings();
binary = settings->binary();
timeout = settings->timeout();
standardArguments = settings->standardArguments();
}
void MercurialJobRunner::enqueueJob(QSharedPointer<HgTask> &job)
{
mutex.lock();
jobs.enqueue(job);
waiter.wakeAll();
mutex.unlock();
}
void MercurialJobRunner::run()
{
getSettings();
forever {
mutex.lock();
while (jobs.count() == 0)
waiter.wait(&mutex);
if (!keepRunning) {
jobs.clear();
mutex.unlock();
return;
}
QSharedPointer<HgTask> job = jobs.dequeue();
mutex.unlock();
task(job);
}
}
void MercurialJobRunner::task(QSharedPointer<HgTask> &job)
{
HgTask *taskData = job.data();
if (taskData->shouldEmit())
//Call the job's signal so the Initator of the job can process the data
//Because the QSharedPointer that holds the HgTask will go out of scope and hence be deleted
//we have to block and wait until the signal is delivered
connect(this, SIGNAL(output(const QByteArray&)), taskData, SIGNAL(rawData(const QByteArray&)),
Qt::BlockingQueuedConnection);
else if (taskData->displayEditor())
//An editor has been created to display the data so send it there
connect(this, SIGNAL(output(const QByteArray&)), taskData->displayEditor(), SLOT(setPlainTextData(const QByteArray&)));
else
//Just output the data to the Mercurial output window
connect(this, SIGNAL(output(const QByteArray &)), plugin->outputPane(), SLOT(append(const QByteArray &)));
QString time = QTime::currentTime().toString(QLatin1String("HH:mm"));
QString starting = tr("%1 Calling: %2 %3\n").arg(time, "hg", taskData->args().join(" "));
//infom the user of what we are going to try and perform
emit info(starting);
if (Constants::debug)
qDebug() << Q_FUNC_INFO << "Repository root is " << taskData->repositoryRoot();
QProcess hgProcess;
hgProcess.setWorkingDirectory(taskData->repositoryRoot());
QStringList args = standardArguments;
args << taskData->args();
hgProcess.start(binary, args);
if (!hgProcess.waitForStarted()) {
QByteArray errorArray(Constants::ERRORSTARTING);
emit error(errorArray);
return;
}
hgProcess.closeWriteChannel();
if (!hgProcess.waitForFinished(timeout)) {
hgProcess.terminate();
QByteArray errorArray(Constants::TIMEDOUT);
emit error(errorArray);
return;
}
if ((hgProcess.exitStatus() == QProcess::NormalExit) && (hgProcess.exitCode() == 0)) {
QByteArray stdout = hgProcess.readAllStandardOutput();
/*
* sometimes success means output is actually on error channel (stderr)
* e.g. "hg revert" outputs "no changes needed to 'file'" on stderr if file has not changed
* from revision specified
*/
if (stdout == "")
stdout = hgProcess.readAllStandardError();
emit output(stdout);
} else {
QByteArray stderr = hgProcess.readAllStandardError();
emit error(stderr);
}
hgProcess.close();
//the signal connection is to last only for the duration of a job/task. next time a new
//output signal connection must be made
disconnect(this, SIGNAL(output(const QByteArray &)), 0, 0);
}

View File

@@ -0,0 +1,79 @@
#ifndef MERCURIALJOBRUNNER_H
#define MERCURIALJOBRUNNER_H
#include <QtCore/QThread>
#include <QtCore/QQueue>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QStringList>
#include <QtCore/QSharedPointer>
#include <QtCore/QString>
namespace VCSBase {
class VCSBaseEditor;
}
namespace Mercurial {
namespace Internal {
class MercurialPlugin;
class HgTask : public QObject
{
Q_OBJECT
public:
HgTask(const QString &workingDir, QStringList &arguments, bool emitRaw=false);
HgTask(const QString &workingDir, QStringList &arguments,
VCSBase::VCSBaseEditor *editor);
bool shouldEmit() { return emitRaw; }
VCSBase::VCSBaseEditor* displayEditor() { return editor; }
QStringList args() { return arguments; }
QString repositoryRoot() { return m_repositoryRoot; }
signals:
void rawData(const QByteArray &data);
private:
QString m_repositoryRoot;
QStringList arguments;
bool emitRaw;
VCSBase::VCSBaseEditor *editor;
};
class MercurialJobRunner : public QThread
{
Q_OBJECT
public:
MercurialJobRunner();
~MercurialJobRunner();
void enqueueJob(QSharedPointer<HgTask> &job);
void restart();
protected:
void run();
signals:
void error(const QByteArray &error);
void info(const QString &notice);
void output(const QByteArray &output);
private:
void task(QSharedPointer<HgTask> &job);
void stop();
void getSettings();
QQueue<QSharedPointer<HgTask> > jobs;
QMutex mutex;
QWaitCondition waiter;
MercurialPlugin *plugin;
bool keepRunning;
QString binary;
QStringList standardArguments;
int timeout;
};
} //namespace Internal
} //namespace Mercurial
#endif // MERCURIALJOBRUNNER_H

View File

@@ -0,0 +1,102 @@
#include "mercurialoutputwindow.h"
#include <QtGui/QListWidget>
#include <QtCore/QDebug>
#include <QtCore/QTextCodec>
using namespace Mercurial::Internal;
MercurialOutputWindow::MercurialOutputWindow()
{
outputListWidgets = new QListWidget;
outputListWidgets->setWindowTitle(tr("Mercurial Output"));
outputListWidgets->setFrameStyle(QFrame::NoFrame);
outputListWidgets->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
MercurialOutputWindow::~MercurialOutputWindow()
{
delete outputListWidgets;
outputListWidgets = 0;
}
QWidget *MercurialOutputWindow::outputWidget(QWidget *parent)
{
outputListWidgets->setParent(parent);
return outputListWidgets;
}
QList<QWidget*> MercurialOutputWindow::toolBarWidgets() const
{
return QList<QWidget *>();
}
QString MercurialOutputWindow::name() const
{
return tr("Mercurial");
}
int MercurialOutputWindow::priorityInStatusBar() const
{
return -1;
}
void MercurialOutputWindow::clearContents()
{
outputListWidgets->clear();
}
void MercurialOutputWindow::visibilityChanged(bool visible)
{
if (visible)
outputListWidgets->setFocus();
}
void MercurialOutputWindow::setFocus()
{
}
bool MercurialOutputWindow::hasFocus()
{
return outputListWidgets->hasFocus();
}
bool MercurialOutputWindow::canFocus()
{
return false;
}
bool MercurialOutputWindow::canNavigate()
{
return false;
}
bool MercurialOutputWindow::canNext()
{
return false;
}
bool MercurialOutputWindow::canPrevious()
{
return false;
}
void MercurialOutputWindow::goToNext()
{
}
void MercurialOutputWindow::goToPrev()
{
}
void MercurialOutputWindow::append(const QString &text)
{
outputListWidgets->addItems(text.split(QLatin1Char('\n')));
outputListWidgets->scrollToBottom();
popup(true);
}
void MercurialOutputWindow::append(const QByteArray &array)
{
append(QTextCodec::codecForLocale()->toUnicode(array));
}

View File

@@ -0,0 +1,49 @@
#ifndef MERCURIALOUTPUTWINDOW_H
#define MERCURIALOUTPUTWINDOW_H
#include <coreplugin/ioutputpane.h>
QT_BEGIN_NAMESPACE
class QListWidget;
QT_END_NAMESPACE
#include <QtCore/QByteArray>
namespace Mercurial {
namespace Internal {
class MercurialOutputWindow: public Core::IOutputPane
{
Q_OBJECT
public:
MercurialOutputWindow();
~MercurialOutputWindow();
QWidget *outputWidget(QWidget *parent);
QList<QWidget*> toolBarWidgets() const;
QString name() const;
int priorityInStatusBar() const;
void clearContents();
void visibilityChanged(bool visible);
void setFocus();
bool hasFocus();
bool canFocus();
bool canNavigate();
bool canNext();
bool canPrevious();
void goToNext();
void goToPrev();
public slots:
void append(const QString &text);
void append(const QByteArray &array);
private:
QListWidget *outputListWidgets;
};
} //namespace Internal
} //namespace Mercurial
#endif // MERCURIALOUTPUTWINDOW_H

View File

@@ -0,0 +1,669 @@
#include "mercurialplugin.h"
#include "optionspage.h"
#include "mercurialoutputwindow.h"
#include "constants.h"
#include "mercurialclient.h"
#include "mercurialcontrol.h"
#include "mercurialeditor.h"
#include "revertdialog.h"
#include "srcdestdialog.h"
#include "commiteditor.h"
#include "clonewizard.h"
#include "mercurialsettings.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/basemode.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/filemanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <projectexplorer/projectexplorer.h>
#include <utils/parameteraction.h>
#include <vcsbase/basevcseditorfactory.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseeditor.h>
#include <QtCore/QtPlugin>
#include <QtGui/QAction>
#include <QtGui/QMenu>
#include <QtGui/QMainWindow>
#include <QtCore/QtDebug>
#include <QtCore/QtGlobal>
#include <QtCore/QDir>
#include <QtGui/QDialog>
#include <QtGui/QFileDialog>
#include <QtCore/QTemporaryFile>
using namespace Mercurial::Internal;
using namespace Mercurial;
bool ListenForClose::editorAboutToClose(Core::IEditor *editor)
{
return MercurialPlugin::instance()->closeEditor(editor);
}
static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
{
VCSBase::RegularCommandOutput, //type
Constants::COMMANDLOG, // kind
Constants::COMMANDLOG, // context
Constants::COMMANDAPP, // mime type
Constants::COMMANDEXT}, //extension
{ VCSBase::LogOutput,
Constants::FILELOG,
Constants::FILELOG,
Constants::LOGAPP,
Constants::LOGEXT},
{ VCSBase::AnnotateOutput,
Constants::ANNOTATELOG,
Constants::ANNOTATELOG,
Constants::ANNOTATEAPP,
Constants::ANNOTATEEXT},
{ VCSBase::DiffOutput,
Constants::DIFFLOG,
Constants::DIFFLOG,
Constants::DIFFAPP,
Constants::DIFFEXT}
};
static const VCSBase::VCSBaseSubmitEditorParameters submitEditorParameters = {
Constants::COMMITMIMETYPE,
Constants::COMMITKIND,
Constants::COMMITKIND
};
// Utility to find a parameter set by type
static inline const VCSBase::VCSBaseEditorParameters *findType(int ie)
{
const VCSBase::EditorContentType et = static_cast<VCSBase::EditorContentType>(ie);
return VCSBase::VCSBaseEditor::findType(editorParameters,
sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters), et);
}
MercurialPlugin *MercurialPlugin::m_instance = 0;
MercurialPlugin::MercurialPlugin()
: mercurialSettings(new MercurialSettings),
outputWindow(0),
optionsPage(0),
client(0),
mercurialVC(0),
projectExplorer(0),
changeLog(0)
{
m_instance = this;
}
MercurialPlugin::~MercurialPlugin()
{
if (client) {
delete client;
client = 0;
}
if (mercurialSettings) {
delete mercurialSettings;
mercurialSettings = 0;
}
deleteCommitLog();
m_instance = 0;
}
bool MercurialPlugin::initialize(const QStringList &arguments, QString *error_message)
{
Q_UNUSED(arguments)
Q_UNUSED(error_message)
typedef VCSBase::VCSEditorFactory<MercurialEditor> MercurialEditorFactory;
core = Core::ICore::instance();
actionManager = core->actionManager();
optionsPage = new OptionsPage();
addAutoReleasedObject(optionsPage);
outputWindow = new MercurialOutputWindow();
addAutoReleasedObject(outputWindow);
client = new MercurialClient();
connect(optionsPage, SIGNAL(settingsChanged()), client, SLOT(settingsChanged()));
mercurialVC = new MercurialControl(client);
addAutoReleasedObject(mercurialVC);
static const char *describeSlot = SLOT(view(QString,QString));
const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
for (int i = 0; i < editorCount; i++)
addAutoReleasedObject(new MercurialEditorFactory(editorParameters + i, client, describeSlot));
addAutoReleasedObject(new VCSBase::VCSSubmitEditorFactory<CommitEditor>(&submitEditorParameters));
addAutoReleasedObject(new CloneWizard);
addAutoReleasedObject(new ListenForClose);
createMenu();
createSubmitEditorActions();
return true;
}
void MercurialPlugin::extensionsInitialized()
{
projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
if (projectExplorer)
connect(projectExplorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
this, SLOT(currentProjectChanged(ProjectExplorer::Project *)));
}
MercurialOutputWindow *MercurialPlugin::outputPane()
{
return outputWindow;
}
MercurialSettings *MercurialPlugin::settings()
{
return mercurialSettings;
}
void MercurialPlugin::createMenu()
{
QList<int> context = QList<int>()<< core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_GLOBAL);
// Create menu item for Mercurial
mercurialContainer = actionManager->createMenu("Mercurial.MercurialMenu");
QMenu *menu = mercurialContainer->menu();
menu->setTitle(tr("Mercurial"));
if (QAction *visibleAction = menu->menuAction()) {
visibleAction->setEnabled(mercurialVC->isEnabled());
connect(mercurialVC, SIGNAL(enabledChanged(bool)), visibleAction, SLOT(setVisible(bool)));
}
createFileActions(context);
createSeparator(context, "FileDirSeperator");
createDirectoryActions(context);
createSeparator(context, "DirRepoSeperator");
createRepositoryActions(context);
createSeparator(context, "Repository Management");
createRepositoryManagementActions(context);
createSeparator(context, "LessUsedfunctionality");
createLessUsedActions(context);
// Request the Tools menu and add the Mercurial menu to it
Core::ActionContainer *toolsMenu = actionManager->actionContainer(Core::Constants::M_TOOLS);
toolsMenu->addMenu(mercurialContainer);
connect(core, SIGNAL(contextChanged(Core::IContext *)), this, SLOT(updateActions()));
connect(core->fileManager(), SIGNAL(currentFileChanged(const QString &)),
this, SLOT(updateActions()));
}
void MercurialPlugin::createFileActions(QList<int> &context)
{
Core::Command *command;
annotateFile = new Core::Utils::ParameterAction(tr("Annotate Current File"), tr("Annotate \"%1\""), Core::Utils::ParameterAction::AlwaysEnabled, this);
command = actionManager->registerAction(annotateFile, Constants::ANNOTATE, context);
command->setAttribute(Core::Command::CA_UpdateText);
connect(annotateFile, SIGNAL(triggered()), this, SLOT(annotateCurrentFile()));
mercurialContainer->addAction(command);
diffFile = new Core::Utils::ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), Core::Utils::ParameterAction::AlwaysEnabled, this);
command = actionManager->registerAction(diffFile, Constants::DIFF, context);
command->setAttribute(Core::Command::CA_UpdateText);
command->setDefaultKeySequence(QKeySequence(tr(Constants::MENUKEY) + tr(Constants::MODIFIER) + "D"));
connect(diffFile, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
mercurialContainer->addAction(command);
logFile = new Core::Utils::ParameterAction(tr("Log Current File"), tr("Log \"%1\""), Core::Utils::ParameterAction::AlwaysEnabled, this);
command = actionManager->registerAction(logFile, Constants::LOG, context);
command->setAttribute(Core::Command::CA_UpdateText);
command->setDefaultKeySequence(QKeySequence(tr(Constants::MENUKEY) + tr(Constants::MODIFIER) + "L"));
connect(logFile, SIGNAL(triggered()), this, SLOT(logCurrentFile()));
mercurialContainer->addAction(command);
revertFile = new Core::Utils::ParameterAction(tr("Revert Current File"), tr("Revert \"%1\""), Core::Utils::ParameterAction::AlwaysEnabled, this);
command = actionManager->registerAction(revertFile, Constants::REVERT, context);
command->setAttribute(Core::Command::CA_UpdateText);
connect(revertFile, SIGNAL(triggered()), this, SLOT(revertCurrentFile()));
mercurialContainer->addAction(command);
statusFile = new Core::Utils::ParameterAction(tr("Status Current File"), tr("Status \"%1\""), Core::Utils::ParameterAction::AlwaysEnabled, this);
command = actionManager->registerAction(statusFile, Constants::STATUS, context);
command->setAttribute(Core::Command::CA_UpdateText);
command->setDefaultKeySequence(QKeySequence(tr(Constants::MENUKEY) + tr(Constants::MODIFIER) + "S"));
connect(statusFile, SIGNAL(triggered()), this, SLOT(statusCurrentFile()));
mercurialContainer->addAction(command);
}
void MercurialPlugin::annotateCurrentFile()
{
client->annotate(currentFile());
}
void MercurialPlugin::diffCurrentFile()
{
client->diff(currentFile());
}
void MercurialPlugin::logCurrentFile()
{
client->log(currentFile());
}
void MercurialPlugin::revertCurrentFile()
{
RevertDialog reverter;
if (reverter.exec() != QDialog::Accepted)
return;
const QString revision = reverter.m_ui->revisionLineEdit->text();
client->revert(currentFile(), revision);
}
void MercurialPlugin::statusCurrentFile()
{
client->status(currentFile());
}
void MercurialPlugin::createDirectoryActions(QList<int> &context)
{
QAction *action;
Core::Command *command;
action = new QAction(tr("Diff"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::DIFFMULTI, context);
connect(action, SIGNAL(triggered()), this, SLOT(diffRepository()));
mercurialContainer->addAction(command);
action = new QAction(tr("Log"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::LOGMULTI, context);
connect(action, SIGNAL(triggered()), this, SLOT(logRepository()));
mercurialContainer->addAction(command);
action = new QAction(tr("Revert"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::REVERTMULTI, context);
connect(action, SIGNAL(triggered()), this, SLOT(revertMulti()));
mercurialContainer->addAction(command);
action = new QAction(tr("Status"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::STATUSMULTI, context);
connect(action, SIGNAL(triggered()), this, SLOT(statusMulti()));
mercurialContainer->addAction(command);
}
void MercurialPlugin::diffRepository()
{
client->diff(currentProjectRoot());
}
void MercurialPlugin::logRepository()
{
client->log(currentProjectRoot());
}
void MercurialPlugin::revertMulti()
{
RevertDialog reverter;
if (reverter.exec() != QDialog::Accepted)
return;
const QString revision = reverter.m_ui->revisionLineEdit->text();
client->revert(currentProjectRoot(), revision);
}
void MercurialPlugin::statusMulti()
{
client->status(currentProjectRoot());
}
void MercurialPlugin::createRepositoryActions(QList<int> &context)
{
QAction *action = new QAction(tr("Pull"), this);
actionList.append(action);
Core::Command *command = actionManager->registerAction(action, Constants::PULL, context);
connect(action, SIGNAL(triggered()), this, SLOT(pull()));
mercurialContainer->addAction(command);
action = new QAction(tr("Push"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::PUSH, context);
connect(action, SIGNAL(triggered()), this, SLOT(push()));
mercurialContainer->addAction(command);
action = new QAction(tr("Update"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::UPDATE, context);
connect(action, SIGNAL(triggered()), this, SLOT(update()));
mercurialContainer->addAction(command);
action = new QAction(tr("Import"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::IMPORT, context);
connect(action, SIGNAL(triggered()), this, SLOT(import()));
mercurialContainer->addAction(command);
action = new QAction(tr("Incoming"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::INCOMING, context);
connect(action, SIGNAL(triggered()), this, SLOT(incoming()));
mercurialContainer->addAction(command);
action = new QAction(tr("Outgoing"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::OUTGOING, context);
connect(action, SIGNAL(triggered()), this, SLOT(outgoing()));
mercurialContainer->addAction(command);
action = new QAction(tr("Commit"), this);
actionList.append(action);
command = actionManager->registerAction(action, Constants::COMMIT, context);
command->setDefaultKeySequence(QKeySequence(tr(Constants::MENUKEY) + tr(Constants::MODIFIER) + "C"));
connect(action, SIGNAL(triggered()), this, SLOT(commit()));
mercurialContainer->addAction(command);
}
void MercurialPlugin::pull()
{
SrcDestDialog dialog;
dialog.setWindowTitle("Pull Source");
if (dialog.exec() != QDialog::Accepted)
return;
QString repository = dialog.getRepositoryString();
client->pull(currentProjectRoot(), repository);
}
void MercurialPlugin::push()
{
SrcDestDialog dialog;
dialog.setWindowTitle("Push Destination");
if (dialog.exec() != QDialog::Accepted)
return;
QString repository = dialog.getRepositoryString();
client->push(currentProjectRoot(), repository);
}
void MercurialPlugin::update()
{
RevertDialog updateDialog;
updateDialog.setWindowTitle("Update");
if (updateDialog.exec() != QDialog::Accepted)
return;
const QString revision = updateDialog.m_ui->revisionLineEdit->text();
client->update(currentProjectRoot(), revision);
}
void MercurialPlugin::import()
{
QFileDialog importDialog;
importDialog.setFileMode(QFileDialog::ExistingFiles);
importDialog.setViewMode(QFileDialog::Detail);
if (importDialog.exec() != QDialog::Accepted)
return;
const QStringList fileNames = importDialog.selectedFiles();
client->import(currentProjectRoot(), fileNames);
}
void MercurialPlugin::incoming()
{
SrcDestDialog dialog;
dialog.setWindowTitle("Incoming Source");
if (dialog.exec() != QDialog::Accepted)
return;
QString repository = dialog.getRepositoryString();
client->incoming(currentProjectRoot(), repository);
}
void MercurialPlugin::outgoing()
{
client->outgoing(currentProjectRoot());
}
void MercurialPlugin::createSubmitEditorActions()
{
QList<int> context = QList<int>()<< core->uniqueIDManager()->uniqueIdentifier(Constants::COMMITKIND);
Core::Command *command;
editorCommit = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this);
command = actionManager->registerAction(editorCommit, Constants::COMMIT, context);
connect(editorCommit, SIGNAL(triggered()), this, SLOT(commitFromEditor()));
editorDiff = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this);
command = actionManager->registerAction(editorDiff, Constants::DIFFEDITOR, context);
editorUndo = new QAction(tr("&Undo"), this);
command = actionManager->registerAction(editorUndo, Core::Constants::UNDO, context);
editorRedo = new QAction(tr("&Redo"), this);
command = actionManager->registerAction(editorRedo, Core::Constants::REDO, context);
}
void MercurialPlugin::commit()
{
if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
return;
connect(client, SIGNAL(parsedStatus(const QList<QPair<QString,QString> > &)),
this, SLOT(showCommitWidget(const QList<QPair<QString,QString> > &)));
client->statusWithSignal(currentProjectRoot());
}
void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &status)
{
//Once we receive our data release the connection so it can be reused elsewhere
disconnect(client, SIGNAL(parsedStatus(const QList<QPair<QString,QString> > &)),
this, SLOT(showCommitWidget(const QList<QPair<QString,QString> > &)));
if (status.isEmpty()) {
outputWindow->append(tr("There are no changes to commit"));
return;
}
deleteCommitLog();
changeLog = new QTemporaryFile(this);
if (!changeLog->open()) {
outputWindow->append(tr("Unable to generate a Tempory File for the Commit Editor"));
return;
}
Core::IEditor *editor = core->editorManager()->openEditor(changeLog->fileName(),
Constants::COMMITKIND);
if (!editor) {
outputWindow->append(tr("Unable to generate an Editor for the commit"));
return;
}
core->editorManager()->ensureEditorManagerVisible();
CommitEditor *commitEditor = qobject_cast<CommitEditor *>(editor);
if (!commitEditor) {
outputWindow->append(tr("Unable to generate a Commit Editor"));
return;
}
commitEditor->setDisplayName(tr("Commit changes for \"") + currentProjectName() + tr("\""));
QString branch = client->branchQuerySync(currentProjectRoot());
commitEditor->setFields(currentProjectRoot(), branch, mercurialSettings->userName(),
mercurialSettings->email(), status);
commitEditor->registerActions(editorUndo, editorRedo, editorCommit, editorDiff);
connect(commitEditor, SIGNAL(diffSelectedFiles(const QStringList &)),
this, SLOT(diffFromEditorSelected(const QStringList &)));
}
void MercurialPlugin::diffFromEditorSelected(const QStringList &files)
{
foreach (QString file, files) {
QFileInfo toDiff(QDir(currentProjectRoot().absoluteFilePath()).absoluteFilePath(file));
client->diff(toDiff);
}
}
void MercurialPlugin::commitFromEditor()
{
if (!changeLog)
return;
//use the same functionality than if the user closes the file without completing the commit
core->editorManager()->closeEditors(core->editorManager()->editorsForFileName(changeLog->fileName()));
}
bool MercurialPlugin::closeEditor(Core::IEditor *editor)
{
if (!changeLog || !editor || qstrcmp(editor->kind(), Constants::COMMITKIND))
return true;
Core::IFile *editorFile = editor->file();
CommitEditor *commitEditor = qobject_cast<CommitEditor *>(editor);
if (!editorFile || !commitEditor)
return true;
bool dummyPrompt = settings()->prompt();
const VCSBase::VCSBaseSubmitEditor::PromptSubmitResult response =
commitEditor->promptSubmit(tr("Close commit editor"), tr("Do you want to commit the changes?"),
tr("Message check failed. Do you want to proceed?"),
&dummyPrompt, settings()->prompt());
switch (response) {
case VCSBase::VCSBaseSubmitEditor::SubmitCanceled:
return false;
case VCSBase::VCSBaseSubmitEditor::SubmitDiscarded:
deleteCommitLog();
return true;
default:
break;
}
const QStringList files = commitEditor->checkedFiles();
if (!files.empty()) {
//save the commit message
core->fileManager()->blockFileChange(editorFile);
editorFile->save();
core->fileManager()->unblockFileChange(editorFile);
const QFileInfo repoRoot(commitEditor->repoRoot());
client->commit(repoRoot, files, commitEditor->committerInfo(),
editorFile->fileName());
}
return true;
}
void MercurialPlugin::deleteCommitLog()
{
if (changeLog) {
delete changeLog;
changeLog = 0;
}
}
void MercurialPlugin::createRepositoryManagementActions(QList<int> &context)
{
//TODO create menu for these options
Q_UNUSED(context);
return;
// QAction *action = new QAction(tr("Branch"), this);
// actionList.append(action);
// Core::Command *command = actionManager->registerAction(action, Constants::BRANCH, context);
// // connect(action, SIGNAL(triggered()), this, SLOT(branch()));
// mercurialContainer->addAction(command);
}
void MercurialPlugin::createLessUsedActions(QList<int> &context)
{
//TODO create menue for these options
Q_UNUSED(context);
return;
}
void MercurialPlugin::createSeparator(const QList<int> &context, const QString &id)
{
QAction *action = new QAction(this);
action->setSeparator(true);
mercurialContainer->addAction(actionManager->registerAction(action, id, context));
}
void MercurialPlugin::updateActions()
{
const QFileInfo file = currentFile();
const QString filename = file.fileName();
const QString repoRoot = client->findTopLevelForFile(file);
bool enable = false;
//File menu Items should only be enabled for files that are below a mercurial repository
enable = !repoRoot.isEmpty();
annotateFile->setParameter(filename);
annotateFile->setEnabled(enable);
diffFile->setParameter(filename);
diffFile->setEnabled(enable);
logFile->setParameter(filename);
logFile->setEnabled(enable);
revertFile->setParameter(filename);
revertFile->setEnabled(enable);
statusFile->setParameter(filename);
statusFile->setEnabled(enable);
//repository actions
if (projectMapper.contains(currentProjectName()))
enable = true;
else
enable = false;
foreach (QAction *action, actionList)
action->setEnabled(enable);
}
QFileInfo MercurialPlugin::currentFile()
{
QString fileName = core->fileManager()->currentFile();
QFileInfo fileInfo(fileName);
return fileInfo;
}
QString MercurialPlugin::currentProjectName()
{
if (projectExplorer)
if (projectExplorer->currentProject())
return projectExplorer->currentProject()->name();
return QString();
}
void MercurialPlugin::currentProjectChanged(ProjectExplorer::Project *project)
{
if (!project)
return;
if (projectMapper.contains(project->name()))
return;
QString repoRoot = client->findTopLevelForFile(QFileInfo(project->file()->fileName()));
if (!repoRoot.isEmpty())
projectMapper.insert(project->name(), QFileInfo(repoRoot));
}
QFileInfo MercurialPlugin::currentProjectRoot()
{
return projectMapper.value(currentProjectName());
}
Q_EXPORT_PLUGIN(MercurialPlugin)

View File

@@ -0,0 +1,165 @@
#ifndef MERCURIALPLUGIN_H
#define MERCURIALPLUGIN_H
#include <extensionsystem/iplugin.h>
#include <coreplugin/icorelistener.h>
#include <QtCore/QFileInfo>
#include <QtCore/QHash>
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
class QAction;
class QTemporaryFile;
QT_END_NAMESPACE
namespace Core {
class ActionManager;
class ActionContainer;
class ICore;
class IVersionControl;
class IEditorFactory;
class IEditor;
namespace Utils {
class ParameterAction;
} //namespace Utils
} // namespace Core
namespace ProjectExplorer {
class ProjectExplorerPlugin;
class Project;
}
namespace Mercurial {
namespace Internal {
class MercurialOutputWindow;
class OptionsPage;
class MercurialClient;
class MercurialControl;
class MercurialEditor;
class MercurialSettings;
class MercurialPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
public:
MercurialPlugin();
virtual ~MercurialPlugin();
bool initialize(const QStringList &arguments, QString *error_message);
void extensionsInitialized();
static MercurialPlugin *instance() { return m_instance; }
QFileInfo currentFile();
QString currentProjectName();
QFileInfo currentProjectRoot();
bool closeEditor(Core::IEditor *editor);
MercurialSettings *settings();
MercurialOutputWindow *outputPane();
private slots:
// File menu action Slots
void annotateCurrentFile();
void diffCurrentFile();
void logCurrentFile();
void revertCurrentFile();
void statusCurrentFile();
//Directory menu Action slots
void diffRepository();
void logRepository();
void revertMulti();
void statusMulti();
//repository menu action slots
void pull();
void push();
void update();
void import();
void incoming();
void outgoing();
void commit();
void showCommitWidget(const QList<QPair<QString, QString> > &status);
void commitFromEditor();
void diffFromEditorSelected(const QStringList &files);
//TODO implement
/* //repository management action slots
void merge();
void branch();
void heads();
void parents();
void tags();
void tip();
void paths();
//less used repository action
void init();
void serve();*/
//change the sates of the actions in the Mercurial Menu i.e. 2 be context sensitive
void updateActions();
void currentProjectChanged(ProjectExplorer::Project *project);
private:
//methods
void createMenu();
void createSubmitEditorActions();
void createSeparator(const QList<int> &context, const QString &id);
void createFileActions(QList<int> &context);
void createDirectoryActions(QList<int> &context);
void createRepositoryActions(QList<int> &context);
void createRepositoryManagementActions(QList<int> &context);
void createLessUsedActions(QList<int> &context);
void deleteCommitLog();
//QString getSettingsByKey(const char * const key);
//Variables
static MercurialPlugin *m_instance;
MercurialSettings *mercurialSettings;
MercurialOutputWindow *outputWindow;
OptionsPage *optionsPage;
MercurialClient *client;
Core::IVersionControl *mercurialVC;
Core::ICore *core;
Core::ActionManager *actionManager;
Core::ActionContainer *mercurialContainer;
ProjectExplorer::ProjectExplorerPlugin *projectExplorer;
//provide a mapping of projectName -> repositoryRoot for each project
QHash<QString, QFileInfo> projectMapper;
QList<QAction *> actionList;
QTemporaryFile *changeLog;
//Menu Items (file actions)
Core::Utils::ParameterAction *annotateFile;
Core::Utils::ParameterAction *diffFile;
Core::Utils::ParameterAction *logFile;
Core::Utils::ParameterAction *renameFile;
Core::Utils::ParameterAction *revertFile;
Core::Utils::ParameterAction *statusFile;
//submit editor actions
QAction *editorCommit;
QAction *editorDiff;
QAction *editorUndo;
QAction *editorRedo;
};
class ListenForClose : public Core::ICoreListener
{
Q_OBJECT
public:
ListenForClose(QObject *parent=0) : Core::ICoreListener(parent) {}
bool editorAboutToClose(Core::IEditor *editor);
};
} //namespace Internal
} //namespace Mercurial
#endif // MERCURIALPLUGIN_H

View File

@@ -0,0 +1,114 @@
#include "mercurialsettings.h"
#include "constants.h"
#include <coreplugin/icore.h>
#include <QtCore/QSettings>
using namespace Mercurial::Internal;
MercurialSettings::MercurialSettings()
{
readSettings();
}
QString MercurialSettings::binary()
{
return bin;
}
QString MercurialSettings::application()
{
return app;
}
QStringList MercurialSettings::standardArguments()
{
return standardArgs;
}
QString MercurialSettings::userName()
{
return user;
}
QString MercurialSettings::email()
{
return mail;
}
int MercurialSettings::logCount()
{
return m_logCount;
}
int MercurialSettings::timeout()
{
//return timeout is in Ms
return m_timeout * 1000;
}
int MercurialSettings::timeoutSeconds()
{
//return timeout in seconds (as the user specifies on the options page
return m_timeout;
}
bool MercurialSettings::prompt()
{
return m_prompt;
}
void MercurialSettings::writeSettings(const QString &application, const QString &userName,
const QString &email, int logCount, int timeout, bool prompt)
{
QSettings *settings = Core::ICore::instance()->settings();
if (settings) {
settings->beginGroup("Mercurial");
settings->setValue(Constants::MERCURIALPATH, application);
settings->setValue(Constants::MERCURIALUSERNAME, userName);
settings->setValue(Constants::MERCURIALEMAIL, email);
settings->setValue(Constants::MERCURIALLOGCOUNT, logCount);
settings->setValue(Constants::MERCURIALTIMEOUT, timeout);
settings->setValue(Constants::MERCURIALPROMPTSUBMIT, prompt);
settings->endGroup();
}
app = application;
user = userName;
mail = email;
m_logCount = logCount;
m_timeout = timeout;
m_prompt = prompt;
setBinAndArgs();
}
void MercurialSettings::readSettings()
{
QSettings *settings = Core::ICore::instance()->settings();
if (settings) {
settings->beginGroup("Mercurial");
app = settings->value(Constants::MERCURIALPATH, Constants::MERCURIALDEFAULT).toString();
user = settings->value(Constants::MERCURIALUSERNAME, "").toString();
mail = settings->value(Constants::MERCURIALEMAIL, "").toString();
m_logCount = settings->value(Constants::MERCURIALLOGCOUNT, 0).toInt();
m_timeout = settings->value(Constants::MERCURIALTIMEOUT, 30).toInt();
m_prompt = settings->value(Constants::MERCURIALPROMPTSUBMIT, true).toBool();
settings->endGroup();
}
setBinAndArgs();
}
void MercurialSettings::setBinAndArgs()
{
standardArgs.clear();
#ifdef Q_OS_WIN
bin = QLatin1String("cmd.exe");
standardArgs << "/c" << app;
#else
bin = app;
#endif
}

View File

@@ -0,0 +1,45 @@
#ifndef MERCURIALSETTINGS_H
#define MERCURIALSETTINGS_H
#include <QtCore/QString>
#include <QtCore/QStringList>
namespace Mercurial {
namespace Internal {
class MercurialSettings
{
public:
MercurialSettings();
QString binary();
QString application();
QStringList standardArguments();
QString userName();
QString email();
int logCount();
int timeout();
int timeoutSeconds();
bool prompt();
void writeSettings(const QString &application, const QString &userName,
const QString &email, int logCount, int timeout, bool prompt);
private:
void readSettings();
void setBinAndArgs();
QString bin; // used because windows requires cmd.exe to run the mercurial binary
// in this case the actual mercurial binary will be part of the standard args
QString app; // this is teh actual mercurial executable
QStringList standardArgs;
QString user;
QString mail;
int m_logCount;
int m_timeout;
bool m_prompt;
};
} //namespace Internal
} //namespace Mercurial
#endif // MERCURIALSETTINGS_H

View File

@@ -0,0 +1,79 @@
#include "optionspage.h"
#include "mercurialsettings.h"
#include "mercurialplugin.h"
#include <utils/pathchooser.h>
#include <vcsbase/vcsbaseconstants.h>
using namespace Mercurial::Internal;
using namespace Mercurial;
OptionsPageWidget::OptionsPageWidget(QWidget *parent) :
QWidget(parent)
{
m_ui.setupUi(this);
m_ui.commandChooser->setExpectedKind(Core::Utils::PathChooser::Command);
m_ui.commandChooser->setPromptDialogTitle(tr("Mercurial Command"));
}
void OptionsPageWidget::updateOptions()
{
MercurialSettings *settings = MercurialPlugin::instance()->settings();
m_ui.commandChooser->setPath(settings->application());
m_ui.defaultUsernameLineEdit->setText(settings->userName());
m_ui.defaultEmailLineEdit->setText(settings->email());
m_ui.logEntriesCount->setValue(settings->logCount());
m_ui.timeout->setValue(settings->timeoutSeconds());
m_ui.promptOnSubmitCheckBox->setChecked(settings->prompt());
}
void OptionsPageWidget::saveOptions()
{
MercurialSettings *settings = MercurialPlugin::instance()->settings();
settings->writeSettings(m_ui.commandChooser->path(), m_ui.defaultUsernameLineEdit->text(),
m_ui.defaultEmailLineEdit->text(), m_ui.logEntriesCount->value(),
m_ui.timeout->value(), m_ui.promptOnSubmitCheckBox->isChecked());
}
OptionsPage::OptionsPage()
{
}
QString OptionsPage::id() const
{
return QLatin1String("Mercurial");
}
QString OptionsPage::trName() const
{
return tr("Mercurial");
}
QString OptionsPage::category() const
{
return QLatin1String(VCSBase::Constants::VCS_SETTINGS_CATEGORY);
}
QString OptionsPage::trCategory() const
{
return QCoreApplication::translate("VCSBase", VCSBase::Constants::VCS_SETTINGS_CATEGORY);
}
QWidget *OptionsPage::createPage(QWidget *parent)
{
if (!optionsPageWidget)
optionsPageWidget = new OptionsPageWidget(parent);
optionsPageWidget.data()->updateOptions();
return optionsPageWidget;
}
void OptionsPage::apply()
{
if (!optionsPageWidget)
return;
optionsPageWidget.data()->saveOptions();
//assume success and emit signal that settings are changed;
emit settingsChanged();
}

View File

@@ -0,0 +1,52 @@
#ifndef OPTIONSPAGE_H
#define OPTIONSPAGE_H
#include "ui_optionspage.h"
#include <coreplugin/dialogs/ioptionspage.h>
#include <QtGui/QWidget>
#include <QtCore/QPointer>
namespace Mercurial {
namespace Internal {
class OptionsPageWidget : public QWidget
{
Q_OBJECT
public:
explicit OptionsPageWidget(QWidget *parent = 0);
void updateOptions();
void saveOptions();
private:
Ui::OptionsPage m_ui;
};
class OptionsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
OptionsPage();
QString id() const;
QString trName() const;
QString category() const;
QString trCategory() const;
QWidget *createPage(QWidget *parent);
void apply();
void finish() { }
signals:
void settingsChanged();
private:
QPointer<OptionsPageWidget> optionsPageWidget;
};
} // namespace Internal
} // namespace Mercurial
#endif // OPTIONSPAGE_H

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mercurial::Internal::OptionsPage</class>
<widget class="QWidget" name="Mercurial::Internal::OptionsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="mercurialCommandLabel">
<property name="text">
<string>Mercurial Command:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Core::Utils::PathChooser" name="commandChooser" native="true"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="showLogEntriesLabel">
<property name="text">
<string>Show Log Entries:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="logEntriesCount">
<property name="toolTip">
<string>The number of recent commit logs to show, choose 0 to see all enteries</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="timeoutSecondsLabel">
<property name="text">
<string>Timeout (Seconds):</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="timeout">
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="promptOnSubmitLabel">
<property name="text">
<string>Prompt On Submit</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="promptOnSubmitCheckBox">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="defaultUsernameLabel">
<property name="toolTip">
<string>Username to use by default on commit.</string>
</property>
<property name="text">
<string>Default Username:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="defaultUsernameLineEdit">
<property name="toolTip">
<string>Username to use by default on commit.</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="defaultEmailLabel">
<property name="toolTip">
<string>Email to use by default on commit.</string>
</property>
<property name="text">
<string>Default Email:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="defaultEmailLineEdit">
<property name="toolTip">
<string>Email to use by default on commit.</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Core::Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,27 @@
#include "revertdialog.h"
using namespace Mercurial::Internal;
RevertDialog::RevertDialog(QWidget *parent) :
QDialog(parent),
m_ui(new Ui::RevertDialog)
{
m_ui->setupUi(this);
}
RevertDialog::~RevertDialog()
{
delete m_ui;
}
void RevertDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
m_ui->retranslateUi(this);
break;
default:
break;
}
}

View File

@@ -0,0 +1,31 @@
#ifndef REVERTDIALOG_H
#define REVERTDIALOG_H
#include "ui_revertdialog.h"
#include <QtGui/QDialog>
namespace Mercurial {
namespace Internal {
class mercurialPlugin;
class RevertDialog : public QDialog
{
Q_OBJECT
public:
RevertDialog(QWidget *parent = 0);
~RevertDialog();
protected:
void changeEvent(QEvent *e);
private:
Ui::RevertDialog *m_ui;
friend class MercurialPlugin;
};
} // namespace Internal
} // namespace Mercurial
#endif // REVERTDIALOG_H

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mercurial::Internal::RevertDialog</class>
<widget class="QDialog" name="Mercurial::Internal::RevertDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>162</height>
</rect>
</property>
<property name="windowTitle">
<string>Revert</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Specify a revision other than the default?</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<widget class="QWidget" name="formLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>361</width>
<height>51</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="revisionLabel">
<property name="text">
<string>Revision:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="revisionLineEdit"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Mercurial::Internal::RevertDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Mercurial::Internal::RevertDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,45 @@
#include "srcdestdialog.h"
#include "ui_srcdestdialog.h"
using namespace Mercurial::Internal;
SrcDestDialog::SrcDestDialog(QWidget *parent) :
QDialog(parent),
m_ui(new Ui::SrcDestDialog)
{
m_ui->setupUi(this);
m_ui->localPathChooser->setExpectedKind(Core::Utils::PathChooser::Directory);
}
SrcDestDialog::~SrcDestDialog()
{
delete m_ui;
}
void SrcDestDialog::setPathChooserKind(Core::Utils::PathChooser::Kind kind)
{
m_ui->localPathChooser->setExpectedKind(kind);
}
QString SrcDestDialog::getRepositoryString()
{
if (m_ui->defaultButton->isChecked())
return QString();
else if (m_ui->localButton->isChecked())
return m_ui->localPathChooser->path();
else
return m_ui->urlLineEdit->text();
}
void SrcDestDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
m_ui->retranslateUi(this);
break;
default:
break;
}
}

View File

@@ -0,0 +1,33 @@
#ifndef SRCDESTDIALOG_H
#define SRCDESTDIALOG_H
#include <QtGui/QDialog>
#include <utils/pathchooser.h>
namespace Mercurial {
namespace Internal {
namespace Ui {
class SrcDestDialog;
}
class SrcDestDialog : public QDialog
{
Q_OBJECT
public:
SrcDestDialog(QWidget *parent = 0);
~SrcDestDialog();
void setPathChooserKind(Core::Utils::PathChooser::Kind kind);
QString getRepositoryString();
protected:
void changeEvent(QEvent *e);
private:
Ui::SrcDestDialog *m_ui;
};
} // namespace Internal
} // namespace Mercurial
#endif // SRCDESTDIALOG_H

View File

@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mercurial::Internal::SrcDestDialog</class>
<widget class="QDialog" name="Mercurial::Internal::SrcDestDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>187</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="defaultButton">
<property name="text">
<string>Default Location:</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="localButton">
<property name="text">
<string>Local filesystem:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="urlButton">
<property name="toolTip">
<string>e.g. https://[user[:pass]@]host[:port]/[path]</string>
</property>
<property name="text">
<string>Specify Url:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Core::Utils::PathChooser" name="localPathChooser" native="true">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="urlLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>e.g. https://[user[:pass]@]host[:port]/[path]</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Core::Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Mercurial::Internal::SrcDestDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>177</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Mercurial::Internal::SrcDestDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>325</x>
<y>177</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>urlButton</sender>
<signal>toggled(bool)</signal>
<receiver>urlLineEdit</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>80</x>
<y>121</y>
</hint>
<hint type="destinationlabel">
<x>332</x>
<y>123</y>
</hint>
</hints>
</connection>
<connection>
<sender>localButton</sender>
<signal>toggled(bool)</signal>
<receiver>localPathChooser</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>112</x>
<y>81</y>
</hint>
<hint type="destinationlabel">
<x>346</x>
<y>81</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -34,6 +34,7 @@ SUBDIRS = plugin_coreplugin \
plugin_genericprojectmanager \
plugin_duieditor \
plugin_qmlprojectmanager \
plugin_mercurial\
debugger/dumper.pro
plugin_coreplugin.subdir = coreplugin
@@ -177,3 +178,9 @@ plugin_qmlprojectmanager.depends = plugin_texteditor
plugin_qmlprojectmanager.depends += plugin_projectexplorer
plugin_qmlprojectmanager.depends += plugin_help
plugin_qmlprojectmanager.depends += plugin_duieditor
plugin_mercurial.subdir = mercurial
plugin_mercurial.depends = plugin_texteditor
plugin_mercurial.depends = plugin_vcsbase
plugin_mercurial.depends += plugin_projectexplorer
plugin_mercurial.depends += plugin_coreplugin

View File

@@ -29,6 +29,9 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Core::Utils::ProjectNameValidatingLineEdit" name="checkoutDirectoryLineEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="pathLabel">
<property name="text">
@@ -39,9 +42,6 @@
<item row="2" column="1">
<widget class="Core::Utils::PathChooser" name="pathChooser"/>
</item>
<item row="1" column="1">
<widget class="Core::Utils::ProjectNameValidatingLineEdit" name="checkoutDirectoryLineEdit"/>
</item>
</layout>
</item>
</layout>