diff --git a/src/plugins/mercurial/Mercurial.pluginspec b/src/plugins/mercurial/Mercurial.pluginspec
new file mode 100644
index 0000000000000000000000000000000000000000..cc7548da31b557cccf7992be844e2efb089bc92d
--- /dev/null
+++ b/src/plugins/mercurial/Mercurial.pluginspec
@@ -0,0 +1,27 @@
+
+ Brian McGillion
+ (C) 2008-2009 Brian McGillion
+
+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.
+ Mercurial integration.
+ http://www.qtsoftware.com
+
+
+
+
+
+
+
diff --git a/src/plugins/mercurial/annotationhighlighter.cpp b/src/plugins/mercurial/annotationhighlighter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a7c8c85a7f382544600f939db66c9c8bc653f85f
--- /dev/null
+++ b/src/plugins/mercurial/annotationhighlighter.cpp
@@ -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();
+}
diff --git a/src/plugins/mercurial/annotationhighlighter.h b/src/plugins/mercurial/annotationhighlighter.h
new file mode 100644
index 0000000000000000000000000000000000000000..25b89b816aba8456d25738697b0411be8840c291
--- /dev/null
+++ b/src/plugins/mercurial/annotationhighlighter.h
@@ -0,0 +1,22 @@
+#ifndef ANNOTATIONHIGHLIGHTER_H
+#define ANNOTATIONHIGHLIGHTER_H
+
+#include
+
+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
diff --git a/src/plugins/mercurial/clonewizard.cpp b/src/plugins/mercurial/clonewizard.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..113b3f03cfbca64016bae8ec5b71cb011f267e4f
--- /dev/null
+++ b/src/plugins/mercurial/clonewizard.cpp
@@ -0,0 +1,59 @@
+#include "clonewizard.h"
+#include "clonewizardpage.h"
+#include "mercurialplugin.h"
+#include "mercurialsettings.h"
+
+#include
+
+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 CloneWizard::createParameterPages(const QString &path)
+{
+ QList wizardPageList;
+ CloneWizardPage *page = new CloneWizardPage;
+ page->setPath(path);
+ wizardPageList.push_back(page);
+ return wizardPageList;
+}
+
+QSharedPointer CloneWizard::createJob(const QList ¶meterPages,
+ QString *checkoutPath)
+{
+ const CloneWizardPage *page = qobject_cast(parameterPages.front());
+
+ if (!page)
+ return QSharedPointer();
+
+ 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(new VCSBase::ProcessCheckoutJob(settings->binary(),
+ args, path));
+}
diff --git a/src/plugins/mercurial/clonewizard.h b/src/plugins/mercurial/clonewizard.h
new file mode 100644
index 0000000000000000000000000000000000000000..789770888095fbaae7c4f66b4276d98030b0d588
--- /dev/null
+++ b/src/plugins/mercurial/clonewizard.h
@@ -0,0 +1,33 @@
+#ifndef CLONEWIZARD_H
+#define CLONEWIZARD_H
+
+#include
+#include
+
+#include
+
+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 createParameterPages(const QString &path);
+ QSharedPointer createJob(const QList ¶meterPages,
+ QString *checkoutPath);
+
+private:
+ QIcon m_icon;
+};
+
+} //namespace Internal
+} //namespace Mercurial
+
+#endif // CLONEWIZARD_H
diff --git a/src/plugins/mercurial/clonewizardpage.cpp b/src/plugins/mercurial/clonewizardpage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..88b790257365c3ab84004591a3d73bff0ec6aef4
--- /dev/null
+++ b/src/plugins/mercurial/clonewizardpage.cpp
@@ -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);
+}
diff --git a/src/plugins/mercurial/clonewizardpage.h b/src/plugins/mercurial/clonewizardpage.h
new file mode 100644
index 0000000000000000000000000000000000000000..a2141e77d064f14d2091e77c436e0b8af7f2adfa
--- /dev/null
+++ b/src/plugins/mercurial/clonewizardpage.h
@@ -0,0 +1,22 @@
+#ifndef CLONEWIZARDPAGE_H
+#define CLONEWIZARDPAGE_H
+
+#include
+
+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
diff --git a/src/plugins/mercurial/commiteditor.cpp b/src/plugins/mercurial/commiteditor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4aae9008d39e730223425c10218505455dee3814
--- /dev/null
+++ b/src/plugins/mercurial/commiteditor.cpp
@@ -0,0 +1,68 @@
+#include "commiteditor.h"
+#include "mercurialcommitwidget.h"
+
+#include
+
+#include
+
+#include //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(widget());
+}
+
+void CommitEditor::setFields(const QFileInfo &repositoryRoot, const QString &branch,
+ const QString &userName, const QString &email,
+ const QList > &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 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();
+}
diff --git a/src/plugins/mercurial/commiteditor.h b/src/plugins/mercurial/commiteditor.h
new file mode 100644
index 0000000000000000000000000000000000000000..507ef3560912f8728e8cc84b891ab19f91235ab9
--- /dev/null
+++ b/src/plugins/mercurial/commiteditor.h
@@ -0,0 +1,40 @@
+#ifndef COMMITEDITOR_H
+#define COMMITEDITOR_H
+
+#include
+
+#include
+
+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 > &repoStatus);
+
+ QString committerInfo();
+ QString repoRoot();
+
+
+private:
+ inline MercurialCommitWidget *commitWidget();
+ VCSBase::SubmitFileModel *fileModel;
+
+};
+
+}
+}
+#endif // COMMITEDITOR_H
diff --git a/src/plugins/mercurial/constants.h b/src/plugins/mercurial/constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0ca62b279ac793836ddcb1826b43b4594cf27b4
--- /dev/null
+++ b/src/plugins/mercurial/constants.h
@@ -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
diff --git a/src/plugins/mercurial/images/hg.png b/src/plugins/mercurial/images/hg.png
new file mode 100644
index 0000000000000000000000000000000000000000..59a238c222649fb1c1e4139f74ae053076a30a4c
Binary files /dev/null and b/src/plugins/mercurial/images/hg.png differ
diff --git a/src/plugins/mercurial/mercurial.pro b/src/plugins/mercurial/mercurial.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f1cf647adef2136702562ed7d8bd69da3d8416b1
--- /dev/null
+++ b/src/plugins/mercurial/mercurial.pro
@@ -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
diff --git a/src/plugins/mercurial/mercurial.qrc b/src/plugins/mercurial/mercurial.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..b001b7e60b57430ad8a91fc7bc552bd12e4c03f7
--- /dev/null
+++ b/src/plugins/mercurial/mercurial.qrc
@@ -0,0 +1,5 @@
+
+
+ images/hg.png
+
+
diff --git a/src/plugins/mercurial/mercurial_dependencies.pri b/src/plugins/mercurial/mercurial_dependencies.pri
new file mode 100644
index 0000000000000000000000000000000000000000..9e7c28e9e1af2cfb121ef3f697d7ff6b0f80b8ec
--- /dev/null
+++ b/src/plugins/mercurial/mercurial_dependencies.pri
@@ -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)
diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d1fc8d48ac3bb2f22d11ff7ede166fde4568745b
--- /dev/null
+++ b/src/plugins/mercurial/mercurialclient.cpp
@@ -0,0 +1,414 @@
+#include "mercurialclient.h"
+#include "mercurialjobrunner.h"
+#include "constants.h"
+#include "mercurialsettings.h"
+#include "mercurialplugin.h"
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 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 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 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 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 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 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 > statusList;
+
+ QStringList rawStatusList = QTextCodec::codecForLocale()->toUnicode(data).split(QLatin1Char('\n'));
+
+ foreach (QString string, rawStatusList) {
+ QPair 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 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 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 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 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 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 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 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 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;
+}
diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h
new file mode 100644
index 0000000000000000000000000000000000000000..ecff87ab73fc96301c447e52573a442f98f0f91b
--- /dev/null
+++ b/src/plugins/mercurial/mercurialclient.h
@@ -0,0 +1,75 @@
+#ifndef MERCURIALCLIENT_H
+#define MERCURIALCLIENT_H
+
+#include
+#include
+#include
+#include
+
+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 > &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
diff --git a/src/plugins/mercurial/mercurialcommitpanel.ui b/src/plugins/mercurial/mercurialcommitpanel.ui
new file mode 100644
index 0000000000000000000000000000000000000000..eadd4953e0dad1edd0f06ceda9e145db955bd0c6
--- /dev/null
+++ b/src/plugins/mercurial/mercurialcommitpanel.ui
@@ -0,0 +1,107 @@
+
+
+ Mercurial::Internal::MercurialCommitPanel
+
+
+
+ 0
+ 0
+ 374
+ 229
+
+
+
+
+ 0
+
+ -
+
+
+ General Information
+
+
+
+ QFormLayout::ExpandingFieldsGrow
+
+
-
+
+
+ Repository:
+
+
+
+ -
+
+
+ repository
+
+
+
+ -
+
+
+ Branch:
+
+
+
+ -
+
+
+ branch
+
+
+
+
+
+
+ -
+
+
+ Commit Information
+
+
+
-
+
+
-
+
+
+ Author:
+
+
+
+ -
+
+
+ -
+
+
+ Email:
+
+
+
+ -
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 161
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/plugins/mercurial/mercurialcommitwidget.cpp b/src/plugins/mercurial/mercurialcommitwidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6874793211c4abb7fa467031fad4343f4354ec92
--- /dev/null
+++ b/src/plugins/mercurial/mercurialcommitwidget.cpp
@@ -0,0 +1,117 @@
+#include "mercurialcommitwidget.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+//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: ').
+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
diff --git a/src/plugins/mercurial/mercurialcommitwidget.h b/src/plugins/mercurial/mercurialcommitwidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d777573a2b75c530bbd23cfc0746469d2ed9d57
--- /dev/null
+++ b/src/plugins/mercurial/mercurialcommitwidget.h
@@ -0,0 +1,35 @@
+#ifndef MERCURIALCOMMITWIDGET_H
+#define MERCURIALCOMMITWIDGET_H
+
+#include "ui_mercurialcommitpanel.h"
+
+#include
+
+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
diff --git a/src/plugins/mercurial/mercurialcontrol.cpp b/src/plugins/mercurial/mercurialcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fbb8781881dcc79dead55b828de7c57fc4280f5b
--- /dev/null
+++ b/src/plugins/mercurial/mercurialcontrol.cpp
@@ -0,0 +1,80 @@
+#include "mercurialcontrol.h"
+#include "mercurialclient.h"
+
+#include
+
+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);
+}
diff --git a/src/plugins/mercurial/mercurialcontrol.h b/src/plugins/mercurial/mercurialcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e5d53e6a7426bf1da6215aee24ade5862171dad
--- /dev/null
+++ b/src/plugins/mercurial/mercurialcontrol.h
@@ -0,0 +1,41 @@
+#ifndef MERCURIALCONTROL_H
+#define MERCURIALCONTROL_H
+
+#include
+
+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
diff --git a/src/plugins/mercurial/mercurialeditor.cpp b/src/plugins/mercurial/mercurialeditor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a541a96dc475db96d0e6985772c15ae56163adc
--- /dev/null
+++ b/src/plugins/mercurial/mercurialeditor.cpp
@@ -0,0 +1,85 @@
+#include "mercurialeditor.h"
+#include "annotationhighlighter.h"
+#include "constants.h"
+#include "mercurialclient.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 MercurialEditor::annotationChanges() const
+{
+ QSet 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 &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();
+}
diff --git a/src/plugins/mercurial/mercurialeditor.h b/src/plugins/mercurial/mercurialeditor.h
new file mode 100644
index 0000000000000000000000000000000000000000..4adea98f8694668b4670a9787cbeb82659b4ea29
--- /dev/null
+++ b/src/plugins/mercurial/mercurialeditor.h
@@ -0,0 +1,32 @@
+#ifndef MERCURIALEDITOR_H
+#define MERCURIALEDITOR_H
+
+#include
+
+#include
+
+namespace Mercurial {
+namespace Internal {
+
+class MercurialEditor : public VCSBase::VCSBaseEditor
+{
+public:
+ explicit MercurialEditor(const VCSBase::VCSBaseEditorParameters *type, QWidget *parent);
+
+private:
+ virtual QSet annotationChanges() const;
+ virtual QString changeUnderCursor(const QTextCursor &cursor) const;
+ virtual VCSBase::DiffHighlighter *createDiffHighlighter() const;
+ virtual VCSBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet &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
diff --git a/src/plugins/mercurial/mercurialjobrunner.cpp b/src/plugins/mercurial/mercurialjobrunner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a3671f9fc897426dfa42be9a61b04a44979c042
--- /dev/null
+++ b/src/plugins/mercurial/mercurialjobrunner.cpp
@@ -0,0 +1,176 @@
+#include "mercurialjobrunner.h"
+#include "mercurialplugin.h"
+#include "mercurialoutputwindow.h"
+#include "constants.h"
+#include "mercurialsettings.h"
+
+#include
+
+#include
+#include
+#include
+#include
+
+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 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 &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 job = jobs.dequeue();
+ mutex.unlock();
+
+ task(job);
+ }
+}
+
+void MercurialJobRunner::task(QSharedPointer &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);
+}
diff --git a/src/plugins/mercurial/mercurialjobrunner.h b/src/plugins/mercurial/mercurialjobrunner.h
new file mode 100644
index 0000000000000000000000000000000000000000..d76ebbfe9e8d52663a4ea8c0f2fbc899ea872f95
--- /dev/null
+++ b/src/plugins/mercurial/mercurialjobrunner.h
@@ -0,0 +1,79 @@
+#ifndef MERCURIALJOBRUNNER_H
+#define MERCURIALJOBRUNNER_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 &job);
+ void restart();
+
+protected:
+ void run();
+
+signals:
+ void error(const QByteArray &error);
+ void info(const QString ¬ice);
+ void output(const QByteArray &output);
+
+private:
+ void task(QSharedPointer &job);
+ void stop();
+ void getSettings();
+
+ QQueue > jobs;
+ QMutex mutex;
+ QWaitCondition waiter;
+ MercurialPlugin *plugin;
+ bool keepRunning;
+ QString binary;
+ QStringList standardArguments;
+ int timeout;
+};
+
+} //namespace Internal
+} //namespace Mercurial
+#endif // MERCURIALJOBRUNNER_H
diff --git a/src/plugins/mercurial/mercurialoutputwindow.cpp b/src/plugins/mercurial/mercurialoutputwindow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..21eca5b1b5ccee78c3957199d66306a08186501b
--- /dev/null
+++ b/src/plugins/mercurial/mercurialoutputwindow.cpp
@@ -0,0 +1,102 @@
+#include "mercurialoutputwindow.h"
+
+#include
+#include
+#include
+
+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 MercurialOutputWindow::toolBarWidgets() const
+{
+ return QList();
+}
+
+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));
+}
diff --git a/src/plugins/mercurial/mercurialoutputwindow.h b/src/plugins/mercurial/mercurialoutputwindow.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5a7db2da877a892517ec64c72532bb484f3e1e5
--- /dev/null
+++ b/src/plugins/mercurial/mercurialoutputwindow.h
@@ -0,0 +1,49 @@
+#ifndef MERCURIALOUTPUTWINDOW_H
+#define MERCURIALOUTPUTWINDOW_H
+
+#include
+
+QT_BEGIN_NAMESPACE
+class QListWidget;
+QT_END_NAMESPACE
+
+#include
+
+namespace Mercurial {
+namespace Internal {
+
+class MercurialOutputWindow: public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ MercurialOutputWindow();
+ ~MercurialOutputWindow();
+
+ QWidget *outputWidget(QWidget *parent);
+ QList 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
diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c3c065371863b61bf57989fe5d45bfa7c1de5eff
--- /dev/null
+++ b/src/plugins/mercurial/mercurialplugin.cpp
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+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(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 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(&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 context = QList()<< 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 &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 &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 &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 context = QList()<< 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 > &)),
+ this, SLOT(showCommitWidget(const QList > &)));
+ client->statusWithSignal(currentProjectRoot());
+}
+
+void MercurialPlugin::showCommitWidget(const QList > &status)
+{
+ //Once we receive our data release the connection so it can be reused elsewhere
+ disconnect(client, SIGNAL(parsedStatus(const QList > &)),
+ this, SLOT(showCommitWidget(const QList > &)));
+
+ 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(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(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 &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 &context)
+{
+ //TODO create menue for these options
+ Q_UNUSED(context);
+ return;
+}
+
+void MercurialPlugin::createSeparator(const QList &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)
diff --git a/src/plugins/mercurial/mercurialplugin.h b/src/plugins/mercurial/mercurialplugin.h
new file mode 100644
index 0000000000000000000000000000000000000000..e1e434fdff00c0d8422dbc241f9146d273edae21
--- /dev/null
+++ b/src/plugins/mercurial/mercurialplugin.h
@@ -0,0 +1,165 @@
+#ifndef MERCURIALPLUGIN_H
+#define MERCURIALPLUGIN_H
+
+#include
+#include
+
+#include
+#include
+#include
+
+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 > &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 &context, const QString &id);
+ void createFileActions(QList &context);
+ void createDirectoryActions(QList &context);
+ void createRepositoryActions(QList &context);
+ void createRepositoryManagementActions(QList &context);
+ void createLessUsedActions(QList &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 projectMapper;
+ QList 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
diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..32ff663990b14aebcea1471016a19034690ebbcf
--- /dev/null
+++ b/src/plugins/mercurial/mercurialsettings.cpp
@@ -0,0 +1,114 @@
+#include "mercurialsettings.h"
+#include "constants.h"
+
+#include
+
+#include
+
+
+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
+}
diff --git a/src/plugins/mercurial/mercurialsettings.h b/src/plugins/mercurial/mercurialsettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..0567412579c475c6f260aea2e97d3a9f3f8fa808
--- /dev/null
+++ b/src/plugins/mercurial/mercurialsettings.h
@@ -0,0 +1,45 @@
+#ifndef MERCURIALSETTINGS_H
+#define MERCURIALSETTINGS_H
+
+#include
+#include
+
+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
diff --git a/src/plugins/mercurial/optionspage.cpp b/src/plugins/mercurial/optionspage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..07d42fd34afc613b56aa31c7c6e32c17b6113cba
--- /dev/null
+++ b/src/plugins/mercurial/optionspage.cpp
@@ -0,0 +1,79 @@
+#include "optionspage.h"
+#include "mercurialsettings.h"
+#include "mercurialplugin.h"
+
+#include
+#include
+
+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();
+}
+
diff --git a/src/plugins/mercurial/optionspage.h b/src/plugins/mercurial/optionspage.h
new file mode 100644
index 0000000000000000000000000000000000000000..83111279acc04906371390611ad1525f28bb7cf1
--- /dev/null
+++ b/src/plugins/mercurial/optionspage.h
@@ -0,0 +1,52 @@
+#ifndef OPTIONSPAGE_H
+#define OPTIONSPAGE_H
+
+#include "ui_optionspage.h"
+
+#include
+
+#include
+#include
+
+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;
+};
+
+} // namespace Internal
+} // namespace Mercurial
+
+#endif // OPTIONSPAGE_H
diff --git a/src/plugins/mercurial/optionspage.ui b/src/plugins/mercurial/optionspage.ui
new file mode 100644
index 0000000000000000000000000000000000000000..7c149f283a43d215ae1272239bd72f5d243b63f7
--- /dev/null
+++ b/src/plugins/mercurial/optionspage.ui
@@ -0,0 +1,126 @@
+
+
+ Mercurial::Internal::OptionsPage
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Form
+
+
+ -
+
+
-
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
-
+
+
+ Mercurial Command:
+
+
+
+ -
+
+
+ -
+
+
+ Show Log Entries:
+
+
+
+ -
+
+
+ The number of recent commit logs to show, choose 0 to see all enteries
+
+
+
+ -
+
+
+ Timeout (Seconds):
+
+
+
+ -
+
+
+ 30
+
+
+
+ -
+
+
+ Prompt On Submit
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Username to use by default on commit.
+
+
+ Default Username:
+
+
+
+ -
+
+
+ Username to use by default on commit.
+
+
+
+ -
+
+
+ Email to use by default on commit.
+
+
+ Default Email:
+
+
+
+ -
+
+
+ Email to use by default on commit.
+
+
+
+
+
+
+
+
+
+
+
+ Core::Utils::PathChooser
+ QWidget
+
+ 1
+
+
+
+
+
diff --git a/src/plugins/mercurial/revertdialog.cpp b/src/plugins/mercurial/revertdialog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb8c516c5cf5ef383323d3d813915c9329e054ed
--- /dev/null
+++ b/src/plugins/mercurial/revertdialog.cpp
@@ -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;
+ }
+}
diff --git a/src/plugins/mercurial/revertdialog.h b/src/plugins/mercurial/revertdialog.h
new file mode 100644
index 0000000000000000000000000000000000000000..82d5f9d70a7d7d2253a5bb0c6165f3e0dc85a9e7
--- /dev/null
+++ b/src/plugins/mercurial/revertdialog.h
@@ -0,0 +1,31 @@
+#ifndef REVERTDIALOG_H
+#define REVERTDIALOG_H
+
+#include "ui_revertdialog.h"
+
+#include
+
+
+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
diff --git a/src/plugins/mercurial/revertdialog.ui b/src/plugins/mercurial/revertdialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..66876dc6f938e66a23ba47fecb673f62d5976020
--- /dev/null
+++ b/src/plugins/mercurial/revertdialog.ui
@@ -0,0 +1,99 @@
+
+
+ Mercurial::Internal::RevertDialog
+
+
+
+ 0
+ 0
+ 400
+ 162
+
+
+
+ Revert
+
+
+ -
+
+
+ Specify a revision other than the default?
+
+
+ true
+
+
+ false
+
+
+
+
+ 10
+ 30
+ 361
+ 51
+
+
+
+
-
+
+
+ Revision:
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ Mercurial::Internal::RevertDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ Mercurial::Internal::RevertDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/plugins/mercurial/srcdestdialog.cpp b/src/plugins/mercurial/srcdestdialog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e115ae6f7943a7e6a32b06e72e0772095dfd6da1
--- /dev/null
+++ b/src/plugins/mercurial/srcdestdialog.cpp
@@ -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;
+ }
+}
diff --git a/src/plugins/mercurial/srcdestdialog.h b/src/plugins/mercurial/srcdestdialog.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3af788a184ba36524a78d9646c25ef821a05050
--- /dev/null
+++ b/src/plugins/mercurial/srcdestdialog.h
@@ -0,0 +1,33 @@
+#ifndef SRCDESTDIALOG_H
+#define SRCDESTDIALOG_H
+
+#include
+#include
+
+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
diff --git a/src/plugins/mercurial/srcdestdialog.ui b/src/plugins/mercurial/srcdestdialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..9677363ee95ac75deac2708f31542920ad00a69f
--- /dev/null
+++ b/src/plugins/mercurial/srcdestdialog.ui
@@ -0,0 +1,152 @@
+
+
+ Mercurial::Internal::SrcDestDialog
+
+
+
+ 0
+ 0
+ 400
+ 187
+
+
+
+ Dialog
+
+
+ -
+
+
-
+
+
+ Default Location:
+
+
+ true
+
+
+
+ -
+
+
+ Local filesystem:
+
+
+
+ -
+
+
+ e.g. https://[user[:pass]@]host[:port]/[path]
+
+
+ Specify Url:
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+ e.g. https://[user[:pass]@]host[:port]/[path]
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+ Core::Utils::PathChooser
+ QWidget
+
+ 1
+
+
+
+
+
+ buttonBox
+ accepted()
+ Mercurial::Internal::SrcDestDialog
+ accept()
+
+
+ 257
+ 177
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ Mercurial::Internal::SrcDestDialog
+ reject()
+
+
+ 325
+ 177
+
+
+ 286
+ 274
+
+
+
+
+ urlButton
+ toggled(bool)
+ urlLineEdit
+ setEnabled(bool)
+
+
+ 80
+ 121
+
+
+ 332
+ 123
+
+
+
+
+ localButton
+ toggled(bool)
+ localPathChooser
+ setEnabled(bool)
+
+
+ 112
+ 81
+
+
+ 346
+ 81
+
+
+
+
+
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 9066a5c4cde0d7b8b0be8c3b988ba76fbdab7b07..f770ae430ab49514b24f283dde6306a170946f3b 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -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
diff --git a/src/plugins/vcsbase/basecheckoutwizardpage.ui b/src/plugins/vcsbase/basecheckoutwizardpage.ui
index 75ac881df2827892a8cb4fc2e061b41965afb882..dc8a3b8c5339ca69108808c751deb4d53fa41df7 100644
--- a/src/plugins/vcsbase/basecheckoutwizardpage.ui
+++ b/src/plugins/vcsbase/basecheckoutwizardpage.ui
@@ -29,6 +29,9 @@
+ -
+
+
-
@@ -39,9 +42,6 @@
-
- -
-
-