diff options
author | con <qtc-commiter@nokia.com> | 2008-12-02 12:01:29 +0100 |
---|---|---|
committer | con <qtc-commiter@nokia.com> | 2008-12-02 12:01:29 +0100 |
commit | 05c35356abc31549c5db6eba31fb608c0365c2a0 (patch) | |
tree | be044530104267afaff13f8943889cb97f8c8bad /src/plugins/perforce | |
download | qt-creator-05c35356abc31549c5db6eba31fb608c0365c2a0.tar.gz |
Initial import
Diffstat (limited to 'src/plugins/perforce')
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 Binary files differnew file mode 100644 index 0000000000..b3597f9ff8 --- /dev/null +++ b/src/plugins/perforce/images/diff.png diff --git a/src/plugins/perforce/images/submit.png b/src/plugins/perforce/images/submit.png Binary files differnew file mode 100644 index 0000000000..4f302302b9 --- /dev/null +++ b/src/plugins/perforce/images/submit.png 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 |