summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtur Shepilko <artur.shepilko@nomadbyte.com>2016-11-16 12:51:32 -0600
committerArtur Shepilko <artur.shepilko@nomadbyte.com>2017-02-09 16:43:38 +0000
commitdea25a6b62d97ddbe4a94c028c3431d91dac5b86 (patch)
tree638759dc25964c3b88bba4d461a8ca3f2df43f71
parent21580dae57709995363cc4e8d50ec4f14025c59c (diff)
Vcs: Add Fossil SCM integration plugin
* Qt Creator base-commit: f77af5e3362cc6c4360ea1d197fb834cd5b072fa * Stand-alone plugin source tree for integration into qtc super-project * Original release: https://github.com/nomadbyte/qtcreator-plugin-fossil * Adapted from Bazaar plugin implementation Configuring Fossil ------------------ 1. Download the [Fossil SCM client](http://fossil-scm.org) and install `fossil` executable file in your `PATH`. 2. Create or designate a directory to store local Fossil repositories and remote clones. For example: `~/fossils/qt`. 3. Configure Version Control Options for the Fossil plugin to use the designated directory as `Local Repositories Default path`. Now Fossil should become available as a VCS choice to create new local repositories, as well as a choice in `New File or Project` to clone a remote Fossil repository. Change-Id: I630184c1b344184d9e08ae2fc24a5e4766f834b9 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
-rw-r--r--doc/src/vcs/creator-vcs-fossil.qdoc87
-rw-r--r--fossil.pro2
-rw-r--r--plugins/fossil/Fossil.json.in19
-rw-r--r--plugins/fossil/annotationhighlighter.cpp51
-rw-r--r--plugins/fossil/annotationhighlighter.h46
-rw-r--r--plugins/fossil/branchinfo.cpp57
-rw-r--r--plugins/fossil/branchinfo.h59
-rw-r--r--plugins/fossil/commiteditor.cpp89
-rw-r--r--plugins/fossil/commiteditor.h57
-rw-r--r--plugins/fossil/configuredialog.cpp99
-rw-r--r--plugins/fossil/configuredialog.h55
-rw-r--r--plugins/fossil/configuredialog.ui132
-rw-r--r--plugins/fossil/constants.h114
-rw-r--r--plugins/fossil/fossil.pro45
-rw-r--r--plugins/fossil/fossil.qrc6
-rw-r--r--plugins/fossil/fossil_dependencies.pri9
-rw-r--r--plugins/fossil/fossilclient.cpp1201
-rw-r--r--plugins/fossil/fossilclient.h132
-rw-r--r--plugins/fossil/fossilcommitpanel.ui177
-rw-r--r--plugins/fossil/fossilcommitwidget.cpp169
-rw-r--r--plugins/fossil/fossilcommitwidget.h76
-rw-r--r--plugins/fossil/fossilcontrol.cpp289
-rw-r--r--plugins/fossil/fossilcontrol.h78
-rw-r--r--plugins/fossil/fossileditor.cpp115
-rw-r--r--plugins/fossil/fossileditor.h53
-rw-r--r--plugins/fossil/fossilplugin.cpp819
-rw-r--r--plugins/fossil/fossilplugin.h146
-rw-r--r--plugins/fossil/fossilsettings.cpp68
-rw-r--r--plugins/fossil/fossilsettings.h69
-rw-r--r--plugins/fossil/optionspage.cpp86
-rw-r--r--plugins/fossil/optionspage.h63
-rw-r--r--plugins/fossil/optionspage.ui226
-rw-r--r--plugins/fossil/pullorpushdialog.cpp110
-rw-r--r--plugins/fossil/pullorpushdialog.h66
-rw-r--r--plugins/fossil/pullorpushdialog.ui235
-rw-r--r--plugins/fossil/revertdialog.ui106
-rw-r--r--plugins/fossil/revisioninfo.cpp37
-rw-r--r--plugins/fossil/revisioninfo.h47
-rw-r--r--plugins/fossil/wizard/fossiljsextension.cpp128
-rw-r--r--plugins/fossil/wizard/fossiljsextension.h61
-rw-r--r--plugins/fossil/wizard/projects/vcs/icon.pngbin0 -> 14500 bytes
-rw-r--r--plugins/fossil/wizard/projects/vcs/wizard.json255
42 files changed, 5739 insertions, 0 deletions
diff --git a/doc/src/vcs/creator-vcs-fossil.qdoc b/doc/src/vcs/creator-vcs-fossil.qdoc
new file mode 100644
index 0000000..a528180
--- /dev/null
+++ b/doc/src/vcs/creator-vcs-fossil.qdoc
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+// **********************************************************************
+// NOTE: the sections are not ordered by their logical order to avoid
+// reshuffling the file each time the index order changes (i.e., often).
+// Run the fixnavi.pl script to adjust the links to the index order.
+// **********************************************************************
+
+/*!
+ \contentspage {Qt Creator Manual}
+ \previouspage creator-vcs-cvs.html
+ \page creator-vcs-fossil.html
+ \nextpage creator-vcs-git.html
+
+ \title Using Fossil
+
+ Fossil is an open source distributed version control system, designed
+ and developed by the creator of SQLite. A stand-alone Fossil executable
+ contains a source control management engine, web interface, issue tracker,
+ wiki, and built-in web server. Fossil is available for Linux, Windows,
+ and \macos.
+
+ \section1 Configuring Fossil
+
+ \list 1
+ \li Download the \l{http://fossil-scm.org}{Fossil SCM client} and install
+ the \c fossil executable file in your \c PATH.
+
+ \li Create or designate a directory to store local Fossil repositories and
+ remote clones. For example: \c ~/fossils/qt.
+
+ \li Configure \uicontrol {Version Control Options} for the Fossil plugin to use
+ the designated directory as \uicontrol {Local Repositories Default path}.
+ \endlist
+
+ Now Fossil should become available as a VCS choice to create new local
+ repositories, as well as a choice in \uicontrol {New File or Project} to
+ clone a remote Fossil repository.
+
+ \section1 Additional Fossil Functions
+
+ In addition to the standard version control system functions described in
+ \l{Using Common Functions}, the \uicontrol Fossil submenu contains
+ the following items:
+ \table
+ \header
+ \li Menu Item
+ \li Description
+ \row
+ \li \uicontrol Pull
+ \li Pull changes from the remote repository.
+ \row
+ \li \uicontrol Push
+ \li Push committed changes to the remote repository.
+ \row
+ \li \uicontrol Update
+ \li Change the version of the current checkout. Any uncommitted
+ changes are retained and applied to the new checkout.
+ \row
+ \li \uicontrol Settings
+ \li Configure the settings of the local repository.
+ \endtable
+
+*/
diff --git a/fossil.pro b/fossil.pro
new file mode 100644
index 0000000..bf71d02
--- /dev/null
+++ b/fossil.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += plugins/fossil
diff --git a/plugins/fossil/Fossil.json.in b/plugins/fossil/Fossil.json.in
new file mode 100644
index 0000000..166fd52
--- /dev/null
+++ b/plugins/fossil/Fossil.json.in
@@ -0,0 +1,19 @@
+{
+ \"Name\" : \"Fossil\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Vendor\" : \"Artur Shepilko\",
+ \"Copyright\" : \"(C) 2016 Artur Shepilko\",
+ \"License\" : [ \"Commercial Usage\",
+ \"\",
+ \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\",
+ \"\",
+ \"GNU General Public License Usage\",
+ \"\",
+ \"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html.\"
+ ],
+ \"Category\" : \"Version Control\",
+ \"Description\" : \"Fossil SCM integration.\",
+ \"Url\" : \"http://www.qt.io\",
+ $$dependencyList
+}
diff --git a/plugins/fossil/annotationhighlighter.cpp b/plugins/fossil/annotationhighlighter.cpp
new file mode 100644
index 0000000..31f3f54
--- /dev/null
+++ b/plugins/fossil/annotationhighlighter.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "annotationhighlighter.h"
+#include "constants.h"
+
+#include <utils/qtcassert.h>
+
+namespace Fossil {
+namespace Internal {
+
+FossilAnnotationHighlighter::FossilAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document) :
+ VcsBase::BaseAnnotationHighlighter(changeNumbers, document),
+ m_changesetIdPattern(Constants::CHANGESET_ID)
+{
+ QTC_CHECK(m_changesetIdPattern.isValid());
+}
+
+QString FossilAnnotationHighlighter::changeNumber(const QString &block) const
+{
+ QRegularExpressionMatch changesetIdMatch = m_changesetIdPattern.match(block);
+ if (changesetIdMatch.hasMatch())
+ return changesetIdMatch.captured(1);
+ return QString();
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/annotationhighlighter.h b/plugins/fossil/annotationhighlighter.h
new file mode 100644
index 0000000..474f3e1
--- /dev/null
+++ b/plugins/fossil/annotationhighlighter.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <vcsbase/baseannotationhighlighter.h>
+#include <QRegularExpression>
+
+namespace Fossil {
+namespace Internal {
+
+class FossilAnnotationHighlighter : public VcsBase::BaseAnnotationHighlighter
+{
+public:
+ explicit FossilAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document = nullptr);
+
+private:
+ QString changeNumber(const QString &block) const final;
+ QRegularExpression m_changesetIdPattern;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/branchinfo.cpp b/plugins/fossil/branchinfo.cpp
new file mode 100644
index 0000000..39a25c2
--- /dev/null
+++ b/plugins/fossil/branchinfo.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "branchinfo.h"
+
+namespace Fossil {
+namespace Internal {
+
+BranchInfo::BranchInfo(const QString &name, BranchFlags flags) :
+ m_name(name),
+ m_flags(flags)
+{ }
+
+const QString &BranchInfo::name() const
+{
+ return m_name;
+}
+
+bool BranchInfo::isCurrent() const
+{
+ return m_flags.testFlag(Current);
+}
+
+bool BranchInfo::isClosed() const
+{
+ return m_flags.testFlag(Closed);
+}
+
+bool BranchInfo::isPrivate() const
+{
+ return m_flags.testFlag(Private);
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/branchinfo.h b/plugins/fossil/branchinfo.h
new file mode 100644
index 0000000..535c81b
--- /dev/null
+++ b/plugins/fossil/branchinfo.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QString>
+
+namespace Fossil {
+namespace Internal {
+
+class BranchInfo
+{
+public:
+ enum BranchFlag {
+ Current = 0x01,
+ Closed = 0x02,
+ Private = 0x04
+ };
+ Q_DECLARE_FLAGS(BranchFlags, BranchFlag)
+
+ explicit BranchInfo(const QString &name = QString(), BranchFlags flags = 0);
+
+public:
+ const QString &name() const;
+ bool isCurrent() const;
+ bool isClosed() const;
+ bool isPrivate() const;
+
+private:
+ QString m_name;
+ BranchFlags m_flags;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(BranchInfo::BranchFlags)
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/commiteditor.cpp b/plugins/fossil/commiteditor.cpp
new file mode 100644
index 0000000..0e9a459
--- /dev/null
+++ b/plugins/fossil/commiteditor.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "branchinfo.h"
+#include "commiteditor.h"
+#include "constants.h"
+#include "fossilcommitwidget.h"
+
+#include <coreplugin/idocument.h>
+#include <vcsbase/submitfilemodel.h>
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+namespace Fossil {
+namespace Internal {
+
+CommitEditor::CommitEditor(const VcsBase::VcsBaseSubmitEditorParameters *parameters) :
+ VcsBase::VcsBaseSubmitEditor(parameters, new FossilCommitWidget)
+{
+ document()->setPreferredDisplayName(tr("Commit Editor"));
+}
+
+FossilCommitWidget *CommitEditor::commitWidget()
+{
+ return static_cast<FossilCommitWidget *>(widget());
+}
+
+void CommitEditor::setFields(const QString &repositoryRoot, const BranchInfo &branch,
+ const QStringList &tags, const QString &userName,
+ const QList<VcsBase::VcsBaseClient::StatusItem> &repoStatus)
+{
+ FossilCommitWidget *fossilWidget = commitWidget();
+ QTC_ASSERT(fossilWidget, return);
+
+ fossilWidget->setFields(repositoryRoot, branch, tags, userName);
+
+ m_fileModel = new VcsBase::SubmitFileModel(this);
+ m_fileModel->setRepositoryRoot(repositoryRoot);
+ m_fileModel->setFileStatusQualifier([](const QString &status, const QVariant &)
+ -> VcsBase::SubmitFileModel::FileStatusHint
+ {
+ if (status == Constants::FSTATUS_ADDED
+ || status == Constants::FSTATUS_ADDED_BY_MERGE
+ || status == Constants::FSTATUS_ADDED_BY_INTEGRATE) {
+ return VcsBase::SubmitFileModel::FileAdded;
+ } else if (status == Constants::FSTATUS_EDITED
+ || status == Constants::FSTATUS_UPDATED_BY_MERGE
+ || status == Constants::FSTATUS_UPDATED_BY_INTEGRATE) {
+ return VcsBase::SubmitFileModel::FileModified;
+ } else if (status == Constants::FSTATUS_DELETED) {
+ return VcsBase::SubmitFileModel::FileDeleted;
+ } else if (status == Constants::FSTATUS_RENAMED) {
+ return VcsBase::SubmitFileModel::FileRenamed;
+ }
+ return VcsBase::SubmitFileModel::FileStatusUnknown;
+ } );
+
+ const QList<VcsBase::VcsBaseClient::StatusItem> toAdd = Utils::filtered(repoStatus,
+ [](const VcsBase::VcsBaseClient::StatusItem &item) { return item.flags != Constants::FSTATUS_UNKNOWN; });
+ for (const VcsBase::VcsBaseClient::StatusItem &item : toAdd)
+ m_fileModel->addFile(item.file, item.flags);
+
+ setFileModel(m_fileModel);
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/commiteditor.h b/plugins/fossil/commiteditor.h
new file mode 100644
index 0000000..2fa6a55
--- /dev/null
+++ b/plugins/fossil/commiteditor.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <vcsbase/vcsbaseclient.h>
+#include <vcsbase/vcsbasesubmiteditor.h>
+
+namespace VcsBase { class SubmitFileModel; }
+
+namespace Fossil {
+namespace Internal {
+
+class BranchInfo;
+class FossilCommitWidget;
+
+class CommitEditor : public VcsBase::VcsBaseSubmitEditor
+{
+ Q_OBJECT
+
+public:
+ explicit CommitEditor(const VcsBase::VcsBaseSubmitEditorParameters *parameters);
+
+ void setFields(const QString &repositoryRoot, const BranchInfo &branch,
+ const QStringList &tags, const QString &userName,
+ const QList<VcsBase::VcsBaseClient::StatusItem> &repoStatus);
+
+ FossilCommitWidget *commitWidget();
+
+private:
+ VcsBase::SubmitFileModel *m_fileModel = nullptr;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/configuredialog.cpp b/plugins/fossil/configuredialog.cpp
new file mode 100644
index 0000000..49ab100
--- /dev/null
+++ b/plugins/fossil/configuredialog.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "configuredialog.h"
+#include "ui_configuredialog.h"
+
+#include "fossilsettings.h"
+
+#include <utils/pathchooser.h>
+
+#include <QDir>
+
+namespace Fossil {
+namespace Internal {
+
+class ConfigureDialogPrivate {
+public:
+ RepositorySettings settings() {
+ m_settings.user = m_ui.userLineEdit->text().trimmed();
+ m_settings.sslIdentityFile = m_ui.sslIdentityFilePathChooser->path();
+ m_settings.autosync =
+ (m_ui.disableAutosyncCheckBox->isChecked() ? RepositorySettings::AutosyncOff
+ : RepositorySettings::AutosyncOn);
+ return m_settings;
+ }
+
+ void updateUi() {
+ m_ui.userLineEdit->setText(m_settings.user.trimmed());
+ m_ui.userLineEdit->selectAll();
+ m_ui.sslIdentityFilePathChooser->setPath(QDir::toNativeSeparators(m_settings.sslIdentityFile));
+ m_ui.disableAutosyncCheckBox->setChecked(m_settings.autosync == RepositorySettings::AutosyncOff);
+ }
+
+ Ui::ConfigureDialog m_ui;
+ RepositorySettings m_settings;
+};
+
+ConfigureDialog::ConfigureDialog(QWidget *parent) : QDialog(parent),
+ d(new ConfigureDialogPrivate)
+{
+ d->m_ui.setupUi(this);
+ d->m_ui.sslIdentityFilePathChooser->setExpectedKind(Utils::PathChooser::File);
+ d->m_ui.sslIdentityFilePathChooser->setPromptDialogTitle(tr("SSL/TLS Identity Key"));
+ setWindowTitle(tr("Configure Repository"));
+ d->updateUi();
+}
+
+ConfigureDialog::~ConfigureDialog()
+{
+ delete d;
+}
+
+const RepositorySettings ConfigureDialog::settings() const
+{
+ return d->settings();
+}
+
+void ConfigureDialog::setSettings(const RepositorySettings &settings)
+{
+ d->m_settings = settings;
+ d->updateUi();
+}
+
+void ConfigureDialog::changeEvent(QEvent *e)
+{
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ d->m_ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/configuredialog.h b/plugins/fossil/configuredialog.h
new file mode 100644
index 0000000..fe72570
--- /dev/null
+++ b/plugins/fossil/configuredialog.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QDialog>
+
+namespace Fossil {
+namespace Internal {
+
+struct RepositorySettings;
+class ConfigureDialogPrivate;
+
+class ConfigureDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit ConfigureDialog(QWidget *parent = nullptr);
+ ~ConfigureDialog() final;
+
+ const RepositorySettings settings() const;
+ void setSettings(const RepositorySettings &settings);
+
+protected:
+ void changeEvent(QEvent *e) final;
+
+private:
+ ConfigureDialogPrivate *d = nullptr;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/configuredialog.ui b/plugins/fossil/configuredialog.ui
new file mode 100644
index 0000000..d68ad2f
--- /dev/null
+++ b/plugins/fossil/configuredialog.ui
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Fossil::Internal::ConfigureDialog</class>
+ <widget class="QDialog" name="Fossil::Internal::ConfigureDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>385</width>
+ <height>202</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Configure Repository</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="repoUserGroupBox">
+ <property name="title">
+ <string>Repository User</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="userLabel">
+ <property name="text">
+ <string>User:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="userLineEdit">
+ <property name="toolTip">
+ <string>Existing user to become an author of changes made to the repository.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="repoSettingsGroupBox">
+ <property name="title">
+ <string>Repository Settings</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="sslIdentityFileLabel">
+ <property name="text">
+ <string>SSL/TLS identity:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Utils::PathChooser" name="sslIdentityFilePathChooser" native="true">
+ <property name="toolTip">
+ <string>SSL/TLS client identity key to use if requested by the server.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QCheckBox" name="disableAutosyncCheckBox">
+ <property name="toolTip">
+ <string>Disable automatic pull prior to commit or update and automatic push after commit or tag or branch creation.</string>
+ </property>
+ <property name="text">
+ <string>Disable auto-sync</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/pathchooser.h</header>
+ <container>1</container>
+ <slots>
+ <signal>editingFinished()</signal>
+ <signal>browsingFinished()</signal>
+ </slots>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Fossil::Internal::ConfigureDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Fossil::Internal::ConfigureDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/plugins/fossil/constants.h b/plugins/fossil/constants.h
new file mode 100644
index 0000000..b18a85e
--- /dev/null
+++ b/plugins/fossil/constants.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtGlobal>
+
+namespace Fossil {
+namespace Constants {
+
+const char VCS_ID_FOSSIL[] = "I.Fossil";
+
+const char FOSSIL[] = "fossil";
+#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
+const char FOSSILREPO[] = "_FOSSIL_";
+#else
+const char FOSSILREPO[] = ".fslckout";
+#endif
+const char FOSSILDEFAULT[] = "fossil";
+const char FOSSIL_CONTEXT[] = "Fossil Context";
+
+const char FOSSIL_FILE_SUFFIX[] = ".fossil";
+const char FOSSIL_FILE_FILTER[] = "Fossil Repositories (*.fossil *.fsl);;All Files (*)";
+
+//changeset identifiers
+const char CHANGESET_ID[] = "([0-9a-f]{5,40})"; // match and capture
+const char CHANGESET_ID_EXACT[] = "[0-9a-f]{5,40}"; // match
+
+//diff chunk identifiers
+const char DIFFFILE_ID_EXACT[] = "[+]{3} (.*)\\s*"; // match and capture
+
+//BaseEditorParameters
+const char FILELOG_ID[] = "Fossil File Log Editor";
+const char FILELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Fossil File Log Editor");
+const char LOGAPP[] = "text/vnd.qtcreator.fossil.log";
+
+const char ANNOTATELOG_ID[] = "Fossil Annotation Editor";
+const char ANNOTATELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Fossil Annotation Editor");
+const char ANNOTATEAPP[] = "text/vnd.qtcreator.fossil.annotation";
+
+const char DIFFLOG_ID[] = "Fossil Diff Editor";
+const char DIFFLOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Fossil Diff Editor");
+const char DIFFAPP[] = "text/x-patch";
+
+//SubmitEditorParameters
+const char COMMIT_ID[] = "Fossil Commit Log Editor";
+const char COMMIT_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Fossil Commit Log Editor");
+const char COMMITMIMETYPE[] = "text/vnd.qtcreator.fossil.commit";
+
+//menu items
+//File menu actions
+const char ADD[] = "Fossil.AddSingleFile";
+const char DELETE[] = "Fossil.DeleteSingleFile";
+const char ANNOTATE[] = "Fossil.Annotate";
+const char DIFF[] = "Fossil.DiffSingleFile";
+const char LOG[] = "Fossil.LogSingleFile";
+const char REVERT[] = "Fossil.RevertSingleFile";
+const char STATUS[] = "Fossil.Status";
+
+//directory menu Actions
+const char DIFFMULTI[] = "Fossil.Action.DiffMulti";
+const char REVERTMULTI[] = "Fossil.Action.RevertAll";
+const char STATUSMULTI[] = "Fossil.Action.StatusMulti";
+const char LOGMULTI[] = "Fossil.Action.LogMulti";
+
+//repository menu actions
+const char PULL[] = "Fossil.Action.Pull";
+const char PUSH[] = "Fossil.Action.Push";
+const char UPDATE[] = "Fossil.Action.Update";
+const char COMMIT[] = "Fossil.Action.Commit";
+const char CONFIGURE_REPOSITORY[] = "Fossil.Action.Settings";
+const char CREATE_REPOSITORY[] = "Fossil.Action.CreateRepository";
+
+//submit editor actions
+const char DIFFEDITOR[] = "Fossil.Action.Editor.Diff";
+
+// File status hint
+const char FSTATUS_ADDED[] = "Added";
+const char FSTATUS_ADDED_BY_MERGE[] = "Added by Merge";
+const char FSTATUS_ADDED_BY_INTEGRATE[] = "Added by Integrate";
+const char FSTATUS_DELETED[] = "Deleted";
+const char FSTATUS_EDITED[] = "Edited";
+const char FSTATUS_UPDATED_BY_MERGE[] = "Updated by Merge";
+const char FSTATUS_UPDATED_BY_INTEGRATE[] = "Updated by Integrate";
+const char FSTATUS_RENAMED[] = "Renamed";
+const char FSTATUS_UNKNOWN[] = "Unknown";
+
+// Fossil Json Wizards
+const char WIZARD_PATH[] = ":/fossil/wizard";
+
+} // namespace Constants
+} // namespace Fossil
diff --git a/plugins/fossil/fossil.pro b/plugins/fossil/fossil.pro
new file mode 100644
index 0000000..3194652
--- /dev/null
+++ b/plugins/fossil/fossil.pro
@@ -0,0 +1,45 @@
+isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE = $$(QTC_SOURCE)
+isEmpty(IDE_SOURCE_TREE): error("You need to set the environment variable QTC_SOURCE to point to the directory where the Qt Creator sources are")
+
+isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE = $$(QTC_BUILD)
+isEmpty(IDE_BUILD_TREE): error("You need to set the environment variable QTC_BUILD to point to the directory where Qt Creator was built")
+
+include($$IDE_SOURCE_TREE/src/qtcreatorplugin.pri)
+SOURCES += \
+ fossilclient.cpp \
+ fossilcontrol.cpp \
+ fossilplugin.cpp \
+ optionspage.cpp \
+ fossilsettings.cpp \
+ commiteditor.cpp \
+ fossilcommitwidget.cpp \
+ fossileditor.cpp \
+ annotationhighlighter.cpp \
+ pullorpushdialog.cpp \
+ branchinfo.cpp \
+ configuredialog.cpp \
+ revisioninfo.cpp \
+ wizard/fossiljsextension.cpp
+HEADERS += \
+ fossilclient.h \
+ constants.h \
+ fossilcontrol.h \
+ fossilplugin.h \
+ optionspage.h \
+ fossilsettings.h \
+ commiteditor.h \
+ fossilcommitwidget.h \
+ fossileditor.h \
+ annotationhighlighter.h \
+ pullorpushdialog.h \
+ branchinfo.h \
+ configuredialog.h \
+ revisioninfo.h \
+ wizard/fossiljsextension.h
+FORMS += \
+ optionspage.ui \
+ revertdialog.ui \
+ fossilcommitpanel.ui \
+ pullorpushdialog.ui \
+ configuredialog.ui
+RESOURCES += fossil.qrc
diff --git a/plugins/fossil/fossil.qrc b/plugins/fossil/fossil.qrc
new file mode 100644
index 0000000..4e19573
--- /dev/null
+++ b/plugins/fossil/fossil.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/fossil">
+ <file>wizard/projects/vcs/icon.png</file>
+ <file>wizard/projects/vcs/wizard.json</file>
+ </qresource>
+</RCC>
diff --git a/plugins/fossil/fossil_dependencies.pri b/plugins/fossil/fossil_dependencies.pri
new file mode 100644
index 0000000..44d5212
--- /dev/null
+++ b/plugins/fossil/fossil_dependencies.pri
@@ -0,0 +1,9 @@
+QTC_PLUGIN_NAME = Fossil
+QTC_LIB_DEPENDS += \
+ extensionsystem \
+ utils
+QTC_PLUGIN_DEPENDS += \
+ texteditor \
+ projectexplorer \
+ coreplugin \
+ vcsbase
diff --git a/plugins/fossil/fossilclient.cpp b/plugins/fossil/fossilclient.cpp
new file mode 100644
index 0000000..6e88166
--- /dev/null
+++ b/plugins/fossil/fossilclient.cpp
@@ -0,0 +1,1201 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "fossilclient.h"
+#include "constants.h"
+
+#include <coreplugin/id.h>
+
+#include <vcsbase/vcsbaseplugin.h>
+#include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/vcsbaseeditorconfig.h>
+#include <vcsbase/vcsoutputwindow.h>
+#include <vcsbase/vcscommand.h>
+
+#include <utils/algorithm.h>
+#include <utils/fileutils.h>
+#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
+
+#include <QSyntaxHighlighter>
+
+#include <QDateTime>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QMap>
+#include <QRegularExpression>
+
+namespace Fossil {
+namespace Internal {
+
+// Parameter widget controlling whitespace diff mode, associated with a parameter
+class FossilDiffConfig : public VcsBase::VcsBaseEditorConfig
+{
+ Q_OBJECT
+
+public:
+ FossilDiffConfig(FossilClient *client, QToolBar *toolBar) :
+ VcsBase::VcsBaseEditorConfig(toolBar)
+ {
+ QTC_ASSERT(client, return);
+
+ VcsBase::VcsBaseClientSettings &settings = client->settings();
+ FossilClient::SupportedFeatures features = client->supportedFeatures();
+
+ if (features.testFlag(FossilClient::DiffIgnoreWhiteSpaceFeature)) {
+ mapSetting(addToggleButton("-w", tr("Ignore All Whitespace")),
+ settings.boolPointer(FossilSettings::diffIgnoreAllWhiteSpaceKey));
+ mapSetting(addToggleButton("--strip-trailing-cr", tr("Strip Trailing CR")),
+ settings.boolPointer(FossilSettings::diffStripTrailingCRKey));
+ }
+ }
+};
+
+// Parameter widget controlling annotate/blame mode
+class FossilAnnotateConfig : public VcsBase::VcsBaseEditorConfig
+{
+ Q_OBJECT
+
+public:
+ FossilAnnotateConfig(FossilClient *client, QToolBar *toolBar) :
+ VcsBase::VcsBaseEditorConfig(toolBar)
+ {
+ QTC_ASSERT(client, return);
+
+ VcsBase::VcsBaseClientSettings &settings = client->settings();
+ FossilClient::SupportedFeatures features = client->supportedFeatures();
+
+ if (features.testFlag(FossilClient::AnnotateBlameFeature)) {
+ mapSetting(addToggleButton("|BLAME|", tr("Show Committers")),
+ settings.boolPointer(FossilSettings::annotateShowCommittersKey));
+ }
+ }
+};
+
+class FossilLogCurrentFileConfig : public VcsBase::VcsBaseEditorConfig
+{
+ Q_OBJECT
+
+public:
+ FossilLogCurrentFileConfig(FossilClient *client, QToolBar *toolBar) :
+ VcsBase::VcsBaseEditorConfig(toolBar)
+ {
+ QTC_ASSERT(client, return);
+ }
+
+};
+
+class FossilLogConfig : public VcsBase::VcsBaseEditorConfig
+{
+ Q_OBJECT
+
+public:
+ FossilLogConfig(FossilClient *client, QToolBar *toolBar) :
+ VcsBase::VcsBaseEditorConfig(toolBar),
+ m_client(client)
+ {
+ QTC_ASSERT(client, return);
+
+ addLineageComboBox();
+ addVerboseToggleButton();
+ addItemTypeComboBox();
+ }
+
+ void addLineageComboBox()
+ {
+ VcsBase::VcsBaseClientSettings &settings = m_client->settings();
+
+ // ancestors/descendants filter
+ // This is a positional argument not an option.
+ // Normally it takes the checkin/branch/tag as an additional parameter
+ // (trunk by default)
+ // So we kludge this by coding it as a meta-option (pipe-separated),
+ // then parse it out in arguments.
+ // All-choice is a blank argument with no additional parameters
+ QList<ComboBoxItem> lineageFilterChoices;
+ lineageFilterChoices << ComboBoxItem(tr("Ancestors"), "ancestors")
+ << ComboBoxItem(tr("Descendants"), "descendants")
+ << ComboBoxItem(tr("Unfiltered"), "");
+ mapSetting(addComboBox(QStringList("|LINEAGE|%1|current"), lineageFilterChoices),
+ settings.stringPointer(FossilSettings::timelineLineageFilterKey));
+ }
+
+ void addVerboseToggleButton()
+ {
+ VcsBase::VcsBaseClientSettings &settings = m_client->settings();
+
+ // show files
+ mapSetting(addToggleButton("-showfiles", tr("Verbose"),
+ tr("Show files changed in each revision")),
+ settings.boolPointer(FossilSettings::timelineVerboseKey));
+ }
+
+ void addItemTypeComboBox()
+ {
+ VcsBase::VcsBaseClientSettings &settings = m_client->settings();
+
+ // option: -t <val>
+ const QList<ComboBoxItem> itemTypeChoices = {
+ ComboBoxItem(tr("All Items"), "all"),
+ ComboBoxItem(tr("File Commits"), "ci"),
+ ComboBoxItem(tr("Technical Notes"), "e"),
+ ComboBoxItem(tr("Tags"), "g"),
+ ComboBoxItem(tr("Tickets"), "t"),
+ ComboBoxItem(tr("Wiki Commits"), "w")
+ };
+
+ // here we setup the ComboBox to map to the "-t <val>", which will produce
+ // the enquoted option-values (e.g "-t all").
+ // Fossil expects separate arguments for option and value ( i.e. "-t" "all")
+ // so we need to handle the splitting explicitly in arguments().
+ mapSetting(addComboBox(QStringList("-t %1"), itemTypeChoices),
+ settings.stringPointer(FossilSettings::timelineItemTypeKey));
+ }
+
+ QStringList arguments() const final
+ {
+ QStringList args;
+
+ // split "-t val" => "-t" "val"
+ foreach (const QString &arg, VcsBaseEditorConfig::arguments()) {
+ if (arg.startsWith("-t")) {
+ args << arg.split(' ');
+
+ } else if (arg.startsWith('|')){
+ // meta-option: "|OPT|val|extra1|..."
+ QStringList params = arg.split('|');
+ QString option = params[1];
+ for (int i = 2; i < params.size(); ++i) {
+ if (option == "LINEAGE" && params[i].isEmpty()) {
+ // empty lineage filter == Unfiltered
+ break;
+ }
+ args << params[i];
+ }
+
+ } else {
+ args << arg;
+ }
+ }
+
+ return args;
+ }
+
+private:
+ FossilClient *m_client;
+};
+
+unsigned FossilClient::makeVersionNumber(int major, int minor, int patch)
+{
+ return (QString().setNum(major).toUInt(0,16) << 16) +
+ (QString().setNum(minor).toUInt(0,16) << 8) +
+ (QString().setNum(patch).toUInt(0,16));
+}
+
+static inline QString versionPart(unsigned part)
+{
+ return QString::number(part & 0xff, 16);
+}
+
+QString FossilClient::makeVersionString(unsigned version)
+{
+ return QString::fromLatin1("%1.%2.%3")
+ .arg(versionPart(version >> 16))
+ .arg(versionPart(version >> 8))
+ .arg(versionPart(version));
+}
+
+FossilClient::FossilClient() : VcsBase::VcsBaseClient(new FossilSettings)
+{
+ setDiffConfigCreator([this](QToolBar *toolBar) {
+ return new FossilDiffConfig(this, toolBar);
+ });
+}
+
+unsigned int FossilClient::synchronousBinaryVersion() const
+{
+ if (settings().binaryPath().isEmpty())
+ return 0;
+
+ QStringList args("version");
+
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(QString(), args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return 0;
+
+ QString output = response.stdOut();
+ output = output.trimmed();
+
+ // fossil version:
+ // "This is fossil version 1.27 [ccdefa355b] 2013-09-30 11:47:18 UTC"
+ QRegularExpression versionPattern("(\\d+)\\.(\\d+)");
+ QTC_ASSERT(versionPattern.isValid(), return 0);
+ QRegularExpressionMatch versionMatch = versionPattern.match(output);
+ QTC_ASSERT(versionMatch.hasMatch(), return 0);
+ const int major = versionMatch.captured(1).toInt();
+ const int minor = versionMatch.captured(2).toInt();
+ const int patch = 0;
+ return makeVersionNumber(major,minor,patch);
+}
+
+QList<BranchInfo> FossilClient::branchListFromOutput(const QString &output, const BranchInfo::BranchFlags defaultFlags)
+{
+ // Branch list format:
+ // " branch-name"
+ // "* current-branch"
+ return Utils::transform(output.split('\n', QString::SkipEmptyParts), [=](const QString& l) {
+ const QString &name = l.mid(2);
+ QTC_ASSERT(!name.isEmpty(), return BranchInfo());
+ const BranchInfo::BranchFlags flags = (l.startsWith("* ") ? defaultFlags | BranchInfo::Current : defaultFlags);
+ return BranchInfo(name, flags);
+ });
+}
+
+BranchInfo FossilClient::synchronousCurrentBranch(const QString &workingDirectory)
+{
+ if (workingDirectory.isEmpty())
+ return BranchInfo();
+
+ // First try to get the current branch from the list of open branches
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, {"branch", "list"});
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return BranchInfo();
+
+ const QString output = sanitizeFossilOutput(response.stdOut());
+ BranchInfo currentBranch = Utils::findOrDefault(branchListFromOutput(output), [](const BranchInfo &b) {
+ return b.isCurrent();
+ });
+
+ if (!currentBranch.isCurrent()) {
+ // If not available from open branches, request it from the list of closed branches.
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, {"branch", "list", "--closed"});
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return BranchInfo();
+
+ const QString output = sanitizeFossilOutput(response.stdOut());
+ currentBranch = Utils::findOrDefault(branchListFromOutput(output, BranchInfo::Closed), [](const BranchInfo &b) {
+ return b.isCurrent();
+ });
+ }
+
+ return currentBranch;
+}
+
+QList<BranchInfo> FossilClient::synchronousBranchQuery(const QString &workingDirectory)
+{
+ // Return a list of all branches, including the closed ones.
+ // Sort the list by branch name.
+
+ if (workingDirectory.isEmpty())
+ return QList<BranchInfo>();
+
+ // First get list of open branches
+ Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, {"branch", "list"});
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return QList<BranchInfo>();
+
+ QString output = sanitizeFossilOutput(response.stdOut());
+ QList<BranchInfo> branches = branchListFromOutput(output);
+
+ // Append a list of closed branches.
+ response = vcsFullySynchronousExec(workingDirectory, {"branch", "list", "--closed"});
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return QList<BranchInfo>();
+
+ output = sanitizeFossilOutput(response.stdOut());
+ branches.append(branchListFromOutput(output, BranchInfo::Closed));
+
+ std::sort(branches.begin(), branches.end(),
+ [](const BranchInfo &a, const BranchInfo &b) { return a.name() < b.name(); });
+ return branches;
+}
+
+RevisionInfo FossilClient::synchronousRevisionQuery(const QString &workingDirectory, const QString &id)
+{
+ // Query details of the given revision/check-out id,
+ // if none specified, provide information about current revision
+ if (workingDirectory.isEmpty())
+ return RevisionInfo();
+
+ QStringList args("info");
+ if (!id.isEmpty())
+ args << id;
+
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return RevisionInfo();
+
+ const QString output = sanitizeFossilOutput(response.stdOut());
+
+ QString revisionId;
+ QString parentId;
+
+ const QRegularExpression idRx("([0-9a-f]{5,40})");
+ QTC_ASSERT(idRx.isValid(), return RevisionInfo());
+
+ for (const QString &l : output.split('\n', QString::SkipEmptyParts)) {
+ if (l.startsWith("checkout: ", Qt::CaseInsensitive)
+ || l.startsWith("uuid: ", Qt::CaseInsensitive)) {
+ const QRegularExpressionMatch idMatch = idRx.match(l);
+ QTC_ASSERT(idMatch.hasMatch(), return RevisionInfo());
+ revisionId = idMatch.captured(1);
+
+ } else if (l.startsWith("parent: ", Qt::CaseInsensitive)){
+ const QRegularExpressionMatch idMatch = idRx.match(l);
+ if (idMatch.hasMatch())
+ parentId = idMatch.captured(1);
+ }
+ }
+
+ // make sure id at least partially matches the retrieved revisionId
+ QTC_ASSERT(revisionId.startsWith(id, Qt::CaseInsensitive), return RevisionInfo());
+
+ if (parentId.isEmpty())
+ parentId = revisionId; // root
+
+ return RevisionInfo(revisionId, parentId);
+}
+
+QStringList FossilClient::synchronousTagQuery(const QString &workingDirectory, const QString &id)
+{
+ // Return a list of tags for the given revision.
+ // If no revision specified, all defined tags are listed.
+ // Tag list includes branch names.
+
+ if (workingDirectory.isEmpty())
+ return QStringList();
+
+ QStringList args({"tag", "list"});
+
+ if (!id.isEmpty())
+ args << id;
+
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return QStringList();
+
+ const QString output = sanitizeFossilOutput(response.stdOut());
+
+ return output.split('\n', QString::SkipEmptyParts);
+}
+
+RepositorySettings FossilClient::synchronousSettingsQuery(const QString &workingDirectory)
+{
+ if (workingDirectory.isEmpty())
+ return RepositorySettings();
+
+ RepositorySettings repoSettings;
+
+ repoSettings.user = synchronousUserDefaultQuery(workingDirectory);
+ if (repoSettings.user.isEmpty())
+ repoSettings.user = settings().stringValue(FossilSettings::userNameKey);
+
+ const QStringList args("settings");
+
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return RepositorySettings();
+
+ const QString output = sanitizeFossilOutput(response.stdOut());
+
+ for (const QString &line : output.split('\n', QString::SkipEmptyParts)) {
+ // parse settings line:
+ // <property> <(local|global)> <value>
+ // Fossil properties are case-insensitive; force them to lower-case.
+ // Values may be in mixed-case; force lower-case for fixed values.
+ const QStringList fields = line.split(' ', QString::SkipEmptyParts);
+
+ const QString property = fields.at(0).toLower();
+ const QString value = (fields.size() >= 3 ? fields.at(2) : QString());
+ const QString lcValue = value.toLower();
+
+ if (property == "autosync") {
+ if (lcValue == "on"
+ || lcValue == "1")
+ repoSettings.autosync = RepositorySettings::AutosyncOn;
+ else if (lcValue == "off"
+ || lcValue == "0")
+ repoSettings.autosync = RepositorySettings::AutosyncOff;
+ else if (lcValue == "pullonly"
+ || lcValue == "2")
+ repoSettings.autosync = RepositorySettings::AutosyncPullOnly;
+ }
+
+ if (property == "ssl-identity") {
+ repoSettings.sslIdentityFile = value;
+ }
+ }
+
+ return repoSettings;
+}
+
+bool FossilClient::synchronousSetSetting(const QString &workingDirectory,
+ const QString &property, const QString &value, bool isGlobal)
+{
+ // set a repository property to the given value
+ // if no value is given, unset the property
+
+ if (workingDirectory.isEmpty() || property.isEmpty())
+ return false;
+
+ QStringList args;
+ if (value.isEmpty())
+ args << "unset" << property;
+ else
+ args << "settings" << property << value;
+
+ if (isGlobal)
+ args << "--global";
+
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ return (response.result == Utils::SynchronousProcessResponse::Finished);
+}
+
+
+bool FossilClient::synchronousConfigureRepository(const QString &workingDirectory, const RepositorySettings &newSettings,
+ const RepositorySettings &currentSettings)
+{
+ if (workingDirectory.isEmpty())
+ return false;
+
+ // apply updated settings vs. current setting if given
+ const bool applyAll = (currentSettings == RepositorySettings());
+
+ if (!newSettings.user.isEmpty()
+ && (applyAll
+ || newSettings.user != currentSettings.user)
+ && !synchronousSetUserDefault(workingDirectory, newSettings.user)){
+ return false;
+ }
+
+ if ((applyAll
+ || newSettings.sslIdentityFile != currentSettings.sslIdentityFile)
+ && !synchronousSetSetting(workingDirectory, "ssl-identity", newSettings.sslIdentityFile)){
+ return false;
+ }
+
+ if (applyAll
+ || newSettings.autosync != currentSettings.autosync) {
+ QString value;
+ switch (newSettings.autosync) {
+ case RepositorySettings::AutosyncOff:
+ value = "off";
+ break;
+ case RepositorySettings::AutosyncOn:
+ value = "on";
+ break;
+ case RepositorySettings::AutosyncPullOnly:
+ value = "pullonly";
+ break;
+ }
+
+ if (!synchronousSetSetting(workingDirectory, "autosync", value))
+ return false;
+ }
+
+ return true;
+}
+
+QString FossilClient::synchronousUserDefaultQuery(const QString &workingDirectory)
+{
+ if (workingDirectory.isEmpty())
+ return QString();
+
+ const QStringList args({"user", "default"});
+
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return QString();
+
+ QString output = sanitizeFossilOutput(response.stdOut());
+
+ return output.trimmed();
+}
+
+bool FossilClient::synchronousSetUserDefault(const QString &workingDirectory, const QString &userName)
+{
+ if (workingDirectory.isEmpty() || userName.isEmpty())
+ return false;
+
+ // set repository-default user
+ const QStringList args({"user", "default", userName, "--user", userName});
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ return (response.result == Utils::SynchronousProcessResponse::Finished);
+}
+
+QString FossilClient::synchronousGetRepositoryURL(const QString &workingDirectory)
+{
+ if (workingDirectory.isEmpty())
+ return QString();
+
+ const QStringList args("remote-url");
+
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return QString();
+
+ QString output = sanitizeFossilOutput(response.stdOut());
+ output = output.trimmed();
+
+ // Fossil returns "off" when no remote-url is set.
+ if (output.isEmpty() || output.toLower() == "off")
+ return QString();
+
+ return output;
+}
+
+struct TopicData
+{
+ QDateTime timeStamp;
+ QString topic;
+};
+
+QString FossilClient::synchronousTopic(const QString &workingDirectory)
+{
+ static QMap<QString, TopicData> topicCache;
+
+ if (workingDirectory.isEmpty())
+ return QString();
+
+ // return current branch name
+
+ const QString topLevel = findTopLevelForFile(workingDirectory);
+ const QFileInfo currentStateFile(topLevel + "/" + Constants::FOSSILREPO);
+
+ TopicData &data = topicCache[workingDirectory];
+ const QDateTime lastModified = currentStateFile.lastModified();
+ if (lastModified == data.timeStamp)
+ return data.topic;
+
+ const BranchInfo branchInfo = synchronousCurrentBranch(workingDirectory);
+ if (branchInfo.name().isEmpty())
+ return QString();
+
+ data.timeStamp = lastModified;
+ data.topic = branchInfo.name();
+ return data.topic;
+}
+
+bool FossilClient::synchronousCreateRepository(const QString &workingDirectory, const QStringList &extraOptions)
+{
+ VcsBase::VcsOutputWindow *outputWindow = VcsBase::VcsOutputWindow::instance();
+
+ // init repository file of the same name as the working directory
+ // use the configured default repository location for path
+ // use the configured default user for admin
+
+ const QString repoName = QDir(workingDirectory).dirName().simplified();
+ const QString repoPath = settings().stringValue(FossilSettings::defaultRepoPathKey);
+ const QString adminUser = settings().stringValue(FossilSettings::userNameKey);
+
+ if (repoName.isEmpty() || repoPath.isEmpty())
+ return false;
+
+ // @TODO: handle spaces in the path
+ // @TODO: what about --template options?
+
+ const Utils::FileName repoFilePath = Utils::FileName::fromString(repoPath)
+ .appendPath(Utils::FileName::fromString(repoName, Constants::FOSSIL_FILE_SUFFIX).toString());
+ QStringList args(vcsCommandString(CreateRepositoryCommand));
+ if (!adminUser.isEmpty())
+ args << "--admin-user" << adminUser;
+ args << extraOptions << repoFilePath.toUserOutput();
+ Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return false;
+
+ QString output = sanitizeFossilOutput(response.stdOut());
+ outputWindow->append(output);
+
+ // check out the created repository file into the working directory
+
+ args.clear();
+ response.clear();
+ output.clear();
+
+ args << "open" << repoFilePath.toUserOutput();
+ response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return false;
+
+ output = sanitizeFossilOutput(response.stdOut());
+ outputWindow->append(output);
+
+ // set user default to admin if specified
+
+ if (!adminUser.isEmpty()) {
+ args.clear();
+ response.clear();
+ output.clear();
+
+ args << "user" << "default" << adminUser << "--user" << adminUser;
+ response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return false;
+
+ QString output = sanitizeFossilOutput(response.stdOut());
+ outputWindow->append(output);
+ }
+
+ resetCachedVcsInfo(workingDirectory);
+
+ return true;
+}
+
+bool FossilClient::synchronousMove(const QString &workingDir,
+ const QString &from, const QString &to,
+ const QStringList &extraOptions)
+{
+ // Fossil move does not rename actual file on disk, only changes it in repo
+ // So try to move the actual file first, then move it in repo to preserve
+ // history in case actual move fails.
+
+ if (!QFile::rename(from, to))
+ return false;
+
+ QStringList args(vcsCommandString(MoveCommand));
+ args << extraOptions << from << to;
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDir, args);
+ return (response.result == Utils::SynchronousProcessResponse::Finished);
+}
+
+bool FossilClient::synchronousPull(const QString &workingDir, const QString &srcLocation, const QStringList &extraOptions)
+{
+ const QString remoteLocation = (!srcLocation.isEmpty() ? srcLocation : synchronousGetRepositoryURL(workingDir));
+ if (remoteLocation.isEmpty())
+ return false;
+
+ QStringList args({vcsCommandString(PullCommand), remoteLocation});
+ args << extraOptions;
+ // Disable UNIX terminals to suppress SSH prompting
+ const unsigned flags =
+ VcsBase::VcsCommand::SshPasswordPrompt
+ | VcsBase::VcsCommand::ShowStdOut
+ | VcsBase::VcsCommand::ShowSuccessMessage;
+ const Utils::SynchronousProcessResponse resp = vcsSynchronousExec(workingDir, args, flags);
+ const bool success = (resp.result == Utils::SynchronousProcessResponse::Finished);
+ if (success)
+ emit changed(QVariant(workingDir));
+ return success;
+}
+
+bool FossilClient::synchronousPush(const QString &workingDir, const QString &dstLocation, const QStringList &extraOptions)
+{
+ const QString remoteLocation = (!dstLocation.isEmpty() ? dstLocation : synchronousGetRepositoryURL(workingDir));
+ if (remoteLocation.isEmpty())
+ return false;
+
+ QStringList args({vcsCommandString(PushCommand), remoteLocation});
+ args << extraOptions;
+ // Disable UNIX terminals to suppress SSH prompting
+ const unsigned flags =
+ VcsBase::VcsCommand::SshPasswordPrompt
+ | VcsBase::VcsCommand::ShowStdOut
+ | VcsBase::VcsCommand::ShowSuccessMessage;
+ const Utils::SynchronousProcessResponse resp = vcsSynchronousExec(workingDir, args, flags);
+ return (resp.result == Utils::SynchronousProcessResponse::Finished);
+}
+
+void FossilClient::commit(const QString &repositoryRoot, const QStringList &files,
+ const QString &commitMessageFile, const QStringList &extraOptions)
+{
+ VcsBaseClient::commit(repositoryRoot, files, commitMessageFile,
+ QStringList(extraOptions) << "-M" << commitMessageFile);
+}
+
+VcsBase::VcsBaseEditorWidget *FossilClient::annotate(
+ const QString &workingDir, const QString &file, const QString &revision,
+ int lineNumber, const QStringList &extraOptions)
+{
+ // 'fossil annotate' command has a variant 'fossil blame'.
+ // blame command attributes a committing username to source lines,
+ // annotate shows line numbers
+
+ QString vcsCmdString = vcsCommandString(AnnotateCommand);
+ const Core::Id kind = vcsEditorKind(AnnotateCommand);
+ const QString id = VcsBase::VcsBaseEditor::getSource(workingDir, QStringList(file));
+ const QString title = vcsEditorTitle(vcsCmdString, id);
+ const QString source = VcsBase::VcsBaseEditor::getSource(workingDir, file);
+
+ VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source,
+ VcsBase::VcsBaseEditor::getCodec(source),
+ vcsCmdString.toLatin1().constData(), id);
+ QStringList effectiveArgs = extraOptions;
+ if (!editor->configurationAdded()) {
+ if (VcsBase::VcsBaseEditorConfig *editorConfig = createAnnotateEditor(editor)) {
+ // editor has been just created, createVcsEditor() didn't set a configuration widget yet
+ connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
+ [=] { return this->annotate(workingDir, file, revision, lineNumber, extraOptions + editorConfig->arguments()); } );
+ effectiveArgs += editorConfig->arguments();
+ editor->setConfigurationAdded();
+ }
+ }
+
+ VcsBase::VcsCommand *cmd = createCommand(workingDir, editor);
+ cmd->setCookie(lineNumber);
+
+ // here we introduce a "|BLAME|" meta-option to allow both annotate and blame modes
+ int pos = effectiveArgs.indexOf("|BLAME|");
+ if (pos != -1) {
+ vcsCmdString = "blame";
+ effectiveArgs.removeAt(pos);
+ }
+ QStringList args(vcsCmdString);
+ args << revisionSpec(revision) << effectiveArgs << "--log" << file;
+
+ enqueueJob(cmd, args);
+ return editor;
+}
+
+bool FossilClient::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ // true for any dir or file other than fossil checkout db-file
+ return !(fileName.toFileInfo().isFile()
+ && fileName.fileName().compare(Constants::FOSSILREPO, Utils::HostOsInfo::fileNameCaseSensitivity()));
+}
+
+QString FossilClient::findTopLevelForFile(const QFileInfo &file) const
+{
+ const QString repositoryCheckFile = Constants::FOSSILREPO;
+ return file.isDir() ?
+ VcsBase::VcsBasePlugin::findRepositoryForDirectory(file.absoluteFilePath(),
+ repositoryCheckFile) :
+ VcsBase::VcsBasePlugin::findRepositoryForDirectory(file.absolutePath(),
+ repositoryCheckFile);
+}
+
+bool FossilClient::managesFile(const QString &workingDirectory, const QString &fileName) const
+{
+ const QStringList args({"finfo", fileName});
+ const Utils::SynchronousProcessResponse response = vcsFullySynchronousExec(workingDirectory, args);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return false;
+ QString output = sanitizeFossilOutput(response.stdOut());
+ return !output.startsWith("no history for file");
+}
+
+unsigned int FossilClient::binaryVersion() const
+{
+ static unsigned int cachedBinaryVersion = 0;
+ static QString cachedBinaryPath;
+
+ const QString currentBinaryPath = settings().binaryPath().toString();
+
+ if (currentBinaryPath.isEmpty())
+ return 0;
+
+ // Invalidate cache on failed version result.
+ // Assume that fossil client options have been changed and will change again.
+ if (!cachedBinaryVersion
+ || currentBinaryPath != cachedBinaryPath) {
+ cachedBinaryVersion = synchronousBinaryVersion();
+ if (cachedBinaryVersion)
+ cachedBinaryPath = currentBinaryPath;
+ else
+ cachedBinaryPath.clear();
+ }
+
+ return cachedBinaryVersion;
+}
+
+QString FossilClient::binaryVersionString() const
+{
+ const unsigned int version = binaryVersion();
+
+ // Fossil itself does not report patch version, only maj.min
+ // Here we include the patch part for general convention consistency
+
+ return makeVersionString(version);
+}
+
+FossilClient::SupportedFeatures FossilClient::supportedFeatures() const
+{
+ // use for legacy client support to test for feature presence
+ // e.g. supportedFeatures().testFlag(TimelineWidthFeature)
+
+ SupportedFeatures features = AllSupportedFeatures; // all inclusive by default (~0U)
+
+ const unsigned int version = binaryVersion();
+
+ if (version < 0x13000) {
+ features &= ~TimelinePathFeature;
+ if (version < 0x12900)
+ features &= ~DiffIgnoreWhiteSpaceFeature;
+ if (version < 0x12800) {
+ features &= ~AnnotateBlameFeature;
+ features &= ~TimelineWidthFeature;
+ }
+ }
+ return features;
+}
+
+void FossilClient::view(const QString &source, const QString &id, const QStringList &extraOptions)
+{
+ QStringList args("diff");
+
+ const QFileInfo fi(source);
+ const QString workingDirectory = fi.isFile() ? fi.absolutePath() : source;
+
+ RevisionInfo revisionInfo = synchronousRevisionQuery(workingDirectory,id);
+
+ args << "--from" << revisionInfo.parentId
+ << "--to" << revisionInfo.id
+ << "-v"
+ << extraOptions;
+
+ const Core::Id kind = vcsEditorKind(DiffCommand);
+ const QString title = vcsEditorTitle(vcsCommandString(DiffCommand), id);
+
+ VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source,
+ VcsBase::VcsBaseEditor::getCodec(source), "view", id);
+ editor->setWorkingDirectory(workingDirectory);
+
+ enqueueJob(createCommand(workingDirectory, editor), args);
+}
+
+class FossilLogHighlighter : QSyntaxHighlighter
+{
+public:
+ explicit FossilLogHighlighter(QTextDocument *parent);
+ virtual void highlightBlock(const QString &text) final;
+
+private:
+ const QRegularExpression m_revisionIdRx;
+ const QRegularExpression m_dateRx;
+};
+
+FossilLogHighlighter::FossilLogHighlighter(QTextDocument * parent) :
+ QSyntaxHighlighter(parent),
+ m_revisionIdRx(Constants::CHANGESET_ID),
+ m_dateRx("([0-9]{4}-[0-9]{2}-[0-9]{2})")
+{
+ QTC_CHECK(m_revisionIdRx.isValid());
+ QTC_CHECK(m_dateRx.isValid());
+}
+
+void FossilLogHighlighter::highlightBlock(const QString &text)
+{
+ // Match the revision-ids and dates -- highlight them for convenience.
+
+ // Format revision-ids
+ QRegularExpressionMatchIterator i = m_revisionIdRx.globalMatch(text);
+ while (i.hasNext()) {
+ const QRegularExpressionMatch revisionIdMatch = i.next();
+ QTextCharFormat charFormat = format(0);
+ charFormat.setForeground(Qt::darkBlue);
+ //charFormat.setFontItalic(true);
+ setFormat(revisionIdMatch.capturedStart(0), revisionIdMatch.capturedLength(0), charFormat);
+ }
+
+ // Format dates
+ i = m_dateRx.globalMatch(text);
+ while (i.hasNext()) {
+ const QRegularExpressionMatch dateMatch = i.next();
+ QTextCharFormat charFormat = format(0);
+ charFormat.setForeground(Qt::darkBlue);
+ charFormat.setFontWeight(QFont::DemiBold);
+ setFormat(dateMatch.capturedStart(0), dateMatch.capturedLength(0), charFormat);
+ }
+}
+
+void FossilClient::log(const QString &workingDir, const QStringList &files,
+ const QStringList &extraOptions,
+ bool enableAnnotationContextMenu)
+{
+ // Show timeline for both repository and a file or path (--path <file-or-path>)
+ // When used for log repository, the files list is empty
+
+ // LEGACY:fallback to log current file with legacy clients
+ SupportedFeatures features = supportedFeatures();
+ if (!files.isEmpty()
+ && !features.testFlag(TimelinePathFeature)) {
+ logCurrentFile(workingDir, files, extraOptions, enableAnnotationContextMenu);
+ return;
+ }
+
+ const QString vcsCmdString = vcsCommandString(LogCommand);
+ const Core::Id kind = vcsEditorKind(LogCommand);
+ const QString id = VcsBase::VcsBaseEditor::getTitleId(workingDir, files);
+ const QString title = vcsEditorTitle(vcsCmdString, id);
+ const QString source = VcsBase::VcsBaseEditor::getSource(workingDir, files);
+ VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source,
+ VcsBase::VcsBaseEditor::getCodec(source),
+ vcsCmdString.toLatin1().constData(), id);
+ editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
+
+ QStringList effectiveArgs = extraOptions;
+ if (!editor->configurationAdded()) {
+ if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(editor)) {
+ // editor has been just created, createVcsEditor() didn't set a configuration widget yet
+ connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
+ [=]() { this->log(workingDir, files, extraOptions + editorConfig->arguments(), enableAnnotationContextMenu); } );
+ effectiveArgs += editorConfig->arguments();
+ editor->setConfigurationAdded();
+ }
+ }
+
+ //@TODO: move highlighter and widgets to fossil editor sources.
+
+ new FossilLogHighlighter(editor->document());
+
+ QStringList args(vcsCmdString);
+ args << effectiveArgs;
+ if (!files.isEmpty())
+ args << "--path" << files;
+ enqueueJob(createCommand(workingDir, editor), args);
+}
+
+void FossilClient::logCurrentFile(const QString &workingDir, const QStringList &files,
+ const QStringList &extraOptions,
+ bool enableAnnotationContextMenu)
+{
+ // Show commit history for the given file/file-revision
+ // NOTE: 'fossil finfo' shows full history from all branches.
+
+ // With newer clients, 'fossil timeline' can handle both repository and file
+ SupportedFeatures features = supportedFeatures();
+ if (features.testFlag(TimelinePathFeature)) {
+ log(workingDir, files, extraOptions, enableAnnotationContextMenu);
+ return;
+ }
+
+ const QString vcsCmdString = "finfo";
+ const Core::Id kind = vcsEditorKind(LogCommand);
+ const QString id = VcsBase::VcsBaseEditor::getTitleId(workingDir, files);
+ const QString title = vcsEditorTitle(vcsCmdString, id);
+ const QString source = VcsBase::VcsBaseEditor::getSource(workingDir, files);
+ VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source,
+ VcsBase::VcsBaseEditor::getCodec(source),
+ vcsCmdString.toLatin1().constData(), id);
+ editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
+
+ QStringList effectiveArgs = extraOptions;
+ if (!editor->configurationAdded()) {
+ if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(editor)) {
+ // editor has been just created, createVcsEditor() didn't set a configuration widget yet
+ connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
+ [=]() { this->logCurrentFile(workingDir, files, extraOptions + editorConfig->arguments(), enableAnnotationContextMenu); } );
+ effectiveArgs += editorConfig->arguments();
+ editor->setConfigurationAdded();
+ }
+ }
+
+ //@TODO: move highlighter and widgets to fossil editor sources.
+
+ new FossilLogHighlighter(editor->document());
+
+ QStringList args(vcsCmdString);
+ args << effectiveArgs << files;
+ enqueueJob(createCommand(workingDir, editor), args);
+}
+
+void FossilClient::revertFile(const QString &workingDir,
+ const QString &file,
+ const QString &revision,
+ const QStringList &extraOptions)
+{
+ QStringList args(vcsCommandString(RevertCommand));
+ if (!revision.isEmpty())
+ args << "-r" << revision;
+
+ args << extraOptions << file;
+
+ // Indicate file list
+ VcsBase::VcsCommand *cmd = createCommand(workingDir);
+ cmd->setCookie(QStringList(workingDir + "/" + file));
+ connect(cmd, &VcsBase::VcsCommand::success, this, &VcsBase::VcsBaseClient::changed, Qt::QueuedConnection);
+ enqueueJob(cmd, args);
+}
+
+void FossilClient::revertAll(const QString &workingDir, const QString &revision, const QStringList &extraOptions)
+{
+ // Fossil allows whole tree revert to latest revision (effectively undoing uncommitted changes).
+ // However it disallows revert to a specific revision for the whole tree, only for selected files.
+ // Use checkout --force command for such case.
+ // NOTE: all uncommitted changes will not be backed up by checkout, unlike revert.
+ // Thus undo for whole tree revert should not be possible.
+
+ QStringList args;
+ if (revision.isEmpty()) {
+ args << vcsCommandString(RevertCommand)
+ << extraOptions;
+
+ } else {
+ args << "checkout" << revision
+ << "--force"
+ << extraOptions;
+ }
+
+ // Indicate repository change
+ VcsBase::VcsCommand *cmd = createCommand(workingDir);
+ cmd->setCookie(QStringList(workingDir));
+ connect(cmd, &VcsBase::VcsCommand::success, this, &VcsBase::VcsBaseClient::changed, Qt::QueuedConnection);
+ enqueueJob(createCommand(workingDir), args);
+}
+
+QString FossilClient::sanitizeFossilOutput(const QString &output) const
+{
+#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
+ // Strip possible extra '\r' in output from the Fossil client on Windows.
+
+ // Fossil client contained a long-standing bug which caused an extraneous '\r'
+ // added to output lines from certain commands in excess of the expected <CR/LF>.
+ // While the output appeared normal on a terminal, in non-interactive context
+ // it would get incorrectly split, resulting in extra empty lines.
+ // Bug fix is fairly recent, so for compatibility we need to strip the '\r'.
+ QString result(output);
+ return result.remove('\r');
+#else
+ return output;
+#endif
+}
+
+QString FossilClient::vcsCommandString(VcsCommandTag cmd) const
+{
+ // override specific client commands
+ // otherwise return baseclient command
+
+ switch (cmd) {
+ case RemoveCommand: return QString("rm");
+ case MoveCommand: return QString("mv");
+ case LogCommand: return QString("timeline");
+
+ default: return VcsBaseClient::vcsCommandString(cmd);
+ }
+}
+
+Core::Id FossilClient::vcsEditorKind(VcsCommandTag cmd) const
+{
+ switch (cmd) {
+ case AnnotateCommand:
+ return Constants::ANNOTATELOG_ID;
+ case DiffCommand:
+ return Constants::DIFFLOG_ID;
+ case LogCommand:
+ return Constants::FILELOG_ID;
+ default:
+ return Core::Id();
+ }
+}
+
+QStringList FossilClient::revisionSpec(const QString &revision) const
+{
+ // Pass the revision verbatim.
+ // Fossil uses a variety of ways to spec the revisions.
+ // In most cases revision is passed directly (SHA1) or via tag.
+ // Tag name may need to be prefixed with tag: to disambiguate it from hex (beef).
+ // Handle the revision option per specific command (e.g. diff, revert ).
+
+ QStringList args;
+ if (!revision.isEmpty())
+ args << revision;
+ return args;
+}
+
+FossilClient::StatusItem FossilClient::parseStatusLine(const QString &line) const
+{
+ StatusItem item;
+
+ // Ref: fossil source 'src/checkin.c' status_report()
+ // Expect at least one non-leading blank space.
+
+ int pos = line.indexOf(' ');
+
+ if (line.isEmpty() || pos < 1)
+ return StatusItem();
+
+ QString label(line.left(pos));
+ QString flags;
+
+ if (label == "EDITED")
+ flags = Constants::FSTATUS_EDITED;
+ else if (label == "ADDED")
+ flags = Constants::FSTATUS_ADDED;
+ else if (label == "RENAMED")
+ flags = Constants::FSTATUS_RENAMED;
+ else if (label == "DELETED")
+ flags = Constants::FSTATUS_DELETED;
+ else if (label == "MISSING")
+ flags = "Missing";
+ else if (label == "ADDED_BY_MERGE")
+ flags = Constants::FSTATUS_ADDED_BY_MERGE;
+ else if (label == "UPDATED_BY_MERGE")
+ flags = Constants::FSTATUS_UPDATED_BY_MERGE;
+ else if (label == "ADDED_BY_INTEGRATE")
+ flags = Constants::FSTATUS_ADDED_BY_INTEGRATE;
+ else if (label == "UPDATED_BY_INTEGRATE")
+ flags = Constants::FSTATUS_UPDATED_BY_INTEGRATE;
+ else if (label == "CONFLICT")
+ flags = "Conflict";
+ else if (label == "EXECUTABLE")
+ flags = "Set Exec";
+ else if (label == "SYMLINK")
+ flags = "Set Symlink";
+ else if (label == "UNEXEC")
+ flags = "Unset Exec";
+ else if (label == "UNLINK")
+ flags = "Unset Symlink";
+ else if (label == "NOT_A_FILE")
+ flags = Constants::FSTATUS_UNKNOWN;
+
+
+ if (flags.isEmpty())
+ return StatusItem();
+
+ // adjust the position to the last space before the file name
+ for (int size = line.size(); (pos+1) < size && line[pos+1].isSpace(); ++pos) {}
+
+ item.flags = flags;
+ item.file = line.mid(pos + 1);
+
+ return item;
+}
+
+VcsBase::VcsBaseEditorConfig *FossilClient::createAnnotateEditor(VcsBase::VcsBaseEditorWidget *editor)
+{
+ return new FossilAnnotateConfig(this, editor->toolBar());
+}
+
+VcsBase::VcsBaseEditorConfig *FossilClient::createLogCurrentFileEditor(VcsBase::VcsBaseEditorWidget *editor)
+{
+ SupportedFeatures features = supportedFeatures();
+
+ if (features.testFlag(TimelinePathFeature))
+ return createLogEditor(editor);
+
+ return new FossilLogCurrentFileConfig(this, editor->toolBar());
+}
+
+VcsBase::VcsBaseEditorConfig *FossilClient::createLogEditor(VcsBase::VcsBaseEditorWidget *editor)
+{
+ return new FossilLogConfig(this, editor->toolBar());
+}
+
+} // namespace Internal
+} // namespace Fossil
+
+#include "fossilclient.moc"
diff --git a/plugins/fossil/fossilclient.h b/plugins/fossil/fossilclient.h
new file mode 100644
index 0000000..7342019
--- /dev/null
+++ b/plugins/fossil/fossilclient.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "fossilsettings.h"
+#include "branchinfo.h"
+#include "revisioninfo.h"
+
+#include <vcsbase/vcsbaseclient.h>
+
+#include <QList>
+
+namespace Fossil {
+namespace Internal {
+
+class FossilSettings;
+class FossilControl;
+
+class FossilClient : public VcsBase::VcsBaseClient
+{
+ Q_OBJECT
+public:
+ enum SupportedFeature {
+ AnnotateBlameFeature = 0x2,
+ TimelineWidthFeature = 0x4,
+ DiffIgnoreWhiteSpaceFeature = 0x8,
+ TimelinePathFeature = 0x10,
+ AllSupportedFeatures = // | all defined features
+ AnnotateBlameFeature
+ | TimelineWidthFeature
+ | DiffIgnoreWhiteSpaceFeature
+ | TimelinePathFeature
+ };
+ Q_DECLARE_FLAGS(SupportedFeatures, SupportedFeature)
+
+ static unsigned makeVersionNumber(int major, int minor, int patch);
+ static QString makeVersionString(unsigned version);
+
+ FossilClient();
+
+ unsigned int synchronousBinaryVersion() const;
+ BranchInfo synchronousCurrentBranch(const QString &workingDirectory);
+ QList<BranchInfo> synchronousBranchQuery(const QString &workingDirectory);
+ RevisionInfo synchronousRevisionQuery(const QString &workingDirectory, const QString &id = QString());
+ QStringList synchronousTagQuery(const QString &workingDirectory, const QString &id = QString());
+ RepositorySettings synchronousSettingsQuery(const QString &workingDirectory);
+ bool synchronousSetSetting(const QString &workingDirectory, const QString &property,
+ const QString &value = QString(), bool isGlobal = false);
+ bool synchronousConfigureRepository(const QString &workingDirectory, const RepositorySettings &newSettings,
+ const RepositorySettings &currentSettings = RepositorySettings());
+ QString synchronousUserDefaultQuery(const QString &workingDirectory);
+ bool synchronousSetUserDefault(const QString &workingDirectory, const QString &userName);
+ QString synchronousGetRepositoryURL(const QString &workingDirectory);
+ QString synchronousTopic(const QString &workingDirectory);
+ bool synchronousCreateRepository(const QString &workingDirectory,
+ const QStringList &extraOptions = QStringList()) final;
+ bool synchronousMove(const QString &workingDir,
+ const QString &from, const QString &to,
+ const QStringList &extraOptions = QStringList()) final;
+ bool synchronousPull(const QString &workingDir,
+ const QString &srcLocation,
+ const QStringList &extraOptions = QStringList()) final;
+ bool synchronousPush(const QString &workingDir,
+ const QString &dstLocation,
+ const QStringList &extraOptions = QStringList()) final;
+ void commit(const QString &repositoryRoot, const QStringList &files,
+ const QString &commitMessageFile, const QStringList &extraOptions = QStringList()) final;
+ VcsBase::VcsBaseEditorWidget *annotate(
+ const QString &workingDir, const QString &file, const QString &revision = QString(),
+ int lineNumber = -1, const QStringList &extraOptions = QStringList()) final;
+ void log(const QString &workingDir, const QStringList &files = QStringList(),
+ const QStringList &extraOptions = QStringList(),
+ bool enableAnnotationContextMenu = false) final;
+ void logCurrentFile(const QString &workingDir, const QStringList &files = QStringList(),
+ const QStringList &extraOptions = QStringList(),
+ bool enableAnnotationContextMenu = false);
+ void revertFile(const QString &workingDir, const QString &file,
+ const QString &revision = QString(),
+ const QStringList &extraOptions = QStringList()) final;
+ void revertAll(const QString &workingDir, const QString &revision = QString(),
+ const QStringList &extraOptions = QStringList()) final;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const;
+ QString findTopLevelForFile(const QFileInfo &file) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const;
+ unsigned int binaryVersion() const;
+ QString binaryVersionString() const;
+ SupportedFeatures supportedFeatures() const;
+ void view(const QString &source, const QString &id,
+ const QStringList &extraOptions = QStringList()) final;
+
+private:
+ static QList<BranchInfo> branchListFromOutput(const QString &output, const BranchInfo::BranchFlags defaultFlags = 0);
+
+ QString sanitizeFossilOutput(const QString &output) const;
+ QString vcsCommandString(VcsCommandTag cmd) const final;
+ Core::Id vcsEditorKind(VcsCommandTag cmd) const final;
+ QStringList revisionSpec(const QString &revision) const final;
+ StatusItem parseStatusLine(const QString &line) const final;
+ VcsBase::VcsBaseEditorConfig *createAnnotateEditor(VcsBase::VcsBaseEditorWidget *editor);
+ VcsBase::VcsBaseEditorConfig *createLogCurrentFileEditor(VcsBase::VcsBaseEditorWidget *editor);
+ VcsBase::VcsBaseEditorConfig *createLogEditor(VcsBase::VcsBaseEditorWidget *editor);
+
+ friend class FossilControl;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(FossilClient::SupportedFeatures)
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossilcommitpanel.ui b/plugins/fossil/fossilcommitpanel.ui
new file mode 100644
index 0000000..b08e788
--- /dev/null
+++ b/plugins/fossil/fossilcommitpanel.ui
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Fossil::Internal::FossilCommitPanel</class>
+ <widget class="QWidget" name="Fossil::Internal::FossilCommitPanel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>374</width>
+ <height>270</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="infoGroup">
+ <property name="title">
+ <string>Current Information</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="1" column="0">
+ <widget class="QLabel" name="localRootLabel">
+ <property name="text">
+ <string>Local root:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="localRootLineEdit">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="currentBranchLabel">
+ <property name="text">
+ <string>Branch:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="currentBranchLineEdit">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="currentTagsLabel">
+ <property name="text">
+ <string>Tags:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="currentTagsLineEdit">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="editGroup">
+ <property name="title">
+ <string>Commit Information</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="branchLabel">
+ <property name="text">
+ <string>New branch:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="branchLineEdit"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="invalidBranchLabel">
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap>:/projectexplorer/images/compile_error.png</pixmap>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QCheckBox" name="isPrivateCheckBox">
+ <property name="toolTip">
+ <string>Create a private check-in that is never synced.
+Children of private check-ins are automatically private.
+Private check-ins are not pushed to the remote repository by default.</string>
+ </property>
+ <property name="text">
+ <string>Private</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="tagsLabel">
+ <property name="text">
+ <string>Tags:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="tagsLineEdit">
+ <property name="toolTip">
+ <string>Tag names to apply; comma-separated.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="authorLabel">
+ <property name="text">
+ <string>Author:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="authorLineEdit"/>
+ </item>
+ <item row="2" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>160</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/plugins/fossil/fossilcommitwidget.cpp b/plugins/fossil/fossilcommitwidget.cpp
new file mode 100644
index 0000000..8e83127
--- /dev/null
+++ b/plugins/fossil/fossilcommitwidget.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "fossilcommitwidget.h"
+#include "branchinfo.h"
+
+#include <texteditor/texteditorsettings.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorconstants.h>
+
+#include <utils/completingtextedit.h>
+#include <utils/qtcassert.h>
+
+#include <QSyntaxHighlighter>
+#include <QTextEdit>
+
+#include <QRegularExpression>
+#include <QDir>
+
+namespace Fossil {
+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(TextEditor::C_COMMENT);
+}
+
+// Highlighter for Fossil submit messages.
+// Marks up [ticket-id] fields in the message.
+class FossilSubmitHighlighter : QSyntaxHighlighter
+{
+public:
+ explicit FossilSubmitHighlighter(Utils::CompletingTextEdit *parent);
+ void highlightBlock(const QString &text) final;
+
+private:
+ const QTextCharFormat m_commentFormat;
+ const QRegularExpression m_keywordPattern;
+};
+
+FossilSubmitHighlighter::FossilSubmitHighlighter(Utils::CompletingTextEdit *parent) : QSyntaxHighlighter(parent),
+ m_commentFormat(commentFormat()),
+ m_keywordPattern("\\[([0-9a-f]{5,40})\\]")
+{
+ QTC_CHECK(m_keywordPattern.isValid());
+}
+
+void FossilSubmitHighlighter::highlightBlock(const QString &text)
+{
+ // Fossil commit message allows listing of [ticket-id],
+ // where ticket-id is a partial SHA1.
+ // Match the ticket-ids and highlight them for convenience.
+
+ // Format keywords
+ QRegularExpressionMatchIterator i = m_keywordPattern.globalMatch(text);
+ while (i.hasNext()) {
+ const QRegularExpressionMatch keywordMatch = i.next();
+ QTextCharFormat charFormat = format(0);
+ charFormat.setFontItalic(true);
+ setFormat(keywordMatch.capturedStart(0), keywordMatch.capturedLength(0), charFormat);
+ }
+}
+
+
+FossilCommitWidget::FossilCommitWidget() : m_commitPanel(new QWidget)
+{
+ m_commitPanelUi.setupUi(m_commitPanel);
+ insertTopWidget(m_commitPanel);
+ new FossilSubmitHighlighter(descriptionEdit());
+ m_branchValidator = new QRegularExpressionValidator(QRegularExpression("[^\\n]*"), this);
+
+ connect(m_commitPanelUi.branchLineEdit, &QLineEdit::textChanged,
+ this, &FossilCommitWidget::branchChanged);
+}
+
+void FossilCommitWidget::setFields(const QString &repoPath, const BranchInfo &branch,
+ const QStringList &tags, const QString &userName)
+{
+ m_commitPanelUi.localRootLineEdit->setText(QDir::toNativeSeparators(repoPath));
+ m_commitPanelUi.currentBranchLineEdit->setText(branch.name());
+ const QString tagsText = tags.join(", ");
+ m_commitPanelUi.currentTagsLineEdit->setText(tagsText);
+ m_commitPanelUi.authorLineEdit->setText(userName);
+
+ branchChanged();
+}
+
+QString FossilCommitWidget::newBranch() const
+{
+ const QString branchName = m_commitPanelUi.branchLineEdit->text().trimmed();
+ return branchName;
+}
+
+QStringList FossilCommitWidget::tags() const
+{
+ QString tagsText = m_commitPanelUi.tagsLineEdit->text().trimmed();
+ if (tagsText.isEmpty())
+ return QStringList();
+
+ tagsText.replace(',', ' ');
+ const QStringList tags = tagsText.split(' ', QString::SkipEmptyParts);
+ return tags;
+}
+
+QString FossilCommitWidget::committer() const
+{
+ const QString author = m_commitPanelUi.authorLineEdit->text();
+ if (author.isEmpty())
+ return QString();
+
+ const QString user = author;
+ return user;
+}
+
+bool FossilCommitWidget::isPrivateOptionEnabled() const
+{
+ return m_commitPanelUi.isPrivateCheckBox->isChecked();
+}
+
+bool FossilCommitWidget::canSubmit() const
+{
+ QString message = cleanupDescription(descriptionText()).trimmed();
+
+ if (m_commitPanelUi.invalidBranchLabel->isVisible() || message.isEmpty())
+ return false;
+
+ return VcsBase::SubmitEditorWidget::canSubmit();
+}
+
+void FossilCommitWidget::branchChanged()
+{
+ m_commitPanelUi.invalidBranchLabel->setVisible(!isValidBranch());
+
+ updateSubmitAction();
+}
+
+bool FossilCommitWidget::isValidBranch() const
+{
+ int pos = m_commitPanelUi.branchLineEdit->cursorPosition();
+ QString text = m_commitPanelUi.branchLineEdit->text();
+ return m_branchValidator->validate(text, pos) == QValidator::Acceptable;
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossilcommitwidget.h b/plugins/fossil/fossilcommitwidget.h
new file mode 100644
index 0000000..55ef70f
--- /dev/null
+++ b/plugins/fossil/fossilcommitwidget.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "ui_fossilcommitpanel.h"
+
+#include <vcsbase/submiteditorwidget.h>
+
+QT_BEGIN_NAMESPACE
+class QValidator;
+QT_END_NAMESPACE
+
+
+namespace Fossil {
+namespace Internal {
+
+class BranchInfo;
+
+/*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 Fossil*/
+
+class FossilCommitWidget : public VcsBase::SubmitEditorWidget
+{
+ Q_OBJECT
+
+public:
+ FossilCommitWidget();
+
+ void setFields(const QString &repoPath,
+ const BranchInfo &newBranch, const QStringList &tags, const QString &userName);
+
+ QString newBranch() const;
+ QStringList tags() const;
+ QString committer() const;
+ bool isPrivateOptionEnabled() const;
+
+protected:
+ bool canSubmit() const;
+
+private slots:
+ void branchChanged();
+
+private:
+ bool isValidBranch() const;
+
+ QWidget *m_commitPanel;
+ Ui::FossilCommitPanel m_commitPanelUi;
+ QValidator *m_branchValidator;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossilcontrol.cpp b/plugins/fossil/fossilcontrol.cpp
new file mode 100644
index 0000000..45ef0c2
--- /dev/null
+++ b/plugins/fossil/fossilcontrol.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "constants.h"
+#include "fossilcontrol.h"
+#include "fossilclient.h"
+#include "fossilplugin.h"
+#include "wizard/fossiljsextension.h"
+
+#include <vcsbase/vcsbaseclientsettings.h>
+#include <vcsbase/vcsbaseconstants.h>
+#include <vcsbase/vcscommand.h>
+
+#include <QFileInfo>
+#include <QProcessEnvironment>
+#include <QVariant>
+#include <QStringList>
+#include <QMap>
+#include <QDir>
+#include <QUrl>
+
+using namespace Fossil::Internal;
+
+FossilControl::FossilControl(FossilClient *client) :
+ m_client(client)
+{ }
+
+QString FossilControl::displayName() const
+{
+ return tr("Fossil");
+}
+
+Core::Id FossilControl::id() const
+{
+ return Core::Id(Constants::VCS_ID_FOSSIL);
+}
+
+bool FossilControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ return m_client->isVcsFileOrDirectory(fileName);
+}
+
+bool FossilControl::managesDirectory(const QString &directory, QString *topLevel) const
+{
+ QFileInfo dir(directory);
+ const QString topLevelFound = m_client->findTopLevelForFile(dir);
+ if (topLevel)
+ *topLevel = topLevelFound;
+ return !topLevelFound.isEmpty();
+}
+
+bool FossilControl::managesFile(const QString &workingDirectory, const QString &fileName) const
+{
+ return m_client->managesFile(workingDirectory, fileName);
+}
+
+bool FossilControl::isConfigured() const
+{
+ const Utils::FileName binary = m_client->vcsBinary();
+ if (binary.isEmpty())
+ return false;
+
+ const QFileInfo fi = binary.toFileInfo();
+ if ( !(fi.exists() && fi.isFile() && fi.isExecutable()) )
+ return false;
+
+ // Local repositories default path must be set and exist
+ const QString repoPath = m_client->settings().stringValue(FossilSettings::defaultRepoPathKey);
+ if (repoPath.isEmpty())
+ return false;
+
+ const QDir dir(repoPath);
+ if (!dir.exists())
+ return false;
+
+ return true;
+}
+
+bool FossilControl::supportsOperation(Operation operation) const
+{
+ bool supported = isConfigured();
+
+ switch (operation) {
+ case Core::IVersionControl::AddOperation:
+ case Core::IVersionControl::DeleteOperation:
+ case Core::IVersionControl::MoveOperation:
+ case Core::IVersionControl::CreateRepositoryOperation:
+ case Core::IVersionControl::AnnotateOperation:
+ case Core::IVersionControl::InitialCheckoutOperation:
+ break;
+ case Core::IVersionControl::SnapshotOperations:
+ supported = false;
+ break;
+ }
+ return supported;
+}
+
+bool FossilControl::vcsOpen(const QString &filename)
+{
+ Q_UNUSED(filename)
+ return true;
+}
+
+bool FossilControl::vcsAdd(const QString &filename)
+{
+ const QFileInfo fi(filename);
+ return m_client->synchronousAdd(fi.absolutePath(), fi.fileName());
+}
+
+bool FossilControl::vcsDelete(const QString &filename)
+{
+ const QFileInfo fi(filename);
+ return m_client->synchronousRemove(fi.absolutePath(), fi.fileName());
+}
+
+bool FossilControl::vcsMove(const QString &from, const QString &to)
+{
+ const QFileInfo fromInfo(from);
+ const QFileInfo toInfo(to);
+ return m_client->synchronousMove(fromInfo.absolutePath(),
+ fromInfo.absoluteFilePath(),
+ toInfo.absoluteFilePath());
+}
+
+bool FossilControl::vcsCreateRepository(const QString &directory)
+{
+ return m_client->synchronousCreateRepository(directory);
+}
+
+bool FossilControl::vcsAnnotate(const QString &file, int line)
+{
+ const QFileInfo fi(file);
+ m_client->annotate(fi.absolutePath(), fi.fileName(), QString(), line);
+ return true;
+}
+
+QString FossilControl::vcsTopic(const QString &directory)
+{
+ return m_client->synchronousTopic(directory);
+}
+
+Core::ShellCommand *FossilControl::createInitialCheckoutCommand(const QString &sourceUrl,
+ const Utils::FileName &baseDirectory,
+ const QString &localName,
+ const QStringList &extraArgs)
+{
+ QMap<QString, QString> options;
+ FossilJsExtension::parseArgOptions(extraArgs, options);
+
+ // Two operating modes:
+ // 1) CloneCheckout:
+ // -- clone from remote-URL or a local-fossil a repository into a local-clone fossil.
+ // -- open/checkout the local-clone fossil
+ // The local-clone fossil must not point to an existing repository.
+ // Clone URL may be either schema-based (http, ssh, file) or an absolute local path.
+ //
+ // 2) LocalCheckout:
+ // -- open/checkout an existing local fossil
+ // Clone URL is an absolute local path and is the same as the local fossil.
+
+ const QString checkoutPath = Utils::FileName(baseDirectory).appendPath(localName).toString();
+ const QString fossilFile = options.value("fossil-file");
+ const Utils::FileName fossilFileName = Utils::FileName::fromUserInput(QDir::fromNativeSeparators(fossilFile));
+ const QString fossilFileNative = fossilFileName.toUserOutput();
+ const QFileInfo cloneRepository(fossilFileName.toString());
+
+ // Check when requested to clone a local repository and clone-into repository file is the same
+ // or not specified.
+ // In this case handle it as local fossil checkout request.
+ const QUrl url(sourceUrl);
+ bool isLocalRepository = (options.value("repository-type") == "localRepo");
+
+ if (url.isLocalFile() || url.isRelative()) {
+ const QFileInfo sourcePath(url.path());
+ isLocalRepository = (sourcePath.canonicalFilePath() == cloneRepository.canonicalFilePath());
+ }
+
+ // set clone repository admin user to configured user name
+ // OR override it with the specified user from clone panel
+ const QString adminUser = options.value("admin-user");
+ const bool disableAutosync = (options.value("settings-autosync") == "off");
+ const QString checkoutBranch = options.value("branch-tag");
+
+ // first create the checkout directory,
+ // as it needs to become a working directory for wizard command jobs
+
+ const QDir checkoutDir(checkoutPath);
+ checkoutDir.mkpath(checkoutPath);
+
+ // Setup the wizard page command job
+ auto command = new VcsBase::VcsCommand(checkoutDir.path(), m_client->processEnvironment());
+
+ if (!isLocalRepository
+ && !cloneRepository.exists()) {
+
+ const QString sslIdentityFile = options.value("ssl-identity");
+ const Utils::FileName sslIdentityFileName = Utils::FileName::fromUserInput(QDir::fromNativeSeparators(sslIdentityFile));
+ const bool includePrivate = (options.value("include-private") == "true");
+
+ QStringList extraOptions;
+ if (includePrivate)
+ extraOptions << "--private";
+ if (!sslIdentityFile.isEmpty())
+ extraOptions << "--ssl-identity" << sslIdentityFileName.toUserOutput();
+ if (!adminUser.isEmpty())
+ extraOptions << "--admin-user" << adminUser;
+
+ // Fossil allows saving the remote address and login. This is used to
+ // facilitate autosync (commit/update) functionality.
+ // When no password is given, it prompts for that.
+ // When both username and password are specified, it prompts whether to
+ // save them.
+ // NOTE: In non-interactive context, these prompts won't work.
+ // Fossil currently does not support SSH_ASKPASS way for login query.
+ //
+ // Alternatively, "--once" option does not save the remote details.
+ // In such case remote details must be provided on the command-line every
+ // time. This also precludes autosync.
+ //
+ // So here we want Fossil to save the remote details when specified.
+
+ QStringList args;
+ args << m_client->vcsCommandString(FossilClient::CloneCommand)
+ << extraOptions
+ << sourceUrl
+ << fossilFileNative;
+ command->addJob(m_client->vcsBinary(), args, -1);
+ }
+
+ // check out the cloned repository file into the working copy directory;
+ // by default the latest revision is checked out
+
+ QStringList args({"open", fossilFileNative});
+ if (!checkoutBranch.isEmpty())
+ args << checkoutBranch;
+ command->addJob(m_client->vcsBinary(), args, -1);
+
+ // set user default to admin user if specified
+ if (!isLocalRepository
+ && !adminUser.isEmpty()) {
+ const QStringList args({ "user", "default", adminUser, "--user", adminUser});
+ command->addJob(m_client->vcsBinary(), args, -1);
+ }
+
+ // turn-off autosync if requested
+ if (!isLocalRepository
+ && disableAutosync) {
+ const QStringList args({"settings", "autosync", "off"});
+ command->addJob(m_client->vcsBinary(), args, -1);
+ }
+
+ return command;
+}
+
+void FossilControl::changed(const QVariant &v)
+{
+ switch (v.type()) {
+ case QVariant::String:
+ emit repositoryChanged(v.toString());
+ break;
+ case QVariant::StringList:
+ emit filesChanged(v.toStringList());
+ break;
+ default:
+ break;
+ }
+}
diff --git a/plugins/fossil/fossilcontrol.h b/plugins/fossil/fossilcontrol.h
new file mode 100644
index 0000000..8a3e53f
--- /dev/null
+++ b/plugins/fossil/fossilcontrol.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <coreplugin/iversioncontrol.h>
+
+QT_BEGIN_NAMESPACE
+class QVariant;
+QT_END_NAMESPACE
+
+namespace Fossil {
+namespace Internal {
+
+class FossilClient;
+
+//Implements just the basics of the Version Control Interface
+//FossilClient handles all the work
+class FossilControl: public Core::IVersionControl
+{
+ Q_OBJECT
+
+public:
+ explicit FossilControl(FossilClient *fossilClient);
+
+ QString displayName() const final;
+ Core::Id id() const final;
+
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
+ bool managesDirectory(const QString &filename, QString *topLevel = 0) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
+ bool isConfigured() const final;
+ bool supportsOperation(Operation operation) const final;
+ bool vcsOpen(const QString &fileName) final;
+ bool vcsAdd(const QString &filename) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
+ bool vcsAnnotate(const QString &file, int line) final;
+ QString vcsTopic(const QString &directory) final;
+ Core::ShellCommand *createInitialCheckoutCommand(const QString &sourceUrl,
+ const Utils::FileName &baseDirectory,
+ const QString &localName,
+ const QStringList &extraArgs) final;
+
+ // To be connected to the VcsTask's success signal to emit the repository/
+ // files changed signals according to the variant's type:
+ // String -> repository, StringList -> files
+ void changed(const QVariant &);
+
+private:
+ FossilClient *const m_client;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossileditor.cpp b/plugins/fossil/fossileditor.cpp
new file mode 100644
index 0000000..c379fd9
--- /dev/null
+++ b/plugins/fossil/fossileditor.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "fossileditor.h"
+#include "annotationhighlighter.h"
+#include "constants.h"
+#include "fossilplugin.h"
+#include "fossilclient.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <utils/qtcassert.h>
+#include <utils/synchronousprocess.h>
+#include <vcsbase/diffandloghighlighter.h>
+
+#include <QRegExp>
+#include <QString>
+#include <QTextCursor>
+#include <QTextBlock>
+#include <QDir>
+#include <QFileInfo>
+
+namespace Fossil {
+namespace Internal {
+
+FossilEditorWidget::FossilEditorWidget() :
+ m_exactChangesetId(Constants::CHANGESET_ID_EXACT),
+ m_firstChangesetId(QString("\n") + Constants::CHANGESET_ID + " "),
+ m_nextChangesetId(m_firstChangesetId)
+{
+ QTC_ASSERT(m_exactChangesetId.isValid(), return);
+ QTC_ASSERT(m_firstChangesetId.isValid(), return);
+ QTC_ASSERT(m_nextChangesetId.isValid(), return);
+
+ setAnnotateRevisionTextFormat(tr("&Annotate %1"));
+ setAnnotatePreviousRevisionTextFormat(tr("Annotate &Parent Revision %1"));
+
+ const QRegExp exactDiffFileIdPattern(Constants::DIFFFILE_ID_EXACT);
+ QTC_ASSERT(exactDiffFileIdPattern.isValid(), return);
+ setDiffFilePattern(exactDiffFileIdPattern);
+
+ const QRegExp logChangePattern("^.*\\[([0-9a-f]{5,40})\\]");
+ QTC_ASSERT(logChangePattern.isValid(), return);
+ setLogEntryPattern(logChangePattern);
+}
+
+QSet<QString> FossilEditorWidget::annotationChanges() const
+{
+
+ const QString txt = toPlainText();
+ if (txt.isEmpty())
+ return QSet<QString>();
+
+ // extract changeset id at the beginning of each annotated line:
+ // <changeid> ...:
+
+ QSet<QString> changes;
+
+ QRegularExpressionMatch firstChangesetIdMatch = m_firstChangesetId.match(txt);
+ if (firstChangesetIdMatch.hasMatch()) {
+ QString changeId = firstChangesetIdMatch.captured(1);
+ changes.insert(changeId);
+
+ QRegularExpressionMatchIterator i = m_nextChangesetId.globalMatch(txt);
+ while (i.hasNext()) {
+ const QRegularExpressionMatch nextChangesetIdMatch = i.next();
+ changeId = nextChangesetIdMatch.captured(1);
+ changes.insert(changeId);
+ }
+ }
+ return changes;
+}
+
+QString FossilEditorWidget::changeUnderCursor(const QTextCursor &cursorIn) const
+{
+ QTextCursor cursor = cursorIn;
+ cursor.select(QTextCursor::WordUnderCursor);
+ if (cursor.hasSelection()) {
+ const QString change = cursor.selectedText();
+ QRegularExpressionMatch exactChangesetIdMatch = m_exactChangesetId.match(change);
+ if (exactChangesetIdMatch.hasMatch())
+ return change;
+ }
+ return QString();
+}
+
+
+VcsBase::BaseAnnotationHighlighter *FossilEditorWidget::createAnnotationHighlighter(const QSet<QString> &changes) const
+{
+ return new FossilAnnotationHighlighter(changes);
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossileditor.h b/plugins/fossil/fossileditor.h
new file mode 100644
index 0000000..e052b93
--- /dev/null
+++ b/plugins/fossil/fossileditor.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QRegularExpression>
+
+namespace Fossil {
+namespace Internal {
+
+class FossilEditorWidget : public VcsBase::VcsBaseEditorWidget
+{
+ Q_OBJECT
+
+public:
+ FossilEditorWidget();
+
+private:
+ QSet<QString> annotationChanges() const final;
+ QString changeUnderCursor(const QTextCursor &cursor) const final;
+ VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const final;
+
+ const QRegularExpression m_exactChangesetId;
+ const QRegularExpression m_firstChangesetId;
+ const QRegularExpression m_nextChangesetId;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossilplugin.cpp b/plugins/fossil/fossilplugin.cpp
new file mode 100644
index 0000000..2fab29b
--- /dev/null
+++ b/plugins/fossil/fossilplugin.cpp
@@ -0,0 +1,819 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "fossilplugin.h"
+#include "constants.h"
+#include "fossilclient.h"
+#include "fossilcontrol.h"
+#include "optionspage.h"
+#include "fossilcommitwidget.h"
+#include "fossileditor.h"
+#include "pullorpushdialog.h"
+#include "configuredialog.h"
+#include "commiteditor.h"
+#include "wizard/fossiljsextension.h"
+
+#include "ui_revertdialog.h"
+
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/id.h>
+#include <coreplugin/vcsmanager.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/idocument.h>
+#include <coreplugin/documentmanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/locator/commandlocator.h>
+#include <coreplugin/jsexpander.h>
+
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projecttree.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/jsonwizard/jsonwizardfactory.h>
+
+#include <utils/parameteraction.h>
+#include <utils/qtcassert.h>
+
+#include <vcsbase/basevcseditorfactory.h>
+#include <vcsbase/basevcssubmiteditorfactory.h>
+#include <vcsbase/vcsbasesubmiteditor.h>
+#include <vcsbase/vcsbaseconstants.h>
+#include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/vcsoutputwindow.h>
+
+#include <QtPlugin>
+#include <QAction>
+#include <QMenu>
+#include <QDir>
+#include <QDialog>
+#include <QMessageBox>
+#include <QFileDialog>
+#include <QRegularExpression>
+
+namespace Fossil {
+namespace Internal {
+
+static const VcsBase::VcsBaseEditorParameters editorParameters[] = {
+ { VcsBase::LogOutput,
+ Constants::FILELOG_ID,
+ Constants::FILELOG_DISPLAY_NAME,
+ Constants::LOGAPP},
+
+ { VcsBase::AnnotateOutput,
+ Constants::ANNOTATELOG_ID,
+ Constants::ANNOTATELOG_DISPLAY_NAME,
+ Constants::ANNOTATEAPP},
+
+ { VcsBase::DiffOutput,
+ Constants::DIFFLOG_ID,
+ Constants::DIFFLOG_DISPLAY_NAME,
+ Constants::DIFFAPP}
+};
+
+static const VcsBase::VcsBaseSubmitEditorParameters submitEditorParameters = {
+ Constants::COMMITMIMETYPE,
+ Constants::COMMIT_ID,
+ Constants::COMMIT_DISPLAY_NAME,
+ VcsBase::VcsBaseSubmitEditorParameters::DiffFiles
+};
+
+
+FossilPlugin *FossilPlugin::m_instance = nullptr;
+
+FossilPlugin::FossilPlugin()
+{
+ m_instance = this;
+}
+
+FossilPlugin::~FossilPlugin()
+{
+ delete m_client;
+ m_client = nullptr;
+ m_instance = nullptr;
+}
+
+bool FossilPlugin::initialize(const QStringList &arguments, QString *errorMessage)
+{
+ Q_UNUSED(arguments);
+ Q_UNUSED(errorMessage);
+
+ Core::Context context(Constants::FOSSIL_CONTEXT);
+
+ m_client = new FossilClient;
+ auto vcsCtrl = new FossilControl(m_client);
+ initializeVcs(vcsCtrl, context);
+ connect(m_client, &VcsBase::VcsBaseClient::changed, vcsCtrl, &FossilControl::changed);
+
+ addAutoReleasedObject(new OptionsPage(vcsCtrl));
+
+ const auto describeFunc = [this](const QString &source, const QString &id) {
+ m_client->view(source, id);
+ };
+
+ const int editorCount = sizeof(editorParameters) / sizeof(VcsBase::VcsBaseEditorParameters);
+ const auto widgetCreator = []() { return new FossilEditorWidget; };
+ for (int i = 0; i < editorCount; i++)
+ addAutoReleasedObject(new VcsBase::VcsEditorFactory(editorParameters + i, widgetCreator, describeFunc));
+
+ addAutoReleasedObject(new VcsBase::VcsSubmitEditorFactory(&submitEditorParameters,
+ []() { return new CommitEditor(&submitEditorParameters); }));
+
+ m_commandLocator = new Core::CommandLocator("Fossil", "fossil", "fossil");
+ addAutoReleasedObject(m_commandLocator);
+
+ ProjectExplorer::JsonWizardFactory::addWizardPath(Utils::FileName::fromString(Constants::WIZARD_PATH));
+ Core::JsExpander::registerQObjectForJs("Fossil", new FossilJsExtension);
+
+ createMenu(context);
+
+ createSubmitEditorActions();
+
+ return true;
+}
+
+FossilPlugin *FossilPlugin::instance()
+{
+ return m_instance;
+}
+
+FossilClient *FossilPlugin::client() const
+{
+ return m_client;
+}
+
+
+void FossilPlugin::createMenu(const Core::Context &context)
+{
+ // Create menu item for Fossil
+ m_fossilContainer = Core::ActionManager::createMenu("Fossil.FossilMenu");
+ QMenu *menu = m_fossilContainer->menu();
+ menu->setTitle(tr("&Fossil"));
+
+ createFileActions(context);
+ m_fossilContainer->addSeparator(context);
+ createDirectoryActions(context);
+ m_fossilContainer->addSeparator(context);
+ createRepositoryActions(context);
+ m_fossilContainer->addSeparator(context);
+
+ // Request the Tools menu and add the Fossil menu to it
+ Core::ActionContainer *toolsMenu = Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
+ toolsMenu->addMenu(m_fossilContainer);
+ m_menuAction = m_fossilContainer->menu()->menuAction();
+}
+
+void FossilPlugin::createFileActions(const Core::Context &context)
+{
+ Core::Command *command;
+
+ m_annotateFile = new Utils::ParameterAction(tr("Annotate Current File"), tr("Annotate \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+ command = Core::ActionManager::registerAction(m_annotateFile, Constants::ANNOTATE, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ connect(m_annotateFile, &QAction::triggered, this, &FossilPlugin::annotateCurrentFile);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ m_diffFile = new Utils::ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+ command = Core::ActionManager::registerAction(m_diffFile, Constants::DIFF, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+I,Meta+D") : tr("ALT+I,Alt+D")));
+ connect(m_diffFile, &QAction::triggered, this, &FossilPlugin::diffCurrentFile);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ m_logFile = new Utils::ParameterAction(tr("Timeline Current File"), tr("Timeline \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+ command = Core::ActionManager::registerAction(m_logFile, Constants::LOG, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+I,Meta+L") : tr("ALT+I,Alt+L")));
+ connect(m_logFile, &QAction::triggered, this, &FossilPlugin::logCurrentFile);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ m_statusFile = new Utils::ParameterAction(tr("Status Current File"), tr("Status \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+ command = Core::ActionManager::registerAction(m_statusFile, Constants::STATUS, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+I,Meta+S") : tr("ALT+I,Alt+S")));
+ connect(m_statusFile, &QAction::triggered, this, &FossilPlugin::statusCurrentFile);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ m_fossilContainer->addSeparator(context);
+
+ m_addAction = new Utils::ParameterAction(tr("Add Current File"), tr("Add \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+ command = Core::ActionManager::registerAction(m_addAction, Constants::ADD, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ connect(m_addAction, &QAction::triggered, this, &FossilPlugin::addCurrentFile);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ m_deleteAction = new Utils::ParameterAction(tr("Delete Current File..."), tr("Delete \"%1\"..."), Utils::ParameterAction::EnabledWithParameter, this);
+ command = Core::ActionManager::registerAction(m_deleteAction, Constants::DELETE, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ connect(m_deleteAction, &QAction::triggered, this, &FossilPlugin::deleteCurrentFile);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ m_revertFile = new Utils::ParameterAction(tr("Revert Current File..."), tr("Revert \"%1\"..."), Utils::ParameterAction::EnabledWithParameter, this);
+ command = Core::ActionManager::registerAction(m_revertFile, Constants::REVERT, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ connect(m_revertFile, &QAction::triggered, this, &FossilPlugin::revertCurrentFile);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+}
+
+void FossilPlugin::addCurrentFile()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasFile(), return);
+ m_client->synchronousAdd(state.currentFileTopLevel(), state.relativeCurrentFile());
+}
+
+void FossilPlugin::deleteCurrentFile()
+{
+ promptToDeleteCurrentFile();
+}
+
+void FossilPlugin::annotateCurrentFile()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasFile(), return);
+ m_client->annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
+}
+
+void FossilPlugin::diffCurrentFile()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasFile(), return);
+ m_client->diff(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
+}
+
+void FossilPlugin::logCurrentFile()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasFile(), return);
+ FossilClient::SupportedFeatures features = m_client->supportedFeatures();
+ QStringList extraOptions;
+ extraOptions << "-n" << QString::number(m_client->settings().intValue(FossilSettings::logCountKey));
+
+ if (features.testFlag(FossilClient::TimelineWidthFeature))
+ extraOptions << "-W" << QString::number(m_client->settings().intValue(FossilSettings::timelineWidthKey));
+
+ // annotate only supported for current revision, so disable context menu
+ bool enableAnnotationContextMenu = false;
+ m_client->logCurrentFile(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()),
+ extraOptions, enableAnnotationContextMenu);
+}
+
+void FossilPlugin::revertCurrentFile()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasFile(), return);
+
+ QDialog dialog(Core::ICore::dialogParent());
+ Ui::RevertDialog revertUi;
+ revertUi.setupUi(&dialog);
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+ m_client->revertFile(state.currentFileTopLevel(),
+ state.relativeCurrentFile(),
+ revertUi.revisionLineEdit->text());
+}
+
+void FossilPlugin::statusCurrentFile()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasFile(), return);
+ m_client->status(state.currentFileTopLevel(), state.relativeCurrentFile());
+}
+
+void FossilPlugin::createDirectoryActions(const Core::Context &context)
+{
+ QAction *action;
+ Core::Command *command;
+
+ action = new QAction(tr("Diff"), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::DIFFMULTI, context);
+ connect(action, &QAction::triggered, this, &FossilPlugin::diffRepository);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ action = new QAction(tr("Timeline"), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::LOGMULTI, context);
+ command->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+I,Meta+T") : tr("ALT+I,Alt+T")));
+ connect(action, &QAction::triggered, this, &FossilPlugin::logRepository);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ action = new QAction(tr("Revert..."), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::REVERTMULTI, context);
+ connect(action, &QAction::triggered, this, &FossilPlugin::revertAll);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ action = new QAction(tr("Status"), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::STATUSMULTI, context);
+ connect(action, &QAction::triggered, this, &FossilPlugin::statusMulti);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+}
+
+
+void FossilPlugin::diffRepository()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+ m_client->diff(state.topLevel());
+}
+
+void FossilPlugin::logRepository()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+ FossilClient::SupportedFeatures features = m_client->supportedFeatures();
+ QStringList extraOptions;
+ extraOptions << "-n" << QString::number(m_client->settings().intValue(FossilSettings::logCountKey));
+
+ if (features.testFlag(FossilClient::TimelineWidthFeature))
+ extraOptions << "-W" << QString::number(m_client->settings().intValue(FossilSettings::timelineWidthKey));
+
+ m_client->log(state.topLevel(), QStringList(), extraOptions);
+}
+
+void FossilPlugin::revertAll()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+
+ QDialog dialog(Core::ICore::dialogParent());
+ Ui::RevertDialog revertUi;
+ revertUi.setupUi(&dialog);
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+ m_client->revertAll(state.topLevel(), revertUi.revisionLineEdit->text());
+}
+
+void FossilPlugin::statusMulti()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+ m_client->status(state.topLevel());
+}
+
+void FossilPlugin::createRepositoryActions(const Core::Context &context)
+{
+ QAction *action = 0;
+ Core::Command *command = 0;
+
+ action = new QAction(tr("Pull..."), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::PULL, context);
+ connect(action, &QAction::triggered, this, &FossilPlugin::pull);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ action = new QAction(tr("Push..."), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::PUSH, context);
+ connect(action, &QAction::triggered, this, &FossilPlugin::push);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ action = new QAction(tr("Update..."), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::UPDATE, context);
+ command->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+I,Meta+U") : tr("ALT+I,Alt+U")));
+ connect(action, &QAction::triggered, this, &FossilPlugin::update);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ action = new QAction(tr("Commit..."), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::COMMIT, context);
+ command->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+I,Meta+C") : tr("ALT+I,Alt+C")));
+ connect(action, &QAction::triggered, this, &FossilPlugin::commit);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ action = new QAction(tr("Settings ..."), this);
+ m_repositoryActionList.append(action);
+ command = Core::ActionManager::registerAction(action, Constants::CONFIGURE_REPOSITORY, context);
+ connect(action, &QAction::triggered, this, &FossilPlugin::configureRepository);
+ m_fossilContainer->addAction(command);
+ m_commandLocator->appendCommand(command);
+
+ // Register "Create Repository..." action in global context, so that it's visible
+ // without active repository to allow creating a new one.
+ m_createRepositoryAction = new QAction(tr("Create Repository..."), this);
+ command = Core::ActionManager::registerAction(m_createRepositoryAction, Constants::CREATE_REPOSITORY);
+ connect(m_createRepositoryAction, &QAction::triggered, this, &FossilPlugin::createRepository);
+ m_fossilContainer->addAction(command);
+}
+
+void FossilPlugin::pull()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+
+ PullOrPushDialog dialog(PullOrPushDialog::PullMode, Core::ICore::dialogParent());
+ dialog.setLocalBaseDirectory(m_client->settings().stringValue(FossilSettings::defaultRepoPathKey));
+ dialog.setDefaultRemoteLocation(m_client->synchronousGetRepositoryURL(state.topLevel()));
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+
+ QString remoteLocation(dialog.remoteLocation());
+ if (remoteLocation.isEmpty())
+ remoteLocation = m_client->synchronousGetRepositoryURL(state.topLevel());
+
+ if (remoteLocation.isEmpty()) {
+ VcsBase::VcsOutputWindow::appendError(tr("Remote repository is not defined."));
+ return;
+ }
+
+ QStringList extraOptions;
+ if (!dialog.isRememberOptionEnabled())
+ extraOptions << "--once";
+ if (dialog.isPrivateOptionEnabled())
+ extraOptions << "--private";
+ m_client->synchronousPull(state.topLevel(), remoteLocation, extraOptions);
+}
+
+void FossilPlugin::push()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+
+ PullOrPushDialog dialog(PullOrPushDialog::PushMode, Core::ICore::dialogParent());
+ dialog.setLocalBaseDirectory(m_client->settings().stringValue(FossilSettings::defaultRepoPathKey));
+ dialog.setDefaultRemoteLocation(m_client->synchronousGetRepositoryURL(state.topLevel()));
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+
+ QString remoteLocation(dialog.remoteLocation());
+ if (remoteLocation.isEmpty())
+ remoteLocation = m_client->synchronousGetRepositoryURL(state.topLevel());
+
+ if (remoteLocation.isEmpty()) {
+ VcsBase::VcsOutputWindow::appendError(tr("Remote repository is not defined."));
+ return;
+ }
+
+ QStringList extraOptions;
+ if (!dialog.isRememberOptionEnabled())
+ extraOptions << "--once";
+ if (dialog.isPrivateOptionEnabled())
+ extraOptions << "--private";
+ m_client->synchronousPush(state.topLevel(), remoteLocation, extraOptions);
+}
+
+void FossilPlugin::update()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+
+ QDialog dialog(Core::ICore::dialogParent());
+ Ui::RevertDialog revertUi;
+ revertUi.setupUi(&dialog);
+ dialog.setWindowTitle(tr("Update"));
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+ m_client->update(state.topLevel(), revertUi.revisionLineEdit->text());
+}
+
+void FossilPlugin::configureRepository()
+{
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+
+ ConfigureDialog dialog;
+
+ // retrieve current settings from the repository
+ RepositorySettings currentSettings = m_client->synchronousSettingsQuery(state.topLevel());
+
+ dialog.setSettings(currentSettings);
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+ const RepositorySettings newSettings = dialog.settings();
+
+ m_client->synchronousConfigureRepository(state.topLevel(), newSettings, currentSettings);
+}
+
+void FossilPlugin::createSubmitEditorActions()
+{
+ Core::Context context(Constants::COMMIT_ID);
+ Core::Command *command;
+
+ m_editorCommit = new QAction(VcsBase::VcsBaseSubmitEditor::submitIcon(), tr("Commit"), this);
+ command = Core::ActionManager::registerAction(m_editorCommit, Constants::COMMIT, context);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ connect(m_editorCommit, &QAction::triggered, this, &FossilPlugin::commitFromEditor);
+
+ m_editorDiff = new QAction(VcsBase::VcsBaseSubmitEditor::diffIcon(), tr("Diff &Selected Files"), this);
+ command = Core::ActionManager::registerAction(m_editorDiff, Constants::DIFFEDITOR, context);
+
+ m_editorUndo = new QAction(tr("&Undo"), this);
+ command = Core::ActionManager::registerAction(m_editorUndo, Core::Constants::UNDO, context);
+
+ m_editorRedo = new QAction(tr("&Redo"), this);
+ command = Core::ActionManager::registerAction(m_editorRedo, Core::Constants::REDO, context);
+}
+
+void FossilPlugin::commit()
+{
+ if (raiseSubmitEditor())
+ return;
+
+ const VcsBase::VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+
+ m_submitRepository = state.topLevel();
+
+ connect(m_client, &VcsBase::VcsBaseClient::parsedStatus,
+ this, &FossilPlugin::showCommitWidget);
+
+ QStringList extraOptions;
+ m_client->emitParsedStatus(m_submitRepository, extraOptions);
+}
+
+void FossilPlugin::showCommitWidget(const QList<VcsBase::VcsBaseClient::StatusItem> &status)
+{
+ //Once we receive our data release the connection so it can be reused elsewhere
+ disconnect(m_client, &VcsBase::VcsBaseClient::parsedStatus,
+ this, &FossilPlugin::showCommitWidget);
+
+ if (status.isEmpty()) {
+ VcsBase::VcsOutputWindow::appendError(tr("There are no changes to commit."));
+ return;
+ }
+
+ // Start new temp file for commit message
+ Utils::TempFileSaver saver;
+ // Keep the file alive, else it removes self and forgets its name
+ saver.setAutoRemove(false);
+ if (!saver.finalize()) {
+ VcsBase::VcsOutputWindow::appendError(saver.errorString());
+ return;
+ }
+
+ Core::IEditor *editor = Core::EditorManager::openEditor(saver.fileName(), Constants::COMMIT_ID);
+ if (!editor) {
+ VcsBase::VcsOutputWindow::appendError(tr("Unable to create an editor for the commit."));
+ return;
+ }
+
+ CommitEditor *commitEditor = qobject_cast<CommitEditor *>(editor);
+
+ if (!commitEditor) {
+ VcsBase::VcsOutputWindow::appendError(tr("Unable to create a commit editor."));
+ return;
+ }
+ setSubmitEditor(commitEditor);
+
+ const QString msg = tr("Commit changes for \"%1\".").
+ arg(QDir::toNativeSeparators(m_submitRepository));
+ commitEditor->document()->setPreferredDisplayName(msg);
+
+ const RevisionInfo currentRevision = m_client->synchronousRevisionQuery(m_submitRepository);
+ const BranchInfo currentBranch = m_client->synchronousCurrentBranch(m_submitRepository);
+ const QString currentUser = m_client->synchronousUserDefaultQuery(m_submitRepository);
+ QStringList tags = m_client->synchronousTagQuery(m_submitRepository, currentRevision.id);
+ // Fossil includes branch name in tag list -- remove.
+ tags.removeAll(currentBranch.name());
+ commitEditor->setFields(m_submitRepository, currentBranch, tags, currentUser, status);
+
+ commitEditor->registerActions(m_editorUndo, m_editorRedo, m_editorCommit, m_editorDiff);
+ connect(commitEditor, &VcsBase::VcsBaseSubmitEditor::diffSelectedFiles,
+ this, &FossilPlugin::diffFromEditorSelected);
+ commitEditor->setCheckScriptWorkingDirectory(m_submitRepository);
+}
+
+void FossilPlugin::diffFromEditorSelected(const QStringList &files)
+{
+ m_client->diff(m_submitRepository, files);
+}
+
+static inline bool ask(QWidget *parent, const QString &title, const QString &question, bool defaultValue = true)
+
+{
+ const QMessageBox::StandardButton defaultButton = defaultValue ? QMessageBox::Yes : QMessageBox::No;
+ return QMessageBox::question(parent, title, question, QMessageBox::Yes|QMessageBox::No, defaultButton) == QMessageBox::Yes;
+}
+
+void FossilPlugin::createRepository()
+{
+ // re-implemented from void VcsBasePlugin::createRepository()
+
+ // Find current starting directory
+ QString directory;
+ if (const ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectTree::currentProject())
+ directory = currentProject->document()->filePath().toFileInfo().absolutePath();
+ // Prompt for a directory that is not under version control yet
+ QWidget *mw = Core::ICore::mainWindow();
+ do {
+ directory = QFileDialog::getExistingDirectory(mw, tr("Choose Checkout Directory"), directory);
+ if (directory.isEmpty())
+ return;
+ const Core::IVersionControl *managingControl = Core::VcsManager::findVersionControlForDirectory(directory);
+ if (managingControl == 0)
+ break;
+ const QString question = tr("The directory \"%1\" is already managed by a version control system (%2)."
+ " Would you like to specify another directory?").arg(directory, managingControl->displayName());
+
+ if (!ask(mw, tr("Repository already under version control"), question))
+ return;
+ } while (true);
+ // Create
+ const bool rc = static_cast<FossilControl *>(versionControl())->vcsCreateRepository(directory);
+ const QString nativeDir = QDir::toNativeSeparators(directory);
+ if (rc) {
+ QMessageBox::information(mw, tr("Repository Created"),
+ tr("A version control repository has been created in %1.").
+ arg(nativeDir));
+ } else {
+ QMessageBox::warning(mw, tr("Repository Creation Failed"),
+ tr("A version control repository could not be created in %1.").
+ arg(nativeDir));
+ }
+}
+
+void FossilPlugin::commitFromEditor()
+{
+ // Close the submit editor
+ m_submitActionTriggered = true;
+ QTC_ASSERT(submitEditor(), return);
+ Core::EditorManager::closeDocument(submitEditor()->document());
+}
+
+bool FossilPlugin::submitEditorAboutToClose()
+{
+ CommitEditor *commitEditor = qobject_cast<CommitEditor *>(submitEditor());
+ QTC_ASSERT(commitEditor, return true);
+ Core::IDocument *editorDocument = commitEditor->document();
+ QTC_ASSERT(editorDocument, return true);
+
+ bool promptOnSubmit = false;
+ 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?"),
+ &promptOnSubmit, !m_submitActionTriggered);
+ m_submitActionTriggered = false;
+
+ switch (response) {
+ case VcsBase::VcsBaseSubmitEditor::SubmitCanceled:
+ return false;
+ case VcsBase::VcsBaseSubmitEditor::SubmitDiscarded:
+ return true;
+ default:
+ break;
+ }
+
+ QStringList files = commitEditor->checkedFiles();
+ if (!files.empty()) {
+ //save the commit message
+ if (!Core::DocumentManager::saveDocument(editorDocument))
+ return false;
+
+ //rewrite entries of the form 'file => newfile' to 'newfile' because
+ //this would mess the commit command
+ for (QStringList::iterator iFile = files.begin(); iFile != files.end(); ++iFile) {
+ const QStringList parts = iFile->split(" => ", QString::SkipEmptyParts);
+ if (!parts.isEmpty())
+ *iFile = parts.last();
+ }
+
+ FossilCommitWidget *commitWidget = commitEditor->commitWidget();
+ QStringList extraOptions;
+ // Author -- override the repository-default user
+ if (!commitWidget->committer().isEmpty())
+ extraOptions << "--user" << commitWidget->committer();
+ // Branch
+ QString branch = commitWidget->newBranch();
+ if (!branch.isEmpty()) {
+ // @TODO: make enquote utility function
+ QString enquotedBranch = branch;
+ if (branch.contains(QRegularExpression("\\s")))
+ enquotedBranch = QString("\"") + branch + "\"";
+ extraOptions << "--branch" << enquotedBranch;
+ }
+ // Tags
+ foreach (QString tag, commitWidget->tags()) {
+ extraOptions << "--tag" << tag;
+ }
+
+ // Whether local commit or not
+ if (commitWidget->isPrivateOptionEnabled())
+ extraOptions += "--private";
+ m_client->commit(m_submitRepository, files, editorDocument->filePath().toString(), extraOptions);
+ }
+ return true;
+}
+
+
+void FossilPlugin::updateActions(VcsBase::VcsBasePlugin::ActionState as)
+{
+ m_createRepositoryAction->setEnabled(true);
+
+ if (!enableMenuAction(as, m_menuAction)) {
+ m_commandLocator->setEnabled(false);
+ return;
+ }
+ const QString filename = currentState().currentFileName();
+ const bool repoEnabled = currentState().hasTopLevel();
+ m_commandLocator->setEnabled(repoEnabled);
+
+ m_annotateFile->setParameter(filename);
+ m_diffFile->setParameter(filename);
+ m_logFile->setParameter(filename);
+ m_addAction->setParameter(filename);
+ m_deleteAction->setParameter(filename);
+ m_revertFile->setParameter(filename);
+ m_statusFile->setParameter(filename);
+
+ foreach (QAction *repoAction, m_repositoryActionList)
+ repoAction->setEnabled(repoEnabled);
+}
+
+} // namespace Internal
+} // namespace Fossil
+
+#ifdef WITH_TESTS
+#include <QTest>
+
+void Fossil::Internal::FossilPlugin::testDiffFileResolving_data()
+{
+ QTest::addColumn<QByteArray>("header");
+ QTest::addColumn<QByteArray>("fileName");
+
+ QTest::newRow("New") << QByteArray(
+ "ADDED src/plugins/fossil/fossilclient.cpp\n"
+ "Index: src/plugins/fossil/fossilclient.cpp\n"
+ "==================================================================\n"
+ "--- src/plugins/fossil/fossilclient.cpp\n"
+ "+++ src/plugins/fossil/fossilclient.cpp\n"
+ "@@ -0,0 +1,295 @@\n"
+ )
+ << QByteArray("src/plugins/fossil/fossilclient.cpp");
+ QTest::newRow("Deleted") << QByteArray(
+ "DELETED src/plugins/fossil/fossilclient.cpp\n"
+ "Index: src/plugins/fossil/fossilclient.cpp\n"
+ "==================================================================\n"
+ "--- src/plugins/fossil/fossilclient.cpp\n"
+ "+++ src/plugins/fossil/fossilclient.cpp\n"
+ "@@ -1,266 +0,0 @@\n"
+ )
+ << QByteArray("src/plugins/fossil/fossilclient.cpp");
+ QTest::newRow("Modified") << QByteArray(
+ "Index: src/plugins/fossil/fossilclient.cpp\n"
+ "==================================================================\n"
+ "--- src/plugins/fossil/fossilclient.cpp\n"
+ "+++ src/plugins/fossil/fossilclient.cpp\n"
+ "@@ -112,22 +112,37 @@\n"
+ )
+ << QByteArray("src/plugins/fossil/fossilclient.cpp");
+}
+
+void Fossil::Internal::FossilPlugin::testDiffFileResolving()
+{
+ VcsBase::VcsBaseEditorWidget::testDiffFileResolving(editorParameters[2].id);
+}
+
+void Fossil::Internal::FossilPlugin::testLogResolving()
+{
+ QByteArray data(
+ "=== 2014-03-08 ===\n"
+ "22:14:02 [ac6d1129b8] Change scaling algorithm. (user: ninja tags: ninja-fixes-5.1)\n"
+ " EDITED src/core/scaler.cpp\n"
+ "20:23:51 [56d6917c3b] *BRANCH* Add width option (conditional). (user: ninja tags: ninja-fixes-5.1)\n"
+ " EDITED src/core/scaler.cpp\n"
+ " EDITED src/core/scaler.h\n"
+ );
+ VcsBase::VcsBaseEditorWidget::testLogResolving(editorParameters[0].id, data, "ac6d1129b8", "56d6917c3b");
+}
+#endif
diff --git a/plugins/fossil/fossilplugin.h b/plugins/fossil/fossilplugin.h
new file mode 100644
index 0000000..da48d24
--- /dev/null
+++ b/plugins/fossil/fossilplugin.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "fossilsettings.h"
+
+#include <vcsbase/vcsbaseclient.h>
+#include <vcsbase/vcsbaseplugin.h>
+#include <coreplugin/icontext.h>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
+namespace Core {
+class ActionContainer;
+class CommandLocator;
+class Id;
+} // namespace Core
+
+namespace Utils { class ParameterAction; }
+
+namespace Fossil {
+namespace Internal {
+
+class OptionsPage;
+class FossilClient;
+class FossilControl;
+class FossilEditorWidget;
+
+class FossilPlugin : public VcsBase::VcsBasePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Fossil.json")
+
+public:
+ FossilPlugin();
+ ~FossilPlugin();
+ bool initialize(const QStringList &arguments, QString *errorMessage);
+
+ static FossilPlugin *instance();
+ FossilClient *client() const;
+
+protected:
+ void updateActions(VcsBase::VcsBasePlugin::ActionState) override;
+ bool submitEditorAboutToClose() override;
+
+private:
+ // File menu action slots
+ void addCurrentFile();
+ void deleteCurrentFile();
+ void annotateCurrentFile();
+ void diffCurrentFile();
+ void logCurrentFile();
+ void revertCurrentFile();
+ void statusCurrentFile();
+
+ // Directory menu action slots
+ void diffRepository();
+ void logRepository();
+ void revertAll();
+ void statusMulti();
+
+ // Repository menu action slots
+ void pull();
+ void push();
+ void update();
+ void configureRepository();
+ void commit();
+ void showCommitWidget(const QList<VcsBase::VcsBaseClient::StatusItem> &status);
+ void commitFromEditor();
+ void diffFromEditorSelected(const QStringList &files);
+ void createRepository();
+
+ // Methods
+ void createMenu(const Core::Context &context);
+ void createSubmitEditorActions();
+ void createFileActions(const Core::Context &context);
+ void createDirectoryActions(const Core::Context &context);
+ void createRepositoryActions(const Core::Context &context);
+
+ // Variables
+ static FossilPlugin *m_instance;
+ FossilClient *m_client = nullptr;
+
+ Core::CommandLocator *m_commandLocator = nullptr;
+ Core::ActionContainer *m_fossilContainer = nullptr;
+
+ QList<QAction *> m_repositoryActionList;
+
+ // Menu Items (file actions)
+ Utils::ParameterAction *m_addAction = nullptr;
+ Utils::ParameterAction *m_deleteAction = nullptr;
+ Utils::ParameterAction *m_annotateFile = nullptr;
+ Utils::ParameterAction *m_diffFile = nullptr;
+ Utils::ParameterAction *m_logFile = nullptr;
+ Utils::ParameterAction *m_renameFile = nullptr;
+ Utils::ParameterAction *m_revertFile = nullptr;
+ Utils::ParameterAction *m_statusFile = nullptr;
+
+ QAction *m_createRepositoryAction = nullptr;
+
+ // Submit editor actions
+ QAction *m_editorCommit = nullptr;
+ QAction *m_editorDiff = nullptr;
+ QAction *m_editorUndo = nullptr;
+ QAction *m_editorRedo = nullptr;
+ QAction *m_menuAction = nullptr;
+
+ QString m_submitRepository;
+ bool m_submitActionTriggered = false;
+
+
+#ifdef WITH_TESTS
+private slots:
+ void testDiffFileResolving_data();
+ void testDiffFileResolving();
+ void testLogResolving();
+#endif
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossilsettings.cpp b/plugins/fossil/fossilsettings.cpp
new file mode 100644
index 0000000..e6f4769
--- /dev/null
+++ b/plugins/fossil/fossilsettings.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "fossilsettings.h"
+#include "constants.h"
+
+#include <QSettings>
+
+namespace Fossil {
+namespace Internal {
+
+const QString FossilSettings::defaultRepoPathKey("defaultRepoPath");
+const QString FossilSettings::sslIdentityFileKey("sslIdentityFile");
+const QString FossilSettings::diffIgnoreAllWhiteSpaceKey("diffIgnoreAllWhiteSpace");
+const QString FossilSettings::diffStripTrailingCRKey("diffStripTrailingCR");
+const QString FossilSettings::annotateShowCommittersKey("annotateShowCommitters");
+const QString FossilSettings::timelineWidthKey("timelineWidth");
+const QString FossilSettings::timelineLineageFilterKey("timelineLineageFilter");
+const QString FossilSettings::timelineVerboseKey("timelineVerbose");
+const QString FossilSettings::timelineItemTypeKey("timelineItemType");
+const QString FossilSettings::disableAutosyncKey("disableAutosync");
+
+FossilSettings::FossilSettings()
+{
+ setSettingsGroup(Constants::FOSSIL);
+ // Override default binary path
+ declareKey(binaryPathKey, Constants::FOSSILDEFAULT);
+ declareKey(defaultRepoPathKey, "");
+ declareKey(sslIdentityFileKey, "");
+ declareKey(diffIgnoreAllWhiteSpaceKey, false);
+ declareKey(diffStripTrailingCRKey, false);
+ declareKey(annotateShowCommittersKey, false);
+ declareKey(timelineWidthKey, 0);
+ declareKey(timelineLineageFilterKey, "");
+ declareKey(timelineVerboseKey, false);
+ declareKey(timelineItemTypeKey, "all");
+ declareKey(disableAutosyncKey, true);
+}
+
+RepositorySettings::RepositorySettings()
+ : autosync(AutosyncOn)
+{
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/fossilsettings.h b/plugins/fossil/fossilsettings.h
new file mode 100644
index 0000000..5a82e8d
--- /dev/null
+++ b/plugins/fossil/fossilsettings.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <vcsbase/vcsbaseclientsettings.h>
+
+namespace Fossil {
+namespace Internal {
+
+class FossilSettings : public VcsBase::VcsBaseClientSettings
+{
+public:
+ static const QString defaultRepoPathKey;
+ static const QString sslIdentityFileKey;
+ static const QString diffIgnoreAllWhiteSpaceKey;
+ static const QString diffStripTrailingCRKey;
+ static const QString annotateShowCommittersKey;
+ static const QString timelineWidthKey;
+ static const QString timelineLineageFilterKey;
+ static const QString timelineVerboseKey;
+ static const QString timelineItemTypeKey;
+ static const QString disableAutosyncKey;
+
+ FossilSettings();
+};
+
+struct RepositorySettings
+{
+ enum AutosyncMode {AutosyncOff = 0, AutosyncOn = 1, AutosyncPullOnly};
+
+ QString user;
+ AutosyncMode autosync;
+ QString sslIdentityFile;
+
+ RepositorySettings();
+};
+
+inline bool operator== (const RepositorySettings &lh, const RepositorySettings &rh)
+{
+ return (lh.user == rh.user
+ && lh.autosync == rh.autosync
+ && lh.sslIdentityFile == rh.sslIdentityFile);
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/optionspage.cpp b/plugins/fossil/optionspage.cpp
new file mode 100644
index 0000000..bc6d16a
--- /dev/null
+++ b/plugins/fossil/optionspage.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "optionspage.h"
+#include "constants.h"
+#include "fossilclient.h"
+#include "fossilsettings.h"
+#include "fossilplugin.h"
+
+#include <coreplugin/icore.h>
+#include <utils/pathchooser.h>
+#include <vcsbase/vcsbaseconstants.h>
+
+#include <QTextStream>
+
+using namespace Fossil::Internal;
+using namespace Fossil;
+
+OptionsPageWidget::OptionsPageWidget(QWidget *parent) :
+ VcsClientOptionsPageWidget(parent)
+{
+ m_ui.setupUi(this);
+ m_ui.commandChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
+ m_ui.commandChooser->setPromptDialogTitle(tr("Fossil Command"));
+ m_ui.commandChooser->setHistoryCompleter("Fossil.Command.History");
+ m_ui.defaultRepoPathChooser->setExpectedKind(Utils::PathChooser::ExistingDirectory);
+ m_ui.defaultRepoPathChooser->setPromptDialogTitle(tr("Fossil Repositories"));
+ m_ui.sslIdentityFilePathChooser->setExpectedKind(Utils::PathChooser::File);
+ m_ui.sslIdentityFilePathChooser->setPromptDialogTitle(tr("SSL/TLS Identity Key"));
+}
+
+VcsBase::VcsBaseClientSettings OptionsPageWidget::settings() const
+{
+ VcsBase::VcsBaseClientSettings s = FossilPlugin::instance()->client()->settings();
+ s.setValue(FossilSettings::binaryPathKey, m_ui.commandChooser->rawPath());
+ s.setValue(FossilSettings::defaultRepoPathKey, m_ui.defaultRepoPathChooser->path());
+ s.setValue(FossilSettings::userNameKey, m_ui.defaultUsernameLineEdit->text().trimmed());
+ s.setValue(FossilSettings::sslIdentityFileKey, m_ui.sslIdentityFilePathChooser->path());
+ s.setValue(FossilSettings::logCountKey, m_ui.logEntriesCount->value());
+ s.setValue(FossilSettings::timelineWidthKey, m_ui.logEntriesWidth->value());
+ s.setValue(FossilSettings::timeoutKey, m_ui.timeout->value());
+ s.setValue(FossilSettings::disableAutosyncKey, m_ui.disableAutosyncCheckBox->isChecked());
+ return s;
+}
+
+void OptionsPageWidget::setSettings(const VcsBase::VcsBaseClientSettings &s)
+{
+ m_ui.commandChooser->setPath(s.stringValue(FossilSettings::binaryPathKey));
+ m_ui.defaultRepoPathChooser->setPath(s.stringValue(FossilSettings::defaultRepoPathKey));
+ m_ui.defaultUsernameLineEdit->setText(s.stringValue(FossilSettings::userNameKey));
+ m_ui.sslIdentityFilePathChooser->setPath(s.stringValue(FossilSettings::sslIdentityFileKey));
+ m_ui.logEntriesCount->setValue(s.intValue(FossilSettings::logCountKey));
+ m_ui.logEntriesWidth->setValue(s.intValue(FossilSettings::timelineWidthKey));
+ m_ui.timeout->setValue(s.intValue(FossilSettings::timeoutKey));
+ m_ui.disableAutosyncCheckBox->setChecked(s.boolValue(FossilSettings::disableAutosyncKey));
+}
+
+OptionsPage::OptionsPage(Core::IVersionControl *control) :
+ VcsClientOptionsPage(control, FossilPlugin::instance()->client())
+{
+ setId(Constants::VCS_ID_FOSSIL);
+ setDisplayName(tr("Fossil"));
+ setWidgetFactory([]() { return new OptionsPageWidget; });
+}
diff --git a/plugins/fossil/optionspage.h b/plugins/fossil/optionspage.h
new file mode 100644
index 0000000..769841c
--- /dev/null
+++ b/plugins/fossil/optionspage.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "ui_optionspage.h"
+
+#include <vcsbase/vcsbaseoptionspage.h>
+
+namespace VcsBase { class VcsBaseClientSettings; } // namespace VcsBase
+
+namespace Fossil {
+namespace Internal {
+
+class FossilSettings;
+
+class OptionsPageWidget : public VcsBase::VcsClientOptionsPageWidget
+{
+ Q_OBJECT
+
+public:
+ explicit OptionsPageWidget(QWidget *parent = 0);
+
+ VcsBase::VcsBaseClientSettings settings() const;
+ void setSettings(const VcsBase::VcsBaseClientSettings &s);
+
+private:
+ Ui::OptionsPage m_ui;
+};
+
+
+class OptionsPage : public VcsBase::VcsClientOptionsPage
+{
+ Q_OBJECT
+
+public:
+ OptionsPage(Core::IVersionControl *control);
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/optionspage.ui b/plugins/fossil/optionspage.ui
new file mode 100644
index 0000000..d573fb8
--- /dev/null
+++ b/plugins/fossil/optionspage.ui
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Fossil::Internal::OptionsPage</class>
+ <widget class="QWidget" name="Fossil::Internal::OptionsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>649</width>
+ <height>336</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="configGroupBox">
+ <property name="title">
+ <string>Configuration</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_3">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="commandLabel">
+ <property name="text">
+ <string>Command:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Utils::PathChooser" name="commandChooser" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="repoGroupBox">
+ <property name="title">
+ <string>Local Repositories</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_4">
+ <item row="0" column="0">
+ <widget class="QLabel" name="defaultRepoPathLabel">
+ <property name="toolTip">
+ <string>Directory to store local repositories by default.</string>
+ </property>
+ <property name="text">
+ <string>Default path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Utils::PathChooser" name="defaultRepoPathChooser" native="true">
+ <property name="toolTip">
+ <string>Directory to store local repositories by default.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="userGroupBox">
+ <property name="title">
+ <string>User</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="defaultUsernameLabel">
+ <property name="text">
+ <string>Default user:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="defaultUsernameLineEdit">
+ <property name="toolTip">
+ <string>Existing user to become an author of changes made to the repository.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="sslIdentityFileLabel">
+ <property name="text">
+ <string>SSL/TLS identity:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="Utils::PathChooser" name="sslIdentityFilePathChooser" native="true">
+ <property name="toolTip">
+ <string>SSL/TLS client identity key to use if requested by the server.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="miscGroupBox">
+ <property name="title">
+ <string>Miscellaneous</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="showLogEntriesLabel">
+ <property name="text">
+ <string>Log count:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="logEntriesCount">
+ <property name="toolTip">
+ <string>The number of recent commit log entries to show. Choose 0 to see all entries.</string>
+ </property>
+ <property name="maximum">
+ <number>1000</number>
+ </property>
+ <property name="value">
+ <number>1000</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="logEntriesWidthLabel">
+ <property name="text">
+ <string>Log width:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QSpinBox" name="logEntriesWidth">
+ <property name="toolTip">
+ <string>The width of log entry line (&gt;20). Choose 0 to see a single line per entry.</string>
+ </property>
+ <property name="maximum">
+ <number>300</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="timeoutSecondsLabel">
+ <property name="text">
+ <string>Timeout:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="5">
+ <widget class="QSpinBox" name="timeout">
+ <property name="suffix">
+ <string>s</string>
+ </property>
+ <property name="value">
+ <number>30</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="6">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>213</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0" colspan="5">
+ <widget class="QCheckBox" name="disableAutosyncCheckBox">
+ <property name="toolTip">
+ <string>Disable automatic pull prior to commit or update and automatic push after commit or tag or branch creation.</string>
+ </property>
+ <property name="text">
+ <string>Disable auto-sync</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/pathchooser.h</header>
+ <container>1</container>
+ <slots>
+ <signal>editingFinished()</signal>
+ <signal>browsingFinished()</signal>
+ </slots>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/plugins/fossil/pullorpushdialog.cpp b/plugins/fossil/pullorpushdialog.cpp
new file mode 100644
index 0000000..7129f51
--- /dev/null
+++ b/plugins/fossil/pullorpushdialog.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "pullorpushdialog.h"
+#include "ui_pullorpushdialog.h"
+
+#include "constants.h"
+
+#include <utils/qtcassert.h>
+
+namespace Fossil {
+namespace Internal {
+
+PullOrPushDialog::PullOrPushDialog(Mode mode, QWidget *parent) : QDialog(parent),
+ m_mode(mode),
+ m_ui(new Ui::PullOrPushDialog)
+{
+ m_ui->setupUi(this);
+ m_ui->localPathChooser->setExpectedKind(Utils::PathChooser::File);
+ m_ui->localPathChooser->setPromptDialogFilter(tr(Constants::FOSSIL_FILE_FILTER));
+
+ switch (m_mode) {
+ case PullMode:
+ this->setWindowTitle(tr("Pull Source"));
+ break;
+ case PushMode:
+ this->setWindowTitle(tr("Push Destination"));
+ break;
+ }
+
+ // select URL text in line edit when clicking the radio button
+ m_ui->localButton->setFocusProxy(m_ui->localPathChooser);
+ m_ui->urlButton->setFocusProxy(m_ui->urlLineEdit);
+ connect(m_ui->urlButton, &QRadioButton::clicked, m_ui->urlLineEdit, &QLineEdit::selectAll);
+
+ this->adjustSize();
+}
+
+PullOrPushDialog::~PullOrPushDialog()
+{
+ delete m_ui;
+}
+
+QString PullOrPushDialog::remoteLocation() const
+{
+ if (m_ui->defaultButton->isChecked())
+ return QString();
+ if (m_ui->localButton->isChecked())
+ return m_ui->localPathChooser->path();
+ return m_ui->urlLineEdit->text();
+}
+
+bool PullOrPushDialog::isRememberOptionEnabled() const
+{
+ if (m_ui->defaultButton->isChecked())
+ return false;
+ return m_ui->rememberCheckBox->isChecked();
+}
+
+bool PullOrPushDialog::isPrivateOptionEnabled() const
+{
+ return m_ui->privateCheckBox->isChecked();
+}
+
+void PullOrPushDialog::setDefaultRemoteLocation(const QString &url)
+{
+ m_ui->urlLineEdit->setText(url);
+}
+
+void PullOrPushDialog::setLocalBaseDirectory(const QString &dir)
+{
+ m_ui->localPathChooser->setBaseDirectory(dir);
+}
+
+void PullOrPushDialog::changeEvent(QEvent *e)
+{
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ m_ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/pullorpushdialog.h b/plugins/fossil/pullorpushdialog.h
new file mode 100644
index 0000000..cffb301
--- /dev/null
+++ b/plugins/fossil/pullorpushdialog.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QDialog>
+
+namespace Fossil {
+namespace Internal {
+
+namespace Ui { class PullOrPushDialog; }
+
+class PullOrPushDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ enum Mode {
+ PullMode,
+ PushMode
+ };
+
+ explicit PullOrPushDialog(Mode mode, QWidget *parent = nullptr);
+ ~PullOrPushDialog() final;
+
+ // Common parameters and options
+ QString remoteLocation() const;
+ bool isRememberOptionEnabled() const;
+ bool isPrivateOptionEnabled() const;
+ void setDefaultRemoteLocation(const QString &url);
+ void setLocalBaseDirectory(const QString &dir);
+ // Pull-specific options
+ // Push-specific options
+
+protected:
+ void changeEvent(QEvent *e) final;
+
+private:
+ Mode m_mode;
+ Ui::PullOrPushDialog *m_ui;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/pullorpushdialog.ui b/plugins/fossil/pullorpushdialog.ui
new file mode 100644
index 0000000..eec4705
--- /dev/null
+++ b/plugins/fossil/pullorpushdialog.ui
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Fossil::Internal::PullOrPushDialog</class>
+ <widget class="QDialog" name="Fossil::Internal::PullOrPushDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>477</width>
+ <height>268</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Remote Location</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="defaultButton">
+ <property name="text">
+ <string>Default location</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QRadioButton" name="localButton">
+ <property name="text">
+ <string>Local filesystem:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="Utils::PathChooser" name="localPathChooser" native="true">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QRadioButton" name="urlButton">
+ <property name="toolTip">
+ <string>For example: https://[user[:pass]@]host[:port]/[path]</string>
+ </property>
+ <property name="text">
+ <string>Specify URL:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="urlLineEdit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>For example: https://[user[:pass]@]host[:port]/[path]</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0" colspan="2">
+ <widget class="QCheckBox" name="rememberCheckBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remember specified location as default</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QCheckBox" name="privateCheckBox">
+ <property name="toolTip">
+ <string>Allow transfer of private branches.</string>
+ </property>
+ <property name="text">
+ <string>Include private branches</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>4</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/pathchooser.h</header>
+ <container>1</container>
+ <slots>
+ <signal>editingFinished()</signal>
+ <signal>browsingFinished()</signal>
+ </slots>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Fossil::Internal::PullOrPushDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>177</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Fossil::Internal::PullOrPushDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>325</x>
+ <y>177</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>urlButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>urlLineEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>80</x>
+ <y>121</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>332</x>
+ <y>123</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>localButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>localPathChooser</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>112</x>
+ <y>81</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>346</x>
+ <y>81</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>urlButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>rememberCheckBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>71</x>
+ <y>92</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>163</x>
+ <y>153</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>localButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>rememberCheckBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>71</x>
+ <y>67</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>163</x>
+ <y>153</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/plugins/fossil/revertdialog.ui b/plugins/fossil/revertdialog.ui
new file mode 100644
index 0000000..1d43276
--- /dev/null
+++ b/plugins/fossil/revertdialog.ui
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Fossil::Internal::RevertDialog</class>
+ <widget class="QDialog" name="Fossil::Internal::RevertDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>120</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Revert</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Specify a revision other than the default?</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <widget class="QWidget" name="formLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>361</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="revisionLabel">
+ <property name="toolTip">
+ <string>Checkout revision, can also be a branch or a tag name.</string>
+ </property>
+ <property name="text">
+ <string>Revision:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="revisionLineEdit">
+ <property name="toolTip">
+ <string>Checkout revision, can also be a branch or a tag name.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Fossil::Internal::RevertDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Fossil::Internal::RevertDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/plugins/fossil/revisioninfo.cpp b/plugins/fossil/revisioninfo.cpp
new file mode 100644
index 0000000..3e63934
--- /dev/null
+++ b/plugins/fossil/revisioninfo.cpp
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "revisioninfo.h"
+
+namespace Fossil {
+namespace Internal {
+
+RevisionInfo::RevisionInfo(const QString &revisionId, const QString &parent) :
+ id(revisionId),
+ parentId(parent)
+{ }
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/revisioninfo.h b/plugins/fossil/revisioninfo.h
new file mode 100644
index 0000000..294bfa2
--- /dev/null
+++ b/plugins/fossil/revisioninfo.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "branchinfo.h"
+
+#include <QString>
+#include <QStringList>
+
+namespace Fossil {
+namespace Internal {
+
+class RevisionInfo
+{
+public:
+ explicit RevisionInfo(const QString &revisionId = QString(), const QString &parent = QString());
+
+ const QString id;
+ const QString parentId;
+
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/wizard/fossiljsextension.cpp b/plugins/fossil/wizard/fossiljsextension.cpp
new file mode 100644
index 0000000..664e1c2
--- /dev/null
+++ b/plugins/fossil/wizard/fossiljsextension.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "fossiljsextension.h"
+#include "../constants.h"
+#include "../fossilclient.h"
+#include "../fossilplugin.h"
+
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
+
+#include <vcsbase/vcsbaseclientsettings.h>
+#include <vcsbase/vcsbaseconstants.h>
+
+using namespace Core;
+
+namespace Fossil {
+namespace Internal {
+
+
+class FossilJsExtensionPrivate {
+
+public:
+ FossilJsExtensionPrivate() :
+ m_vscId(Constants::VCS_ID_FOSSIL) { }
+
+ FossilClient *client() const {
+ return FossilPlugin::instance()->client();
+ }
+
+ Core::Id m_vscId;
+};
+
+
+void FossilJsExtension::parseArgOptions(const QStringList &args, QMap<QString, QString> &options)
+{
+ options.clear();
+
+ foreach (const QString &arg, args) {
+ if (arg.isEmpty()) continue;
+
+ QStringList opt = arg.split('|', QString::KeepEmptyParts);
+ options.insert(opt[0], opt.size() > 1 ? opt[1] : QString());
+ }
+}
+
+FossilJsExtension::FossilJsExtension() :
+ d(new FossilJsExtensionPrivate)
+{ }
+
+FossilJsExtension::~FossilJsExtension()
+{
+ delete d;
+}
+
+bool FossilJsExtension::isConfigured() const
+{
+ IVersionControl *vc = VcsManager::versionControl(d->m_vscId);
+ return vc && vc->isConfigured();
+}
+
+QString FossilJsExtension::displayName() const
+{
+ IVersionControl *vc = VcsManager::versionControl(d->m_vscId);
+ return vc ? vc->displayName() : QString();
+}
+
+QString FossilJsExtension::defaultAdminUser() const
+{
+ if (!isConfigured())
+ return QString();
+
+ VcsBase::VcsBaseClientSettings &settings = d->client()->settings();
+ return settings.stringValue(FossilSettings::userNameKey);
+}
+
+QString FossilJsExtension::defaultSslIdentityFile() const
+{
+ if (!isConfigured())
+ return QString();
+
+ VcsBase::VcsBaseClientSettings &settings = d->client()->settings();
+ return settings.stringValue(FossilSettings::sslIdentityFileKey);
+}
+
+QString FossilJsExtension::defaultLocalRepoPath() const
+{
+ if (!isConfigured())
+ return QString();
+
+ VcsBase::VcsBaseClientSettings &settings = d->client()->settings();
+ return settings.stringValue(FossilSettings::defaultRepoPathKey);
+}
+
+bool FossilJsExtension::defaultDisableAutosync() const
+{
+ if (!isConfigured())
+ return false;
+
+ VcsBase::VcsBaseClientSettings &settings = d->client()->settings();
+ return settings.boolValue(FossilSettings::disableAutosyncKey);
+}
+
+} // namespace Internal
+} // namespace Fossil
+
diff --git a/plugins/fossil/wizard/fossiljsextension.h b/plugins/fossil/wizard/fossiljsextension.h
new file mode 100644
index 0000000..d1f90d2
--- /dev/null
+++ b/plugins/fossil/wizard/fossiljsextension.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 Artur Shepilko
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <vcsbase/wizard/vcsjsextension.h>
+
+#include <QStringList>
+#include <QMap>
+#include <QObject>
+
+namespace Fossil {
+namespace Internal {
+
+class FossilJsExtensionPrivate;
+
+class FossilJsExtension : public QObject
+{
+ Q_OBJECT
+
+public:
+ static void parseArgOptions(const QStringList &args, QMap<QString, QString> &options);
+
+ FossilJsExtension();
+ ~FossilJsExtension();
+
+ Q_INVOKABLE bool isConfigured() const;
+ Q_INVOKABLE QString displayName() const;
+ Q_INVOKABLE QString defaultAdminUser() const;
+ Q_INVOKABLE QString defaultSslIdentityFile() const;
+ Q_INVOKABLE QString defaultLocalRepoPath() const;
+ Q_INVOKABLE bool defaultDisableAutosync() const;
+
+private:
+ FossilJsExtensionPrivate *d = nullptr;
+};
+
+} // namespace Internal
+} // namespace Fossil
diff --git a/plugins/fossil/wizard/projects/vcs/icon.png b/plugins/fossil/wizard/projects/vcs/icon.png
new file mode 100644
index 0000000..496f881
--- /dev/null
+++ b/plugins/fossil/wizard/projects/vcs/icon.png
Binary files differ
diff --git a/plugins/fossil/wizard/projects/vcs/wizard.json b/plugins/fossil/wizard/projects/vcs/wizard.json
new file mode 100644
index 0000000..30423ed
--- /dev/null
+++ b/plugins/fossil/wizard/projects/vcs/wizard.json
@@ -0,0 +1,255 @@
+{
+ "version": 1,
+ "kind": "project",
+ "id": "I.Fossil",
+ "category": "T.Import",
+ "trDescription": "Clones a Fossil repository and tries to load the contained project.",
+ "trDisplayName": "Fossil Clone",
+ "trDisplayCategory": "Import Project",
+ "icon": "icon.png",
+ "enabled": "%{JS: [ %{Plugins} ].indexOf('Fossil') >= 0}",
+
+ "options":
+ [
+ { "key": "vcsId", "value": "I.Fossil" },
+ { "key": "vcsName", "value": "%{JS: Vcs.displayName('%{vcsId}')}" },
+ { "key": "isCloneRepo", "value": "%{JS: '%{RepoType}' === 'cloneRepo' }" },
+ { "key": "isLocalRepo", "value": "%{JS: '%{RepoType}' === 'localRepo' }" },
+ { "key": "SR", "value": "%{JS: '%{Repo}'.replace(/\\.(fossil|fsl)$/, '') }"},
+ { "key": "defaultDir", "value": "%{JS: %{isCloneRepo} ? '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/\\./, '-') : %{isLocalRepo} ? Util.baseName('%{LocalRepo}') : '' }"},
+ { "key": "defaultFossilName", "value": "%{JS: %{isCloneRepo} ? '%{defaultDir}' : %{isLocalRepo} ? Util.completeBaseName('%{LocalRepo}') : '' }" },
+ { "key": "defaultLocalRepoPath", "value": "%{JS: Fossil.defaultLocalRepoPath() }" },
+ { "key": "defaultSslIdentityFile", "value": "%{JS: Fossil.defaultSslIdentityFile() }" },
+ { "key": "defaultDisableAutosync", "value": "%{JS: Fossil.defaultDisableAutosync() }" },
+ { "key": "SourceRepo", "value": "%{JS: %{isCloneRepo} ? '%{Repo}' : %{isLocalRepo} ? '%{LocalRepo}' : '' }" },
+ { "key": "TargetPath", "value": "%{Path}/%{Dir}" },
+ { "key": "FossilFile", "value": "%{defaultLocalRepoPath}/%{FossilName}.fossil" },
+ { "key": "argRepoType", "value": "repository-type|%{RepoType}" },
+ { "key": "argBranchTag", "value": "%{JS: '%{Branch}' ? 'branch-tag|%{Branch}' : '' }" },
+ { "key": "argAdminUser", "value": "%{JS: '%{AdminUser}' ? 'admin-user|%{AdminUser}' : '' }" },
+ { "key": "argSslIdentity", "value": "%{JS: '%{SslIdentity}' ? 'ssl-identity|%{SslIdentity}' : '' }" },
+ { "key": "argIncludePrivate", "value": "%{JS: '%{IncludePrivate}' ? 'include-private|%{IncludePrivate}' : '' }" },
+ { "key": "argDisableAutosync", "value": "%{JS: '%{DisableAutosync}' ? 'settings-autosync|%{DisableAutosync}' : '' }" },
+ { "key": "argFossilFile", "value": "fossil-file|%{FossilFile}" }
+ ],
+
+ "pages":
+ [
+ {
+ "trDisplayName": "Configuration",
+ "trShortTitle": "Configuration",
+ "trSubTitle": "Please configure <b>%{vcsName}</b> now.",
+ "typeId": "VcsConfiguration",
+ "enabled": "%{JS: !Vcs.isConfigured('%{vcsId}')}",
+ "data": { "vcsId": "%{vcsId}" }
+ },
+ {
+ "trDisplayName": "Select repository location type",
+ "trShortTitle": "Repository",
+ "typeId": "Fields",
+ "data":
+ [
+ {
+ "name": "RepoType",
+ "type": "ComboBox",
+ "data":
+ {
+ "index": 0,
+ "items":
+ [
+ { "trKey": "Remote repository clone", "value": "cloneRepo" },
+ { "trKey": "Local repository checkout", "value": "localRepo" }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "trDisplayName": "Location",
+ "trShortTitle": "Location",
+ "trSubTitle": "Specify repository location, branch, checkout destination, and options.",
+ "typeId": "Fields",
+ "data" :
+ [
+ {
+ "name": "GotSource",
+ "type": "LineEdit",
+ "visible": false,
+ "mandatory": true,
+ "isComplete": "%{JS: '%{FossilName}' === '' || (%{isCloneRepo} && !Util.exists('%{FossilFile}')) }",
+ "trIncompleteMessage": "The clone fossil already exists in local repositories path.",
+ "data":
+ {
+ "trText": "%{JS: (%{isCloneRepo} && '%{Repo}' !== '' && '%{FossilName}' !== '') || (%{isLocalRepo} && '%{LocalRepo}' !== '') ? 'true' : '' }"
+ }
+ },
+ {
+ "name": "Repo",
+ "trDisplayName": "Remote repository:",
+ "trToolTip": "For example: https://[user[:pass]@]host[:port]/[path]",
+ "type": "LineEdit",
+ "enabled": "%{isCloneRepo}",
+ "mandatory": false
+ },
+ {
+ "name": "FossilName",
+ "trDisplayName": "Local clone:",
+ "trToolTip": "Base name of a new local fossil file to clone into.",
+ "type": "LineEdit",
+ "enabled": "%{isCloneRepo}",
+ "mandatory": false,
+ "data":
+ {
+ "trText": "%{defaultFossilName}"
+ }
+ },
+ {
+ "name": "LocalRepo",
+ "trDisplayName": "Local repository:",
+ "trToolTip": "Path of an existing local fossil file to check out from.",
+ "type": "PathChooser",
+ "enabled": "%{isLocalRepo}",
+ "mandatory": false,
+ "data":
+ {
+ "kind": "file",
+ "basePath": "%{defaultLocalRepoPath}"
+ }
+ },
+ {
+ "name": "Branch",
+ "trDisplayName": "Branch:",
+ "type": "LineEdit",
+ "mandatory": false,
+ "data":
+ {
+ "trPlaceholder": "<default branch>"
+ }
+ },
+ {
+ "name": "Sp1",
+ "type": "Spacer",
+ "data": { "factor": 2 }
+ },
+ {
+ "name": "Dir",
+ "trDisplayName": "Checkout directory:",
+ "type": "LineEdit",
+ "isComplete": "%{JS: '%{Dir}' === '' || !Util.exists('%{TargetPath}')}",
+ "trIncompleteMessage": "The checkout directory already exists in the filesystem.",
+ "data":
+ {
+ "trText": "%{defaultDir}"
+ }
+ },
+ {
+ "name": "Path",
+ "trDisplayName": "Create in:",
+ "type": "PathChooser",
+ "data":
+ {
+ "kind": "existingDirectory",
+ "basePath": "%{InitialPath}",
+ "path": "%{InitialPath}"
+ }
+ },
+ {
+ "name": "Sp2",
+ "type": "Spacer",
+ "data": { "factor": 2 }
+ },
+ {
+ "name": "AdminUser",
+ "trDisplayName": "Admin user:",
+ "trToolTip": "Privileged user added automatically to the created local repository.",
+ "type": "LineEdit",
+ "mandatory": false,
+ "enabled": "%{isCloneRepo}",
+ "data":
+ {
+ "trText": "%{JS: Fossil.defaultAdminUser()}"
+ }
+ },
+ {
+ "name": "SslIdentity",
+ "trDisplayName": "SSL/TLS identity:",
+ "trToolTip": "SSL/TLS client identity key to use if requested by the server.",
+ "type": "PathChooser",
+ "mandatory": false,
+ "enabled": "%{isCloneRepo}",
+ "data":
+ {
+ "kind": "file",
+ "path": "%{defaultSslIdentityFile}"
+ }
+ },
+ {
+ "name": "IncludePrivate",
+ "trDisplayName": "Include private branches",
+ "trToolTip": "Allow transfer of private branches.",
+ "type": "CheckBox",
+ "enabled": "%{isCloneRepo}",
+ "data":
+ {
+ "checkedValue": "true",
+ "uncheckedValue": ""
+ }
+ },
+ {
+ "name": "DisableAutosync",
+ "trDisplayName": "Disable auto-sync",
+ "trToolTip": "Disable automatic pull prior to commit or update and automatic push after commit or tag or branch creation.",
+ "type": "CheckBox",
+ "enabled": "%{isCloneRepo}",
+ "data":
+ {
+ "checkedValue": "off",
+ "uncheckedValue": "",
+ "checked": "%{defaultDisableAutosync}"
+ }
+ }
+
+ ]
+ },
+ {
+ "trDisplayName": "Checkout",
+ "trShortTitle": "Checkout",
+ "typeId": "VcsCommand",
+ "data" :
+ {
+ "vcsId": "%{vcsId}",
+ "trRunMessage": "Running Fossil clone...",
+ "repository": "%{SourceRepo}",
+ "baseDirectory": "%{Path}",
+ "checkoutName": "%{Dir}",
+ "extraArguments":
+ [
+ "%{argRepoType}",
+ "%{argBranchTag}",
+ "%{argAdminUser}",
+ "%{argSslIdentity}",
+ "%{argIncludePrivate}",
+ "%{argDisableAutosync}",
+ "%{argFossilFile}"
+ ],
+ "extraJobs" :
+ [
+ {
+ "command": "fossil",
+ "arguments": [ "version" ]
+ }
+ ]
+ }
+ }
+ ],
+
+ "generators":
+ [
+ {
+ "typeId": "Scanner",
+ "data": {
+ "subdirectoryPatterns": [ "^src$" ]
+ }
+ }
+ ]
+}