summaryrefslogtreecommitdiff
path: root/src/plugins/git
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/git')
-rw-r--r--src/plugins/git/ScmGit.pluginspec13
-rw-r--r--src/plugins/git/TODO.txt26
-rw-r--r--src/plugins/git/annotationhighlighter.cpp53
-rw-r--r--src/plugins/git/annotationhighlighter.h58
-rw-r--r--src/plugins/git/changeselectiondialog.cpp71
-rw-r--r--src/plugins/git/changeselectiondialog.h63
-rw-r--r--src/plugins/git/changeselectiondialog.ui91
-rw-r--r--src/plugins/git/commitdata.cpp96
-rw-r--r--src/plugins/git/commitdata.h81
-rw-r--r--src/plugins/git/git.pro35
-rw-r--r--src/plugins/git/gitclient.cpp635
-rw-r--r--src/plugins/git/gitclient.h168
-rw-r--r--src/plugins/git/gitconstants.h58
-rw-r--r--src/plugins/git/giteditor.cpp145
-rw-r--r--src/plugins/git/giteditor.h68
-rw-r--r--src/plugins/git/gitoutputwindow.cpp122
-rw-r--r--src/plugins/git/gitoutputwindow.h79
-rw-r--r--src/plugins/git/gitplugin.cpp717
-rw-r--r--src/plugins/git/gitplugin.h163
-rw-r--r--src/plugins/git/gitsubmiteditor.cpp92
-rw-r--r--src/plugins/git/gitsubmiteditor.h67
-rw-r--r--src/plugins/git/gitsubmiteditorwidget.cpp69
-rw-r--r--src/plugins/git/gitsubmiteditorwidget.h73
-rw-r--r--src/plugins/git/gitsubmitpanel.ui101
-rw-r--r--src/plugins/git/settingspage.cpp115
-rw-r--r--src/plugins/git/settingspage.h82
-rw-r--r--src/plugins/git/settingspage.ui135
27 files changed, 3476 insertions, 0 deletions
diff --git a/src/plugins/git/ScmGit.pluginspec b/src/plugins/git/ScmGit.pluginspec
new file mode 100644
index 0000000000..689cc30a57
--- /dev/null
+++ b/src/plugins/git/ScmGit.pluginspec
@@ -0,0 +1,13 @@
+<plugin name="ScmGit" version="0.1" compatVersion="0.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Git integration.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="VCSBase" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/git/TODO.txt b/src/plugins/git/TODO.txt
new file mode 100644
index 0000000000..2913ba5f46
--- /dev/null
+++ b/src/plugins/git/TODO.txt
@@ -0,0 +1,26 @@
+- Make texts translateable
+- Do not use QErrorMessage, Creator standard error instead?
+Commands:
+ - P2:
+ - branch [list, create, delete]
+ - checkout [with/without creation]
+ - combine both above to a single dialog?
+ - P3:
+ - stash [creating, listing, applying]
+ - allow to use external viewer instead of greenhouse one
+ as these have more functionality usually
+
+GUI:
+ - Better diff view
+ - Commit view View (reuse diff view?)
+ - Commit action View
+ - Able to add further files to commit (list of modified/untracked files)
+ - use List for Log (and allow 10+ entries)
+ - Have commits clickable for 'git show'
+Backend:
+ - Don't use forked processes, instead find a library connection like libgit-thin
+ - http://repo.or.cz/w/git/libgit-gsoc.git
+ - apply to SCM Manager in Greenhouse, currently it's mostly independent
+
+Suggestions:
+ - Bjorn: Use a "Summary" Lineedit in the commit dialog to make commits look nicer on gitweb or such.
diff --git a/src/plugins/git/annotationhighlighter.cpp b/src/plugins/git/annotationhighlighter.cpp
new file mode 100644
index 0000000000..534c45395b
--- /dev/null
+++ b/src/plugins/git/annotationhighlighter.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "annotationhighlighter.h"
+#include <QtCore/QDebug>
+
+namespace Git {
+namespace Internal {
+
+GitAnnotationHighlighter::GitAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document) :
+ VCSBase::BaseAnnotationHighlighter(changeNumbers, document),
+ m_blank(QLatin1Char(' '))
+{
+}
+
+QString GitAnnotationHighlighter::changeNumber(const QString &block) const
+{
+ const int pos = block.indexOf(m_blank, 4);
+ return pos > 1 ? block.left(pos) : QString();
+}
+
+}
+}
diff --git a/src/plugins/git/annotationhighlighter.h b/src/plugins/git/annotationhighlighter.h
new file mode 100644
index 0000000000..3368e4dc9f
--- /dev/null
+++ b/src/plugins/git/annotationhighlighter.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ANNOTATIONHIGHLIGHTER_H
+#define ANNOTATIONHIGHLIGHTER_H
+
+#include <vcsbase/baseannotationhighlighter.h>
+
+namespace Git {
+namespace Internal {
+
+// Annotation highlighter for p4 triggering on 'changenumber:'
+class GitAnnotationHighlighter : public VCSBase::BaseAnnotationHighlighter
+{
+ Q_OBJECT
+public:
+ explicit GitAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document = 0);
+
+private:
+ virtual QString changeNumber(const QString &block) const;
+
+ const QChar m_blank;
+};
+
+} //namespace Git
+} //namespace Internal
+
+#endif
diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp
new file mode 100644
index 0000000000..6491614b5f
--- /dev/null
+++ b/src/plugins/git/changeselectiondialog.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "changeselectiondialog.h"
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+
+using namespace Git::Internal;
+
+ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.repositoryButton, SIGNAL(clicked()), this, SLOT(selectWorkingDirectory()));
+}
+
+void ChangeSelectionDialog::selectWorkingDirectory()
+{
+ static QString location = QString();
+ location = QFileDialog::getExistingDirectory(this,
+ QLatin1String("Select Git repository"),
+ location);
+ if (location.isEmpty())
+ return;
+
+ // Verify that the location is a repository
+ // We are polite, we also allow to specify a directory, which is not
+ // the head directory of the repository.
+ QDir repository(location);
+ do {
+ if (repository.entryList(QDir::AllDirs).contains(QLatin1String(".git"))) {
+ m_ui.repositoryEdit->setText(repository.absolutePath());
+ return;
+ }
+ } while (repository.cdUp());
+
+ // Did not find a repo
+ QMessageBox::critical(this, QLatin1String("Error"),
+ QLatin1String("Selected directory is not a Git repository"));
+
+}
diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h
new file mode 100644
index 0000000000..02d0aa76d3
--- /dev/null
+++ b/src/plugins/git/changeselectiondialog.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CHANGESELECTIONDIALOG_H
+#define CHANGESELECTIONDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_changeselectiondialog.h"
+
+namespace Git {
+namespace Internal {
+
+ class GitPlugin;
+
+class ChangeSelectionDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ChangeSelectionDialog(QWidget *parent = 0);
+
+public slots:
+ void selectWorkingDirectory();
+
+private:
+ friend class GitPlugin;
+ Ui_ChangeSelectionDialog m_ui;
+
+};
+
+} //namespace Internal
+} //namespace Git
+
+#endif // CHANGESELECTIONDIALOG_H
diff --git a/src/plugins/git/changeselectiondialog.ui b/src/plugins/git/changeselectiondialog.ui
new file mode 100644
index 0000000000..34f2718ec8
--- /dev/null
+++ b/src/plugins/git/changeselectiondialog.ui
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChangeSelectionDialog</class>
+ <widget class="QDialog" name="ChangeSelectionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>401</width>
+ <height>142</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Repository Location:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="repositoryEdit"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="repositoryButton">
+ <property name="text">
+ <string>Select</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Change:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="changeNumberEdit"/>
+ </item>
+ <item row="2" column="0" colspan="3">
+ <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>ChangeSelectionDialog</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>ChangeSelectionDialog</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/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp
new file mode 100644
index 0000000000..aafafe1566
--- /dev/null
+++ b/src/plugins/git/commitdata.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "commitdata.h"
+
+#include <QtCore/QDebug>
+
+namespace Git {
+namespace Internal {
+
+void GitSubmitEditorPanelInfo::clear()
+{
+ repository.clear();
+ description.clear();
+ branch.clear();
+}
+
+QDebug operator<<(QDebug d, const GitSubmitEditorPanelInfo &data)
+{
+ d.nospace() << "Rep: " << data.repository << " Descr: " << data.description
+ << " branch: " << data.branch;
+ return d;
+}
+
+void GitSubmitEditorPanelData::clear()
+{
+ author.clear();
+ email.clear();
+}
+
+QString GitSubmitEditorPanelData::authorString() const
+{
+ QString rc;
+ rc += QLatin1Char('"');
+ rc += author;
+ rc += QLatin1String(" <");
+ rc += email;
+ rc += QLatin1String(">\"");
+ return rc;
+}
+
+QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &data)
+{
+ d.nospace() << " author:" << data.author << " email: " << data.email;
+ return d;
+}
+
+void CommitData::clear()
+{
+ panelInfo.clear();
+ panelData.clear();
+
+ commitFiles.clear();
+ notUpdatedFiles.clear();
+ untrackedFiles.clear();
+}
+
+QDebug operator<<(QDebug d, const CommitData &data)
+{
+ d << data.panelInfo << data.panelData;
+ d.nospace() << "Commit: " << data.commitFiles << " Not updated: "
+ << data.notUpdatedFiles << " Untracked: " << data.untrackedFiles;
+ return d;
+}
+
+}
+}
diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h
new file mode 100644
index 0000000000..94a82005ae
--- /dev/null
+++ b/src/plugins/git/commitdata.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMMITDATA_H
+#define COMMITDATA_H
+
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+QT_END_NAMESPACE
+
+namespace Git {
+namespace Internal {
+
+ // Read-only
+ struct GitSubmitEditorPanelInfo {
+ void clear();
+ QString repository;
+ QString description;
+ QString branch;
+ };
+
+ QDebug operator<<(QDebug d, const GitSubmitEditorPanelInfo &);
+
+ struct GitSubmitEditorPanelData {
+ void clear();
+ // Format as "John Doe <jdoe@foobar.com>"
+ QString authorString() const;
+
+ QString author;
+ QString email;
+ };
+
+ QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &);
+
+ struct CommitData {
+ void clear();
+ GitSubmitEditorPanelInfo panelInfo;
+ GitSubmitEditorPanelData panelData;
+ QStringList commitFiles;
+ QStringList notUpdatedFiles;
+ QStringList untrackedFiles;
+ };
+
+ QDebug operator<<(QDebug d, const CommitData &);
+
+
+}
+}
+
+#endif
diff --git a/src/plugins/git/git.pro b/src/plugins/git/git.pro
new file mode 100644
index 0000000000..258639dcbe
--- /dev/null
+++ b/src/plugins/git/git.pro
@@ -0,0 +1,35 @@
+TEMPLATE = lib
+TARGET = ScmGit
+include(../../qworkbenchplugin.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/vcsbase/vcsbase.pri)
+include(../../libs/utils/utils.pri)
+
+HEADERS += gitplugin.h \
+ gitconstants.h \
+ gitoutputwindow.h \
+ gitclient.h \
+ changeselectiondialog.h \
+ commitdata.h \
+ settingspage.h \
+ giteditor.h \
+ annotationhighlighter.h \
+ gitsubmiteditorwidget.h \
+ gitsubmiteditor.h
+
+SOURCES += gitplugin.cpp \
+ gitoutputwindow.cpp \
+ gitclient.cpp \
+ changeselectiondialog.cpp \
+ commitdata.cpp \
+ settingspage.cpp \
+ giteditor.cpp \
+ annotationhighlighter.cpp \
+ gitsubmiteditorwidget.cpp \
+ gitsubmiteditor.cpp
+
+FORMS += changeselectiondialog.ui \
+ settingspage.ui \
+ gitsubmitpanel.ui
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
new file mode 100644
index 0000000000..b3f7107861
--- /dev/null
+++ b/src/plugins/git/gitclient.cpp
@@ -0,0 +1,635 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitclient.h"
+#include "gitplugin.h"
+#include "gitconstants.h"
+#include "commitdata.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/progressmanager/progressmanagerinterface.h>
+#include <vcsbase/vcsbaseeditor.h>
+#include <texteditor/itexteditor.h>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QFuture>
+
+#include <QtGui/QErrorMessage>
+
+using namespace Git;
+using namespace Git::Internal;
+
+const char* const kGitCommand = "git";
+const char* const kGitDirectoryC = ".git";
+const char* const kBranchIndicatorC = "# On branch";
+
+static inline QString msgServerFailure()
+{
+ return GitClient::tr(
+"Note that the git plugin for QtCreator is not able to interact with the server "
+"so far. Thus, manual ssh-identification etc. will not work.");
+}
+
+inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property, const QString &entry)
+{
+ foreach (Core::IEditor *ed, core->editorManager()->openedEditors())
+ if (ed->property(property).toString() == entry)
+ return ed;
+ return 0;
+}
+
+GitClient::GitClient(GitPlugin* plugin, Core::ICore *core) :
+ m_msgWait(tr("Waiting for data...")),
+ m_plugin(plugin),
+ m_core(core)
+{
+}
+
+GitClient::~GitClient()
+{
+}
+
+bool GitClient::vcsOpen(const QString &fileName)
+{
+ return m_plugin->vcsOpen(fileName);
+}
+
+QString GitClient::findRepositoryForFile(const QString &fileName)
+{
+ const QString gitDirectory = QLatin1String(kGitDirectoryC);
+ const QFileInfo info(fileName);
+ QDir dir = info.absoluteDir();
+ do {
+ if (dir.entryList(QDir::AllDirs|QDir::Hidden).contains(gitDirectory))
+ return dir.absolutePath();
+ } while (dir.cdUp());
+
+ return QString();
+}
+
+QString GitClient::findRepositoryForDirectory(const QString &dir)
+{
+ const QString gitDirectory = QLatin1String(kGitDirectoryC);
+ QDir directory(dir);
+ do {
+ if (directory.entryList(QDir::AllDirs|QDir::Hidden).contains(gitDirectory))
+ return directory.absolutePath();
+ } while (directory.cdUp());
+
+ return QString();
+}
+
+// Return source file or directory string depending on parameters
+// ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file').
+static QString source(const QString &workingDirectory, const QString &fileName)
+{
+ if (fileName.isEmpty())
+ return workingDirectory;
+ QString rc = workingDirectory;
+ if (!rc.isEmpty() && !rc.endsWith(QDir::separator()))
+ rc += QDir::separator();
+ rc += fileName;
+ return rc;
+}
+
+/* Create an editor associated to VCS output of a source file/directory
+ * (using the file's codec). Makes use of a dynamic property to find an
+ * existing instance and to reuse it (in case, say, 'git diff foo' is
+ * already open). */
+VCSBase::VCSBaseEditor
+ *GitClient::createVCSEditor(const QString &kind,
+ QString title,
+ // Source file or directory
+ const QString &source,
+ bool setSourceCodec,
+ // Dynamic property and value to identify that editor
+ const char *registerDynamicProperty,
+ const QString &dynamicPropertyValue) const
+{
+ VCSBase::VCSBaseEditor *rc = 0;
+ Core::IEditor* outputEditor = locateEditor(m_core, registerDynamicProperty, dynamicPropertyValue);
+ if (outputEditor) {
+ // Exists already
+ outputEditor->createNew(m_msgWait);
+ rc = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
+ Q_ASSERT(rc);
+ m_core->editorManager()->setCurrentEditor(outputEditor);
+ } else {
+ // Create new, set wait message, set up with source and codec
+ outputEditor = m_core->editorManager()->newFile(kind, &title, m_msgWait);
+ outputEditor->setProperty(registerDynamicProperty, dynamicPropertyValue);
+ rc = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
+ Q_ASSERT(rc);
+ rc->setSource(source);
+ if (setSourceCodec)
+ rc->setCodec(VCSBase::VCSBaseEditor::getCodec(m_core, source));
+ }
+ return rc;
+}
+
+void GitClient::diff(const QString &workingDirectory, const QStringList &fileNames)
+{
+ if (Git::Constants::debug)
+ qDebug() << "diff" << workingDirectory << fileNames;
+ QStringList arguments;
+ arguments << QLatin1String("diff") << fileNames;
+
+ const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND);
+ const QString title = tr("Git Diff");
+
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingDirectory, true, "originalFileName", workingDirectory);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+
+}
+
+void GitClient::diff(const QString &workingDirectory, const QString &fileName)
+{
+ if (Git::Constants::debug)
+ qDebug() << "diff" << workingDirectory << fileName;
+ QStringList arguments;
+ arguments << QLatin1String("diff");
+ if (!fileName.isEmpty())
+ arguments << fileName;
+
+ const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND);
+ const QString title = tr("Git Diff %1").arg(fileName);
+ const QString sourceFile = source(workingDirectory, fileName);
+
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "originalFileName", sourceFile);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::status(const QString &workingDirectory)
+{
+ executeGit(workingDirectory, QStringList(QLatin1String("status")), m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::log(const QString &workingDirectory, const QString &fileName)
+{
+ if (Git::Constants::debug)
+ qDebug() << "log" << workingDirectory << fileName;
+ QStringList arguments;
+ int logCount = 10;
+ if (m_plugin->m_settingsPage && m_plugin->m_settingsPage->logCount() > 0)
+ logCount = m_plugin->m_settingsPage->logCount();
+
+ arguments << QLatin1String("log") << QLatin1String("-n")
+ << QString::number(logCount);
+ if (!fileName.isEmpty())
+ arguments << fileName;
+
+ const QString title = tr("Git Log %1").arg(fileName);
+ const QString kind = QLatin1String(Git::Constants::GIT_LOG_EDITOR_KIND);
+ const QString sourceFile = source(workingDirectory, fileName);
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, false, "logFileName", sourceFile);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::show(const QString &source, const QString &id)
+{
+ if (Git::Constants::debug)
+ qDebug() << "show" << source << id;
+ QStringList arguments(QLatin1String("show"));
+ arguments << id;
+
+ const QString title = tr("Git Show %1").arg(id);
+ const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND);
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source, true, "show", id);
+
+ const QFileInfo sourceFi(source);
+ const QString workDir = sourceFi.isDir() ? sourceFi.absoluteFilePath() : sourceFi.absolutePath();
+ executeGit(workDir, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::blame(const QString &workingDirectory, const QString &fileName)
+{
+ if (Git::Constants::debug)
+ qDebug() << "blame" << workingDirectory << fileName;
+ QStringList arguments(QLatin1String("blame"));
+ arguments << fileName;
+
+ const QString kind = QLatin1String(Git::Constants::GIT_BLAME_EDITOR_KIND);
+ const QString title = tr("Git Blame %1").arg(fileName);
+ const QString sourceFile = source(workingDirectory, fileName);
+
+ VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "blameFileName", sourceFile);
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor);
+}
+
+void GitClient::checkout(const QString &workingDirectory, const QString &fileName)
+{
+ // Passing an empty argument as the file name is very dangereous, since this makes
+ // git checkout apply to all files. Almost looks like a bug in git.
+ if (fileName.isEmpty())
+ return;
+
+ QStringList arguments;
+ arguments << QLatin1String("checkout") << QLatin1String("HEAD") << QLatin1String("--")
+ << fileName;
+
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::hardReset(const QString &workingDirectory, const QString &commit)
+{
+ QStringList arguments;
+ arguments << QLatin1String("reset") << QLatin1String("--hard");
+ if (!commit.isEmpty())
+ arguments << commit;
+
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::addFile(const QString &workingDirectory, const QString &fileName)
+{
+ QStringList arguments;
+ arguments << QLatin1String("add") << fileName;
+
+ executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true);
+}
+
+bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringList &files)
+{
+ QByteArray outputText;
+ QByteArray errorText;
+ QStringList arguments;
+ arguments << "add" << files;
+ const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ if (!rc) {
+ const QString errorMessage = tr("Unable to add %n file(s) to %1: %2", 0, files.size()).
+ arg(workingDirectory, QString::fromLocal8Bit(errorText));
+ m_plugin->m_outputWindow->append(errorMessage);
+ m_plugin->m_outputWindow->popup(false);
+ }
+ return rc;
+}
+
+void GitClient::executeGit(const QString &workingDirectory, const QStringList &arguments,
+ GitOutputWindow *outputWindow, VCSBase::VCSBaseEditor* editor,
+ bool outputToWindow)
+{
+ if (Git::Constants::debug)
+ qDebug() << "executeGit" << workingDirectory << arguments << editor;
+ outputWindow->clearContents();
+
+ QProcess process;
+ ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
+
+ if (m_plugin->m_settingsPage && !m_plugin->m_settingsPage->adoptEnvironment())
+ environment.set(QLatin1String("PATH"), m_plugin->m_settingsPage->path());
+
+ GitCommand* command = new GitCommand();
+ if (outputToWindow) {
+ Q_ASSERT(outputWindow);
+ connect(command, SIGNAL(outputText(QString)), outputWindow, SLOT(append(QString)));
+ connect(command, SIGNAL(outputData(QByteArray)), outputWindow, SLOT(appendData(QByteArray)));
+ } else {
+ Q_ASSERT(editor);
+ connect(command, SIGNAL(outputText(QString)), editor, SLOT(setPlainText(QString)));
+ connect(command, SIGNAL(outputData(QByteArray)), editor, SLOT(setPlainTextData(QByteArray)));
+ }
+
+ if (outputWindow)
+ connect(command, SIGNAL(errorText(QString)), outputWindow, SLOT(append(QString)));
+
+ command->execute(arguments, workingDirectory, environment);
+}
+
+bool GitClient::synchronousGit(const QString &workingDirectory
+ , const QStringList &arguments
+ , QByteArray* outputText
+ , QByteArray* errorText)
+{
+ if (Git::Constants::debug)
+ qDebug() << "synchronousGit" << workingDirectory << arguments;
+ QProcess process;
+
+ process.setWorkingDirectory(workingDirectory);
+
+ ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
+ if (m_plugin->m_settingsPage && !m_plugin->m_settingsPage->adoptEnvironment())
+ environment.set(QLatin1String("PATH"), m_plugin->m_settingsPage->path());
+ process.setEnvironment(environment.toStringList());
+
+ process.start(QLatin1String(kGitCommand), arguments);
+ if (!process.waitForFinished()) {
+ if (errorText)
+ *errorText = "Error: Git timed out";
+ return false;
+ }
+
+ if (outputText)
+ *outputText = process.readAllStandardOutput();
+
+ if (errorText)
+ *errorText = process.readAllStandardError();
+
+ if (Git::Constants::debug)
+ qDebug() << "synchronousGit ex=" << process.exitCode();
+ return process.exitCode() == 0;
+}
+
+/* Parse a git status file list:
+ * \code
+ # Changes to be committed:
+ #<tab>modified:<blanks>git.pro
+ # Changed but not updated:
+ #<tab>modified:<blanks>git.pro
+ # Untracked files:
+ #<tab>modified:<blanks>git.pro
+ \endcode
+*/
+static bool parseFiles(const QStringList &lines, CommitData *d)
+{
+ enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles };
+
+ const QString branchIndicator = QLatin1String(kBranchIndicatorC);
+ const QString commitIndicator = QLatin1String("# Changes to be committed:");
+ const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:");
+ const QString untrackedIndicator = QLatin1String("# Untracked files:");
+
+ State s = None;
+
+ const QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+[^ ]+"));
+ Q_ASSERT(filesPattern.isValid());
+
+ const QStringList::const_iterator cend = lines.constEnd();
+ for (QStringList::const_iterator it = lines.constBegin(); it != cend; ++it) {
+ const QString line = *it;
+ if (line.startsWith(branchIndicator)) {
+ d->panelInfo.branch = line.mid(branchIndicator.size() + 1);
+ } else {
+ if (line.startsWith(commitIndicator)) {
+ s = CommitFiles;
+ } else {
+ if (line.startsWith(notUpdatedIndicator)) {
+ s = NotUpdatedFiles;
+ } else {
+ if (line.startsWith(untrackedIndicator)) {
+ s = UntrackedFiles;
+ } else {
+ if (filesPattern.exactMatch(line)) {
+ const QString fileSpec = line.mid(2).simplified();
+ switch (s) {
+ case CommitFiles:
+ d->commitFiles.push_back(fileSpec);
+ break;
+ case NotUpdatedFiles:
+ d->notUpdatedFiles.push_back(fileSpec);
+ break;
+ case UntrackedFiles:
+ d->untrackedFiles.push_back(fileSpec);
+ break;
+ case None:
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return !d->commitFiles.empty() || !d->notUpdatedFiles.empty() || !d->untrackedFiles.empty();
+}
+
+bool GitClient::getCommitData(const QString &workingDirectory,
+ QString *commitTemplate,
+ CommitData *d,
+ QString *errorMessage)
+{
+ d->clear();
+
+ // Find repo
+ const QString repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory);
+ if (repoDirectory.isEmpty()) {
+ *errorMessage = tr("Unable to determine the repository for %1.").arg(workingDirectory);
+ return false;
+ }
+
+ d->panelInfo.repository = repoDirectory;
+
+ QDir gitDir(repoDirectory);
+ if (!gitDir.cd(QLatin1String(kGitDirectoryC))) {
+ *errorMessage = tr("The repository %1 is not initialized yet.").arg(repoDirectory);
+ return false;
+ }
+
+ // Read description
+ const QString descriptionFile = gitDir.absoluteFilePath(QLatin1String("description"));
+ if (QFileInfo(descriptionFile).isFile()) {
+ QFile file(descriptionFile);
+ if (file.open(QIODevice::ReadOnly|QIODevice::Text))
+ d->panelInfo.description = QString::fromLocal8Bit(file.readAll()).trimmed();
+ }
+
+ // Run status. Note that it has exitcode 1 if there are no added files.
+ QByteArray outputText;
+ QByteArray errorText;
+ const bool statusRc = synchronousGit(workingDirectory, QStringList(QLatin1String("status")), &outputText, &errorText);
+ if (!statusRc) {
+ // Something fatal
+ if (!outputText.contains(kBranchIndicatorC)) {
+ *errorMessage = tr("Unable to obtain the project status: %1").arg(QString::fromLocal8Bit(errorText));
+ return false;
+ }
+ // All unchanged
+ if (outputText.contains("nothing to commit")) {
+ *errorMessage = tr("There are no modified files.");
+ return false;
+ }
+ }
+
+ // Output looks like:
+ // # On branch [branchname]
+ // # Changes to be committed:
+ // # (use "git reset HEAD <file>..." to unstage)
+ // #
+ // # modified: somefile.cpp
+ // # new File: somenew.h
+ // #
+ // # Changed but not updated:
+ // # (use "git add <file>..." to update what will be committed)
+ // #
+ // # modified: someother.cpp
+ // #
+ // # Untracked files:
+ // # (use "git add <file>..." to include in what will be committed)
+ // #
+ // # list of files...
+
+ const QStringList lines = QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r')).split(QLatin1Char('\n'));
+ if (!parseFiles(lines, d)) {
+ *errorMessage = tr("Unable to parse the file output.");
+ return false;
+ }
+
+ d->panelData.author = readConfigValue(workingDirectory, QLatin1String("user.name"));
+ d->panelData.email = readConfigValue(workingDirectory, QLatin1String("user.email"));
+
+ // Get the commit template
+ const QString templateFilename = readConfigValue(workingDirectory, QLatin1String("commit.template"));
+ if (!templateFilename.isEmpty()) {
+ QFile templateFile(templateFilename);
+ if (templateFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ *commitTemplate = QString::fromLocal8Bit(templateFile.readAll());
+ } else {
+ qWarning("Unable to read commit template %s: %s",
+ qPrintable(templateFilename),
+ qPrintable(templateFile.errorString()));
+ }
+ }
+ return true;
+}
+
+bool GitClient::addAndCommit(const QString &workingDirectory,
+ const GitSubmitEditorPanelData &data,
+ const QString &messageFile,
+ const QStringList &files)
+{
+ // Re-add all to make sure we have the latest changes
+ if (!synchronousAdd(workingDirectory, files))
+ return false;
+
+ // Do the final commit
+ QStringList args;
+ args << QLatin1String("commit")
+ << QLatin1String("-F") << QDir::toNativeSeparators(messageFile)
+ << QLatin1String("--author") << data.authorString();
+
+ QByteArray outputText;
+ QByteArray errorText;
+ const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
+ const QString message = rc ?
+ tr("Committed %n file(s).", 0, files.size()) :
+ tr("Unable to commit %n file(s): %1", 0, files.size()).arg(QString::fromLocal8Bit(errorText));
+
+ m_plugin->m_outputWindow->append(message);
+ m_plugin->m_outputWindow->popup(false);
+ return rc;
+}
+
+void GitClient::pull(const QString &workingDirectory)
+{
+ executeGit(workingDirectory, QStringList(QLatin1String("pull")), m_plugin->m_outputWindow, 0,true);
+}
+
+void GitClient::push(const QString &workingDirectory)
+{
+ executeGit(workingDirectory, QStringList(QLatin1String("push")), m_plugin->m_outputWindow, 0,true);
+}
+
+QString GitClient::readConfig(const QString &workingDirectory, const QStringList &configVar)
+{
+ QStringList arguments;
+ arguments << QLatin1String("config") << configVar;
+
+ QByteArray outputText;
+ if (synchronousGit(workingDirectory, arguments, &outputText))
+ return outputText;
+ return QString();
+}
+
+// Read a single-line config value, return trimmed
+QString GitClient::readConfigValue(const QString &workingDirectory, const QString &configVar)
+{
+ return readConfig(workingDirectory, QStringList(configVar)).remove(QLatin1Char('\n'));
+}
+
+GitCommand::GitCommand()
+{
+}
+
+GitCommand::~GitCommand()
+{
+}
+
+void GitCommand::execute(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment)
+{
+ if (Git::Constants::debug)
+ qDebug() << "GitCommand::execute" << workingDirectory << arguments;
+
+ // For some reason QtConcurrent::run() only works on this
+ QFuture<void> task = QtConcurrent::run(this, &GitCommand::run
+ , arguments
+ , workingDirectory
+ , environment);
+ QString taskName = QLatin1String("Git ") + arguments[0];
+
+ Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ core->progressManager()->addTask(task, taskName
+ , QLatin1String("Git.action")
+ , Core::ProgressManagerInterface::CloseOnSuccess);
+}
+
+void GitCommand::run(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment)
+{
+ if (Git::Constants::debug)
+ qDebug() << "GitCommand::run" << workingDirectory << arguments;
+ QProcess process;
+ if (!workingDirectory.isEmpty())
+ process.setWorkingDirectory(workingDirectory);
+
+ ProjectExplorer::Environment env = environment;
+ if (env.toStringList().isEmpty())
+ env = ProjectExplorer::Environment::systemEnvironment();
+ process.setEnvironment(env.toStringList());
+
+ process.start(QLatin1String(kGitCommand), arguments);
+ if (!process.waitForFinished()) {
+ emit errorText(QLatin1String("Error: Git timed out"));
+ return;
+ }
+
+ const QByteArray output = process.readAllStandardOutput();
+ if (output.isEmpty()) {
+ if (arguments.at(0) == QLatin1String("diff"))
+ emit outputText(tr("The file does not differ from HEAD"));
+ } else {
+ emit outputData(output);
+ }
+ const QByteArray error = process.readAllStandardError();
+ if (!error.isEmpty())
+ emit errorText(QString::fromLocal8Bit(error));
+
+ // As it is used asynchronously, we need to delete ourselves
+ this->deleteLater();
+}
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
new file mode 100644
index 0000000000..f91eefda66
--- /dev/null
+++ b/src/plugins/git/gitclient.h
@@ -0,0 +1,168 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITCLIENT_H
+#define GITCLIENT_H
+
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <projectexplorer/environment.h>
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QErrorMessage;
+QT_END_NAMESPACE
+
+namespace Core {
+ class ICore;
+}
+
+namespace VCSBase {
+ class VCSBaseEditor;
+}
+
+namespace Git {
+namespace Internal {
+
+class GitPlugin;
+class GitOutputWindow;
+class GitCommand;
+struct CommitData;
+struct GitSubmitEditorPanelData;
+
+class GitClient : public Core::IVersionControl
+{
+ Q_OBJECT
+public:
+ explicit GitClient(GitPlugin *plugin, Core::ICore *core);
+ ~GitClient();
+ bool vcsOpen(const QString &fileName);
+ bool vcsAdd(const QString&) {return false;}
+ bool vcsDelete(const QString&) {return false;}
+ bool managesDirectory(const QString&) const {return false;}
+ QString findTopLevelForDirectory(const QString&) const {return QString();}
+
+ static QString findRepositoryForFile(const QString &fileName);
+ static QString findRepositoryForDirectory(const QString &dir);
+
+ void diff(const QString &workingDirectory,
+ const QString &fileName);
+ void diff(const QString &workingDirectory,
+ const QStringList &fileNames);
+
+ void status(const QString &workingDirectory);
+ void log(const QString &workingDirectory
+ , const QString &fileName);
+ void blame(const QString &workingDirectory
+ , const QString &fileName);
+ void showCommit(const QString &workingDirectory
+ , const QString &commit);
+ void checkout(const QString &workingDirectory
+ , const QString &file);
+ void hardReset(const QString &workingDirectory
+ , const QString &commit);
+ void addFile(const QString &workingDirectory
+ , const QString &fileName);
+ bool synchronousAdd(const QString &workingDirectory,
+ const QStringList &files);
+ void pull(const QString &workingDirectory);
+ void push(const QString &workingDirectory);
+
+ QString readConfig(const QString &workingDirectory
+ , const QStringList &configVar);
+
+ QString readConfigValue(const QString &workingDirectory,
+ const QString &configVar);
+
+ bool getCommitData(const QString &workingDirectory,
+ QString *commitTemplate,
+ CommitData *d,
+ QString *errorMessage);
+
+ bool addAndCommit(const QString &workingDirectory,
+ const GitSubmitEditorPanelData &data,
+ const QString &messageFile,
+ const QStringList &files);
+
+public slots:
+ void show(const QString &source, const QString &id);
+
+private:
+ VCSBase::VCSBaseEditor *createVCSEditor(const QString &kind,
+ QString title,
+ const QString &source,
+ bool setSourceCodec,
+ const char *registerDynamicProperty,
+ const QString &dynamicPropertyValue) const;
+
+
+ void executeGit(const QString &workingDirectory
+ , const QStringList &arguments
+ , GitOutputWindow *outputWindow
+ , VCSBase::VCSBaseEditor* editor = 0
+ , bool outputToWindow = false);
+
+ bool synchronousGit(const QString &workingDirectory
+ , const QStringList &arguments
+ , QByteArray* outputText = 0
+ , QByteArray* errorText = 0);
+
+ const QString m_msgWait;
+ GitPlugin *m_plugin;
+ Core::ICore *m_core;
+};
+
+class GitCommand : public QObject
+{
+ Q_OBJECT
+public:
+ GitCommand();
+ ~GitCommand();
+ void execute(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment);
+ void run(const QStringList &arguments
+ , const QString &workingDirectory
+ , const ProjectExplorer::Environment &environment);
+
+Q_SIGNALS:
+ void outputData(const QByteArray&);
+ void outputText(const QString&);
+ void errorText(const QString&);
+};
+
+ }
+}
+
+#endif // GITCLIENT_H
diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h
new file mode 100644
index 0000000000..a74c903031
--- /dev/null
+++ b/src/plugins/git/gitconstants.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GIT_CONSTANTS_H
+#define GIT_CONSTANTS_H
+
+namespace Git {
+ namespace Constants {
+ const char * const GIT_COMMAND_LOG_EDITOR_KIND = "Git Command Log Editor";
+ const char * const GIT_LOG_EDITOR_KIND = "Git File Log Editor";
+ const char * const GIT_BLAME_EDITOR_KIND = "Git Annotation Editor";
+ const char * const GIT_DIFF_EDITOR_KIND = "Git Diff Editor";
+
+ const char * const C_GITSUBMITEDITOR = "Git Submit Editor";
+ const char * const GITSUBMITEDITOR_KIND = "Git Submit Editor";
+ const char * const SUBMIT_CURRENT = "Nokia.Git.SubmitCurrentLog";
+ const char * const DIFF_SELECTED = "Nokia.Git.DiffSelectedFilesInLog";
+ const char * const SUBMIT_MIMETYPE = "application/vnd.nokia.text.git.submit";
+
+ // TODO: For the moment, trust p4 is loaded...
+ const char * const ICON_SUBMIT = ":/trolltech.perforce/images/submit.png";
+ const char * const ICON_DIFF = ":/trolltech.perforce/images/diff.png";
+
+ const char * const DIFF_FILE_INDICATOR = "--- ";
+ enum { debug = 0 };
+ }
+}
+
+#endif // GIT_CONSTANTS_H
diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp
new file mode 100644
index 0000000000..3bf31da698
--- /dev/null
+++ b/src/plugins/git/giteditor.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "giteditor.h"
+#include "annotationhighlighter.h"
+#include "gitconstants.h"
+#include "gitplugin.h"
+#include "gitclient.h"
+
+#include <vcsbase/diffhighlighter.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QSet>
+#include <QtCore/QRegExp>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtGui/QTextEdit>
+#include <QtGui/QTextCursor>
+
+#define CHANGE_PATTERN_8C "[a-f0-9]{8,8}"
+#define CHANGE_PATTERN_40C "[a-f0-9]{40,40}"
+
+namespace Git {
+namespace Internal {
+
+// ------------ GitEditor
+GitEditor::GitEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent) :
+ VCSBase::VCSBaseEditor(type, parent),
+ m_changeNumberPattern8(QLatin1String(CHANGE_PATTERN_8C)),
+ m_changeNumberPattern40(QLatin1String(CHANGE_PATTERN_40C))
+{
+ Q_ASSERT(m_changeNumberPattern8.isValid());
+ Q_ASSERT(m_changeNumberPattern40.isValid());
+ if (Git::Constants::debug)
+ qDebug() << "GitEditor::GitEditor" << type->type << type->kind;
+}
+
+QSet<QString> GitEditor::annotationChanges() const
+{
+ QSet<QString> changes;
+ const QString txt = toPlainText();
+ if (txt.isEmpty())
+ return changes;
+ // Hunt for first change number in annotation: "<change>:"
+ QRegExp r(QLatin1String("^("CHANGE_PATTERN_8C") "));
+ Q_ASSERT(r.isValid());
+ if (r.indexIn(txt) != -1) {
+ changes.insert(r.cap(1));
+ r.setPattern(QLatin1String("\n("CHANGE_PATTERN_8C") "));
+ Q_ASSERT(r.isValid());
+ int pos = 0;
+ while ((pos = r.indexIn(txt, pos)) != -1) {
+ pos += r.matchedLength();
+ changes.insert(r.cap(1));
+ }
+ }
+ if (Git::Constants::debug)
+ qDebug() << "GitEditor::annotationChanges() returns #" << changes.size();
+ return changes;
+}
+
+QString GitEditor::changeUnderCursor(const QTextCursor &c) const
+{
+ QTextCursor cursor = c;
+ // Any number is regarded as change number.
+ cursor.select(QTextCursor::WordUnderCursor);
+ if (!cursor.hasSelection())
+ return QString();
+ const QString change = cursor.selectedText();
+ if (Git::Constants::debug > 1)
+ qDebug() << "GitEditor:::changeUnderCursor:" << change;
+ if (m_changeNumberPattern8.exactMatch(change))
+ return change;
+ if (m_changeNumberPattern40.exactMatch(change))
+ return change;
+ return QString();
+}
+
+VCSBase::DiffHighlighter *GitEditor::createDiffHighlighter() const
+{
+ const QRegExp filePattern(QLatin1String("^[-+][-+][-+] [ab].*"));
+ return new VCSBase::DiffHighlighter(filePattern);
+}
+
+VCSBase::BaseAnnotationHighlighter *GitEditor::createAnnotationHighlighter(const QSet<QString> &changes) const
+{
+ return new GitAnnotationHighlighter(changes);
+}
+
+QString GitEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const
+{
+ QString errorMessage;
+ // Check for "+++ b/src/plugins/git/giteditor.cpp" (blame and diff)
+ // Go back chunks.
+ const QString newFileIndicator = QLatin1String("+++ b/");
+ for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) {
+ QString diffFileName = block.text();
+ if (diffFileName.startsWith(newFileIndicator)) {
+ diffFileName.remove(0, newFileIndicator.size());
+ const QString fileOrDir = source();
+ const QString repo = QFileInfo(fileOrDir).isDir() ?
+ GitClient::findRepositoryForDirectory(fileOrDir) : GitClient::findRepositoryForFile(fileOrDir);
+ const QString absPath = QDir(repo).absoluteFilePath(diffFileName);
+ if (Git::Constants::debug)
+ qDebug() << "fileNameFromDiffSpecification" << repo << diffFileName << absPath;
+ return absPath;
+ }
+ }
+ return QString();
+}
+
+}
+}
diff --git a/src/plugins/git/giteditor.h b/src/plugins/git/giteditor.h
new file mode 100644
index 0000000000..87e71597dd
--- /dev/null
+++ b/src/plugins/git/giteditor.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITEDITOR_H
+#define GITEDITOR_H
+
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QtCore/QRegExp>
+
+namespace Git {
+namespace Internal {
+
+class GitPlugin;
+
+class GitEditor : public VCSBase::VCSBaseEditor
+{
+ Q_OBJECT
+
+public:
+ explicit GitEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent);
+
+private:
+ virtual QSet<QString> annotationChanges() const;
+ virtual QString changeUnderCursor(const QTextCursor &) const;
+ virtual VCSBase::DiffHighlighter *createDiffHighlighter() const;
+ virtual VCSBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const;
+ virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const;
+
+ const QRegExp m_changeNumberPattern8;
+ const QRegExp m_changeNumberPattern40;
+ GitPlugin *m_plugin;
+};
+
+} // namespace Git
+} // namespace Internal
+
+#endif // GITEDITOR_H
diff --git a/src/plugins/git/gitoutputwindow.cpp b/src/plugins/git/gitoutputwindow.cpp
new file mode 100644
index 0000000000..e8210ed035
--- /dev/null
+++ b/src/plugins/git/gitoutputwindow.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitoutputwindow.h"
+
+#include <QtCore/QTextCodec>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+
+using namespace Git::Internal;
+
+GitOutputWindow::GitOutputWindow()
+ : Core::IOutputPane()
+{
+ m_outputListWidget = new QListWidget;
+ m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_outputListWidget->setFrameStyle(QFrame::NoFrame);
+
+ m_outputListWidget->setWindowTitle(tr("Git Output"));
+}
+
+GitOutputWindow::~GitOutputWindow()
+{
+ delete m_outputListWidget;
+}
+
+QWidget *GitOutputWindow::outputWidget(QWidget *parent)
+{
+ m_outputListWidget->setParent(parent);
+ return m_outputListWidget;
+}
+
+QString GitOutputWindow::name() const
+{
+ return tr("Git");
+}
+
+void GitOutputWindow::clearContents()
+{
+ m_outputListWidget->clear();
+}
+
+void GitOutputWindow::visibilityChanged(bool b)
+{
+ if (b)
+ m_outputListWidget->setFocus();
+}
+
+bool GitOutputWindow::hasFocus()
+{
+ return m_outputListWidget->hasFocus();
+}
+
+bool GitOutputWindow::canFocus()
+{
+ return false;
+}
+
+void GitOutputWindow::setFocus()
+{
+}
+
+void GitOutputWindow::setText(const QString &text)
+{
+ clearContents();
+ append(text);
+}
+
+void GitOutputWindow::append(const QString &text)
+{
+ const QStringList lines = text.split(QLatin1Char('\n'));
+ foreach (const QString &s, lines)
+ m_outputListWidget->addItem(s);
+ popup();
+}
+
+void GitOutputWindow::setData(const QByteArray &data)
+{
+ setText(QTextCodec::codecForLocale()->toUnicode(data));
+}
+
+void GitOutputWindow::appendData(const QByteArray &data)
+{
+ append(QTextCodec::codecForLocale()->toUnicode(data));
+}
+
+int GitOutputWindow::priorityInStatusBar() const
+{
+ return -1;
+}
diff --git a/src/plugins/git/gitoutputwindow.h b/src/plugins/git/gitoutputwindow.h
new file mode 100644
index 0000000000..ed776c5df4
--- /dev/null
+++ b/src/plugins/git/gitoutputwindow.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITOUTPUTWINDOW_H
+#define GITOUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+#include <QtGui/QListWidgetItem>
+
+namespace Git {
+namespace Internal {
+
+
+class GitOutputWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ GitOutputWindow();
+ ~GitOutputWindow();
+
+ QWidget *outputWidget(QWidget *parent);
+ QList<QWidget*> toolBarWidgets(void) const { return QList<QWidget *>(); }
+
+ QString name() const;
+ int priorityInStatusBar() const;
+ void clearContents();
+ void visibilityChanged(bool visible);
+
+ bool canFocus();
+ bool hasFocus();
+ void setFocus();
+
+public slots:
+ void setText(const QString &text);
+ void append(const QString &text);
+ void setData(const QByteArray &data);
+ void appendData(const QByteArray &data);
+
+private:
+ QListWidget *m_outputListWidget;
+};
+
+} // namespace Internal
+} // namespace Git
+
+#endif
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
new file mode 100644
index 0000000000..cbb08cc05a
--- /dev/null
+++ b/src/plugins/git/gitplugin.cpp
@@ -0,0 +1,717 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitplugin.h"
+#include "gitclient.h"
+#include "giteditor.h"
+#include "gitconstants.h"
+#include "changeselectiondialog.h"
+#include "gitsubmiteditor.h"
+#include "commitdata.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <vcsbase/basevcseditorfactory.h>
+#include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/basevcssubmiteditorfactory.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QDir>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtGui/QFileDialog>
+
+static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
+{
+ VCSBase::RegularCommandOutput,
+ Git::Constants::GIT_COMMAND_LOG_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_git_commandlog",
+ "gitlog"},
+{ VCSBase::LogOutput,
+ Git::Constants::GIT_LOG_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_git_filelog",
+ "gitfilelog"},
+{ VCSBase::AnnotateOutput,
+ Git::Constants::GIT_BLAME_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "application/vnd.nokia.text.scs_git_annotation",
+ "gitsannotate"},
+{ VCSBase::DiffOutput,
+ Git::Constants::GIT_DIFF_EDITOR_KIND,
+ Core::Constants::C_GLOBAL,
+ "text/x-patch","diff"}
+};
+
+// Utility to find a parameter set by type
+static inline const VCSBase::VCSBaseEditorParameters *findType(int ie)
+{
+ const VCSBase::EditorContentType et = static_cast<VCSBase::EditorContentType>(ie);
+ return VCSBase::VCSBaseEditor::findType(editorParameters, sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters), et);
+}
+
+using namespace Git;
+using namespace Git::Internal;
+
+// CoreListener
+
+bool CoreListener::editorAboutToClose(Core::IEditor *editor)
+{
+ return m_plugin->editorAboutToClose(editor);
+}
+
+// GitPlugin
+
+GitPlugin *GitPlugin::m_instance = 0;
+
+GitPlugin::GitPlugin() :
+ m_core(0),
+ m_diffAction(0),
+ m_diffProjectAction(0),
+ m_statusAction(0),
+ m_statusProjectAction(0),
+ m_logAction(0),
+ m_blameAction(0),
+ m_logProjectAction(0),
+ m_undoFileAction(0),
+ m_undoProjectAction(0),
+ m_showAction(0),
+ m_addAction(0),
+ m_commitAction(0),
+ m_pullAction(0),
+ m_pushAction(0),
+ m_submitCurrentAction(0),
+ m_diffSelectedFilesAction(0),
+ m_undoAction(0),
+ m_redoAction(0),
+ m_projectExplorer(0),
+ m_gitClient(0),
+ m_outputWindow(0),
+ m_changeSelectionDialog(0),
+ m_settingsPage(0),
+ m_coreListener(0),
+ m_submitEditorFactory(0),
+ m_changeTmpFile(0)
+{
+ Q_ASSERT(m_instance == 0);
+ m_instance = this;
+}
+
+GitPlugin::~GitPlugin()
+{
+ if (m_outputWindow) {
+ removeObject(m_outputWindow);
+ delete m_outputWindow;
+ m_outputWindow = 0;
+ }
+
+ if (m_settingsPage) {
+ removeObject(m_settingsPage);
+ delete m_settingsPage;
+ m_settingsPage = 0;
+ }
+
+ if (!m_editorFactories.empty()) {
+ foreach(Core::IEditorFactory* pf, m_editorFactories)
+ removeObject(pf);
+ qDeleteAll(m_editorFactories);
+ }
+
+ if (m_coreListener) {
+ removeObject(m_coreListener);
+ delete m_coreListener;
+ m_coreListener = 0;
+ }
+
+ if (m_submitEditorFactory) {
+ removeObject(m_submitEditorFactory);
+ m_submitEditorFactory = 0;
+ }
+
+ cleanChangeTmpFile();
+ delete m_gitClient;
+ m_instance = 0;
+}
+
+void GitPlugin::cleanChangeTmpFile()
+{
+ if (m_changeTmpFile) {
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ }
+}
+
+GitPlugin *GitPlugin::instance()
+{
+ return m_instance;
+}
+
+static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = {
+ Git::Constants::SUBMIT_MIMETYPE,
+ Git::Constants::GITSUBMITEDITOR_KIND,
+ Git::Constants::C_GITSUBMITEDITOR,
+ Core::Constants::UNDO,
+ Core::Constants::REDO,
+ Git::Constants::SUBMIT_CURRENT,
+ Git::Constants::DIFF_SELECTED
+};
+
+
+bool GitPlugin::initialize(const QStringList &arguments, QString *error_message)
+{
+ typedef VCSBase::VCSEditorFactory<GitEditor> GitEditorFactory;
+ typedef VCSBase::VCSSubmitEditorFactory<GitSubmitEditor> GitSubmitEditorFactory;
+
+ Q_UNUSED(arguments);
+ Q_UNUSED(error_message);
+
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ m_gitClient = new GitClient(this, m_core);
+ // Create the globalcontext list to register actions accordingly
+ QList<int> globalcontext;
+ globalcontext << m_core->uniqueIDManager()->
+ uniqueIdentifier(Core::Constants::C_GLOBAL);
+
+ // Create the output Window
+ m_outputWindow = new GitOutputWindow();
+ addObject(m_outputWindow);
+
+ // Create the settings Page
+ m_settingsPage = new SettingsPage();
+ addObject(m_settingsPage);
+
+ static const char *describeSlot = SLOT(show(QString,QString));
+ const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
+ for (int i = 0; i < editorCount; i++) {
+ m_editorFactories.push_back(new GitEditorFactory(editorParameters + i, m_core, m_gitClient, describeSlot));
+ addObject(m_editorFactories.back());
+ }
+
+ m_coreListener = new CoreListener(this);
+ addObject(m_coreListener);
+
+ m_submitEditorFactory = new GitSubmitEditorFactory(&submitParameters);
+ addObject(m_submitEditorFactory);
+
+ //register actions
+ Core::ActionManagerInterface *actionManager = m_core->actionManager();
+
+ Core::IActionContainer *toolsContainer =
+ actionManager->actionContainer(Core::Constants::M_TOOLS);
+
+ Core::IActionContainer *gitContainer =
+ actionManager->createMenu(QLatin1String("Git"));
+ gitContainer->menu()->setTitle(tr("&Git"));
+ toolsContainer->addMenu(gitContainer);
+
+ Core::ICommand *command;
+ QAction *tmpaction;
+
+ m_diffAction = new QAction(tr("Diff current file"), this);
+ command = actionManager->registerAction(m_diffAction, "Git.Diff", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+D")));
+ connect(m_diffAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
+ gitContainer->addAction(command);
+
+ m_statusAction = new QAction(tr("File Status"), this);
+ command = actionManager->registerAction(m_statusAction, "Git.Status", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+S")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_statusAction, SIGNAL(triggered()), this, SLOT(statusFile()));
+ gitContainer->addAction(command);
+
+ m_logAction = new QAction(tr("Log File"), this);
+ command = actionManager->registerAction(m_logAction, "Git.Log", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+L")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_logAction, SIGNAL(triggered()), this, SLOT(logFile()));
+ gitContainer->addAction(command);
+
+ m_blameAction = new QAction(tr("Blame"), this);
+ command = actionManager->registerAction(m_blameAction, "Git.Blame", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+B")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_blameAction, SIGNAL(triggered()), this, SLOT(blameFile()));
+ gitContainer->addAction(command);
+
+ m_undoFileAction = new QAction(tr("Undo Changes"), this);
+ command = actionManager->registerAction(m_undoFileAction, "Git.Undo", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+U")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_undoFileAction, SIGNAL(triggered()), this, SLOT(undoFileChanges()));
+ gitContainer->addAction(command);
+
+ m_addAction = new QAction(tr("Add File"), this);
+ command = actionManager->registerAction(m_addAction, "Git.Add", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+A")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_addAction, SIGNAL(triggered()), this, SLOT(addFile()));
+ gitContainer->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = actionManager->registerAction(tmpaction, QLatin1String("Git.Sep.Project"), globalcontext);
+ gitContainer->addAction(command);
+
+ m_diffProjectAction = new QAction(tr("Diff current project"), this);
+ command = actionManager->registerAction(m_diffProjectAction, "Git.DiffProject", globalcontext);
+ command->setDefaultKeySequence(QKeySequence("Alt+G,Alt+Shift+D"));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffCurrentProject()));
+ gitContainer->addAction(command);
+
+ m_statusProjectAction = new QAction(tr("Project status"), this);
+ command = actionManager->registerAction(m_statusProjectAction, "Git.StatusProject", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_statusProjectAction, SIGNAL(triggered()), this, SLOT(statusProject()));
+ gitContainer->addAction(command);
+
+ m_logProjectAction = new QAction(tr("Log project"), this);
+ command = actionManager->registerAction(m_logProjectAction, "Git.LogProject", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+K")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_logProjectAction, SIGNAL(triggered()), this, SLOT(logProject()));
+ gitContainer->addAction(command);
+
+ m_undoProjectAction = new QAction(tr("Undo Project Changes"), this);
+ command = actionManager->registerAction(m_undoProjectAction, "Git.UndoProject", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_undoProjectAction, SIGNAL(triggered()), this, SLOT(undoProjectChanges()));
+ gitContainer->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = actionManager->registerAction(tmpaction, QLatin1String("Git.Sep.Global"), globalcontext);
+ gitContainer->addAction(command);
+
+ m_showAction = new QAction(tr("Show commit..."), this);
+ command = actionManager->registerAction(m_showAction, "Git.ShowCommit", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_showAction, SIGNAL(triggered()), this, SLOT(showCommit()));
+ gitContainer->addAction(command);
+
+ m_commitAction = new QAction(tr("Commit..."), this);
+ command = actionManager->registerAction(m_commitAction, "Git.Commit", globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+C")));
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_commitAction, SIGNAL(triggered()), this, SLOT(startCommit()));
+ gitContainer->addAction(command);
+
+ m_pullAction = new QAction(tr("Pull"), this);
+ command = actionManager->registerAction(m_pullAction, "Git.Pull", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_pullAction, SIGNAL(triggered()), this, SLOT(pull()));
+ gitContainer->addAction(command);
+
+ m_pushAction = new QAction(tr("Push"), this);
+ command = actionManager->registerAction(m_pushAction, "Git.Push", globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ connect(m_pushAction, SIGNAL(triggered()), this, SLOT(push()));
+ gitContainer->addAction(command);
+
+ // Submit editor
+ QList<int> submitContext;
+ submitContext.push_back(m_core->uniqueIDManager()->uniqueIdentifier(QLatin1String(Constants::C_GITSUBMITEDITOR)));
+ m_submitCurrentAction = new QAction(QIcon(Constants::ICON_SUBMIT), tr("Commit"), this);
+ command = actionManager->registerAction(m_submitCurrentAction, Constants::SUBMIT_CURRENT, submitContext);
+ // TODO
+ connect(m_submitCurrentAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
+
+ m_diffSelectedFilesAction = new QAction(QIcon(Constants::ICON_DIFF), tr("Diff Selected Files"), this);
+ command = actionManager->registerAction(m_diffSelectedFilesAction, Constants::DIFF_SELECTED, submitContext);
+
+ m_undoAction = new QAction(tr("&Undo"), this);
+ command = actionManager->registerAction(m_undoAction, Core::Constants::UNDO, submitContext);
+
+ m_redoAction = new QAction(tr("&Redo"), this);
+ command = actionManager->registerAction(m_redoAction, Core::Constants::REDO, submitContext);
+
+ // Ask for updates of our actions, in case context switches
+ connect(m_core, SIGNAL(contextChanged(Core::IContext *)),
+ this, SLOT(updateActions()));
+ connect(m_core->fileManager(), SIGNAL(currentFileChanged(const QString &)),
+ this, SLOT(updateActions()));
+
+ return true;
+}
+
+void GitPlugin::extensionsInitialized()
+{
+ m_projectExplorer = ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+}
+
+bool GitPlugin::vcsOpen(const QString &fileName)
+{
+ Q_UNUSED(fileName);
+ return false;
+}
+
+void GitPlugin::submitEditorDiff(const QStringList &files)
+{
+ if (files.empty())
+ return;
+ m_gitClient->diff(m_submitRepository, files);
+}
+
+void GitPlugin::diffCurrentFile()
+{
+ QFileInfo fileInfo = currentFile();
+ QString fileName = fileInfo.fileName();
+ QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->diff(workingDirectory, fileName);
+}
+
+void GitPlugin::diffCurrentProject()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->diff(workingDirectory, QString());
+}
+
+QFileInfo GitPlugin::currentFile()
+{
+ QString fileName = m_core->fileManager()->currentFile();
+ QFileInfo fileInfo(fileName);
+ return fileInfo;
+}
+
+QString GitPlugin::getWorkingDirectory()
+{
+ QString workingDirectory;
+ if (m_projectExplorer && m_projectExplorer->currentNode()) {
+ workingDirectory = QFileInfo(m_projectExplorer->currentNode()->path()).absolutePath();
+ }
+ if (Git::Constants::debug > 1)
+ qDebug() << Q_FUNC_INFO << "Project" << workingDirectory;
+
+ if (workingDirectory.isEmpty())
+ workingDirectory = QFileInfo(m_core->fileManager()->currentFile()).absolutePath();
+ if (Git::Constants::debug > 1)
+ qDebug() << Q_FUNC_INFO << "file" << workingDirectory;
+
+ if (workingDirectory.isEmpty()) {
+ m_outputWindow->clearContents();
+ m_outputWindow->append(tr("Could not find working directory"));
+ m_outputWindow->popup();
+ return QString();
+ }
+ return workingDirectory;
+}
+
+void GitPlugin::statusProject()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->status(workingDirectory);
+}
+
+void GitPlugin::statusFile()
+{
+ m_gitClient->status(currentFile().absolutePath());
+}
+
+void GitPlugin::logFile()
+{
+ const QFileInfo fileInfo = currentFile();
+ const QString fileName = fileInfo.fileName();
+ const QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->log(workingDirectory, fileName);
+}
+
+void GitPlugin::blameFile()
+{
+ const QFileInfo fileInfo = currentFile();
+ const QString fileName = fileInfo.fileName();
+ const QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->blame(workingDirectory, fileName);
+}
+
+void GitPlugin::logProject()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->log(workingDirectory, QString());
+}
+
+void GitPlugin::undoFileChanges()
+{
+ QFileInfo fileInfo = currentFile();
+ QString fileName = fileInfo.fileName();
+ QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->checkout(workingDirectory, fileName);
+}
+
+void GitPlugin::undoProjectChanges()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->hardReset(workingDirectory, QString());
+}
+
+void GitPlugin::addFile()
+{
+ QFileInfo fileInfo = currentFile();
+ QString fileName = fileInfo.fileName();
+ QString workingDirectory = fileInfo.absolutePath();
+ m_gitClient->addFile(workingDirectory, fileName);
+}
+
+void GitPlugin::startCommit()
+{
+ if (m_changeTmpFile) {
+ m_outputWindow->append(tr("Another submit is currently beeing executed."));
+ m_outputWindow->popup(false);
+ return;
+ }
+
+ // Find repository and get commit data
+ const QFileInfo currentFileInfo = currentFile();
+ if (!currentFileInfo.exists())
+ return;
+
+ const QString workingDirectory = currentFileInfo.absolutePath();
+ QString errorMessage, commitTemplate;
+ CommitData data;
+ if (!m_gitClient->getCommitData(workingDirectory, &commitTemplate, &data, &errorMessage)) {
+ m_outputWindow->append(errorMessage);
+ m_outputWindow->popup(false);
+ return;
+ }
+
+ m_submitRepository = data.panelInfo.repository;
+
+ if (Git::Constants::debug)
+ qDebug() << Q_FUNC_INFO << data << commitTemplate;
+
+ // Start new temp file with message template
+ QTemporaryFile *changeTmpFile = new QTemporaryFile(this);
+ changeTmpFile->setAutoRemove(true);
+ if (!changeTmpFile->open()) {
+ m_outputWindow->append(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
+ delete changeTmpFile;
+ return;
+ }
+ m_changeTmpFile = changeTmpFile;
+ m_changeTmpFile->write(commitTemplate.toLocal8Bit());
+ m_changeTmpFile->flush();
+ // Keep the file alive, else it removes self and forgets
+ // its name
+ m_changeTmpFile->seek(0);
+ openSubmitEditor(m_changeTmpFile->fileName(), data);
+}
+
+Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const CommitData &cd)
+{
+ Core::IEditor *editor = m_core->editorManager()->openEditor(fileName, QLatin1String(Constants::GITSUBMITEDITOR_KIND));
+ if (Git::Constants::debug)
+ qDebug() << Q_FUNC_INFO << fileName << editor;
+ m_core->editorManager()->ensureEditorManagerVisible();
+ GitSubmitEditor *submitEditor = qobject_cast<GitSubmitEditor*>(editor);
+ Q_ASSERT(submitEditor);
+ // The actions are for some reason enabled by the context switching
+ // mechanism. Disable them correctly.
+ m_submitCurrentAction->setEnabled(!cd.commitFiles.empty());
+ m_diffSelectedFilesAction->setEnabled(false);
+ m_undoAction->setEnabled(false);
+ m_redoAction->setEnabled(false);
+ submitEditor->setCommitData(cd);
+ connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(submitEditorDiff(QStringList)));
+ return editor;
+}
+
+void GitPlugin::submitCurrentLog()
+{
+ // Close the submit editor
+ QList<Core::IEditor*> editors;
+ editors.push_back(m_core->editorManager()->currentEditor());
+ m_core->editorManager()->closeEditors(editors);
+}
+
+bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor)
+{
+ // Closing a submit editor?
+ if (!m_changeTmpFile || !iEditor || qstrcmp(iEditor->kind(), Constants::GITSUBMITEDITOR_KIND))
+ return true;
+ Core::IFile *fileIFace = iEditor->file();
+ const GitSubmitEditor *editor = qobject_cast<GitSubmitEditor *>(iEditor);
+ if (!fileIFace || !editor)
+ return true;
+ // Submit editor closing. Make it write out the commit message
+ // and retrieve files
+ const QFileInfo editorFile(fileIFace->fileName());
+ const QFileInfo changeFile(m_changeTmpFile->fileName());
+ // Paranoia!
+ if (editorFile.absoluteFilePath() != changeFile.absoluteFilePath())
+ return true;
+ // Prompt user.
+ const QMessageBox::StandardButton answer = QMessageBox::question(m_core->mainWindow(), tr("Closing git editor"), tr("Do you want to commit the change?"),
+ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
+ switch (answer) {
+ case QMessageBox::Cancel:
+ return false; // Keep editing and change file
+ case QMessageBox::No:
+ cleanChangeTmpFile();
+ return true; // Cancel all
+ default:
+ break;
+ }
+ // Go ahead!
+ const QStringList fileList = editor->checkedFiles();
+ if (Git::Constants::debug)
+ qDebug() << Q_FUNC_INFO << fileList;
+ if (!fileList.empty()) {
+ // get message & commit
+ m_core->fileManager()->blockFileChange(fileIFace);
+ fileIFace->save();
+ m_core->fileManager()->unblockFileChange(fileIFace);
+
+ m_gitClient->addAndCommit(m_submitRepository,
+ editor->panelData(),
+ m_changeTmpFile->fileName(),
+ fileList);
+ }
+ cleanChangeTmpFile();
+ return true;
+}
+
+void GitPlugin::pull()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->pull(workingDirectory);
+}
+
+void GitPlugin::push()
+{
+ QString workingDirectory = getWorkingDirectory();
+ if (workingDirectory.isEmpty())
+ return;
+ m_gitClient->push(workingDirectory);
+}
+
+void GitPlugin::updateActions()
+{
+ QFileInfo current = currentFile();
+ const QString fileName = current.fileName();
+ const QString currentDirectory = getWorkingDirectory();
+ QString repository = m_gitClient->findRepositoryForFile(current.absoluteFilePath());
+ // First check for file commands and if the current file is inside
+ // a Git-repository
+ m_diffAction->setText(tr("Diff %1").arg(fileName));
+ m_statusAction->setText(tr("Status related to %1").arg(fileName));
+ m_logAction->setText(tr("Log %1").arg(fileName));
+ m_blameAction->setText(tr("Blame %1").arg(fileName));
+ m_undoFileAction->setText(tr("Undo changes for %1").arg(fileName));
+ m_addAction->setText(tr("Add %1").arg(fileName));
+ if (repository.isEmpty()) {
+ // If the file is not in a repository, the corresponding project will
+ // be neither and we can disable everything and return
+ m_diffAction->setEnabled(false);
+ m_statusAction->setEnabled(false);
+ m_logAction->setEnabled(false);
+ m_blameAction->setEnabled(false);
+ m_undoFileAction->setEnabled(false);
+ m_addAction->setEnabled(false);
+ m_diffProjectAction->setEnabled(false);
+ m_diffProjectAction->setText(tr("Diff Project"));
+ m_statusProjectAction->setText(tr("Status Project"));
+ m_statusProjectAction->setEnabled(false);
+ m_logProjectAction->setText(tr("Log Project"));
+ m_logProjectAction->setEnabled(false);
+ return;
+ } else {
+ // We only know the file is in some repository, we do not know
+ // anything about any project so far.
+ m_diffAction->setEnabled(true);
+ m_statusAction->setEnabled(true);
+ m_logAction->setEnabled(true);
+ m_blameAction->setEnabled(true);
+ m_undoFileAction->setEnabled(true);
+ m_addAction->setEnabled(true);
+ }
+
+ if (m_projectExplorer && m_projectExplorer->currentNode()
+ && m_projectExplorer->currentNode()->projectNode()) {
+ QString name = QFileInfo(m_projectExplorer->currentNode()->projectNode()->path()).baseName();
+ m_diffProjectAction->setEnabled(true);
+ m_diffProjectAction->setText(tr("Diff Project %1").arg(name));
+ m_statusProjectAction->setEnabled(true);
+ m_statusProjectAction->setText(tr("Status Project %1").arg(name));
+ m_logProjectAction->setEnabled(true);
+ m_logProjectAction->setText(tr("Log Project %1").arg(name));
+ } else {
+ m_diffProjectAction->setEnabled(false);
+ m_diffProjectAction->setText(tr("Diff Project"));
+ m_statusProjectAction->setEnabled(false);
+ m_statusProjectAction->setText(tr("Status Project"));
+ m_logProjectAction->setEnabled(false);
+ m_logProjectAction->setText(tr("Log Project"));
+ }
+}
+
+void GitPlugin::showCommit()
+{
+ if (!m_changeSelectionDialog)
+ m_changeSelectionDialog = new ChangeSelectionDialog();
+
+ const QFileInfo currentInfo = currentFile();
+ QString repositoryLocation = m_gitClient->findRepositoryForFile(currentInfo.absoluteFilePath());
+ if (!repositoryLocation.isEmpty())
+ m_changeSelectionDialog->m_ui.repositoryEdit->setText(repositoryLocation);
+
+ if (m_changeSelectionDialog->exec() != QDialog::Accepted)
+ return;
+ const QString change = m_changeSelectionDialog->m_ui.changeNumberEdit->text();
+ if (change .isEmpty())
+ return;
+
+ m_gitClient->show(m_changeSelectionDialog->m_ui.repositoryEdit->text(), change);
+}
+
+Q_EXPORT_PLUGIN(GitPlugin)
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
new file mode 100644
index 0000000000..c57c380fcf
--- /dev/null
+++ b/src/plugins/git/gitplugin.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITPLUGIN_H
+#define GITPLUGIN_H
+
+#include "gitoutputwindow.h"
+#include "settingspage.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/icorelistener.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QAction;
+class QTemporaryFile;
+QT_END_NAMESPACE
+
+namespace Core {
+ class IEditorFactory;
+ class ICore;
+}
+
+namespace Git {
+namespace Internal {
+
+ class GitPlugin;
+ class GitClient;
+ class ChangeSelectionDialog;
+ class GitSubmitEditor;
+ struct CommitData;
+
+// Just a proxy for GitPlugin
+class CoreListener : public Core::ICoreListener
+{
+ Q_OBJECT
+public:
+ CoreListener(GitPlugin *plugin) : m_plugin(plugin) { }
+ bool editorAboutToClose(Core::IEditor *editor);
+ bool coreAboutToClose() { return true; }
+private:
+ GitPlugin *m_plugin;
+};
+
+class GitPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ GitPlugin();
+ ~GitPlugin();
+ static GitPlugin *instance();
+
+ bool vcsOpen(const QString &fileName);
+
+ bool initialize(const QStringList &arguments
+ , QString *error_message);
+ void extensionsInitialized();
+
+ QString getWorkingDirectory();
+
+public slots:
+ void updateActions();
+ bool editorAboutToClose(Core::IEditor *editor);
+
+private slots:
+ void diffCurrentFile();
+ void diffCurrentProject();
+ void submitEditorDiff(const QStringList &);
+ void submitCurrentLog();
+ void statusFile();
+ void statusProject();
+ void logFile();
+ void blameFile();
+ void logProject();
+ void undoFileChanges();
+ void undoProjectChanges();
+ void addFile();
+
+ void showCommit();
+ void startCommit();
+ void pull();
+ void push();
+
+private:
+ friend class GitClient;
+ QFileInfo currentFile();
+ Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd);
+ void cleanChangeTmpFile();
+
+ static GitPlugin *m_instance;
+ Core::ICore *m_core;
+ QAction *m_diffAction;
+ QAction *m_diffProjectAction;
+ QAction *m_statusAction;
+ QAction *m_statusProjectAction;
+ QAction *m_logAction;
+ QAction *m_blameAction;
+ QAction *m_logProjectAction;
+ QAction *m_undoFileAction;
+ QAction *m_undoProjectAction;
+ QAction *m_showAction;
+ QAction *m_addAction;
+ QAction *m_commitAction;
+ QAction *m_pullAction;
+ QAction *m_pushAction;
+
+ QAction *m_submitCurrentAction;
+ QAction *m_diffSelectedFilesAction;
+ QAction *m_undoAction;
+ QAction *m_redoAction;
+
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ GitClient *m_gitClient;
+ GitOutputWindow *m_outputWindow;
+ ChangeSelectionDialog *m_changeSelectionDialog;
+ SettingsPage *m_settingsPage;
+ QList<Core::IEditorFactory*> m_editorFactories;
+ CoreListener *m_coreListener;
+ Core::IEditorFactory *m_submitEditorFactory;
+ QString m_submitRepository;
+ QTemporaryFile *m_changeTmpFile;
+};
+
+} // namespace Git
+} // namespace Internal
+
+#endif
diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp
new file mode 100644
index 0000000000..bf0d78af57
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditor.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitsubmiteditor.h"
+#include "gitsubmiteditorwidget.h"
+#include "gitconstants.h"
+#include "commitdata.h"
+
+#include <QtCore/QDebug>
+
+namespace Git {
+namespace Internal {
+
+GitSubmitEditor::GitSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent) :
+ VCSBaseSubmitEditor(parameters, new GitSubmitEditorWidget(parent))
+{
+ setDisplayName(tr("Git Commit"));
+}
+
+GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget()
+{
+ return static_cast<GitSubmitEditorWidget *>(widget());
+}
+
+QStringList GitSubmitEditor::vcsFileListToFileList(const QStringList &rawList) const
+{
+ QStringList rc;
+ foreach (const QString &rf, rawList)
+ rc.push_back(fileFromChangeLine(rf));
+ return rc;
+}
+
+void GitSubmitEditor::setCommitData(const CommitData &d)
+{
+ submitEditorWidget()->setPanelData(d.panelData);
+ submitEditorWidget()->setPanelInfo(d.panelInfo);
+
+ // Commited: Checked, user cannot uncheck
+ addFiles(d.commitFiles, true, false);
+ // Not Updated: User can check
+ addFiles(d.notUpdatedFiles, false, true);
+ addFiles(d.untrackedFiles, false, true);
+}
+
+GitSubmitEditorPanelData GitSubmitEditor::panelData() const
+{
+ return const_cast<GitSubmitEditor*>(this)->submitEditorWidget()->panelData();
+}
+
+QString GitSubmitEditor::fileFromChangeLine(const QString &line)
+{
+ QString rc = line;
+ // "modified: mainwindow.cpp"
+ const int index = rc.indexOf(QLatin1Char(':'));
+ if (index != -1)
+ rc.remove(0, index + 1);
+ const QChar blank(' ');
+ while (rc.startsWith(blank))
+ rc.remove(0, 1);
+ return rc;
+}
+}
+}
diff --git a/src/plugins/git/gitsubmiteditor.h b/src/plugins/git/gitsubmiteditor.h
new file mode 100644
index 0000000000..b424361a6a
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditor.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITSUBMITEDITOR_H
+#define GITSUBMITEDITOR_H
+
+#include <vcsbase/vcsbasesubmiteditor.h>
+
+namespace Git {
+namespace Internal {
+
+class GitSubmitEditorWidget;
+struct CommitData;
+struct GitSubmitEditorPanelData;
+
+/* */
+class GitSubmitEditor : public VCSBase::VCSBaseSubmitEditor
+{
+ Q_OBJECT
+public:
+ explicit GitSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent);
+
+ void setCommitData(const CommitData &);
+ GitSubmitEditorPanelData panelData() const;
+
+ static QString fileFromChangeLine(const QString &line);
+
+protected:
+ virtual QStringList vcsFileListToFileList(const QStringList &) const;
+
+private:
+ inline GitSubmitEditorWidget *submitEditorWidget();
+};
+
+} // namespace Internal
+} // namespace Git
+
+#endif // GITSUBMITEDITOR_H
diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp
new file mode 100644
index 0000000000..aede10acd8
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditorwidget.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "gitsubmiteditorwidget.h"
+#include "commitdata.h"
+
+namespace Git {
+namespace Internal {
+
+GitSubmitEditorWidget::GitSubmitEditorWidget(QWidget *parent) :
+ Core::Utils::SubmitEditorWidget(parent),
+ m_gitSubmitPanel(new QWidget)
+{
+ m_gitSubmitPanelUi.setupUi(m_gitSubmitPanel);
+ insertTopWidget(m_gitSubmitPanel);
+}
+
+void GitSubmitEditorWidget::setPanelInfo(const GitSubmitEditorPanelInfo &info)
+{
+ m_gitSubmitPanelUi.repositoryLabel->setText(info.repository);
+ m_gitSubmitPanelUi.descriptionLabel->setText(info.description);
+ m_gitSubmitPanelUi.branchLabel->setText(info.branch);
+}
+
+GitSubmitEditorPanelData GitSubmitEditorWidget::panelData() const
+{
+ GitSubmitEditorPanelData rc;
+ rc.author = m_gitSubmitPanelUi.authorLineEdit->text();
+ rc.email = m_gitSubmitPanelUi.emailLineEdit->text();
+ return rc;
+};
+
+void GitSubmitEditorWidget::setPanelData(const GitSubmitEditorPanelData &data)
+{
+ m_gitSubmitPanelUi.authorLineEdit->setText(data.author);
+ m_gitSubmitPanelUi.emailLineEdit->setText(data.email);
+}
+
+}
+}
diff --git a/src/plugins/git/gitsubmiteditorwidget.h b/src/plugins/git/gitsubmiteditorwidget.h
new file mode 100644
index 0000000000..7a842f50ef
--- /dev/null
+++ b/src/plugins/git/gitsubmiteditorwidget.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GITSUBMITEDITORWIDGET_H
+#define GITSUBMITEDITORWIDGET_H
+
+#include "ui_gitsubmitpanel.h"
+#include <utils/submiteditorwidget.h>
+
+namespace Git {
+namespace Internal {
+
+struct GitSubmitEditorPanelInfo;
+struct GitSubmitEditorPanelData;
+
+/* Submit editor widget with 2 additional panes:
+ * 1) Info with branch, description, etc
+ * 2) Data, with author and email to edit.
+ * The file contents is the submit message.
+ * The previously added files will be added 'checked' to the file list, the
+ * remaining un-added and untracked files will be added 'unchecked' for the
+ * user to click. */
+
+class GitSubmitEditorWidget : public Core::Utils::SubmitEditorWidget
+{
+
+public:
+ explicit GitSubmitEditorWidget(QWidget *parent = 0);
+
+
+ GitSubmitEditorPanelData panelData() const;
+ void setPanelData(const GitSubmitEditorPanelData &data);
+
+ void setPanelInfo(const GitSubmitEditorPanelInfo &info);
+
+private:
+ QWidget *m_gitSubmitPanel;
+ Ui::GitSubmitPanel m_gitSubmitPanelUi;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // GITSUBMITEDITORWIDGET_H
diff --git a/src/plugins/git/gitsubmitpanel.ui b/src/plugins/git/gitsubmitpanel.ui
new file mode 100644
index 0000000000..8a42052a99
--- /dev/null
+++ b/src/plugins/git/gitsubmitpanel.ui
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Git::Internal::GitSubmitPanel</class>
+ <widget class="QWidget" name="Git::Internal::GitSubmitPanel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>201</width>
+ <height>210</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="infoGroup">
+ <property name="title">
+ <string>General Information</string>
+ </property>
+ <layout class="QFormLayout" name="infoFormLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="repositoryLabelLabel">
+ <property name="text">
+ <string>Repository:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="repositoryLabel">
+ <property name="text">
+ <string>repository</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="descriptionLabelLabel">
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>description</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="branchLabelLabel">
+ <property name="text">
+ <string>Branch:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="branchLabel">
+ <property name="text">
+ <string>branch</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="editGroup">
+ <property name="title">
+ <string>Commit Information</string>
+ </property>
+ <layout class="QFormLayout" name="editFormLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="authorLabel">
+ <property name="text">
+ <string>Author:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="authorLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="emailLabel">
+ <property name="text">
+ <string>Email:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="emailLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp
new file mode 100644
index 0000000000..90f6371c0a
--- /dev/null
+++ b/src/plugins/git/settingspage.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "settingspage.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QSettings>
+#include <QtGui/QLineEdit>
+#include <QtGui/QFileDialog>
+#include <QtCore/QDebug>
+
+using namespace Git::Internal;
+
+static const char *groupC = "Git";
+static const char *sysEnvKeyC = "SysEnv";
+static const char *pathKeyC = "Path";
+static const char *logCountKeyC = "LogCount";
+
+SettingsPage::SettingsPage()
+{
+ Core::ICore *coreIFace = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (coreIFace)
+ m_settings = coreIFace->settings();
+
+ if (m_settings) {
+ m_settings->beginGroup(QLatin1String(groupC));
+ m_adopt = m_settings->value(QLatin1String(sysEnvKeyC), true).toBool();
+ m_path = m_settings->value(QLatin1String(pathKeyC), QString()).toString();
+ m_logCount = m_settings->value(QLatin1String(logCountKeyC), 10).toInt();
+ m_settings->endGroup();
+ }
+}
+
+QString SettingsPage::name() const
+{
+ return tr("General");
+}
+
+QString SettingsPage::category() const
+{
+ return QLatin1String("Git");
+}
+
+QString SettingsPage::trCategory() const
+{
+ return tr("Git");
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_ui.setupUi(w);
+ m_ui.adoptCheckBox->setChecked(m_adopt);
+ m_ui.pathLineEdit->setText(m_path);
+ m_ui.logLineEdit->setText(QString::number(m_logCount));
+
+ connect(m_ui.adoptButton, SIGNAL(clicked()), this, SLOT(setSystemPath()));
+ return w;
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ m_adopt = m_ui.adoptCheckBox->isChecked();
+ m_path = m_ui.pathLineEdit->text();
+ m_logCount = m_ui.logLineEdit->text().toInt();
+
+ if (!m_settings)
+ return;
+
+ m_settings->beginGroup(QLatin1String(groupC));
+ m_settings->setValue(QLatin1String(sysEnvKeyC), m_adopt);
+ m_settings->setValue(QLatin1String(pathKeyC), m_path);
+ m_settings->setValue(QLatin1String(logCountKeyC), m_logCount);
+ m_settings->endGroup();
+}
+
+void SettingsPage::setSystemPath()
+{
+ m_path = qgetenv("PATH");
+ m_ui.pathLineEdit->setText(m_path);
+}
diff --git a/src/plugins/git/settingspage.h b/src/plugins/git/settingspage.h
new file mode 100644
index 0000000000..de627bd9ce
--- /dev/null
+++ b/src/plugins/git/settingspage.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SETTINGSPAGE_H
+#define SETTINGSPAGE_H
+
+#include <QtGui/QWidget>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_settingspage.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace Git {
+namespace Internal {
+
+class SettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ SettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ bool adoptEnvironment() const { return m_adopt; }
+ int logCount() const { return m_logCount; }
+ QString path() const { return m_path; }
+
+private slots:
+ void setSystemPath();
+
+private:
+ Ui_SettingsPage m_ui;
+ QSettings *m_settings;
+
+ bool m_adopt;
+ QString m_path;
+ int m_logCount;
+};
+
+} //namespace Internal
+} //namespace Git
+
+#endif
diff --git a/src/plugins/git/settingspage.ui b/src/plugins/git/settingspage.ui
new file mode 100644
index 0000000000..738413e676
--- /dev/null
+++ b/src/plugins/git/settingspage.ui
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Git::Internal::SettingsPage</class>
+ <widget class="QWidget" name="Git::Internal::SettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>345</width>
+ <height>177</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="adoptCheckBox">
+ <property name="text">
+ <string>Use System Environment</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Environment variables</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>PATH:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="pathLineEdit"/>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="adoptButton">
+ <property name="text">
+ <string>Adopt</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>52</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt; font-weight:600;&quot;&gt;Note&lt;/span&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; that Git needs Perl in the environment as well&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Commit display count:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="logLineEdit">
+ <property name="toolTip">
+ <string>Note that huge amount of commits might take some time.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>pathLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>adoptCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>groupBox</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>144</x>
+ <y>33</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>139</x>
+ <y>65</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>