summaryrefslogtreecommitdiff
path: root/src/plugins/perforce
diff options
context:
space:
mode:
authorcon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
committercon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
commit05c35356abc31549c5db6eba31fb608c0365c2a0 (patch)
treebe044530104267afaff13f8943889cb97f8c8bad /src/plugins/perforce
downloadqt-creator-05c35356abc31549c5db6eba31fb608c0365c2a0.tar.gz
Initial import
Diffstat (limited to 'src/plugins/perforce')
-rw-r--r--src/plugins/perforce/Perforce.mimetypes.xml10
-rw-r--r--src/plugins/perforce/Perforce.pluginspec13
-rw-r--r--src/plugins/perforce/annotationhighlighter.cpp52
-rw-r--r--src/plugins/perforce/annotationhighlighter.h58
-rw-r--r--src/plugins/perforce/changenumberdialog.cpp52
-rw-r--r--src/plugins/perforce/changenumberdialog.h61
-rw-r--r--src/plugins/perforce/changenumberdialog.ui79
-rw-r--r--src/plugins/perforce/images/diff.pngbin0 -> 204 bytes
-rw-r--r--src/plugins/perforce/images/submit.pngbin0 -> 309 bytes
-rw-r--r--src/plugins/perforce/p4.h48
-rw-r--r--src/plugins/perforce/pendingchangesdialog.cpp72
-rw-r--r--src/plugins/perforce/pendingchangesdialog.h59
-rw-r--r--src/plugins/perforce/pendingchangesdialog.ui99
-rw-r--r--src/plugins/perforce/perforce.pro38
-rw-r--r--src/plugins/perforce/perforce.qrc7
-rw-r--r--src/plugins/perforce/perforce_dependencies.pri5
-rw-r--r--src/plugins/perforce/perforceconstants.h53
-rw-r--r--src/plugins/perforce/perforceeditor.cpp159
-rw-r--r--src/plugins/perforce/perforceeditor.h67
-rw-r--r--src/plugins/perforce/perforceoutputwindow.cpp166
-rw-r--r--src/plugins/perforce/perforceoutputwindow.h87
-rw-r--r--src/plugins/perforce/perforceplugin.cpp1270
-rw-r--r--src/plugins/perforce/perforceplugin.h250
-rw-r--r--src/plugins/perforce/perforcesettings.cpp95
-rw-r--r--src/plugins/perforce/perforcesettings.h65
-rw-r--r--src/plugins/perforce/perforcesubmiteditor.cpp194
-rw-r--r--src/plugins/perforce/perforcesubmiteditor.h84
-rw-r--r--src/plugins/perforce/perforcesubmiteditorwidget.cpp55
-rw-r--r--src/plugins/perforce/perforcesubmiteditorwidget.h60
-rw-r--r--src/plugins/perforce/perforceversioncontrol.cpp69
-rw-r--r--src/plugins/perforce/perforceversioncontrol.h60
-rw-r--r--src/plugins/perforce/promptdialog.ui128
-rw-r--r--src/plugins/perforce/settingspage.cpp110
-rw-r--r--src/plugins/perforce/settingspage.h84
-rw-r--r--src/plugins/perforce/settingspage.ui148
-rw-r--r--src/plugins/perforce/submitpanel.ui100
-rw-r--r--src/plugins/perforce/workbenchclientuser.cpp285
-rw-r--r--src/plugins/perforce/workbenchclientuser.h111
38 files changed, 4353 insertions, 0 deletions
diff --git a/src/plugins/perforce/Perforce.mimetypes.xml b/src/plugins/perforce/Perforce.mimetypes.xml
new file mode 100644
index 0000000000..3c2d332771
--- /dev/null
+++ b/src/plugins/perforce/Perforce.mimetypes.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="application/vnd.nokia.text.p4.submit">
+ <comment>Perforce submit template</comment>
+ <sub-class-of type="text/plain"/>
+ <magic priority="50">
+ <match value="# A Perforce Change Specification." type="string" offset="0"/>
+ </magic>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/perforce/Perforce.pluginspec b/src/plugins/perforce/Perforce.pluginspec
new file mode 100644
index 0000000000..367b3afd79
--- /dev/null
+++ b/src/plugins/perforce/Perforce.pluginspec
@@ -0,0 +1,13 @@
+<plugin name="Perforce" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Perforce 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/perforce/annotationhighlighter.cpp b/src/plugins/perforce/annotationhighlighter.cpp
new file mode 100644
index 0000000000..ab4b855c4b
--- /dev/null
+++ b/src/plugins/perforce/annotationhighlighter.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** 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"
+
+namespace Perforce {
+namespace Internal {
+
+PerforceAnnotationHighlighter::PerforceAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document) :
+ VCSBase::BaseAnnotationHighlighter(changeNumbers, document),
+ m_colon(QLatin1Char(':'))
+{
+}
+
+QString PerforceAnnotationHighlighter::changeNumber(const QString &block) const
+{
+ const int pos = block.indexOf(m_colon);
+ return pos > 1 ? block.left(pos) : QString();
+}
+
+}
+}
diff --git a/src/plugins/perforce/annotationhighlighter.h b/src/plugins/perforce/annotationhighlighter.h
new file mode 100644
index 0000000000..e162753c4b
--- /dev/null
+++ b/src/plugins/perforce/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 Perforce {
+namespace Internal {
+
+// Annotation highlighter for p4 triggering on 'changenumber:'
+class PerforceAnnotationHighlighter : public VCSBase::BaseAnnotationHighlighter
+{
+ Q_OBJECT
+public:
+ explicit PerforceAnnotationHighlighter(const ChangeNumbers &changeNumbers,
+ QTextDocument *document = 0);
+
+private:
+ virtual QString changeNumber(const QString &block) const;
+
+ const QChar m_colon;
+};
+
+} //namespace Perforce
+} //namespace Internal
+
+#endif
diff --git a/src/plugins/perforce/changenumberdialog.cpp b/src/plugins/perforce/changenumberdialog.cpp
new file mode 100644
index 0000000000..8bf5827900
--- /dev/null
+++ b/src/plugins/perforce/changenumberdialog.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** 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 <QtGui/QIntValidator>
+
+#include "changenumberdialog.h"
+
+using namespace Perforce::Internal;
+
+ChangeNumberDialog::ChangeNumberDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ m_ui.numberLineEdit->setValidator(new QIntValidator(0, 1000000, this));
+}
+
+int ChangeNumberDialog::number() const
+{
+ if (m_ui.numberLineEdit->text().isEmpty())
+ return -1;
+ bool ok;
+ return m_ui.numberLineEdit->text().toInt(&ok);
+}
diff --git a/src/plugins/perforce/changenumberdialog.h b/src/plugins/perforce/changenumberdialog.h
new file mode 100644
index 0000000000..cc2429f297
--- /dev/null
+++ b/src/plugins/perforce/changenumberdialog.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** 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 CHANGENUMBERDIALOG_H
+#define CHANGENUMBERDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_changenumberdialog.h"
+
+namespace Perforce {
+namespace Internal {
+
+// Input a change number for pending changes.
+class ChangeNumberDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ChangeNumberDialog(QWidget *parent = 0);
+ int number() const;
+
+private:
+ Ui::ChangeNumberDialog m_ui;
+
+};
+
+} //namespace Perforce
+} //namespace Internal
+
+#endif
+
+
diff --git a/src/plugins/perforce/changenumberdialog.ui b/src/plugins/perforce/changenumberdialog.ui
new file mode 100644
index 0000000000..6fbcbc32e3
--- /dev/null
+++ b/src/plugins/perforce/changenumberdialog.ui
@@ -0,0 +1,79 @@
+<ui version="4.0" >
+ <class>Perforce::Internal::ChangeNumberDialog</class>
+ <widget class="QDialog" name="Perforce::Internal::ChangeNumberDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>319</width>
+ <height>76</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Change Number</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="numberLineEdit" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Change Number:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Perforce::Internal::ChangeNumberDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>59</x>
+ <y>24</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>160</x>
+ <y>38</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Perforce::Internal::ChangeNumberDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>59</x>
+ <y>24</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>160</x>
+ <y>38</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/images/diff.png b/src/plugins/perforce/images/diff.png
new file mode 100644
index 0000000000..b3597f9ff8
--- /dev/null
+++ b/src/plugins/perforce/images/diff.png
Binary files differ
diff --git a/src/plugins/perforce/images/submit.png b/src/plugins/perforce/images/submit.png
new file mode 100644
index 0000000000..4f302302b9
--- /dev/null
+++ b/src/plugins/perforce/images/submit.png
Binary files differ
diff --git a/src/plugins/perforce/p4.h b/src/plugins/perforce/p4.h
new file mode 100644
index 0000000000..70c1838491
--- /dev/null
+++ b/src/plugins/perforce/p4.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+**
+** 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 P4_API_INCL
+#define P4_API_INCL
+
+#include <qconfig.h>
+
+#ifdef USE_P4_API
+#
+# if defined(Q_OS_WIN) && defined(SetPort)
+# undef SetPort
+# endif
+#
+# include <clientapi.h>
+# include <diff.h>
+#endif
+
+#endif // P4_API_INCL
diff --git a/src/plugins/perforce/pendingchangesdialog.cpp b/src/plugins/perforce/pendingchangesdialog.cpp
new file mode 100644
index 0000000000..971153ba97
--- /dev/null
+++ b/src/plugins/perforce/pendingchangesdialog.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** 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 <QtCore/QRegExp>
+
+#include "pendingchangesdialog.h"
+
+using namespace Perforce::Internal;
+
+PendingChangesDialog::PendingChangesDialog(const QString &data, QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ if (!data.isEmpty()) {
+ QRegExp r("Change\\s(\\d+).*\\s\\*pending\\*\\s(.+)\n");
+ r.setMinimal(true);
+ int pos = 0;
+ QListWidgetItem *item;
+ while ((pos = r.indexIn(data, pos)) != -1) {
+ item = new QListWidgetItem(tr("Change %1: %2").arg(r.cap(1))
+ .arg(r.cap(2).trimmed()), m_ui.listWidget);
+ item->setData(234, r.cap(1).trimmed());
+ ++pos;
+ }
+ }
+ m_ui.listWidget->setSelectionMode(QListWidget::SingleSelection);
+ if (m_ui.listWidget->count()) {
+ m_ui.listWidget->setCurrentRow(0);
+ m_ui.submitButton->setEnabled(true);
+ } else {
+ m_ui.submitButton->setEnabled(false);
+ }
+}
+
+int PendingChangesDialog::changeNumber() const
+{
+ QListWidgetItem *item = m_ui.listWidget->item(m_ui.listWidget->currentRow());
+ if (!item)
+ return -1;
+ bool ok = true;
+ int i = item->data(234).toInt(&ok);
+ return ok ? i : -1;
+}
diff --git a/src/plugins/perforce/pendingchangesdialog.h b/src/plugins/perforce/pendingchangesdialog.h
new file mode 100644
index 0000000000..b31acf367a
--- /dev/null
+++ b/src/plugins/perforce/pendingchangesdialog.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** 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 PENDINGCHANGESDIALOG_H
+#define PENDINGCHANGESDIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "ui_pendingchangesdialog.h"
+
+namespace Perforce {
+namespace Internal {
+
+class PendingChangesDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ PendingChangesDialog(const QString &data, QWidget *parent = 0);
+ int changeNumber() const;
+
+private:
+ Ui::PendingChangesDialog m_ui;
+};
+
+} //namespace Perforce
+} //namespace Internal
+
+#endif
+
diff --git a/src/plugins/perforce/pendingchangesdialog.ui b/src/plugins/perforce/pendingchangesdialog.ui
new file mode 100644
index 0000000000..bcee662a02
--- /dev/null
+++ b/src/plugins/perforce/pendingchangesdialog.ui
@@ -0,0 +1,99 @@
+<ui version="4.0" >
+ <class>Perforce::Internal::PendingChangesDialog</class>
+ <widget class="QDialog" name="Perforce::Internal::PendingChangesDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>333</width>
+ <height>126</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>P4 Pending Changes</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="listWidget" />
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>131</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="submitButton" >
+ <property name="text" >
+ <string>Submit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>submitButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Perforce::Internal::PendingChangesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>278</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>96</x>
+ <y>254</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Perforce::Internal::PendingChangesDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>369</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>179</x>
+ <y>282</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/perforce.pro b/src/plugins/perforce/perforce.pro
new file mode 100644
index 0000000000..992777f172
--- /dev/null
+++ b/src/plugins/perforce/perforce.pro
@@ -0,0 +1,38 @@
+TEMPLATE = lib
+TARGET = Perforce
+
+include(../../qworkbenchplugin.pri)
+include(perforce_dependencies.pri)
+
+HEADERS += p4.h \
+ perforceplugin.h \
+ perforceoutputwindow.h \
+ settingspage.h \
+ perforceeditor.h \
+ changenumberdialog.h \
+ perforcesubmiteditor.h \
+ pendingchangesdialog.h \
+ perforceconstants.h \
+ perforceversioncontrol.h \
+ perforcesettings.h \
+ annotationhighlighter.h \
+ perforcesubmiteditorwidget.h
+
+SOURCES += perforceplugin.cpp \
+ perforceoutputwindow.cpp \
+ settingspage.cpp \
+ perforceeditor.cpp \
+ changenumberdialog.cpp \
+ perforcesubmiteditor.cpp \
+ pendingchangesdialog.cpp \
+ perforceversioncontrol.cpp \
+ perforcesettings.cpp \
+ annotationhighlighter.cpp \
+ perforcesubmiteditorwidget.cpp
+
+FORMS += settingspage.ui \
+ changenumberdialog.ui \
+ pendingchangesdialog.ui \
+ submitpanel.ui
+
+RESOURCES += perforce.qrc
diff --git a/src/plugins/perforce/perforce.qrc b/src/plugins/perforce/perforce.qrc
new file mode 100644
index 0000000000..de0db02a3d
--- /dev/null
+++ b/src/plugins/perforce/perforce.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/trolltech.perforce" >
+ <file>images/diff.png</file>
+ <file>images/submit.png</file>
+ <file>Perforce.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/perforce/perforce_dependencies.pri b/src/plugins/perforce/perforce_dependencies.pri
new file mode 100644
index 0000000000..9e7c28e9e1
--- /dev/null
+++ b/src/plugins/perforce/perforce_dependencies.pri
@@ -0,0 +1,5 @@
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/vcsbase/vcsbase.pri)
+include(../../libs/utils/utils.pri)
diff --git a/src/plugins/perforce/perforceconstants.h b/src/plugins/perforce/perforceconstants.h
new file mode 100644
index 0000000000..57cfb7ef3a
--- /dev/null
+++ b/src/plugins/perforce/perforceconstants.h
@@ -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.
+**
+***************************************************************************/
+#ifndef PERFORCE_CONSTANTS_H
+#define PERFORCE_CONSTANTS_H
+
+namespace Perforce {
+ namespace Constants {
+ const char * const C_PERFORCEEDITOR = "Perforce Editor";
+
+ const char * const PERFORCEEDITOR_KIND = "Perforce Editor";
+ const char * const C_PERFORCESUBMITEDITOR = "Perforce Submit Editor";
+ const char * const PERFORCESUBMITEDITOR_KIND = "Perforce Submit Editor";
+ const char * const ICON_SUBMIT = ":/trolltech.perforce/images/submit.png";
+ const char * const ICON_DIFF = ":/trolltech.perforce/images/diff.png";
+ const char * const SUBMIT_CURRENT = "Nokia.Perforce.SubmitCurrentLog";
+ const char * const DIFF_SELECTED = "Nokia.Perforce.DiffSelectedFilesInLog";
+ const char * const SUBMIT_MIMETYPE = "application/vnd.nokia.text.p4.submit";
+
+ enum { debug = 0 };
+ }
+}
+
+#endif // PERFORCE_CONSTANTS_H
diff --git a/src/plugins/perforce/perforceeditor.cpp b/src/plugins/perforce/perforceeditor.cpp
new file mode 100644
index 0000000000..dd9da666f2
--- /dev/null
+++ b/src/plugins/perforce/perforceeditor.cpp
@@ -0,0 +1,159 @@
+/***************************************************************************
+**
+** 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 "perforceeditor.h"
+#include "annotationhighlighter.h"
+#include "perforceplugin.h"
+#include "perforceconstants.h"
+#include "perforceplugin.h"
+
+#include <vcsbase/diffhighlighter.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QSet>
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLayout>
+#include <QtGui/QTextEdit>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QTextCursor>
+#include <QtCore/QProcess>
+
+namespace Perforce {
+namespace Internal {
+
+// ------------ PerforceEditor
+PerforceEditor::PerforceEditor(const VCSBase::VCSBaseEditorParameters *type,
+ QWidget *parent) :
+ VCSBase::VCSBaseEditor(type, parent),
+ m_changeNumberPattern(QLatin1String("^\\d+$")),
+ m_plugin(PerforcePlugin::perforcePluginInstance())
+{
+ Q_ASSERT(m_changeNumberPattern.isValid());
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforceEditor::PerforceEditor" << type->type << type->kind;
+}
+
+QSet<QString> PerforceEditor::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("^(\\d+):"));
+ Q_ASSERT(r.isValid());
+ if (r.indexIn(txt) != -1) {
+ changes.insert(r.cap(1));
+ r.setPattern(QLatin1String("\n(\\d+):"));
+ Q_ASSERT(r.isValid());
+ int pos = 0;
+ while ((pos = r.indexIn(txt, pos)) != -1) {
+ pos += r.matchedLength();
+ changes.insert(r.cap(1));
+ }
+ }
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforceEditor::annotationChanges() returns #" << changes.size();
+ return changes;
+}
+
+QString PerforceEditor::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();
+ return m_changeNumberPattern.exactMatch(change) ? change : QString();
+}
+
+VCSBase::DiffHighlighter *PerforceEditor::createDiffHighlighter() const
+{
+ const QRegExp filePattern(QLatin1String("^====.*"));
+ return new VCSBase::DiffHighlighter(filePattern);
+}
+
+VCSBase::BaseAnnotationHighlighter *PerforceEditor::createAnnotationHighlighter(const QSet<QString> &changes) const
+{
+ return new PerforceAnnotationHighlighter(changes);
+}
+
+QString PerforceEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const
+{
+ QString errorMessage;
+ const QString diffIndicator = QLatin1String("==== ");
+ const QString diffEndIndicator = QLatin1String(" ====");
+ // Go back chunks. Note that for 'describe', an extra, empty line
+ // occurs.
+ for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) {
+ QString diffFileName = block.text();
+ if (diffFileName.startsWith(diffIndicator) && diffFileName.endsWith(diffEndIndicator)) {
+ // Split:
+ // 1) "==== //depot/.../mainwindow.cpp#2 - /depot/.../mainwindow.cpp ===="
+ // (as created by p4 diff) or
+ // 2) "==== //depot/.../mainwindow.cpp#15 (text) ===="
+ // (as created by p4 describe).
+ diffFileName.remove(0, diffIndicator.size());
+ diffFileName.truncate(diffFileName.size() - diffEndIndicator.size());
+ const int separatorPos = diffFileName.indexOf(QLatin1String(" - "));
+ if (separatorPos == -1) {
+ // ==== depot path (text) ==== (p4 describe)
+ const int blankPos = diffFileName.indexOf(QLatin1Char(' '));
+ if (blankPos == -1)
+ return QString();
+ diffFileName.truncate(blankPos);
+ } else {
+ // ==== depot path - local path ==== (p4 diff)
+ diffFileName.truncate(separatorPos);
+ }
+ // Split off revision "#4"
+ const int revisionPos = diffFileName.lastIndexOf(QLatin1Char('#'));
+ if (revisionPos != -1 && revisionPos < diffFileName.length() - 1)
+ diffFileName.truncate(revisionPos);
+ // Ask plugin to map back
+ const QString fileName = m_plugin->fileNameFromPerforceName(diffFileName.trimmed(), &errorMessage);
+ if (fileName.isEmpty())
+ qWarning(errorMessage.toUtf8().constData());
+ return fileName;
+ }
+ }
+ return QString();
+}
+
+} // namespace Internal
+} // namespace Perforce
diff --git a/src/plugins/perforce/perforceeditor.h b/src/plugins/perforce/perforceeditor.h
new file mode 100644
index 0000000000..2ca9b0304e
--- /dev/null
+++ b/src/plugins/perforce/perforceeditor.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 PERFORCEEDITOR_H
+#define PERFORCEEDITOR_H
+
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QtCore/QRegExp>
+
+namespace Perforce {
+namespace Internal {
+
+class PerforcePlugin;
+
+class PerforceEditor : public VCSBase::VCSBaseEditor
+{
+ Q_OBJECT
+
+public:
+ explicit PerforceEditor(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_changeNumberPattern;
+ PerforcePlugin *m_plugin;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif // PERFORCEEDITOR_H
diff --git a/src/plugins/perforce/perforceoutputwindow.cpp b/src/plugins/perforce/perforceoutputwindow.cpp
new file mode 100644
index 0000000000..4d37d6a9af
--- /dev/null
+++ b/src/plugins/perforce/perforceoutputwindow.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+**
+** 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 <QtGui/QKeyEvent>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+
+#include "perforceoutputwindow.h"
+#include "perforceplugin.h"
+
+using namespace Perforce::Internal;
+
+PerforceOutputWindow::PerforceOutputWindow(PerforcePlugin *p4Plugin)
+ : m_p4Plugin(p4Plugin)
+{
+ m_outputListWidget = new QListWidget;
+ m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_outputListWidget->setFrameStyle(QFrame::NoFrame);
+
+ m_outputListWidget->setWindowTitle(tr("Perforce Output"));
+
+ m_diffAction = new QAction(tr("Diff"), this);
+ connect(m_diffAction, SIGNAL(triggered()), this, SLOT(diff()));
+
+ connect(m_outputListWidget, SIGNAL(itemActivated(QListWidgetItem*)),
+ this, SLOT(openFiles()));
+}
+
+PerforceOutputWindow::~PerforceOutputWindow()
+{
+ delete m_outputListWidget;
+}
+
+bool PerforceOutputWindow::hasFocus()
+{
+ return m_outputListWidget->hasFocus();
+}
+
+bool PerforceOutputWindow::canFocus()
+{
+ return false;
+}
+
+void PerforceOutputWindow::setFocus()
+{
+
+}
+
+QWidget *PerforceOutputWindow::outputWidget(QWidget *parent)
+{
+ m_outputListWidget->setParent(parent);
+ return m_outputListWidget;
+}
+
+QString PerforceOutputWindow::name() const
+{
+ return tr("Perforce");
+}
+
+void PerforceOutputWindow::clearContents()
+{
+ m_outputListWidget->clear();
+}
+
+void PerforceOutputWindow::visibilityChanged(bool /* b */)
+{
+
+}
+
+void PerforceOutputWindow::append(const QString &txt, bool doPopup)
+{
+ const QStringList lines = txt.split(QLatin1Char('\n'));
+ foreach (const QString &s, lines)
+ m_outputListWidget->addItem(s);
+ m_outputListWidget->scrollToBottom();
+ if (doPopup)
+ popup();
+}
+
+void PerforceOutputWindow::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu *menu = new QMenu(m_outputListWidget);
+ menu->addAction(m_diffAction);
+ menu->exec(event->globalPos());
+ delete menu;
+}
+
+void PerforceOutputWindow::diff()
+{
+ QStringList files;
+ foreach (QListWidgetItem *i, m_outputListWidget->selectedItems()) {
+ if (m_outputListWidget->row(i) > 0)
+ files.append(getFileName(i));
+ }
+ if (files.count() == 0 && m_outputListWidget->row(m_outputListWidget->currentItem()) > 0)
+ files.append(getFileName(m_outputListWidget->currentItem()));
+
+ m_p4Plugin->p4Diff(files);
+}
+
+QString PerforceOutputWindow::getFileName(const QListWidgetItem *item)
+{
+ QString fileName;
+ if (!item || item->text().isEmpty())
+ return fileName;
+
+ QString line = item->text();
+ QRegExp regExp("(/.+)#\\d+\\s-\\s(.+)$");
+ regExp.setMinimal(true);
+ if (regExp.indexIn(line) > -1 && regExp.numCaptures() >= 1) {
+ fileName = regExp.cap(1);
+ QString description;
+ if (regExp.numCaptures() >= 2)
+ description = regExp.cap(2);
+ }
+ return fileName;
+}
+
+void PerforceOutputWindow::openFiles()
+{
+ QStringList files;
+ foreach (QListWidgetItem *i, m_outputListWidget->selectedItems()) {
+ if (m_outputListWidget->row(i) > 0)
+ files.append(getFileName(i));
+ }
+ if (files.count() == 0 && m_outputListWidget->row(m_outputListWidget->currentItem()) > 0)
+ files.append(getFileName(m_outputListWidget->currentItem()));
+
+ m_p4Plugin->openFiles(files);
+}
+
+int PerforceOutputWindow::priorityInStatusBar() const
+{
+ return -1;
+}
diff --git a/src/plugins/perforce/perforceoutputwindow.h b/src/plugins/perforce/perforceoutputwindow.h
new file mode 100644
index 0000000000..7391ca667d
--- /dev/null
+++ b/src/plugins/perforce/perforceoutputwindow.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** 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 PERFORCEOUTPUTWINDOW_H
+#define PERFORCEOUTPUTWINDOW_H
+
+#include <coreplugin/ioutputpane.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QListWidget>
+#include <QtGui/QListWidgetItem>
+
+namespace Perforce {
+namespace Internal {
+
+class PerforcePlugin;
+
+class PerforceOutputWindow : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ PerforceOutputWindow(PerforcePlugin *p4Plugin);
+ ~PerforceOutputWindow();
+
+ 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 append(const QString &txt, bool doPopup = false);
+
+private slots:;
+ void diff();
+ void openFiles();
+
+private:
+ void contextMenuEvent(QContextMenuEvent *event);
+
+ static QString getFileName(const QListWidgetItem *item);
+
+ PerforcePlugin *m_p4Plugin;
+ QListWidget *m_outputListWidget;
+ QAction *m_diffAction;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
new file mode 100644
index 0000000000..b3d2f43a26
--- /dev/null
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -0,0 +1,1270 @@
+/***************************************************************************
+**
+** 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 "p4.h"
+#include "perforceplugin.h"
+#include "perforceoutputwindow.h"
+#include "settingspage.h"
+#include "perforcesubmiteditor.h"
+#include "changenumberdialog.h"
+#include "perforceconstants.h"
+#include "perforceversioncontrol.h"
+#include "perforceeditor.h"
+#include "pendingchangesdialog.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <utils/synchronousprocess.h>
+#include <vcsbase/basevcseditorfactory.h>
+#include <vcsbase/basevcssubmiteditorfactory.h>
+#include <vcsbase/vcsbaseeditor.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+#include <QtCore/QTextCodec>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtGui/QFileDialog>
+
+using namespace Perforce::Internal;
+
+enum { p4Timeout = 20000 };
+
+static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
+{
+ VCSBase::RegularCommandOutput,
+ "Perforce Command Log Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "application/vnd.nokia.text.scs_commandlog",
+ "scslog"},
+{ VCSBase::LogOutput,
+ "Perforce File Log Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "application/vnd.nokia.text.scs_filelog",
+ "scsfilelog"},
+{ VCSBase::AnnotateOutput,
+ "Perforce Annotation Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "application/vnd.nokia.text.scs_annotation",
+ "scsannotate"},
+{ VCSBase::DiffOutput,
+ "Perforce Diff Editor",
+ Perforce::Constants::C_PERFORCEEDITOR,
+ "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);
+}
+
+static inline QString debugCodec(const QTextCodec *c)
+{
+ return c ? QString::fromAscii(c->name()) : QString::fromAscii("Null codec");
+}
+
+const char * const PerforcePlugin::PERFORCE_MENU = "Perforce.Menu";
+const char * const PerforcePlugin::EDIT = "Perforce.Edit";
+const char * const PerforcePlugin::ADD = "Perforce.Add";
+const char * const PerforcePlugin::DELETE_FILE = "Perforce.Delete";
+const char * const PerforcePlugin::OPENED = "Perforce.Opened";
+const char * const PerforcePlugin::REVERT = "Perforce.Revert";
+const char * const PerforcePlugin::DIFF_CURRENT = "Perforce.DiffCurrent";
+const char * const PerforcePlugin::DIFF_PROJECT = "Perforce.DiffProject";
+const char * const PerforcePlugin::DIFF_ALL = "Perforce.DiffAll";
+const char * const PerforcePlugin::RESOLVE = "Perforce.Resolve";
+const char * const PerforcePlugin::SUBMIT = "Perforce.Submit";
+const char * const PerforcePlugin::PENDING_CHANGES = "Perforce.PendingChanges";
+const char * const PerforcePlugin::DESCRIBE = "Perforce.Describe";
+const char * const PerforcePlugin::ANNOTATE_CURRENT = "Perforce.AnnotateCurrent";
+const char * const PerforcePlugin::ANNOTATE = "Perforce.Annotate";
+const char * const PerforcePlugin::FILELOG_CURRENT = "Perforce.FilelogCurrent";
+const char * const PerforcePlugin::FILELOG = "Perforce.Filelog";
+const char * const PerforcePlugin::SEPARATOR1 = "Perforce.Separator1";
+const char * const PerforcePlugin::SEPARATOR2 = "Perforce.Separator2";
+const char * const PerforcePlugin::SEPARATOR3 = "Perforce.Separator3";
+
+////
+// CoreListener
+////
+
+bool CoreListener::editorAboutToClose(Core::IEditor *editor)
+{
+ return m_plugin->editorAboutToClose(editor);
+}
+
+////
+// PerforcePlugin
+////
+
+Core::ICore *PerforcePlugin::m_coreInstance = NULL;
+PerforcePlugin *PerforcePlugin::m_perforcePluginInstance = NULL;
+
+PerforcePlugin::PerforcePlugin() :
+ m_perforceOutputWindow(0),
+ m_settingsPage(0),
+ m_editAction(0),
+ m_addAction(0),
+ m_deleteAction(0),
+ m_openedAction(0),
+ m_revertAction(0),
+ m_diffCurrentAction(0),
+ m_diffProjectAction(0),
+ m_diffAllAction(0),
+ m_resolveAction(0),
+ m_submitAction(0),
+ m_pendingAction(0),
+ m_describeAction(0),
+ m_annotateCurrentAction(0),
+ m_annotateAction(0),
+ m_filelogCurrentAction(0),
+ m_filelogAction(0),
+ m_changeTmpFile(0),
+#ifdef USE_P4_API
+ m_workbenchClientUser(0),
+#endif
+ m_coreListener(0),
+ m_submitEditorFactory(0),
+ m_versionControl(0)
+{
+}
+
+static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = {
+ Perforce::Constants::SUBMIT_MIMETYPE,
+ Perforce::Constants::PERFORCESUBMITEDITOR_KIND,
+ Perforce::Constants::C_PERFORCESUBMITEDITOR,
+ Core::Constants::UNDO,
+ Core::Constants::REDO,
+ Perforce::Constants::SUBMIT_CURRENT,
+ Perforce::Constants::DIFF_SELECTED
+};
+
+bool PerforcePlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ typedef VCSBase::VCSEditorFactory<PerforceEditor> PerforceEditorFactory;
+ typedef VCSBase::VCSSubmitEditorFactory<PerforceSubmitEditor> PerforceSubmitEditorFactory;
+
+ m_coreInstance = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ if (!m_coreInstance->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.perforce/Perforce.mimetypes.xml"), errorMessage))
+ return false;
+ m_perforcePluginInstance = this;
+
+ if (QSettings *settings = m_coreInstance->settings())
+ m_settings.fromSettings(settings);
+
+ m_perforceOutputWindow = new PerforceOutputWindow(this);
+ addObject(m_perforceOutputWindow);
+
+ m_settingsPage = new SettingsPage;
+ addObject(m_settingsPage);
+
+ // Editor factories
+ m_submitEditorFactory = new PerforceSubmitEditorFactory(&submitParameters);
+ addObject(m_submitEditorFactory);
+
+ static const char *describeSlot = SLOT(describe(QString,QString));
+ const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
+ for (int i = 0; i < editorCount; i++) {
+ m_editorFactories.push_back(new PerforceEditorFactory(editorParameters + i, m_coreInstance, this, describeSlot));
+ addObject(m_editorFactories.back());
+ }
+
+ m_versionControl = new PerforceVersionControl(this);
+ addObject(m_versionControl);
+
+#ifdef USE_P4_API
+ m_workbenchClientUser = new WorkbenchClientUser(m_perforceOutputWindow, this);
+ m_enableP4APIActions = true;
+#endif
+
+ m_coreListener = new CoreListener(this);
+ addObject(m_coreListener);
+
+
+ //register actions
+ Core::ActionManagerInterface *am = m_coreInstance->actionManager();
+
+ Core::IActionContainer *mtools =
+ am->actionContainer(Core::Constants::M_TOOLS);
+
+ Core::IActionContainer *mperforce =
+ am->createMenu(QLatin1String(PERFORCE_MENU));
+ mperforce->menu()->setTitle(tr("&Perforce"));
+ mtools->addMenu(mperforce);
+
+ QList<int> globalcontext;
+ globalcontext << Core::Constants::C_GLOBAL_ID;
+
+ QList<int> perforcesubmitcontext;
+ perforcesubmitcontext <<
+ m_coreInstance->uniqueIDManager()->uniqueIdentifier(Constants::C_PERFORCESUBMITEDITOR);
+
+ Core::ICommand *command;
+ QAction *tmpaction;
+
+ m_editAction = new QAction(tr("Edit"), this);
+ command = am->registerAction(m_editAction, PerforcePlugin::EDIT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+E")));
+ command->setDefaultText(tr("Edit File"));
+ connect(m_editAction, SIGNAL(triggered()), this, SLOT(openCurrentFile()));
+ mperforce->addAction(command);
+
+ m_addAction = new QAction(tr("Add"), this);
+ command = am->registerAction(m_addAction, PerforcePlugin::ADD, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+A")));
+ command->setDefaultText(tr("Add File"));
+ connect(m_addAction, SIGNAL(triggered()), this, SLOT(addCurrentFile()));
+ mperforce->addAction(command);
+
+ m_deleteAction = new QAction(tr("Delete"), this);
+ command = am->registerAction(m_deleteAction, PerforcePlugin::DELETE_FILE, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultText(tr("Delete File"));
+ connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(deleteCurrentFile()));
+ mperforce->addAction(command);
+
+ m_revertAction = new QAction(tr("Revert"), this);
+ command = am->registerAction(m_revertAction, PerforcePlugin::REVERT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+R")));
+ command->setDefaultText(tr("Revert File"));
+ connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile()));
+ mperforce->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Edit"), globalcontext);
+ mperforce->addAction(command);
+
+ m_diffCurrentAction = new QAction(tr("Diff Current File"), this);
+ command = am->registerAction(m_diffCurrentAction, PerforcePlugin::DIFF_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultText(tr("Diff Current File"));
+ connect(m_diffCurrentAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
+ mperforce->addAction(command);
+
+ m_diffProjectAction = new QAction(tr("Diff Current Project/Session"), this);
+ command = am->registerAction(m_diffProjectAction, PerforcePlugin::DIFF_PROJECT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+D")));
+ command->setDefaultText(tr("Diff Current Project/Session"));
+ connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffCurrentProject()));
+ mperforce->addAction(command);
+
+ m_diffAllAction = new QAction(tr("Diff Opened Files"), this);
+ command = am->registerAction(m_diffAllAction, PerforcePlugin::DIFF_ALL, globalcontext);
+ connect(m_diffAllAction, SIGNAL(triggered()), this, SLOT(diffAllOpened()));
+ mperforce->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Diff"), globalcontext);
+ mperforce->addAction(command);
+
+ m_openedAction = new QAction(tr("Opened"), this);
+ command = am->registerAction(m_openedAction, PerforcePlugin::OPENED, globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+O")));
+ connect(m_openedAction, SIGNAL(triggered()), this, SLOT(printOpenedFileList()));
+ mperforce->addAction(command);
+
+#ifdef USE_P4_API
+ m_resolveAction = new QAction(tr("Resolve"), this);
+ command = am->registerAction(m_resolveAction, PerforcePlugin::RESOLVE, globalcontext);
+ connect(m_resolveAction, SIGNAL(triggered()), this, SLOT(resolve()));
+ mperforce->addAction(command);
+#endif
+
+ m_submitAction = new QAction(tr("Submit Project"), this);
+ command = am->registerAction(m_submitAction, PerforcePlugin::SUBMIT, globalcontext);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+S")));
+ connect(m_submitAction, SIGNAL(triggered()), this, SLOT(submit()));
+ mperforce->addAction(command);
+
+ m_pendingAction = new QAction(tr("Pending Changes..."), this);
+ command = am->registerAction(m_pendingAction, PerforcePlugin::PENDING_CHANGES, globalcontext);
+ connect(m_pendingAction, SIGNAL(triggered()), this, SLOT(printPendingChanges()));
+ mperforce->addAction(command);
+
+ tmpaction = new QAction(this);
+ tmpaction->setSeparator(true);
+ command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Changes"), globalcontext);
+ mperforce->addAction(command);
+
+ m_describeAction = new QAction(tr("Describe..."), this);
+ command = am->registerAction(m_describeAction, PerforcePlugin::DESCRIBE, globalcontext);
+ connect(m_describeAction, SIGNAL(triggered()), this, SLOT(describeChange()));
+ mperforce->addAction(command);
+
+ m_annotateCurrentAction = new QAction(tr("Annotate Current File"), this);
+ command = am->registerAction(m_annotateCurrentAction, PerforcePlugin::ANNOTATE_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultText(tr("Annotate Current File"));
+ connect(m_annotateCurrentAction, SIGNAL(triggered()), this, SLOT(annotateCurrentFile()));
+ mperforce->addAction(command);
+
+ m_annotateAction = new QAction(tr("Annotate..."), this);
+ command = am->registerAction(m_annotateAction, PerforcePlugin::ANNOTATE, globalcontext);
+ connect(m_annotateAction, SIGNAL(triggered()), this, SLOT(annotate()));
+ mperforce->addAction(command);
+
+ m_filelogCurrentAction = new QAction(tr("Filelog Current File"), this);
+ command = am->registerAction(m_filelogCurrentAction, PerforcePlugin::FILELOG_CURRENT, globalcontext);
+ command->setAttribute(Core::ICommand::CA_UpdateText);
+ command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+F")));
+ command->setDefaultText(tr("Filelog Current File"));
+ connect(m_filelogCurrentAction, SIGNAL(triggered()), this, SLOT(filelogCurrentFile()));
+ mperforce->addAction(command);
+
+ m_filelogAction = new QAction(tr("Filelog..."), this);
+ command = am->registerAction(m_filelogAction, PerforcePlugin::FILELOG, globalcontext);
+ connect(m_filelogAction, SIGNAL(triggered()), this, SLOT(filelog()));
+ mperforce->addAction(command);
+
+ m_submitCurrentLogAction = new QAction(QIcon(Constants::ICON_SUBMIT), tr("Submit"), this);
+ command = am->registerAction(m_submitCurrentLogAction, Constants::SUBMIT_CURRENT, perforcesubmitcontext);
+ connect(m_submitCurrentLogAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
+
+ m_diffSelectedFiles = new QAction(QIcon(Constants::ICON_DIFF), tr("Diff Selected Files"), this);
+ command = am->registerAction(m_diffSelectedFiles, Constants::DIFF_SELECTED, perforcesubmitcontext);
+
+ m_undoAction = new QAction(tr("&Undo"), this);
+ command = am->registerAction(m_undoAction, Core::Constants::UNDO, perforcesubmitcontext);
+
+ m_redoAction = new QAction(tr("&Redo"), this);
+ command = am->registerAction(m_redoAction, Core::Constants::REDO, perforcesubmitcontext);
+
+ connect(m_coreInstance, SIGNAL(contextChanged(Core::IContext *)),
+ this, SLOT(updateActions()));
+
+ connect(m_coreInstance->fileManager(), SIGNAL(currentFileChanged(const QString &)),
+ this, SLOT(updateActions()));
+
+ return true;
+}
+
+void PerforcePlugin::extensionsInitialized()
+{
+ m_projectExplorer = ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+ if (m_projectExplorer) {
+ connect(m_projectExplorer,
+ SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
+ this, SLOT(updateActions()));
+ }
+ updateActions();
+}
+
+void PerforcePlugin::openCurrentFile()
+{
+ runP4Cmd(QStringList() << QLatin1String("edit") << currentFileName(), QStringList(), true);
+}
+
+void PerforcePlugin::addCurrentFile()
+{
+ runP4Cmd(QStringList() << QLatin1String("add") << currentFileName(), QStringList(), true);
+}
+
+void PerforcePlugin::deleteCurrentFile()
+{
+ runP4Cmd(QStringList() << QLatin1String("delete") << currentFileName(), QStringList(), true);
+}
+
+void PerforcePlugin::revertCurrentFile()
+{
+ Q_ASSERT(m_coreInstance);
+
+ const QString fileName = currentFileName();
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName);
+ QStringList args;
+ args << QLatin1String("diff") << QLatin1String("-sa");
+ PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec);
+ if (result.error)
+ return;
+
+ if (!result.stdOut.isEmpty()) {
+ bool doNotRevert = QMessageBox::warning(0, tr("p4 revert"),
+ tr("The file has been changed. Do you want to revert it?"),
+ QMessageBox::Yes, QMessageBox::No)
+ == QMessageBox::No;
+ if (doNotRevert)
+ return;
+ }
+
+ Core::FileManager *fm = m_coreInstance->fileManager();
+ QList<Core::IFile *> files = fm->managedFiles(fileName);
+ foreach (Core::IFile *file, files) {
+ fm->blockFileChange(file);
+ }
+ PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true);
+ Core::IFile::ReloadBehavior tempBehavior =
+ Core::IFile::ReloadAll;
+ foreach (Core::IFile *file, files) {
+ file->modified(&tempBehavior);
+ fm->unblockFileChange(file);
+ }
+}
+
+void PerforcePlugin::diffCurrentFile()
+{
+ p4Diff(QStringList(currentFileName()));
+}
+
+void PerforcePlugin::diffCurrentProject()
+{
+ Q_ASSERT(m_projectExplorer);
+ QStringList files;
+ QString name;
+ ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject();
+ if (currentProject) {
+ files << currentProject->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ name = currentProject->name();
+ } else if (m_projectExplorer->session()) {
+ name = m_projectExplorer->session()->file()->fileName();
+ QList<ProjectExplorer::Project *> projects = m_projectExplorer->session()->projects();
+ foreach (ProjectExplorer::Project *project, projects)
+ files << project->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ }
+ QStringList nativeFiles;
+ foreach (const QString &f, files)
+ nativeFiles << QDir::toNativeSeparators(f);
+ p4Diff(nativeFiles, name);
+}
+
+void PerforcePlugin::diffAllOpened()
+{
+ p4Diff(QStringList());
+}
+
+void PerforcePlugin::printOpenedFileList()
+{
+ Core::IEditor *e = m_coreInstance->editorManager()->currentEditor();
+ if (e)
+ e->widget()->setFocus();
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("opened"), QStringList(), true);
+}
+
+#ifdef USE_P4_API
+void PerforcePlugin::resolve()
+{
+ m_workbenchClientUser->setMode(WorkbenchClientUser::Resolve);
+ runP4APICmd(QLatin1String("resolve"));
+}
+#endif
+
+void PerforcePlugin::submit()
+{
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command()) {
+ showOutput(tr("No p4 executable specified!"));
+ return;
+ }
+
+ if (m_changeTmpFile) {
+ showOutput(tr("Another submit is currently executed."));
+ m_perforceOutputWindow->popup(false);
+ return;
+ }
+
+ m_changeTmpFile = new QTemporaryFile(this);
+ if (!m_changeTmpFile->open()) {
+ showOutput(tr("Cannot create temporary file."));
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ PerforceResponse result = runP4Cmd(QStringList()<< QLatin1String("change") << QLatin1String("-o"), QStringList(), false);
+ if (result.error) {
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ m_changeTmpFile->write(result.stdOut.toAscii());
+ m_changeTmpFile->seek(0);
+
+ // Assemble file list of project
+ Q_ASSERT(m_projectExplorer);
+ QStringList files;
+ QString name;
+ ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject();
+ if (currentProject) {
+ files << currentProject->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ name = currentProject->name();
+ } else if (m_projectExplorer->session()) {
+ name = m_projectExplorer->session()->file()->fileName();
+ QList<ProjectExplorer::Project *> projects = m_projectExplorer->session()->projects();
+ foreach (ProjectExplorer::Project *project, projects)
+ files << project->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ }
+ QStringList nativeFiles;
+ foreach (const QString &f, files)
+ nativeFiles << QDir::toNativeSeparators(f);
+
+ PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles, false);
+ if (result2.error) {
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ QStringList stdOutLines = result2.stdOut.split(QLatin1Char('\n'));
+ QStringList depotFileNames;
+ foreach(const QString &line, stdOutLines) {
+ if (line.startsWith("... depotFile")) {
+ depotFileNames.append(line.mid(14));
+ }
+ }
+ if (depotFileNames.isEmpty()) {
+ showOutput(tr("Project has no files"));
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return;
+ }
+
+ openPerforceSubmitEditor(m_changeTmpFile->fileName(), depotFileNames);
+}
+
+Core::IEditor *PerforcePlugin::openPerforceSubmitEditor(const QString &fileName, const QStringList &depotFileNames)
+{
+ Core::IEditor *editor =
+ m_coreInstance->editorManager()->openEditor(fileName, Constants::PERFORCESUBMITEDITOR_KIND);
+ m_coreInstance->editorManager()->ensureEditorManagerVisible();
+ PerforceSubmitEditor *submitEditor = dynamic_cast<PerforceSubmitEditor*>(editor);
+ Q_ASSERT(submitEditor);
+ submitEditor->restrictToProjectFiles(depotFileNames);
+ connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(slotDiff(QStringList)));
+ // The actions are for some reason enabled by the context switching
+ // mechanism. Disable them correctly.
+ m_diffSelectedFiles->setEnabled(false);
+ m_undoAction->setEnabled(false);
+ m_redoAction->setEnabled(false);
+ return editor;
+}
+
+void PerforcePlugin::printPendingChanges()
+{
+ qApp->setOverrideCursor(Qt::WaitCursor);
+ PendingChangesDialog dia(pendingChangesData(), m_coreInstance->mainWindow());
+ qApp->restoreOverrideCursor();
+ if (dia.exec() == QDialog::Accepted) {
+ int i = dia.changeNumber();
+ PerforceResponse result = runP4Cmd(QStringList()<<"submit"<<"-c"<<QString::number(i), QStringList(), true);
+ }
+}
+
+void PerforcePlugin::describeChange()
+{
+ ChangeNumberDialog dia;
+ if (dia.exec() == QDialog::Accepted && dia.number() > 0)
+ describe(QString(), QString::number(dia.number()));
+}
+
+void PerforcePlugin::annotateCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ annotate(file);
+}
+
+void PerforcePlugin::annotate()
+{
+ const QString file = QFileDialog::getOpenFileName(0, tr("p4 annotate"), currentFileName());
+ if (!file.isEmpty())
+ annotate(file);
+}
+
+void PerforcePlugin::annotate(const QString &fileName)
+{
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName);
+ QStringList args;
+ args << QLatin1String("annotate") << QLatin1String("-cqi") << fileName;
+ const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec);
+ if (!result.error) {
+ const QFileInfo fi(fileName);
+ showOutputInEditor(tr("p4 annotate %1").arg(fi.fileName()), result.stdOut, VCSBase::AnnotateOutput, codec);
+ }
+}
+
+void PerforcePlugin::filelogCurrentFile()
+{
+ const QString file = currentFileName();
+ if (!file.isEmpty())
+ filelog(file);
+}
+
+void PerforcePlugin::filelog()
+{
+ const QString file = QFileDialog::getOpenFileName(0, tr("p4 filelog"), currentFileName());
+ if (!file.isEmpty())
+ filelog(file);
+}
+
+void PerforcePlugin::filelog(const QString &fileName)
+{
+ QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName);
+ QStringList args;
+ args << QLatin1String("filelog") << QLatin1String("-li") << fileName;
+ const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec);
+ if (!result.error) {
+ const QFileInfo fi(fileName);
+ showOutputInEditor(tr("p4 filelog %1").arg(fi.fileName()), result.stdOut, VCSBase::LogOutput, codec);
+ }
+}
+
+void PerforcePlugin::updateActions()
+{
+ QString fileName = currentFileName();
+ QString baseName = QFileInfo(fileName).fileName();
+ const bool hasFile = !currentFileName().isEmpty();
+ m_editAction->setEnabled(hasFile);
+ m_addAction->setEnabled(hasFile);
+ m_deleteAction->setEnabled(hasFile);
+ m_revertAction->setEnabled(hasFile);
+ m_diffCurrentAction->setEnabled(hasFile);
+ m_annotateCurrentAction->setEnabled(hasFile);
+ m_filelogCurrentAction->setEnabled(hasFile);
+ if (hasFile) {
+ m_editAction->setText(tr("Edit %1").arg(baseName));
+ m_addAction->setText(tr("Add %1").arg(baseName));
+ m_deleteAction->setText(tr("Delete %1").arg(baseName));
+ m_revertAction->setText(tr("Revert %1").arg(baseName));
+ m_diffCurrentAction->setText(tr("Diff %1").arg(baseName));
+ m_annotateCurrentAction->setText(tr("Annotate %1").arg(baseName));
+ m_filelogCurrentAction->setText(tr("Filelog %1").arg(baseName));
+ } else {
+ m_editAction->setText(tr("Edit"));
+ m_addAction->setText(tr("Add"));
+ m_deleteAction->setText(tr("Delete"));
+ m_revertAction->setText(tr("Revert"));
+ m_diffCurrentAction->setText(tr("Diff"));
+ m_annotateCurrentAction->setText(tr("Annotate Current File"));
+ m_filelogCurrentAction->setText(tr("Filelog Current File"));
+ }
+ if (m_projectExplorer && m_projectExplorer->currentProject()) {
+ m_diffProjectAction->setEnabled(true);
+ m_diffProjectAction->setText(tr("Diff Project %1").arg(m_projectExplorer->currentProject()->name()));
+ m_submitAction->setEnabled(true);
+ } else {
+ m_diffProjectAction->setEnabled(false);
+ m_diffProjectAction->setText(tr("Diff Current Project/Soluion"));
+ m_submitAction->setEnabled(false);
+ }
+ m_diffAllAction->setEnabled(true);
+ m_openedAction->setEnabled(true);
+ m_describeAction->setEnabled(true);
+ m_annotateAction->setEnabled(true);
+ m_filelogAction->setEnabled(true);
+ m_pendingAction->setEnabled(true);
+
+
+#ifdef USE_P4_API
+ m_resolveAction->setEnabled(m_enableP4APIActions);
+#endif
+}
+
+bool PerforcePlugin::managesDirectory(const QString &directory) const
+{
+ const QString p4Path = directory + QLatin1String("/...");
+ QStringList args;
+ args << QLatin1String("fstat") << QLatin1String("-m1") << p4Path;
+
+ const PerforceResponse result = runP4Cmd(args, QStringList(), false, false);
+ return result.stdOut.contains("depotFile") || result.stdErr.contains("... - no such file(s)");
+}
+
+QString PerforcePlugin::findTopLevelForDirectory(const QString & /* dir */) const
+{
+ // First check with p4 client -o
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("client") << QLatin1String("-o"), QStringList(), false, false);
+ if (result.error)
+ return QString::null;
+
+ QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)"));
+ regExp.setMinimal(true);
+ if (regExp.indexIn(result.stdOut) != -1) {
+ QString file = regExp.cap(2).trimmed();
+ if (QFileInfo(file).exists())
+ return file;
+ }
+ return QString::null;
+}
+
+bool PerforcePlugin::vcsOpen(const QString &fileName)
+{
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("edit") << QDir::toNativeSeparators(fileName), QStringList(), true);
+ return !result.error;
+}
+
+bool PerforcePlugin::vcsAdd(const QString &fileName)
+{
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("add") << fileName, QStringList(), true);
+ return !result.error;
+}
+
+bool PerforcePlugin::vcsDelete(const QString &fileName)
+{
+ PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true);
+ PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("delete") << fileName, QStringList(), true);
+ // TODO need to carefully parse the actual messages from perforce
+ // or do a fstat before to decide what to do
+
+ // Different states are:
+ // File is in depot and unopened => p4 delete %
+ // File is in depot and opened => p4 revert %, p4 delete %
+ // File is not in depot => p4 revert %
+ return !(result.error && result2.error);
+}
+
+PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
+ const QStringList &extraArgs,
+ bool showStdOutInOutputWindow,
+ bool showStdErrInOutputWindow,
+ QTextCodec *outputCodec) const
+{
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforcePlugin::runP4Cmd" << args << extraArgs << debugCodec(outputCodec);
+ PerforceResponse response;
+ response.error = true;
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command()) {
+ response.message = tr("No p4 executable specified!");
+ m_perforceOutputWindow->append(response.message, true);
+ return response;
+ }
+
+ // handle extra args
+ QTemporaryFile tempfile;
+ tempfile.setAutoRemove(true);
+ const QChar newLine = QLatin1Char('\n');
+ const QChar blank = QLatin1Char(' ');
+ QStringList actualArgs = basicP4Args();
+ if (!extraArgs.isEmpty()) {
+ if (tempfile.open()) {
+ QTextStream stream(&tempfile);
+ stream << extraArgs.join(QString(newLine));
+ actualArgs << QLatin1String("-x") << tempfile.fileName();
+ tempfile.close();
+ } else {
+ qWarning()<<"Could not create temporary file. Appending all file names to command line.";
+ actualArgs << extraArgs;
+ }
+ }
+ actualArgs << args;
+
+ response.command = m_settings.p4Command;
+ response.command += blank;
+ response.command += actualArgs.join(QString(blank));
+ const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm"));
+ const QString outputText = tr("%1 Executing: %2\n").arg(timeStamp, response.command);
+ showOutput(outputText, false);
+
+ // Run, connect stderr to the output window
+ Core::Utils::SynchronousProcess process;
+ process.setTimeout(p4Timeout);
+ process.setStdOutCodec(outputCodec);
+ process.setEnvironment(environment());
+
+ // connect stderr to the output window if desired
+ if (showStdErrInOutputWindow) {
+ process.setStdErrBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool)));
+ }
+
+ // connect stdout to the output window if desired
+ if (showStdOutInOutputWindow) {
+ process.setStdOutBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool)));
+ }
+
+ const Core::Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command, actualArgs);
+ if (Perforce::Constants::debug)
+ qDebug() << sp_resp;
+
+ response.error = true;
+ response.stdErr = sp_resp.stdErr;
+ response.stdOut = sp_resp.stdOut;
+ switch (sp_resp.result) {
+ case Core::Utils::SynchronousProcessResponse::Finished:
+ response.error = false;
+ break;
+ case Core::Utils::SynchronousProcessResponse::FinishedError:
+ response.message = tr("The process terminated with exit code %1.").arg(sp_resp.exitCode);
+ break;
+ case Core::Utils::SynchronousProcessResponse::TerminatedAbnormally:
+ response.message = tr("The process terminated abnormally.");
+ break;
+ case Core::Utils::SynchronousProcessResponse::StartFailed:
+ response.message = tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(m_settings.p4Command);
+ break;
+ case Core::Utils::SynchronousProcessResponse::Hang:
+ response.message = tr("Subversion did not respond within timeout limit (%1 ms).").arg(p4Timeout );
+ break;
+ }
+ if (response.error)
+ m_perforceOutputWindow->append(response.message, true);
+
+
+ return response;
+}
+
+Core::IEditor * PerforcePlugin::showOutputInEditor(const QString& title, const QString output,
+ int editorType, QTextCodec *codec)
+{
+ const VCSBase::VCSBaseEditorParameters *params = findType(editorType);
+ Q_ASSERT(params);
+ const QString kind = QLatin1String(params->kind);
+ if (Perforce::Constants::debug)
+ qDebug() << "PerforcePlugin::showOutputInEditor" << title << kind << "Size= " << output.size() << " Type=" << editorType << debugCodec(codec);
+ QString s = title;
+ Core::IEditor *ediface = m_coreInstance->editorManager()->
+ newFile(kind, &s, output.toLocal8Bit());
+ PerforceEditor *e = qobject_cast<PerforceEditor*>(ediface->widget());
+ if (!e)
+ return 0;
+ s.replace(QLatin1Char(' '), QLatin1Char('_'));
+ e->setSuggestedFileName(s);
+ if (codec)
+ e->setCodec(codec);
+ return e->editableInterface();
+}
+
+QStringList PerforcePlugin::environment() const
+{
+ QStringList newEnv = QProcess::systemEnvironment();
+ const QString name = "P4DIFF";
+ for (int i=0; i<newEnv.count(); ++i) {
+ if (newEnv.at(i).startsWith(name)) {
+ newEnv.removeAt(i);
+ return newEnv;
+ }
+ }
+ return newEnv;
+}
+
+void PerforcePlugin::slotDiff(const QStringList &files)
+{
+ p4Diff(files);
+}
+
+void PerforcePlugin::p4Diff(const QStringList &files, QString diffname)
+{
+ Core::IEditor *editor = 0;
+ bool displayInEditor = true;
+ Core::IEditor *existingEditor = 0;
+ QTextCodec *codec = files.empty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(m_coreInstance, files.front());
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << files << debugCodec(codec);
+
+ // diff of a single file? re-use an existing view if possible to support the common
+ // usage pattern of continuously changing and diffing a file
+ if (files.count() == 1) {
+ const QString fileName = files.at(0);
+ if (diffname.isEmpty()) {
+ const QFileInfo fi(fileName);
+ diffname = fi.fileName();
+ }
+
+ foreach (Core::IEditor *ed, m_coreInstance->editorManager()->openedEditors()) {
+ if (ed->property("originalFileName").toString() == fileName) {
+ existingEditor = ed;
+ displayInEditor = false;
+ break;
+ }
+ }
+ }
+
+ const PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("diff") << QLatin1String("-du"), files, false, codec);
+ if (result.error)
+ return;
+
+ if (displayInEditor)
+ editor = showOutputInEditor(tr("p4 diff %1").arg(diffname), result.stdOut, VCSBase::DiffOutput, codec);
+
+
+ if (files.count() == 1) {
+ if (displayInEditor && editor != 0) {
+ editor->setProperty("originalFileName", files.at(0));
+ } else if (!displayInEditor && existingEditor) {
+ if (existingEditor) {
+ existingEditor->createNew(result.stdOut);
+ m_coreInstance->editorManager()->setCurrentEditor(existingEditor);
+ }
+ }
+ }
+}
+
+void PerforcePlugin::describe(const QString & source, const QString &n)
+{
+ QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(m_coreInstance, source);
+ QStringList args;
+ args << QLatin1String("describe") << QLatin1String("-du") << n;
+ const PerforceResponse result = runP4Cmd(args, QStringList(), codec);
+ if (!result.error)
+ showOutputInEditor(tr("p4 describe %1").arg(n), result.stdOut, VCSBase::DiffOutput, codec);
+}
+
+void PerforcePlugin::submitCurrentLog()
+{
+ m_coreInstance->editorManager()->closeEditors(QList<Core::IEditor*>()
+ << m_coreInstance->editorManager()->currentEditor());
+}
+
+bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
+{
+ if (!m_changeTmpFile || !editor)
+ return true;
+ Core::IFile *fileIFace = editor->file();
+ if (!fileIFace)
+ return true;
+ QFileInfo editorFile(fileIFace->fileName());
+ QFileInfo changeFile(m_changeTmpFile->fileName());
+ if (editorFile.absoluteFilePath() == changeFile.absoluteFilePath()) {
+ const QMessageBox::StandardButton answer = QMessageBox::question(m_coreInstance->mainWindow(), tr("Closing p4 Editor"), tr("Do you want to submit this change list?"),
+ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
+ if (answer == QMessageBox::Cancel) {
+ return false;
+ }
+
+ m_coreInstance->fileManager()->blockFileChange(fileIFace);
+ fileIFace->save();
+ m_coreInstance->fileManager()->unblockFileChange(fileIFace);
+ if (answer == QMessageBox::Yes) {
+ QByteArray change = m_changeTmpFile->readAll();
+ m_changeTmpFile->close();
+ if (!checkP4Command()) {
+ showOutput(tr("No p4 executable specified!"));
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return false;
+ }
+ QProcess proc;
+ proc.setEnvironment(environment());
+
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("submit") << QLatin1String("-i"));
+ if (!proc.waitForStarted(3000)) {
+ showOutput(tr("Cannot execute p4 submit."));
+ QApplication::restoreOverrideCursor();
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return false;
+ }
+ proc.write(change);
+ proc.closeWriteChannel();
+
+ if (!proc.waitForFinished()) {
+ showOutput(tr("Cannot execute p4 submit."));
+ QApplication::restoreOverrideCursor();
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ return false;
+ }
+ QString output = QString::fromUtf8(proc.readAll());
+ showOutput(output);
+ if (output.contains("Out of date files must be resolved or reverted")) {
+ QMessageBox::warning(editor->widget(), "Pending change", "Could not submit the change, because your workspace was out of date. Created a pending submit instead.");
+ }
+ QApplication::restoreOverrideCursor();
+ }
+ m_changeTmpFile->close();
+ delete m_changeTmpFile;
+ m_changeTmpFile = 0;
+ }
+ return true;
+}
+
+void PerforcePlugin::openFiles(const QStringList &files)
+{
+ foreach (QString s, files) {
+ m_coreInstance->editorManager()->openEditor(clientFilePath(s));
+ }
+ m_coreInstance->editorManager()->ensureEditorManagerVisible();
+}
+
+QString PerforcePlugin::clientFilePath(const QString &serverFilePath)
+{
+ QString path;
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command())
+ return path;
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ QProcess proc;
+ proc.setEnvironment(environment());
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("fstat") << serverFilePath);
+
+ if (proc.waitForFinished(3000)) {
+ QString output = QString::fromUtf8(proc.readAllStandardOutput());
+ if (!output.isEmpty()) {
+ QRegExp r(QLatin1String("\\.\\.\\.\\sclientFile\\s(.+)\n"));
+ r.setMinimal(true);
+ if (r.indexIn(output) != -1)
+ path = r.cap(1).trimmed();
+ }
+ }
+ QApplication::restoreOverrideCursor();
+ return path;
+}
+
+QString PerforcePlugin::currentFileName()
+{
+ QString fileName = m_coreInstance->fileManager()->currentFile();
+
+ // TODO: Use FileManager::fixPath
+ const QFileInfo fileInfo(fileName);
+ if (fileInfo.exists())
+ fileName = fileInfo.absoluteFilePath();
+ fileName = QDir::toNativeSeparators(fileName);
+ return fileName;
+}
+
+QStringList PerforcePlugin::basicP4Args() const
+{
+ QStringList lst;
+ if (!m_settings.defaultEnv) {
+ lst << QLatin1String("-c") << m_settings.p4Client;
+ lst << QLatin1String("-p") << m_settings.p4Port;
+ lst << QLatin1String("-u") << m_settings.p4User;
+ }
+ return lst;
+}
+
+bool PerforcePlugin::checkP4Command() const
+{
+ if (m_settings.p4Command.isEmpty())
+ return false;
+ return true;
+}
+
+#ifdef USE_P4_API
+void PerforcePlugin::runP4APICmd(const QString &cmd, const QStringList &args)
+{
+ m_enableP4APIActions = false;
+ updateActions();
+
+ ClientApi client;
+ if (!m_settings.defaultEnv) {
+ client.SetClient(m_settings.p4Client.toLatin1().constData());
+ client.SetPort(m_settings.p4Port.toLatin1().constData());
+ client.SetUser(m_settings.p4User.toLatin1().constData());
+ }
+
+ Error err;
+ m_coreInstance->messageManager()->displayStatusBarMessage(tr("Connecting to p4 server..."));
+ client.SetProtocol("api", "56");
+ client.Init(&err);
+ if (err.Test()) {
+ StrBuf msg;
+ err.Fmt(&msg);
+ QMessageBox::critical(m_coreInstance->mainWindow(), tr("Perforce Plugin"), tr("Failed to connect to p4 server <b>%1</b>!").arg(msg.Text()));
+ client.Final(&err);
+ m_coreInstance->messageManager()->displayStatusBarMessage(tr("Connection to p4 server failed!"), 3000);
+ return;
+ }
+ m_coreInstance->messageManager()->displayStatusBarMessage(tr("Connection to p4 server established."), 3000);
+
+ // ????
+ //client.SetCwd("c:\\depot\\research\\qworkbench\\src");
+
+ int argc = args.count();
+ char **argv = (char**)malloc(argc*sizeof(char*));
+ int i = 0;
+ foreach (QString s, args)
+ argv[i++] = qstrdup(s.toLatin1().constData());
+
+ client.SetArgv( argc, argv );
+ try {
+ client.Run(cmd.toLatin1().constData(), m_workbenchClientUser);
+ } catch (...) {
+ QMessageBox::critical(m_coreInstance->mainWindow(), tr("Perforce Plugin"), tr("Failed to run command <b>%1</b>!").arg(cmd));
+ }
+ client.Final(&err);
+ i = 0;
+ while (i<argc)
+ free(argv[i++]);
+ free(argv);
+
+ m_enableP4APIActions = true;
+ updateActions();
+
+ Core::IEditor *edt = m_coreInstance->editorManager()->currentEditor();
+ if (edt && edt->widget())
+ edt->widget()->setFocus();
+}
+#endif
+
+QString PerforcePlugin::pendingChangesData()
+{
+ QString data;
+ Q_ASSERT(m_coreInstance);
+ if (!checkP4Command())
+ return data;
+
+ QString user;
+ QProcess proc;
+ proc.setEnvironment(environment());
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("info"));
+ if (proc.waitForFinished(3000)) {
+ QString output = QString::fromUtf8(proc.readAllStandardOutput());
+ if (!output.isEmpty()) {
+ QRegExp r(QLatin1String("User\\sname:\\s(\\S+)\\s*\n"));
+ r.setMinimal(true);
+ if (r.indexIn(output) != -1)
+ user = r.cap(1).trimmed();
+ }
+ }
+ if (user.isEmpty())
+ return data;
+ proc.start(m_settings.p4Command,
+ basicP4Args() << QLatin1String("changes") << QLatin1String("-s") << QLatin1String("pending") << QLatin1String("-u") << user);
+ if (proc.waitForFinished(3000))
+ data = QString::fromUtf8(proc.readAllStandardOutput());
+ return data;
+}
+
+void PerforcePlugin::showOutput(const QString &output, bool popup) const
+{
+ m_perforceOutputWindow->append(output, popup);
+}
+
+PerforcePlugin::~PerforcePlugin()
+{
+ if (m_settingsPage) {
+ removeObject(m_settingsPage);
+ delete m_settingsPage;
+ m_settingsPage = 0;
+ }
+
+#ifdef USE_P4_API
+ if (m_workbenchClientUser) {
+ delete m_workbenchClientUser;
+ m_workbenchClientUser = 0;
+ }
+#endif
+ if (m_perforceOutputWindow) {
+ removeObject(m_perforceOutputWindow);
+ delete m_perforceOutputWindow;
+ m_perforceOutputWindow = 0;
+ }
+ if (m_submitEditorFactory) {
+ removeObject(m_submitEditorFactory);
+ delete m_submitEditorFactory;
+ m_submitEditorFactory = 0;
+ }
+ if (m_versionControl) {
+ removeObject(m_versionControl);
+ delete m_versionControl;
+ m_versionControl = 0;
+ }
+
+ if (!m_editorFactories.empty()) {
+ foreach(Core::IEditorFactory* pf, m_editorFactories)
+ removeObject(pf);
+ qDeleteAll(m_editorFactories);
+ m_editorFactories.clear();
+ }
+
+ if (m_coreListener) {
+ removeObject(m_coreListener);
+ delete m_coreListener;
+ m_coreListener = 0;
+ }
+}
+
+PerforceSettings PerforcePlugin::settings() const
+{
+ return m_settings;
+}
+
+void PerforcePlugin::setSettings(const PerforceSettings &s)
+{
+ if (s != m_settings) {
+ m_settings = s;
+ if (QSettings *settings = m_coreInstance->settings())
+ m_settings.toSettings(settings);
+ }
+}
+
+// Map a perforce name "//xx" to its real name in the file system
+QString PerforcePlugin::fileNameFromPerforceName(const QString& perforceName,
+ QString *errorMessage) const
+{
+ // All happy, already mapped
+ if (!perforceName.startsWith(QLatin1String("//")))
+ return perforceName;
+ // "where" remaps the file to client file tree
+ QProcess proc;
+ QStringList args(basicP4Args());
+ args << QLatin1String("where") << perforceName;
+ proc.start(m_settings.p4Command, args);
+ if (!proc.waitForFinished()) {
+ *errorMessage = tr("Timeout waiting for \"where\" (%1).").arg(perforceName);
+ return QString();
+ }
+
+ QString output = QString::fromLocal8Bit(proc.readAllStandardOutput());
+ if (output.endsWith(QLatin1Char('\r')))
+ output.chop(1);
+ if (output.endsWith(QLatin1Char('\n')))
+ output.chop(1);
+
+ if (output.isEmpty()) {
+ *errorMessage = tr("Error running \"where\" on %1: The file is not mapped").arg(perforceName);
+ return QString();
+ }
+ const QString rc = output.mid(output.lastIndexOf(QLatin1Char(' ')) + 1);
+ if (Perforce::Constants::debug)
+ qDebug() << "fileNameFromPerforceName" << perforceName << rc;
+ return rc;
+}
+
+Q_EXPORT_PLUGIN(PerforcePlugin)
+
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
new file mode 100644
index 0000000000..d03d24515f
--- /dev/null
+++ b/src/plugins/perforce/perforceplugin.h
@@ -0,0 +1,250 @@
+/***************************************************************************
+**
+** 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 PERFORCEPLUGIN_H
+#define PERFORCEPLUGIN_H
+
+#include "perforcesettings.h"
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/icorelistener.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+#include <extensionsystem/iplugin.h>
+
+#ifdef USE_P4_API
+#include "workbenchclientuser.h"
+#else
+
+#endif
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QAction;
+class QTemporaryFile;
+class QTextCodec;
+QT_END_NAMESPACE
+
+namespace Core {
+ class IEditorFactory;
+}
+
+namespace Perforce {
+namespace Internal {
+class PerforceOutputWindow;
+class SettingsPage;
+class PerforceVersionControl;
+class PerforcePlugin;
+
+// Just a proxy for PerforcePlugin
+class CoreListener : public Core::ICoreListener
+{
+ Q_OBJECT
+public:
+ CoreListener(PerforcePlugin *plugin) : m_plugin(plugin) { }
+ bool editorAboutToClose(Core::IEditor *editor);
+ bool coreAboutToClose() { return true; }
+private:
+ PerforcePlugin *m_plugin;
+};
+
+struct PerforceResponse
+{
+ bool error;
+ QString command;
+ QString stdOut;
+ QString stdErr;
+ QString message;
+};
+
+class PerforcePlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ PerforcePlugin();
+ ~PerforcePlugin();
+
+ QStringList basicP4Args() const;
+ inline SettingsPage *settingsPage() const { return m_settingsPage; }
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+
+ bool managesDirectory(const QString &directory) const;
+ QString findTopLevelForDirectory(const QString &directory) const;
+ bool vcsOpen(const QString &fileName);
+ bool vcsAdd(const QString &fileName);
+ bool vcsDelete(const QString &filename);
+ // Displays the message for the submit mesage
+ bool editorAboutToClose(Core::IEditor *editor);
+
+ void p4Diff(const QStringList &files, QString diffname = QString());
+
+ Core::IEditor *openPerforceSubmitEditor(const QString &fileName, const QStringList &depotFileNames);
+
+ static Core::ICore *coreInstance() {Q_ASSERT(m_coreInstance); return m_coreInstance;}
+ static PerforcePlugin *perforcePluginInstance() {Q_ASSERT(m_perforcePluginInstance); return m_perforcePluginInstance;}
+
+ PerforceSettings settings() const;
+ void setSettings(const PerforceSettings &s);
+
+ // Map a perforce name "//xx" to its real name in the file system
+ QString fileNameFromPerforceName(const QString& perforceName, QString *errorMessage) const;
+
+public slots:
+ void describe(const QString &source, const QString &n);
+
+private slots:;
+ void openCurrentFile();
+ void addCurrentFile();
+ void deleteCurrentFile();
+ void revertCurrentFile();
+ void printOpenedFileList();
+ void diffCurrentFile();
+ void diffCurrentProject();
+ void diffAllOpened();
+ void submit();
+ void describeChange();
+ void annotateCurrentFile();
+ void annotate();
+ void filelogCurrentFile();
+ void filelog();
+
+ void updateActions();
+ void submitCurrentLog();
+ void printPendingChanges();
+ void slotDiff(const QStringList &files);
+
+#ifdef USE_P4_API
+ void resolve();
+#endif
+
+private:
+ QStringList environment() const;
+
+ Core::IEditor *showOutputInEditor(const QString& title, const QString output,
+ int editorType,
+ QTextCodec *codec = 0);
+ // args are passed as command line arguments
+ // extra args via a tempfile and the option -x "temp-filename"
+ PerforceResponse runP4Cmd(const QStringList &args,
+ const QStringList &extraArgs = QStringList(),
+ bool showStdOutInOutputWindow = false,
+ bool showStdErrInOutputWindow = true,
+ QTextCodec *outputCodec = 0) const;
+
+ void openFiles(const QStringList &files);
+
+ QString clientFilePath(const QString &serverFilePath);
+ QString currentFileName();
+ bool checkP4Command() const;
+ void showOutput(const QString &output, bool popup = false) const;
+ void annotate(const QString &fileName);
+ void filelog(const QString &fileName);
+
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ PerforceOutputWindow *m_perforceOutputWindow;
+ SettingsPage *m_settingsPage;
+ QList<Core::IEditorFactory*> m_editorFactories;
+
+ QAction *m_editAction;
+ QAction *m_addAction;
+ QAction *m_deleteAction;
+ QAction *m_openedAction;
+ QAction *m_revertAction;
+ QAction *m_diffCurrentAction;
+ QAction *m_diffProjectAction;
+ QAction *m_diffAllAction;
+ QAction *m_resolveAction;
+ QAction *m_submitAction;
+ QAction *m_pendingAction;
+ QAction *m_describeAction;
+ QAction *m_annotateCurrentAction;
+ QAction *m_annotateAction;
+ QAction *m_filelogCurrentAction;
+ QAction *m_filelogAction;
+ QAction *m_submitCurrentLogAction;
+ QAction *m_diffSelectedFiles;
+
+ QAction *m_undoAction;
+ QAction *m_redoAction;
+
+ QTemporaryFile *m_changeTmpFile;
+
+ static const char * const PERFORCE_MENU;
+ static const char * const EDIT;
+ static const char * const ADD;
+ static const char * const DELETE_FILE;
+ static const char * const OPENED;
+ static const char * const REVERT;
+ static const char * const DIFF_ALL;
+ static const char * const DIFF_PROJECT;
+ static const char * const DIFF_CURRENT;
+ static const char * const RESOLVE;
+ static const char * const SUBMIT;
+ static const char * const PENDING_CHANGES;
+ static const char * const DESCRIBE;
+ static const char * const ANNOTATE_CURRENT;
+ static const char * const ANNOTATE;
+ static const char * const FILELOG_CURRENT;
+ static const char * const FILELOG;
+ static const char * const SEPARATOR1;
+ static const char * const SEPARATOR2;
+ static const char * const SEPARATOR3;
+
+ static Core::ICore *m_coreInstance;
+ static PerforcePlugin *m_perforcePluginInstance;
+ QString pendingChangesData();
+
+#ifdef USE_P4_API
+ void runP4APICmd(const QString &cmd, const QStringList &args = QStringList());
+ WorkbenchClientUser *m_workbenchClientUser;
+ bool m_enableP4APIActions;
+#endif
+
+ CoreListener *m_coreListener;
+ Core::IEditorFactory *m_submitEditorFactory;
+ PerforceVersionControl *m_versionControl;
+ PerforceSettings m_settings;
+
+ friend class PerforceOutputWindow;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif // PERFORCEPLUGIN_H
diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp
new file mode 100644
index 0000000000..d01df8a545
--- /dev/null
+++ b/src/plugins/perforce/perforcesettings.cpp
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** 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 "perforcesettings.h"
+
+#include <QtCore/QSettings>
+
+static const char *groupC = "Perforce";
+static const char *commandKeyC = "Command";
+static const char *defaultKeyC = "Default";
+static const char *portKeyC = "Port";
+static const char *clientKeyC = "Client";
+static const char *userKeyC = "User";
+
+static QString defaultCommand()
+{
+ QString rc;
+ rc = QLatin1String("p4");
+#if defined(Q_OS_WIN32)
+ rc.append(QLatin1String(".exe"));
+#endif
+ return rc;
+}
+
+namespace Perforce {
+namespace Internal {
+
+PerforceSettings::PerforceSettings() :
+ p4Command(defaultCommand()),
+ defaultEnv(true)
+{
+}
+
+void PerforceSettings::fromSettings(QSettings *settings)
+{
+ settings->beginGroup(QLatin1String(groupC));
+ p4Command = settings->value(QLatin1String(commandKeyC), defaultCommand()).toString();
+ defaultEnv = settings->value(QLatin1String(defaultKeyC), true).toBool();
+ p4Port = settings->value(QLatin1String(portKeyC), QString()).toString();
+ p4Client = settings->value(QLatin1String(clientKeyC), QString()).toString();
+ p4User = settings->value(QLatin1String(userKeyC), QString()).toString();
+ settings->endGroup();
+
+}
+
+void PerforceSettings::toSettings(QSettings *settings) const
+{
+ settings->beginGroup(QLatin1String(groupC));
+ settings->setValue(commandKeyC, p4Command);
+ settings->setValue(defaultKeyC, defaultEnv);
+ settings->setValue(portKeyC, p4Port);
+ settings->setValue(clientKeyC, p4Client);
+ settings->setValue(userKeyC, p4User);
+ settings->endGroup();
+}
+
+bool PerforceSettings::equals(const PerforceSettings &s) const
+{
+ return p4Command == s.p4Command && p4Port == s.p4Port
+ && p4Client == s.p4Client && p4User == s.p4User
+ && defaultEnv == s.defaultEnv;
+}
+
+}
+}
+
diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h
new file mode 100644
index 0000000000..aa2782e47b
--- /dev/null
+++ b/src/plugins/perforce/perforcesettings.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** 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 PERFOCESETTINGS_H
+#define PERFOCESETTINGS_H
+
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace Perforce {
+namespace Internal {
+
+struct PerforceSettings {
+ PerforceSettings();
+ void fromSettings(QSettings *);
+ void toSettings(QSettings *) const;
+ bool equals(const PerforceSettings &s) const;
+
+ QString p4Command;
+ QString p4Port;
+ QString p4Client;
+ QString p4User;
+ bool defaultEnv;
+};
+
+inline bool operator==(const PerforceSettings &p1, const PerforceSettings &p2)
+ { return p1.equals(p2); }
+inline bool operator!=(const PerforceSettings &p1, const PerforceSettings &p2)
+ { return !p1.equals(p2); }
+}
+}
+
+#endif
diff --git a/src/plugins/perforce/perforcesubmiteditor.cpp b/src/plugins/perforce/perforcesubmiteditor.cpp
new file mode 100644
index 0000000000..3e5188e5d8
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditor.cpp
@@ -0,0 +1,194 @@
+/***************************************************************************
+**
+** 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 "perforcesubmiteditor.h"
+#include "perforcesubmiteditorwidget.h"
+#include "perforceplugin.h"
+#include "perforceconstants.h"
+
+#include <QtCore/QDebug>
+
+namespace Perforce {
+namespace Internal {
+
+PerforceSubmitEditor::PerforceSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent) :
+ VCSBaseSubmitEditor(parameters, new PerforceSubmitEditorWidget(parent))
+{
+ setDisplayName(tr("Perforce Submit"));
+}
+
+PerforceSubmitEditorWidget *PerforceSubmitEditor::submitEditorWidget()
+{
+ return static_cast<PerforceSubmitEditorWidget *>(widget());
+}
+
+QStringList PerforceSubmitEditor::vcsFileListToFileList(const QStringList &rawList) const
+{
+ QStringList rc;
+ foreach (const QString &rf, rawList)
+ rc.push_back(fileFromChangeLine(rf));
+ return rc;
+}
+
+QString PerforceSubmitEditor::fileContents() const
+{
+ const_cast<PerforceSubmitEditor*>(this)->updateEntries();
+ QString text;
+ QTextStream out(&text);
+ QMapIterator<QString, QString> it(m_entries);
+ while (it.hasNext()) {
+ it.next();
+ out << it.key() << ":" << it.value();
+ }
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << text;
+ return text;
+}
+
+bool PerforceSubmitEditor::setFileContents(const QString &contents)
+{
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << contents;
+ if (!parseText(contents))
+ return false;
+ updateFields();
+ return true;
+}
+
+bool PerforceSubmitEditor::parseText(QString text)
+{
+ const QRegExp formField(QLatin1String("^\\S+:"));
+ const QString newLine = QString(QLatin1Char('\n'));
+
+ int match;
+ int matchLen;
+ QTextStream stream(&text, QIODevice::ReadOnly);
+ QString line;
+ QString key;
+ QString value;
+ line = stream.readLine();
+ while (!stream.atEnd()) {
+ match = formField.indexIn(line);
+ if (match == 0) {
+ matchLen = formField.matchedLength();
+ key = line.left(matchLen-1);
+ value = line.mid(matchLen) + newLine;
+ while (!stream.atEnd()) {
+ line = stream.readLine();
+ if (formField.indexIn(line) != -1)
+ break;
+ value += line + newLine;
+ }
+ m_entries.insert(key, value);
+ } else {
+ line = stream.readLine();
+ }
+ }
+ return true;
+}
+
+void PerforceSubmitEditor::restrictToProjectFiles(const QStringList &knownProjectFiles)
+{
+ QStringList allFiles = submitEditorWidget()->fileList();
+ const int oldSize = allFiles.size();
+ for (int i = oldSize - 1; i >= 0; i--)
+ if (!knownProjectFiles.contains(fileFromChangeLine(allFiles.at(i))))
+ allFiles.removeAt(i);
+ if (allFiles.size() != oldSize)
+ submitEditorWidget()->setFileList(allFiles);
+ if (Perforce::Constants::debug)
+ qDebug() << Q_FUNC_INFO << oldSize << "->" << allFiles.size();
+}
+
+QString PerforceSubmitEditor::fileFromChangeLine(const QString &line)
+{
+ QString rc = line;
+ // " foo.cpp#add"
+ const int index = rc.lastIndexOf(QLatin1Char('#'));
+ if (index != -1)
+ rc.truncate(index);
+ return rc.trimmed();
+}
+
+void PerforceSubmitEditor::updateFields()
+{
+ PerforceSubmitEditorWidget *widget = submitEditorWidget();
+ widget->setData(m_entries.value(QLatin1String("Change")).trimmed(),
+ m_entries.value(QLatin1String("Client")).trimmed(),
+ m_entries.value(QLatin1String("User")).trimmed());
+
+ const QString newLine = QString(QLatin1Char('\n'));
+ QStringList lines = m_entries.value(QLatin1String("Description")).split(newLine);
+ lines.removeFirst(); // that is the line break after 'Description:'
+ lines.removeLast(); // that is the empty line at the end
+
+ const QRegExp leadingTabPattern = QRegExp(QLatin1String("^\\t"));
+ Q_ASSERT(leadingTabPattern.isValid());
+
+ lines.replaceInStrings(leadingTabPattern, QString());
+ widget->setDescriptionText(lines.join(newLine));
+
+ lines = m_entries.value(QLatin1String("Files")).split(newLine);
+ lines.replaceInStrings(leadingTabPattern, QString());
+ QStringList fileList;
+ foreach (const QString &line, lines)
+ if (!line.isEmpty())
+ fileList.push_back(line);
+ widget->setFileList(fileList);
+}
+
+void PerforceSubmitEditor::updateEntries()
+{
+ const QString newLine = QString(QLatin1Char('\n'));
+ const QString tab = QString(QLatin1Char('\t'));
+
+ QStringList lines = submitEditorWidget()->trimmedDescriptionText().split(newLine);
+ while (lines.last().isEmpty())
+ lines.removeLast();
+ // Description
+ lines.replaceInStrings(QRegExp(QLatin1String("^")), tab);
+ m_entries.insert(QLatin1String("Description"), newLine + lines.join(newLine) + QLatin1String("\n\n"));
+ QString files = newLine;
+ // Files
+ const QStringList fileList = submitEditorWidget()->fileList();
+ const int count = fileList.size();
+ for (int i = 0; i < count; i++) {
+ files += tab;
+ files += fileList.at(i);
+ files += newLine;
+ }
+ files += newLine;
+ m_entries.insert(QLatin1String("Files"), files);
+}
+
+}
+}
diff --git a/src/plugins/perforce/perforcesubmiteditor.h b/src/plugins/perforce/perforcesubmiteditor.h
new file mode 100644
index 0000000000..af0d3d0e2c
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditor.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** 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 PERFORCESUBMITEDITOR_H
+#define PERFORCESUBMITEDITOR_H
+
+#include <vcsbase/vcsbasesubmiteditor.h>
+
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+
+namespace Perforce {
+namespace Internal {
+
+class PerforceSubmitEditorWidget;
+class PerforcePlugin;
+
+/* PerforceSubmitEditor: In p4, the file list is contained in the
+ * submit message file (change list). On setting the file contents,
+ * it is split apart in message and file list and re-assembled
+ * when retrieving the file list.
+ * As a p4 submit starts with all opened files, there is API to restrict
+ * the file list to current project files in question
+ * (restrictToProjectFiles()). */
+class PerforceSubmitEditor : public VCSBase::VCSBaseSubmitEditor
+{
+ Q_OBJECT
+
+public:
+ explicit PerforceSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent);
+
+ /* The p4 submit starts with all opened files. Restrict
+ * it to the current project files in question. */
+ void restrictToProjectFiles(const QStringList &files);
+
+ static QString fileFromChangeLine(const QString &line);
+
+protected:
+ virtual QStringList vcsFileListToFileList(const QStringList &) const;
+ virtual QString fileContents() const;
+ virtual bool setFileContents(const QString &contents);
+
+private:
+ inline PerforceSubmitEditorWidget *submitEditorWidget();
+ bool parseText(QString text);
+ void updateFields();
+ void updateEntries();
+
+ QMap<QString, QString> m_entries;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // PERFORCESUBMITEDITOR_H
diff --git a/src/plugins/perforce/perforcesubmiteditorwidget.cpp b/src/plugins/perforce/perforcesubmiteditorwidget.cpp
new file mode 100644
index 0000000000..1a4c8251b1
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditorwidget.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+**
+** 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 "perforcesubmiteditorwidget.h"
+
+namespace Perforce {
+namespace Internal {
+
+PerforceSubmitEditorWidget::PerforceSubmitEditorWidget(QWidget *parent) :
+ Core::Utils::SubmitEditorWidget(parent),
+ m_submitPanel(new QGroupBox)
+{
+ m_submitPanelUi.setupUi(m_submitPanel);
+ insertTopWidget(m_submitPanel);
+}
+
+void PerforceSubmitEditorWidget::setData(const QString &change,
+ const QString &client,
+ const QString &userName)
+{
+ m_submitPanelUi.changeNumber->setText(change);
+ m_submitPanelUi.clientName->setText(client);
+ m_submitPanelUi.userName->setText(userName);
+}
+}
+}
diff --git a/src/plugins/perforce/perforcesubmiteditorwidget.h b/src/plugins/perforce/perforcesubmiteditorwidget.h
new file mode 100644
index 0000000000..fe79f65da2
--- /dev/null
+++ b/src/plugins/perforce/perforcesubmiteditorwidget.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** 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 PERFORCESUBMITEDITORWIDGET_H
+#define PERFORCESUBMITEDITORWIDGET_H
+
+#include "ui_submitpanel.h"
+#include <utils/submiteditorwidget.h>
+
+namespace Perforce {
+namespace Internal {
+
+/* Submit editor widget with additional information pane
+ * at the top. */
+class PerforceSubmitEditorWidget : public Core::Utils::SubmitEditorWidget
+{
+
+public:
+ explicit PerforceSubmitEditorWidget(QWidget *parent = 0);
+
+ void setData(const QString &change, const QString &client, const QString &userName);
+
+private:
+ QGroupBox *m_submitPanel;
+ Ui::SubmitPanel m_submitPanelUi;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // PERFORCESUBMITEDITORWIDGET_H
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
new file mode 100644
index 0000000000..5cbc8e4880
--- /dev/null
+++ b/src/plugins/perforce/perforceversioncontrol.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 "perforceversioncontrol.h"
+#include "perforceplugin.h"
+
+namespace Perforce {
+namespace Internal {
+
+PerforceVersionControl::PerforceVersionControl(PerforcePlugin *plugin) :
+ m_plugin(plugin)
+{
+}
+
+bool PerforceVersionControl::vcsOpen(const QString &fileName)
+{
+ return m_plugin->vcsOpen(fileName);
+}
+
+bool PerforceVersionControl::vcsAdd(const QString &fileName)
+{
+ return m_plugin->vcsAdd(fileName);
+}
+
+bool PerforceVersionControl::vcsDelete(const QString &fileName)
+{
+ return m_plugin->vcsDelete(fileName);
+}
+
+bool PerforceVersionControl::managesDirectory(const QString &directory) const
+{
+ return m_plugin->managesDirectory(directory);
+}
+
+QString PerforceVersionControl::findTopLevelForDirectory(const QString &directory) const
+{
+ return m_plugin->findTopLevelForDirectory(directory);
+}
+}
+}
diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h
new file mode 100644
index 0000000000..5f10935749
--- /dev/null
+++ b/src/plugins/perforce/perforceversioncontrol.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** 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 PERFORCEVERSIONCONTROL_H
+#define PERFORCEVERSIONCONTROL_H
+
+#include <coreplugin/iversioncontrol.h>
+
+namespace Perforce {
+namespace Internal {
+class PerforcePlugin;
+
+// Just a proxy for PerforcePlugin
+class PerforceVersionControl : public Core::IVersionControl
+{
+ Q_OBJECT
+public:
+ explicit PerforceVersionControl(PerforcePlugin *plugin);
+ bool managesDirectory(const QString &directory) const;
+ virtual QString findTopLevelForDirectory(const QString &directory) const;
+ virtual bool vcsOpen(const QString &fileName);
+ virtual bool vcsAdd(const QString &fileName);
+ virtual bool vcsDelete(const QString &filename);
+
+private:
+ PerforcePlugin *m_plugin;
+};
+
+}
+}
+#endif
diff --git a/src/plugins/perforce/promptdialog.ui b/src/plugins/perforce/promptdialog.ui
new file mode 100644
index 0000000000..aecf8d3337
--- /dev/null
+++ b/src/plugins/perforce/promptdialog.ui
@@ -0,0 +1,128 @@
+<ui version="4.0" >
+ <class>Perforce::Internal::PromptDialog</class>
+ <widget class="QDialog" name="Perforce::Internal::PromptDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>308</width>
+ <height>113</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Perforce Prompt</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="msgLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::AutoText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton" >
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>okButton</sender>
+ <signal>clicked()</signal>
+ <receiver>Perforce::Internal::PromptDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>278</x>
+ <y>253</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>96</x>
+ <y>254</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/settingspage.cpp b/src/plugins/perforce/settingspage.cpp
new file mode 100644
index 0000000000..7413e9526c
--- /dev/null
+++ b/src/plugins/perforce/settingspage.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** 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 "perforcesettings.h"
+#include "perforceplugin.h"
+
+#include <QtGui/QLineEdit>
+#include <QtGui/QFileDialog>
+
+using namespace Perforce::Internal;
+
+SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.browseButton, SIGNAL(clicked()), this, SLOT(browseForCommand()));
+}
+
+PerforceSettings SettingsPageWidget::settings() const
+{
+ PerforceSettings rc;
+ rc.p4Command = m_ui.p4CmdLineEdit->text();
+ rc.defaultEnv = m_ui.defaultCheckBox->isChecked();
+ rc.p4Port = m_ui.portLineEdit->text();
+ rc.p4Client = m_ui.clientLineEdit->text();
+ rc.p4User = m_ui.userLineEdit->text();
+ return rc;
+}
+
+void SettingsPageWidget::setSettings(const PerforceSettings &s)
+{
+ m_ui.p4CmdLineEdit->setText(s.p4Command);
+ m_ui.defaultCheckBox->setChecked(s.defaultEnv);
+ m_ui.portLineEdit->setText(s.p4Port);
+ m_ui.clientLineEdit->setText(s.p4Client);
+ m_ui.userLineEdit->setText(s.p4User);
+}
+
+void SettingsPageWidget::browseForCommand()
+{
+ const QString cmd = QFileDialog::getOpenFileName(window(), tr("Perforce Command"));
+ if (!cmd.isEmpty())
+ m_ui.p4CmdLineEdit->setText(cmd);
+}
+
+
+SettingsPage::SettingsPage()
+{
+}
+
+QString SettingsPage::name() const
+{
+ return tr("General");
+}
+
+QString SettingsPage::category() const
+{
+ return QLatin1String("Perforce");
+}
+
+QString SettingsPage::trCategory() const
+{
+ return tr("Perforce");
+}
+
+QWidget *SettingsPage::createPage(QWidget *parent)
+{
+ if (!m_widget)
+ m_widget = new SettingsPageWidget(parent);
+ m_widget->setSettings(PerforcePlugin::perforcePluginInstance()->settings());
+ return m_widget;
+}
+
+void SettingsPage::finished(bool accepted)
+{
+ if (!accepted || !m_widget)
+ return;
+
+ PerforcePlugin::perforcePluginInstance()->setSettings(m_widget->settings());
+}
diff --git a/src/plugins/perforce/settingspage.h b/src/plugins/perforce/settingspage.h
new file mode 100644
index 0000000000..bbbbce923c
--- /dev/null
+++ b/src/plugins/perforce/settingspage.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** 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 <QtCore/QPointer>
+#include <QtGui/QWidget>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_settingspage.h"
+
+namespace Perforce {
+namespace Internal {
+
+struct PerforceSettings;
+
+class SettingsPageWidget : public QWidget {
+ Q_OBJECT
+public:
+ explicit SettingsPageWidget(QWidget *parent);
+
+ PerforceSettings settings() const;
+ void setSettings(const PerforceSettings &);
+
+private slots:;
+ void browseForCommand();
+
+private:
+ Ui::SettingsPage m_ui;
+};
+
+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);
+
+private:
+ QPointer<SettingsPageWidget> m_widget;
+};
+
+} // namespace Internal
+} // namespace Perforce
+
+#endif // SETTINGSPAGE_H
diff --git a/src/plugins/perforce/settingspage.ui b/src/plugins/perforce/settingspage.ui
new file mode 100644
index 0000000000..1379b7b666
--- /dev/null
+++ b/src/plugins/perforce/settingspage.ui
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Perforce::Internal::SettingsPage</class>
+ <widget class="QWidget" name="Perforce::Internal::SettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>276</width>
+ <height>198</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>P4 Command:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="p4CmdLineEdit"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="browseButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="defaultCheckBox">
+ <property name="text">
+ <string>Use default P4 environment variables</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">
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="clientLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>P4 Client:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>P4 User:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>P4 Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="userLineEdit"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="portLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </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>portLineEdit</tabstop>
+ <tabstop>clientLineEdit</tabstop>
+ <tabstop>userLineEdit</tabstop>
+ <tabstop>p4CmdLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>defaultCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>groupBox</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>134</x>
+ <y>51</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>139</x>
+ <y>65</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/perforce/submitpanel.ui b/src/plugins/perforce/submitpanel.ui
new file mode 100644
index 0000000000..5ce1f259f3
--- /dev/null
+++ b/src/plugins/perforce/submitpanel.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Perforce::Internal::SubmitPanel</class>
+ <widget class="QGroupBox" name="Perforce::Internal::SubmitPanel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>-2</y>
+ <width>402</width>
+ <height>134</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Submit</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="horizontalSpacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Change:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="changeNumber">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Client:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="clientName">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>User:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="userName">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/perforce/workbenchclientuser.cpp b/src/plugins/perforce/workbenchclientuser.cpp
new file mode 100644
index 0000000000..084a31e5a0
--- /dev/null
+++ b/src/plugins/perforce/workbenchclientuser.cpp
@@ -0,0 +1,285 @@
+/***************************************************************************
+**
+** 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 "workbenchclientuser.h"
+#include "perforceoutputwindow.h"
+#include "perforceplugin.h"
+
+#include <coreplugin/filemanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QTemporaryFile>
+#include <QtGui/QMessageBox>
+#include <QtGui/QRadioButton>
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+
+using namespace Perforce::Internal;
+
+PromptDialog::PromptDialog(const QString &choice, const QString &text,
+ QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ m_ui.msgLabel->setText(text);
+
+ const QChar closingParenthesis = QLatin1Char(')');
+ const QStringList opts = choice.split(QString(closingParenthesis));
+ int row = 0;
+ int column = 0;
+ QString opt;
+ QRadioButton *rb = 0;
+ for (int i=0; i<opts.count(); ++i) {
+ opt = opts.at(i).trimmed();
+ if (opt.isEmpty() || opt.startsWith(QLatin1String("Help")))
+ continue;
+ if (i == opts.count()-1)
+ opt = QLatin1String("Default(") + opt.left(opt.length()-1);
+ opt.append(QLatin1String(")"));
+ rb = new QRadioButton(opt, this);
+ rb->setChecked(true);
+ if (column>0 && column%3==0)
+ ++row;
+ m_ui.gridLayout->addWidget(rb, row, column%3, 1, 1);
+ ++column;
+
+ const int j = opt.lastIndexOf(QLatin1Char('('));
+ opt = opt.mid(j+1, opt.lastIndexOf(closingParenthesis)-j-1);
+ m_optionsMap.insert(rb, opt);
+ }
+}
+
+QString PromptDialog::input() const
+{
+ QMapIterator<QRadioButton*, QString> it(m_optionsMap);
+ while (it.hasNext()) {
+ it.next();
+ if (it.key()->isChecked())
+ return it.value();
+ }
+ return QString();
+}
+
+WorkbenchClientUser::WorkbenchClientUser(PerforceOutputWindow *out, PerforcePlugin *plugin) :
+ QObject(out),
+ m_plugin(plugin),
+ m_coreIFace(PerforcePlugin::coreInstance()),
+ m_currentEditorIface(0),
+ m_userCancelled(false),
+ m_mode(Submit),
+ m_perforceOutputWindow(out),
+ m_skipNextMsg(false),
+ m_eventLoop(new QEventLoop(this))
+{
+ connect(m_coreIFace, SIGNAL(coreAboutToClose()),
+ this, SLOT(cancelP4Command()));
+}
+
+WorkbenchClientUser::~WorkbenchClientUser()
+{
+}
+
+void WorkbenchClientUser::setMode(WorkbenchClientUser::Mode mode)
+{
+ m_mode = mode;
+}
+
+void WorkbenchClientUser::cancelP4Command()
+{
+ m_userCancelled = true;
+ m_eventLoop->quit();
+}
+
+void WorkbenchClientUser::Message(Error* err)
+{
+ StrBuf buf;
+ err->Fmt(&buf);
+ QString s = buf.Text();
+ m_perforceOutputWindow->append(s);
+ if (!m_skipNextMsg) {
+ if (err->GetSeverity() == E_FAILED || err->GetSeverity() == E_FATAL) {
+ if (!s.startsWith("Client side operation(s) failed."))
+ m_errMsg.append(s);
+ } else {
+ m_msg.append(s);
+ }
+ }
+ m_skipNextMsg = false;
+}
+
+void WorkbenchClientUser::displayErrorMsg(const QString &msg)
+{
+ if (msg.isEmpty())
+ return;
+
+ const QString title = tr("Perforce Error");
+ switch (m_mode) {
+ case Submit: {
+ QMessageBox msgBox(QMessageBox::Critical, title, msg, QMessageBox::Ok, m_coreIFace->mainWindow());
+ msgBox.setDetailedText(m_msg);
+ msgBox.exec();
+ }
+ break;
+ default:
+ QMessageBox::critical(m_coreIFace->mainWindow(), title, msg);
+ break;
+ }
+ m_errMsg.clear();
+}
+
+void WorkbenchClientUser::OutputError(const char *errBuf)
+{
+ QString s(errBuf);
+ s = s.trimmed();
+ m_perforceOutputWindow->append(s);
+ displayErrorMsg(s);
+}
+
+void WorkbenchClientUser::Finished()
+{
+ m_errMsg = m_errMsg.trimmed();
+ displayErrorMsg(m_errMsg);
+ m_msg.clear();
+ m_currentEditorIface = 0;
+ m_userCancelled = false;
+ m_skipNextMsg = false;
+}
+
+bool WorkbenchClientUser::editorAboutToClose(Core::IEditor *editor)
+{
+ if (editor && editor == m_currentEditorIface) {
+ if (m_mode == WorkbenchClientUser::Submit) {
+ const QMessageBox::StandardButton answer =
+ QMessageBox::question(m_coreIFace->mainWindow(),
+ tr("Closing p4 Editor"),
+ tr("Do you want to submit this change list?"),
+ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
+ if (answer == QMessageBox::Cancel)
+ return false;
+ if (answer == QMessageBox::No)
+ m_userCancelled = true;
+ m_coreIFace->fileManager()->blockFileChange(m_currentEditorIface->file());
+ m_currentEditorIface->file()->save();
+ m_coreIFace->fileManager()->unblockFileChange(m_currentEditorIface->file());
+ }
+ m_eventLoop->quit();
+ m_currentEditorIface = 0;
+ }
+ return true;
+}
+
+void WorkbenchClientUser::Diff(FileSys *f1, FileSys *f2, int, char *, Error *err)
+{
+ if (!f1->IsTextual() || !f2->IsTextual())
+ return;
+
+ FileSys *file1 = File(FST_BINARY);
+ file1->Set(f1->Name());
+
+ FileSys *file2 = File(FST_BINARY);
+ file2->Set(f2->Name());
+
+ QTemporaryFile tmp;
+ tmp.open();
+ QString fileName = tmp.fileName();
+
+ {
+ ::Diff d;
+ d.SetInput(file1, file2, DiffFlags(), err);
+ if (!err->Test())
+ d.SetOutput(fileName.toLatin1().constData(), err);
+ if (!err->Test())
+ d.DiffUnified();
+ d.CloseOutput(err);
+ }
+ delete file1;
+ delete file2;
+
+ QString title = QString("diff %1").arg(f1->Name());
+ m_currentEditorIface = m_coreIFace->editorManager()->newFile("Perforce Editor", &title, tmp.readAll());
+ if (!m_currentEditorIface) {
+ err->Set(E_FAILED, "p4 data could not be opened!");
+ return;
+ }
+ m_userCancelled = false;
+ m_eventLoop->exec();
+ if (m_userCancelled)
+ err->Set(E_FAILED, "");
+}
+
+void WorkbenchClientUser::Edit(FileSys *f, Error *err)
+{
+ QString fileName(f->Name());
+ if (m_mode == Submit) {
+ m_currentEditorIface = m_plugin->openPerforceSubmitEditor(fileName, QStringList());
+ }
+ else {
+ m_currentEditorIface = m_coreIFace->editorManager()->openEditor(fileName);
+ m_coreIFace->editorManager()->ensureEditorManagerVisible();
+ }
+ if (!m_currentEditorIface) {
+ err->Set(E_FAILED, "p4 data could not be opened!");
+ return;
+ }
+ m_userCancelled = false;
+ m_eventLoop->exec();
+ if (m_userCancelled)
+ err->Set(E_FAILED, "");
+}
+
+void WorkbenchClientUser::Prompt(const StrPtr &msg, StrBuf &answer, int , Error *err)
+{
+ if (m_userCancelled) {
+ err->Set(E_FATAL, "");
+ return;
+ }
+ PromptDialog dia(msg.Text(), m_msg, qobject_cast<QWidget*>(m_coreIFace));
+ dia.exec();
+ answer = qstrdup(dia.input().toLatin1().constData());
+ if (m_mode == WorkbenchClientUser::Resolve) {
+ if (strcmp(answer.Text(), "e") == 0) {
+ ;
+ } else if (strcmp(answer.Text(), "d") == 0) {
+ ;
+ } else {
+ m_msg.clear();
+ m_skipNextMsg = true;
+ }
+ }
+}
+
+void WorkbenchClientUser::ErrorPause(char *msg, Error *)
+{
+ QMessageBox::warning(m_coreIFace->mainWindow(), tr("Perforce Error"), QString::fromUtf8(msg));
+}
diff --git a/src/plugins/perforce/workbenchclientuser.h b/src/plugins/perforce/workbenchclientuser.h
new file mode 100644
index 0000000000..9ee25e1857
--- /dev/null
+++ b/src/plugins/perforce/workbenchclientuser.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** 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 WORKBENCHCLIENTUSER_H
+#define WORKBENCHCLIENTUSER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <coreplugin/icorelistener.h>
+#include "p4.h"
+
+#include "ui_promptdialog.h"
+
+QT_BEGIN_NAMESPACE
+class QRadioButton;
+class QEventLoop;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+class IEditor;
+}
+
+namespace Perforce {
+namespace Internal {
+
+class PerforceOutputWindow;
+class PerforcePlugin;
+
+class PromptDialog : public QDialog
+{
+public:
+ PromptDialog(const QString &choice, const QString &text,
+ QWidget *parent = 0);
+ QString input() const;
+
+private:
+ Ui::PromptDialog m_ui;
+ QMap<QRadioButton*, QString> m_optionsMap;
+};
+
+class WorkbenchClientUser : public QObject, public ClientUser
+{
+ Q_OBJECT
+
+public:
+ enum Mode {Submit, Resolve};
+ WorkbenchClientUser(PerforceOutputWindow *out, PerforcePlugin *plugin);
+ ~WorkbenchClientUser();
+ void setMode(WorkbenchClientUser::Mode mode);
+
+ void Message(Error* err);
+ void OutputError(const char *errBuf);
+ void Finished();
+ void Diff(FileSys *f1, FileSys *f2, int, char *, Error *err);
+ void Edit( FileSys *f, Error *err);
+ void Prompt(const StrPtr &msg, StrBuf &answer, int , Error *err);
+ void ErrorPause(char *msg, Error *);
+ bool editorAboutToClose(Core::IEditor *editor);
+
+private slots:
+ void cancelP4Command();
+
+private:
+ void displayErrorMsg(const QString &msg);
+
+ PerforcePlugin *m_plugin;
+ Core::ICore *m_coreIFace;
+ Core::IEditor *m_currentEditorIface;
+ bool m_userCancelled;
+ Mode m_mode;
+ PerforceOutputWindow *m_perforceOutputWindow;
+ QString m_msg;
+ QString m_errMsg;
+ bool m_skipNextMsg;
+ QEventLoop *m_eventLoop;
+};
+
+} // namespace Perforce
+} // namespace Internal
+
+#endif