diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index edaab39fbdbc4a07cb393792494e8f9c993f8c72..f30c348edc4afd6db1a0e0a888590f89cfb84c08 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -48,13 +48,6 @@ public: virtual QString name() const = 0; - virtual bool isEnabled() const = 0; - - /*! - * Enable the VCS, that is, make its menu actions visible. - */ - virtual void setEnabled(bool enabled) = 0; - /*! * Returns whether files in this directory should be managed with this * version control. diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index e07ba2ff12e6608afb17099d8542b7bbbf96d60b..500454758798bad9ccdf4a0e1b64b8842c371439 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -46,15 +46,18 @@ enum { debug = 0 }; namespace Core { typedef QList<IVersionControl *> VersionControlList; +typedef QMap<QString, IVersionControl *> VersionControlCache; static inline VersionControlList allVersionControls() { return ExtensionSystem::PluginManager::instance()->getObjects<IVersionControl>(); } -// ---- VCSManagerPrivate +// ---- VCSManagerPrivate: +// Maintains a cache of top-level directory->version control. + struct VCSManagerPrivate { - QMap<QString, IVersionControl *> m_cachedMatches; + VersionControlCache m_cachedMatches; }; VCSManager::VCSManager(QObject *parent) : @@ -79,57 +82,48 @@ void VCSManager::extensionsInitialized() } } -void VCSManager::setVCSEnabled(const QString &directory) -{ - if (debug) - qDebug() << Q_FUNC_INFO << directory; - IVersionControl* managingVCS = findVersionControlForDirectory(directory); - const VersionControlList versionControls = allVersionControls(); - foreach (IVersionControl *versionControl, versionControls) { - const bool newEnabled = versionControl == managingVCS; - if (newEnabled != versionControl->isEnabled()) - versionControl->setEnabled(newEnabled); - } -} - -void VCSManager::setAllVCSEnabled() -{ - if (debug) - qDebug() << Q_FUNC_INFO; - const VersionControlList versionControls = allVersionControls(); - foreach (IVersionControl *versionControl, versionControls) - if (!versionControl->isEnabled()) - versionControl->setEnabled(true); -} - -IVersionControl* VCSManager::findVersionControlForDirectory(const QString &directory) +IVersionControl* VCSManager::findVersionControlForDirectory(const QString &directory, + QString *topLevelDirectory) { - // first look into the cache, check the whole name - - { - const QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directory); - if (it != m_d->m_cachedMatches.constEnd()) - return it.value(); + typedef VersionControlCache::const_iterator VersionControlCacheConstIterator; + const VersionControlCacheConstIterator cacheEnd = m_d->m_cachedMatches.constEnd(); + + if (topLevelDirectory) + topLevelDirectory->clear(); + + // First check if the directory has an entry, meaning it is a top level + const VersionControlCacheConstIterator fullPathIt = m_d->m_cachedMatches.constFind(directory); + if (fullPathIt != cacheEnd) { + if (topLevelDirectory) + *topLevelDirectory = directory; + return fullPathIt.value(); } + // Split the path, starting from top, try to find the matching repository int pos = 0; const QChar slash = QLatin1Char('/'); while (true) { - int index = directory.indexOf(slash, pos); + const int index = directory.indexOf(slash, pos); if (index == -1) break; const QString directoryPart = directory.left(index); - QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directoryPart); - if (it != m_d->m_cachedMatches.constEnd()) + const VersionControlCacheConstIterator it = m_d->m_cachedMatches.constFind(directoryPart); + if (it != cacheEnd) { + if (topLevelDirectory) + *topLevelDirectory = it.key(); return it.value(); - pos = index+1; + } + pos = index + 1; } - // ah nothing so ask the IVersionControls directly + // Nothing: ask the IVersionControls directly, insert the toplevel into the cache. const VersionControlList versionControls = allVersionControls(); foreach (IVersionControl * versionControl, versionControls) { if (versionControl->managesDirectory(directory)) { - m_d->m_cachedMatches.insert(versionControl->findTopLevelForDirectory(directory), versionControl); + const QString topLevel = versionControl->findTopLevelForDirectory(directory); + m_d->m_cachedMatches.insert(topLevel, versionControl); + if (topLevelDirectory) + *topLevelDirectory = topLevel; return versionControl; } } @@ -152,4 +146,14 @@ bool VCSManager::showDeleteDialog(const QString &fileName) return vc->vcsDelete(fileName); } +CORE_EXPORT QDebug operator<<(QDebug in, const VCSManager &v) +{ + QDebug nospace = in.nospace(); + const VersionControlCache::const_iterator cend = v.m_d->m_cachedMatches.constEnd(); + for (VersionControlCache::const_iterator it = v.m_d->m_cachedMatches.constBegin(); it != cend; ++it) + nospace << "Directory: " << it.key() << ' ' << it.value()->name() << '\n'; + nospace << '\n'; + return in; +} + } // namespace Core diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h index 772243dd95767278786b0cdc306bdb1a3cbbd600..eb5b67a1b2703c1c4d00483648e92f4eb43d1b56 100644 --- a/src/plugins/coreplugin/vcsmanager.h +++ b/src/plugins/coreplugin/vcsmanager.h @@ -35,20 +35,26 @@ #include <QtCore/QString> #include <QtCore/QObject> +QT_BEGIN_NAMESPACE +class QDebug; +QT_END_NAMESPACE + namespace Core { struct VCSManagerPrivate; class IVersionControl; -// The VCSManager has only one notable function: -// findVersionControlFor(), which returns the IVersionControl * for a given -// filename. Note that the VCSManager assumes that if a IVersionControl * -// manages a directory, then it also manages all the files and all the -// subdirectories. -// -// It works by asking all IVersionControl * if they manage the file, and ask -// for the topmost directory it manages. This information is cached and -// VCSManager thus knows pretty fast which IVersionControl * is responsible. +/* VCSManager: + * 1) Provides functionality for finding the IVersionControl * for a given + * filename (findVersionControlForDirectory). Note that the VCSManager assumes + * that if a IVersionControl * manages a directory, then it also manages + * all the files and all the subdirectories. + * It works by asking all IVersionControl * if they manage the file, and ask + * for the topmost directory it manages. This information is cached and + * VCSManager thus knows pretty fast which IVersionControl * is responsible. + * 2) Passes on the changes from the version controls caused by updating or + * branching repositories and routes them to its signals (repositoryChanged, + * filesChanged). */ class CORE_EXPORT VCSManager : public QObject { @@ -60,19 +66,16 @@ public: void extensionsInitialized(); - IVersionControl *findVersionControlForDirectory(const QString &directory); - - // Enable the VCS managing a certain directory only. This should - // be used by project manager classes. - void setVCSEnabled(const QString &directory); - // Enable all VCS. - void setAllVCSEnabled(); + IVersionControl *findVersionControlForDirectory(const QString &directory, + QString *topLevelDirectory = 0); // Shows a confirmation dialog, whether the file should also be deleted // from revision control Calls sccDelete on the file. Returns false // if a failure occurs bool showDeleteDialog(const QString &fileName); + friend CORE_EXPORT QDebug operator<<(QDebug in, const VCSManager &); + signals: void repositoryChanged(const QString &repository); void filesChanged(const QStringList &files); @@ -81,6 +84,8 @@ private: VCSManagerPrivate *m_d; }; +CORE_EXPORT QDebug operator<<(QDebug in, const VCSManager &); + } // namespace Core #endif // VCSMANAGER_H diff --git a/src/plugins/cvs/cvscontrol.cpp b/src/plugins/cvs/cvscontrol.cpp index 1689f22052798b8bfa1d3d9143bf23cc8baf2c50..01858d771ca6cf6c2e9fa0a02202be268b9b854b 100644 --- a/src/plugins/cvs/cvscontrol.cpp +++ b/src/plugins/cvs/cvscontrol.cpp @@ -44,19 +44,6 @@ QString CVSControl::name() const return QLatin1String("cvs"); } -bool CVSControl::isEnabled() const -{ - return m_enabled; -} - -void CVSControl::setEnabled(bool enabled) -{ - if (m_enabled != enabled) { - m_enabled = enabled; - emit enabledChanged(m_enabled); - } -} - bool CVSControl::supportsOperation(Operation operation) const { bool rc = true; diff --git a/src/plugins/cvs/cvscontrol.h b/src/plugins/cvs/cvscontrol.h index c6adb7ffa9c019d617186446fd45123affee08aa..0234d16b9578972baaa212083860f4cc465c782b 100644 --- a/src/plugins/cvs/cvscontrol.h +++ b/src/plugins/cvs/cvscontrol.h @@ -45,9 +45,6 @@ public: explicit CVSControl(CVSPlugin *plugin); virtual QString name() const; - virtual bool isEnabled() const; - virtual void setEnabled(bool enabled); - virtual bool managesDirectory(const QString &directory) const; virtual QString findTopLevelForDirectory(const QString &directory) const; @@ -59,9 +56,6 @@ public: void emitRepositoryChanged(const QString &s); void emitFilesChanged(const QStringList &l); -signals: - void enabledChanged(bool); - private: bool m_enabled; CVSPlugin *m_plugin; diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 5f5849a17a95d5bf458278ceddcc7065d3ce894c..bfa406a39b0f368f75c6cb520eb7793d9d11f518 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -151,7 +151,7 @@ Core::IEditor* locateEditor(const char *property, const QString &entry) CVSPlugin *CVSPlugin::m_cvsPluginInstance = 0; CVSPlugin::CVSPlugin() : - m_versionControl(0), + VCSBase::VCSBasePlugin(QLatin1String(CVS::Constants::CVSCOMMITEDITOR_KIND)), m_projectExplorer(0), m_addAction(0), m_deleteAction(0), @@ -168,6 +168,7 @@ CVSPlugin::CVSPlugin() : m_submitDiffAction(0), m_submitUndoAction(0), m_submitRedoAction(0), + m_menuAction(0), m_submitActionTriggered(false) { } @@ -205,10 +206,8 @@ static inline Core::Command *createSeparator(QObject *parent, return ami->registerAction(tmpaction, id, globalcontext); } -bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage) +bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMessage) { - Q_UNUSED(arguments); - typedef VCSBase::VCSSubmitEditorFactory<CVSSubmitEditor> CVSSubmitEditorFactory; typedef VCSBase::VCSEditorFactory<CVSEditor> CVSEditorFactory; using namespace Constants; @@ -216,21 +215,17 @@ bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage) using namespace Core::Constants; using namespace ExtensionSystem; + VCSBase::VCSBasePlugin::initialize(new CVSControl(this)); + m_cvsPluginInstance = this; Core::ICore *core = Core::ICore::instance(); if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.cvs/CVS.mimetypes.xml"), errorMessage)) return false; - - m_versionControl = new CVSControl(this); - addAutoReleasedObject(m_versionControl); - if (QSettings *settings = core->settings()) m_settings.fromSettings(settings); - addAutoReleasedObject(new CoreListener(this)); - addAutoReleasedObject(new SettingsPage); addAutoReleasedObject(new CVSSubmitEditorFactory(&submitParameters)); @@ -250,10 +245,7 @@ bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage) ami->createMenu(QLatin1String(CMD_ID_CVS_MENU)); cvsMenu->menu()->setTitle(tr("&CVS")); toolsContainer->addMenu(cvsMenu); - if (QAction *ma = cvsMenu->menu()->menuAction()) { - ma->setEnabled(m_versionControl->isEnabled()); - connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool))); - } + m_menuAction = cvsMenu->menu()->menuAction(); QList<int> globalcontext; globalcontext << core->uniqueIDManager()->uniqueIdentifier(C_GLOBAL); @@ -360,30 +352,21 @@ bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_submitRedoAction = new QAction(tr("&Redo"), this); command = ami->registerAction(m_submitRedoAction, Core::Constants::REDO, cvscommitcontext); - - connect(Core::ICore::instance(), SIGNAL(contextChanged(Core::IContext *)), this, SLOT(updateActions())); - return true; } void CVSPlugin::extensionsInitialized() { m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance(); - if (m_projectExplorer) { - connect(m_projectExplorer, - SIGNAL(currentProjectChanged(ProjectExplorer::Project*)), - m_cvsPluginInstance, SLOT(updateActions())); - } - updateActions(); } -bool CVSPlugin::editorAboutToClose(Core::IEditor *iEditor) +bool CVSPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor) { - if (!iEditor || !isCommitEditorOpen() || qstrcmp(Constants::CVSCOMMITEDITOR, iEditor->kind())) + if (!isCommitEditorOpen()) return true; - Core::IFile *fileIFace = iEditor->file(); - const CVSSubmitEditor *editor = qobject_cast<CVSSubmitEditor *>(iEditor); + Core::IFile *fileIFace = submitEditor->file(); + const CVSSubmitEditor *editor = qobject_cast<CVSSubmitEditor *>(submitEditor); if (!fileIFace || !editor) return true; @@ -488,8 +471,11 @@ CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName) return submitEditor; } -void CVSPlugin::updateActions() +void CVSPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as) { + if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction)) + return; + m_diffProjectAction->setEnabled(true); m_commitAllAction->setEnabled(true); m_statusAction->setEnabled(true); @@ -554,7 +540,7 @@ void CVSPlugin::revertCurrentFile() const CVSResponse revertResponse = runCVS(args, files, cvsShortTimeOut, true); if (revertResponse.result == CVSResponse::Ok) { fcb.setModifiedReload(true); - m_versionControl->emitFilesChanged(files); + cvsVersionControl()->emitFilesChanged(files); } } @@ -738,7 +724,7 @@ void CVSPlugin::updateProject() const CVSResponse response = runCVS(args, topLevels, cvsLongTimeOut, true); if (response.result == CVSResponse::Ok) foreach(const QString &topLevel, topLevels) - m_versionControl->emitRepositoryChanged(topLevel); + cvsVersionControl()->emitRepositoryChanged(topLevel); } } @@ -1193,6 +1179,11 @@ QString CVSPlugin::findTopLevelForDirectoryI(const QString &directory) const return QString(); } +CVSControl *CVSPlugin::cvsVersionControl() const +{ + return static_cast<CVSControl *>(versionControl()); +} + } } Q_EXPORT_PLUGIN(CVS::Internal::CVSPlugin) diff --git a/src/plugins/cvs/cvsplugin.h b/src/plugins/cvs/cvsplugin.h index a1515cfc931431761ed10390c824135b8de00394..268c4848afc565adcd393efd382cb6d728d3ebd5 100644 --- a/src/plugins/cvs/cvsplugin.h +++ b/src/plugins/cvs/cvsplugin.h @@ -33,8 +33,7 @@ #include "cvssettings.h" #include "cvsutils.h" -#include <coreplugin/icorelistener.h> -#include <extensionsystem/iplugin.h> +#include <vcsbase/vcsbaseplugin.h> QT_BEGIN_NAMESPACE class QDir; @@ -55,6 +54,10 @@ namespace ProjectExplorer { class ProjectExplorerPlugin; } +namespace VCSBase { + class VCSBaseSubmitEditor; +} + namespace CVS { namespace Internal { @@ -80,7 +83,7 @@ struct CVSResponse * the diff editor has an additional property specifying the * base directory for its interaction to work. */ -class CVSPlugin : public ExtensionSystem::IPlugin +class CVSPlugin : public VCSBase::VCSBasePlugin { Q_OBJECT @@ -90,7 +93,6 @@ public: virtual bool initialize(const QStringList &arguments, QString *error_message); virtual void extensionsInitialized(); - virtual bool editorAboutToClose(Core::IEditor *editor); void cvsDiff(const QStringList &files, QString diffname = QString()); @@ -108,7 +110,6 @@ public: static CVSPlugin *cvsPluginInstance(); private slots: - void updateActions(); void addCurrentFile(); void deleteCurrentFile(); void revertCurrentFile(); @@ -124,6 +125,10 @@ private slots: void submitCurrentLog(); void diffFiles(const QStringList &); +protected: + virtual void updateActions(VCSBase::VCSBasePlugin::ActionState); + virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor); + private: bool isCommitEditorOpen() const; QString currentFileName() const; @@ -152,9 +157,9 @@ private: void startCommit(const QString &file); bool commit(const QString &messageFile, const QStringList &subVersionFileList); void cleanCommitMessageFile(); + inline CVSControl *cvsVersionControl() const; CVSSettings m_settings; - CVSControl *m_versionControl; QString m_commitMessageFileName; ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer; @@ -175,32 +180,12 @@ private: QAction *m_submitDiffAction; QAction *m_submitUndoAction; QAction *m_submitRedoAction; + QAction *m_menuAction; bool m_submitActionTriggered; static CVSPlugin *m_cvsPluginInstance; }; -// Just a proxy for CVSPlugin -class CoreListener : public Core::ICoreListener -{ - Q_OBJECT -public: - CoreListener(CVSPlugin *plugin) : m_plugin(plugin) { } - - // Start commit when submit editor closes - bool editorAboutToClose(Core::IEditor *editor) { - return m_plugin->editorAboutToClose(editor); - } - - // TODO: how to handle that ??? - bool coreAboutToClose() { - return true; - } - -private: - CVSPlugin *m_plugin; -}; - } // namespace CVS } // namespace Internal diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp index 3274ec7ebc7e26f32ffe16378277394dde6adfa3..a99fab61aedf382251a1ee485845bbf11ae7f818 100644 --- a/src/plugins/git/changeselectiondialog.cpp +++ b/src/plugins/git/changeselectiondialog.cpp @@ -32,7 +32,8 @@ #include <QtGui/QFileDialog> #include <QtGui/QMessageBox> -using namespace Git::Internal; +namespace Git { +namespace Internal { ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent) : QDialog(parent) @@ -42,6 +43,21 @@ ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent) setWindowTitle(tr("Select a Git commit")); } +QString ChangeSelectionDialog::change() const +{ + return m_ui.changeNumberEdit->text(); +} + +QString ChangeSelectionDialog::repository() const +{ + return m_ui.repositoryEdit->text(); +} + +void ChangeSelectionDialog::setRepository(const QString &s) +{ + m_ui.repositoryEdit->setText(s); +} + void ChangeSelectionDialog::selectWorkingDirectory() { static QString location = QString(); @@ -67,3 +83,6 @@ void ChangeSelectionDialog::selectWorkingDirectory() tr("Selected directory is not a Git repository")); } + +} +} diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h index 28330b0a1981995c53d45ce02d2e7f5b79426185..33f8cc6972faf2fc1388cb50640c133bb0efea76 100644 --- a/src/plugins/git/changeselectiondialog.h +++ b/src/plugins/git/changeselectiondialog.h @@ -37,21 +37,22 @@ namespace Git { namespace Internal { -class GitPlugin; - class ChangeSelectionDialog : public QDialog { Q_OBJECT public: ChangeSelectionDialog(QWidget *parent = 0); + QString change() const; + + QString repository() const; + void setRepository(const QString &s); + public slots: void selectWorkingDirectory(); -private: - friend class GitPlugin; +private: Ui_ChangeSelectionDialog m_ui; - }; } // namespace Internal diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 486196174af14489508f7d708bca781dfa2f8130..a7fda8a1abcf782ece5fb9eb5181ced0cfcf29a5 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -147,19 +147,6 @@ QString GitClient::findRepositoryForDirectory(const QString &dir) return QString(); } -// Return source file or directory string depending on parameters -// ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file'). -static QString source(const QString &workingDirectory, const QString &fileName) -{ - if (fileName.isEmpty()) - return workingDirectory; - QString rc = workingDirectory; - if (!rc.isEmpty() && !rc.endsWith(QDir::separator())) - rc += QDir::separator(); - rc += fileName; - return rc; -} - /* Create an editor associated to VCS output of a source file/directory * (using the file's codec). Makes use of a dynamic property to find an * existing instance and to reuse it (in case, say, 'git diff foo' is @@ -253,8 +240,7 @@ void GitClient::diff(const QString &workingDirectory, const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND); const QString title = tr("Git Diff %1").arg(fileName); - const QString sourceFile = source(workingDirectory, fileName); - + const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, fileName); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "originalFileName", sourceFile); executeGit(workingDirectory, arguments, editor); } @@ -267,10 +253,10 @@ void GitClient::status(const QString &workingDirectory) executeGit(workingDirectory, statusArgs, 0, true); } -void GitClient::log(const QString &workingDirectory, const QString &fileName) +void GitClient::log(const QString &workingDirectory, const QStringList &fileNames) { if (Git::Constants::debug) - qDebug() << "log" << workingDirectory << fileName; + qDebug() << "log" << workingDirectory << fileNames; QStringList arguments; arguments << QLatin1String("log") << QLatin1String(noColorOption); @@ -278,12 +264,14 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName) if (m_settings.logCount > 0) arguments << QLatin1String("-n") << QString::number(m_settings.logCount); - if (!fileName.isEmpty()) - arguments << fileName; + if (!fileNames.isEmpty()) + arguments.append(fileNames); - const QString title = tr("Git Log %1").arg(fileName); + const QString msgArg = fileNames.empty() ? workingDirectory : + fileNames.join(QString(", ")); + const QString title = tr("Git Log %1").arg(msgArg); const QString kind = QLatin1String(Git::Constants::GIT_LOG_EDITOR_KIND); - const QString sourceFile = source(workingDirectory, fileName); + const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, fileNames); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, false, "logFileName", sourceFile); executeGit(workingDirectory, arguments, editor); } @@ -313,7 +301,7 @@ void GitClient::blame(const QString &workingDirectory, const QString &fileName, const QString kind = QLatin1String(Git::Constants::GIT_BLAME_EDITOR_KIND); const QString title = tr("Git Blame %1").arg(fileName); - const QString sourceFile = source(workingDirectory, fileName); + const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, fileName); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "blameFileName", sourceFile); executeGit(workingDirectory, arguments, editor, false, GitCommand::NoReport, lineNumber); @@ -912,7 +900,7 @@ void GitClient::revert(const QStringList &files) QString errorMessage; switch (revertI(files, &isDirectory, &errorMessage)) { case RevertOk: - m_plugin->versionControl()->emitFilesChanged(files); + m_plugin->gitVersionControl()->emitFilesChanged(files); break; case RevertCanceled: break; @@ -1020,7 +1008,7 @@ void GitClient::connectRepositoryChanged(const QString & repository, GitCommand if (!m_repositoryChangedSignalMapper) { m_repositoryChangedSignalMapper = new QSignalMapper(this); connect(m_repositoryChangedSignalMapper, SIGNAL(mapped(QString)), - m_plugin->versionControl(), SIGNAL(repositoryChanged(QString))); + m_plugin->gitVersionControl(), SIGNAL(repositoryChanged(QString))); } m_repositoryChangedSignalMapper->setMapping(cmd, repository); connect(cmd, SIGNAL(success()), m_repositoryChangedSignalMapper, SLOT(map()), diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 76da31203479171106ff7c997bc1e5a0a6bbea18..ef53fd3ff88f8df3407e71c1874196342b3dfaa2 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -79,7 +79,7 @@ public: const QStringList &unstagedFileNames, const QStringList &stagedFileNames= QStringList()); void status(const QString &workingDirectory); - void log(const QString &workingDirectory, const QString &fileName); + void log(const QString &workingDirectory, const QStringList &fileNames); void blame(const QString &workingDirectory, const QString &fileName, int lineNumber = -1); void showCommit(const QString &workingDirectory, const QString &commit); void checkout(const QString &workingDirectory, const QString &file); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 6e442bec7f240e3a0f8a5f062cb7421d3d61aa6f..5c0954b263168fd8066b54e29f5a89333c537f16 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -56,10 +56,6 @@ #include <vcsbase/basevcssubmiteditorfactory.h> #include <vcsbase/vcsbaseoutputwindow.h> -#include <projectexplorer/projectexplorer.h> -#include <projectexplorer/project.h> -#include <projectexplorer/projectnodes.h> - #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFileInfo> @@ -105,23 +101,16 @@ static inline const VCSBase::VCSBaseEditorParameters *findType(int ie) using namespace Git; using namespace Git::Internal; -// CoreListener - -bool CoreListener::editorAboutToClose(Core::IEditor *editor) -{ - return m_plugin->editorAboutToClose(editor); -} - // GitPlugin GitPlugin *GitPlugin::m_instance = 0; GitPlugin::GitPlugin() : + VCSBase::VCSBasePlugin(QLatin1String(Git::Constants::GITSUBMITEDITOR_KIND)), m_core(0), m_diffAction(0), m_diffProjectAction(0), - m_statusAction(0), - m_statusProjectAction(0), + m_statusRepositoryAction(0), m_logAction(0), m_blameAction(0), m_logProjectAction(0), @@ -141,8 +130,8 @@ GitPlugin::GitPlugin() : m_stashPopAction(0), m_stashListAction(0), m_branchListAction(0), + m_menuAction(0), m_gitClient(0), - m_versionControl(0), m_changeSelectionDialog(0), m_submitActionTriggered(false) { @@ -192,15 +181,17 @@ static Core::Command *createSeparator(Core::ActionManager *am, bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) { + Q_UNUSED(arguments) + Q_UNUSED(errorMessage) + typedef VCSBase::VCSEditorFactory<GitEditor> GitEditorFactory; typedef VCSBase::VCSSubmitEditorFactory<GitSubmitEditor> GitSubmitEditorFactory; - Q_UNUSED(arguments) - Q_UNUSED(errorMessage) + VCSBase::VCSBasePlugin::initialize(new GitVersionControl(m_gitClient)); m_core = Core::ICore::instance(); m_gitClient = new GitClient(this); - // Create the globalco6664324b12a3339d18251df1cd69a1da06d1e2dcntext list to register actions accordingly + // Create the globalcontext list to register actions accordingly QList<int> globalcontext; globalcontext << m_core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_GLOBAL); @@ -212,13 +203,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) for (int i = 0; i < editorCount; i++) addAutoReleasedObject(new GitEditorFactory(editorParameters + i, m_gitClient, describeSlot)); - addAutoReleasedObject(new CoreListener(this)); - addAutoReleasedObject(new GitSubmitEditorFactory(&submitParameters)); - - m_versionControl = new GitVersionControl(m_gitClient); - addAutoReleasedObject(m_versionControl); - addAutoReleasedObject(new CloneWizard); addAutoReleasedObject(new Gitorious::Internal::GitoriousCloneWizard); @@ -232,11 +217,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) actionManager->createMenu(QLatin1String("Git")); gitContainer->menu()->setTitle(tr("&Git")); toolsContainer->addMenu(gitContainer); - if (QAction *ma = gitContainer->menu()->menuAction()) { - ma->setEnabled(m_versionControl->isEnabled()); - connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool))); - } - + m_menuAction = gitContainer->menu()->menuAction(); Core::Command *command; m_diffAction = new Utils::ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); @@ -246,13 +227,6 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) connect(m_diffAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile())); gitContainer->addAction(command); - m_statusAction = new Utils::ParameterAction(tr("File Status"), tr("Status Related to \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); - command = actionManager->registerAction(m_statusAction, "Git.Status", globalcontext); - command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+S"))); - command->setAttribute(Core::Command::CA_UpdateText); - connect(m_statusAction, SIGNAL(triggered()), this, SLOT(statusFile())); - gitContainer->addAction(command); - m_logAction = new Utils::ParameterAction(tr("Log File"), tr("Log of \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); command = actionManager->registerAction(m_logAction, "Git.Log", globalcontext); command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+L"))); @@ -296,10 +270,9 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffCurrentProject())); gitContainer->addAction(command); - m_statusProjectAction = new Utils::ParameterAction(tr("Project Status"), tr("Status Project \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); - command = actionManager->registerAction(m_statusProjectAction, "Git.StatusProject", globalcontext); - command->setAttribute(Core::Command::CA_UpdateText); - connect(m_statusProjectAction, SIGNAL(triggered()), this, SLOT(statusProject())); + m_statusRepositoryAction = new QAction(tr("Repository Status"), this); + command = actionManager->registerAction(m_statusRepositoryAction, "Git.StatusRepository", globalcontext); + connect(m_statusRepositoryAction, SIGNAL(triggered()), this, SLOT(statusRepository())); gitContainer->addAction(command); m_logProjectAction = new Utils::ParameterAction(tr("Log Project"), tr("Log Project \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); @@ -386,12 +359,6 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_redoAction = new QAction(tr("&Redo"), this); command = actionManager->registerAction(m_redoAction, Core::Constants::REDO, submitContext); - // Ask for updates of our actions, in case context switches - connect(m_core, SIGNAL(contextChanged(Core::IContext *)), - this, SLOT(updateActions())); - connect(m_core->fileManager(), SIGNAL(currentFileChanged(const QString &)), - this, SLOT(updateActions())); - return true; } @@ -399,9 +366,9 @@ void GitPlugin::extensionsInitialized() { } -GitVersionControl *GitPlugin::versionControl() const +GitVersionControl *GitPlugin::gitVersionControl() const { - return m_versionControl; + return static_cast<GitVersionControl *>(versionControl()); } void GitPlugin::submitEditorDiff(const QStringList &unstaged, const QStringList &staged) @@ -411,127 +378,83 @@ void GitPlugin::submitEditorDiff(const QStringList &unstaged, const QStringList void GitPlugin::diffCurrentFile() { - const QFileInfo fileInfo = currentFile(); - const QString fileName = fileInfo.fileName(); - const QString workingDirectory = fileInfo.absolutePath(); - m_gitClient->diff(workingDirectory, QStringList(), fileName); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasFile(), return) + m_gitClient->diff(state.currentFileTopLevel(), QStringList(), state.relativeCurrentFile()); } void GitPlugin::diffCurrentProject() { - QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; - m_gitClient->diff(workingDirectory, QStringList(), QString()); -} - -QFileInfo GitPlugin::currentFile() const -{ - QString fileName = m_core->fileManager()->currentFile(); - QFileInfo fileInfo(fileName); - return fileInfo; -} - -QString GitPlugin::getWorkingDirectory() -{ - QString workingDirectory; - if (const ProjectExplorer::ProjectExplorerPlugin *p = ProjectExplorer::ProjectExplorerPlugin::instance()) - if (p && p->currentNode()) - workingDirectory = QFileInfo(p->currentNode()->path()).absolutePath(); - - if (Git::Constants::debug > 1) - qDebug() << Q_FUNC_INFO << "Project" << workingDirectory; - - if (workingDirectory.isEmpty()) - workingDirectory = QFileInfo(m_core->fileManager()->currentFile()).absolutePath(); - if (Git::Constants::debug > 1) - qDebug() << Q_FUNC_INFO << "file" << workingDirectory; - - if (workingDirectory.isEmpty()) { - VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Could not find working directory")); - return QString(); - } - return workingDirectory; + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasProject(), return) + m_gitClient->diff(state.currentProjectTopLevel(), QStringList(), state.relativeCurrentProject()); } -void GitPlugin::statusProject() +void GitPlugin::statusRepository() { - QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; - m_gitClient->status(workingDirectory); -} - -void GitPlugin::statusFile() -{ - m_gitClient->status(currentFile().absolutePath()); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) + m_gitClient->status(state.topLevel()); } void GitPlugin::logFile() { - const QFileInfo fileInfo = currentFile(); - const QString fileName = fileInfo.fileName(); - const QString workingDirectory = fileInfo.absolutePath(); - m_gitClient->log(workingDirectory, fileName); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasFile(), return) + m_gitClient->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile())); } void GitPlugin::blameFile() { - const QFileInfo fileInfo = currentFile(); - const QString fileName = fileInfo.fileName(); - const QString workingDirectory = fileInfo.absolutePath(); - - m_gitClient->blame(workingDirectory, fileName, - VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor(fileInfo.absoluteFilePath())); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasFile(), return) + const int lineNumber = VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor(state.currentFile()); + m_gitClient->blame(state.currentFileTopLevel(), state.relativeCurrentFile(), lineNumber); } void GitPlugin::logProject() { - QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; - m_gitClient->log(workingDirectory, QString()); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasProject(), return) + m_gitClient->log(state.currentProjectTopLevel(), state.relativeCurrentProject()); } void GitPlugin::undoFileChanges() { - const QFileInfo fileInfo = currentFile(); - Core::FileChangeBlocker fcb(fileInfo.filePath()); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasFile(), return) + Core::FileChangeBlocker fcb(state.currentFile()); fcb.setModifiedReload(true); - - m_gitClient->revert(QStringList(fileInfo.absoluteFilePath())); + m_gitClient->revert(QStringList(state.currentFile())); } void GitPlugin::undoProjectChanges() { - const QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) + const QString msg = tr("Would you like to revert all pending changes to the repository\n%1?").arg(state.topLevel()); const QMessageBox::StandardButton answer = QMessageBox::question(m_core->mainWindow(), - tr("Revert"), - tr("Would you like to revert all pending changes to the project?"), + tr("Revert"), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::No) return; - m_gitClient->hardReset(workingDirectory, QString()); + m_gitClient->hardReset(state.topLevel(), QString()); } void GitPlugin::stageFile() { - const QFileInfo fileInfo = currentFile(); - const QString fileName = fileInfo.fileName(); - const QString workingDirectory = fileInfo.absolutePath(); - m_gitClient->addFile(workingDirectory, fileName); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasFile(), return) + m_gitClient->addFile(state.currentFileTopLevel(), state.relativeCurrentFile()); } void GitPlugin::unstageFile() { - const QFileInfo fileInfo = currentFile(); - const QString fileName = fileInfo.fileName(); - const QString workingDirectory = fileInfo.absolutePath(); - m_gitClient->synchronousReset(workingDirectory, QStringList(fileName)); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasFile(), return) + m_gitClient->synchronousReset(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile())); } void GitPlugin::startCommit() @@ -543,15 +466,12 @@ void GitPlugin::startCommit() return; } - // Find repository and get commit data - const QFileInfo currentFileInfo = currentFile(); - if (!currentFileInfo.exists()) - return; + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) - const QString workingDirectory = currentFileInfo.absolutePath(); QString errorMessage, commitTemplate; CommitData data; - if (!m_gitClient->getCommitData(workingDirectory, &commitTemplate, &data, &errorMessage)) { + if (!m_gitClient->getCommitData(state.topLevel(), &commitTemplate, &data, &errorMessage)) { VCSBase::VCSBaseOutputWindow::instance()->append(errorMessage); return; } @@ -606,13 +526,12 @@ void GitPlugin::submitCurrentLog() m_core->editorManager()->closeEditors(editors); } -bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor) +bool GitPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor) { - // Closing a submit editor? - if (!iEditor || !isCommitEditorOpen() || qstrcmp(iEditor->kind(), Constants::GITSUBMITEDITOR_KIND)) - return true; - Core::IFile *fileIFace = iEditor->file(); - const GitSubmitEditor *editor = qobject_cast<GitSubmitEditor *>(iEditor); + if (!isCommitEditorOpen()) + return false; + Core::IFile *fileIFace = submitEditor->file(); + const GitSubmitEditor *editor = qobject_cast<GitSubmitEditor *>(submitEditor); if (!fileIFace || !editor) return true; // Submit editor closing. Make it write out the commit message @@ -668,15 +587,14 @@ bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor) void GitPlugin::pull() { - const QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) - switch (m_gitClient->ensureStash(workingDirectory)) { + switch (m_gitClient->ensureStash(state.topLevel())) { case GitClient::StashUnchanged: case GitClient::Stashed: case GitClient::NotStashed: - m_gitClient->pull(workingDirectory); + m_gitClient->pull(state.topLevel()); default: break; } @@ -684,34 +602,33 @@ void GitPlugin::pull() void GitPlugin::push() { - const QString workingDirectory = getWorkingDirectory(); - if (!workingDirectory.isEmpty()) - m_gitClient->push(workingDirectory); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) + m_gitClient->push(state.topLevel()); } void GitPlugin::stash() { - const QString workingDirectory = getWorkingDirectory(); - if (!workingDirectory.isEmpty()) - m_gitClient->stash(workingDirectory); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) + m_gitClient->stash(state.topLevel()); } void GitPlugin::stashPop() { - const QString workingDirectory = getWorkingDirectory(); - if (!workingDirectory.isEmpty()) - m_gitClient->stashPop(workingDirectory); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) + m_gitClient->stashPop(state.topLevel()); } void GitPlugin::branchList() { - const QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) QString errorMessage; BranchDialog dialog(m_core->mainWindow()); - if (!dialog.init(m_gitClient, workingDirectory, &errorMessage)) { + if (!dialog.init(m_gitClient, state.topLevel(), &errorMessage)) { VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage); return; } @@ -720,85 +637,67 @@ void GitPlugin::branchList() void GitPlugin::stashList() { - const QString workingDirectory = getWorkingDirectory(); - if (!workingDirectory.isEmpty()) - m_gitClient->stashList(workingDirectory); + const VCSBase::VCSBasePluginState state = currentState(); + QTC_ASSERT(state.hasTopLevel(), return) + m_gitClient->stashList(state.topLevel()); } -void GitPlugin::updateActions() +void GitPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as) { - const QFileInfo current = currentFile(); - const QString fileName = current.fileName(); - const QString currentDirectory = getWorkingDirectory(); - const QString repository = m_gitClient->findRepositoryForFile(current.absoluteFilePath()); - // First check for file commands and if the current file is inside - // a Git-repository + if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction)) + return; + + const QString fileName = currentState().currentFileName(); m_diffAction->setParameter(fileName); - m_statusAction->setParameter(fileName); m_logAction->setParameter(fileName); m_blameAction->setParameter(fileName); m_undoFileAction->setParameter(fileName); m_stageAction->setParameter(fileName); m_unstageAction->setParameter(fileName); - bool enabled = !fileName.isEmpty() && !repository.isEmpty(); - m_diffAction->setEnabled(enabled); - m_statusAction->setEnabled(enabled); - m_logAction->setEnabled(enabled); - m_blameAction->setEnabled(enabled); - m_undoFileAction->setEnabled(enabled); - m_stageAction->setEnabled(enabled); - m_unstageAction->setEnabled(enabled); - - if (repository.isEmpty()) { - // If the file is not in a repository, the corresponding project will - // be neither and we can disable everything and return - m_diffProjectAction->setEnabled(false); - m_diffProjectAction->setParameter(repository); - m_statusProjectAction->setParameter(repository); - m_statusProjectAction->setEnabled(false); - m_logProjectAction->setParameter(repository); - m_logProjectAction->setEnabled(false); - m_undoProjectAction->setEnabled(false); - return; - } + bool fileEnabled = !fileName.isEmpty(); + m_diffAction->setEnabled(fileEnabled); + m_logAction->setEnabled(fileEnabled); + m_blameAction->setEnabled(fileEnabled); + m_undoFileAction->setEnabled(fileEnabled); + m_stageAction->setEnabled(fileEnabled); + m_unstageAction->setEnabled(fileEnabled); - // We only know the file is in some repository, we do not know - // anything about any project so far. - QString project; - if (const ProjectExplorer::ProjectExplorerPlugin *p = ProjectExplorer::ProjectExplorerPlugin::instance()) { - if (const ProjectExplorer::Node *node = p->currentNode()) - if (const ProjectExplorer::Node *projectNode = node->projectNode()) - project = QFileInfo(projectNode->path()).completeBaseName(); - } + const QString projectName = currentState().currentProjectName(); + const bool projectEnabled = !projectName.isEmpty(); + m_diffProjectAction->setEnabled(projectEnabled); + m_diffProjectAction->setParameter(projectName); + m_logProjectAction->setEnabled(projectEnabled); + m_logProjectAction->setParameter(projectName); + m_undoProjectAction->setEnabled(projectEnabled); + + const bool repositoryEnabled = currentState().hasTopLevel(); + m_statusRepositoryAction->setEnabled(repositoryEnabled); + m_branchListAction->setEnabled(repositoryEnabled); + m_stashListAction->setEnabled(repositoryEnabled); + m_stashPopAction->setEnabled(repositoryEnabled); - enabled = !project.isEmpty(); - m_diffProjectAction->setEnabled(enabled); - m_diffProjectAction->setParameter(project); - m_statusProjectAction->setEnabled(enabled); - m_statusProjectAction->setParameter(project); - m_logProjectAction->setEnabled(enabled); - m_logProjectAction->setParameter(project); - m_undoProjectAction->setEnabled(enabled); + // Prompts for repo. + m_showAction->setEnabled(true); } void GitPlugin::showCommit() { + const VCSBase::VCSBasePluginState state = currentState(); + if (!m_changeSelectionDialog) m_changeSelectionDialog = new ChangeSelectionDialog(); - const QFileInfo currentInfo = currentFile(); - QString repositoryLocation = m_gitClient->findRepositoryForFile(currentInfo.absoluteFilePath()); - if (!repositoryLocation.isEmpty()) - m_changeSelectionDialog->m_ui.repositoryEdit->setText(repositoryLocation); + if (state.hasTopLevel()) + m_changeSelectionDialog->setRepository(state.topLevel()); if (m_changeSelectionDialog->exec() != QDialog::Accepted) return; - const QString change = m_changeSelectionDialog->m_ui.changeNumberEdit->text(); + const QString change = m_changeSelectionDialog->change(); if (change.isEmpty()) return; - m_gitClient->show(m_changeSelectionDialog->m_ui.repositoryEdit->text(), change); + m_gitClient->show(m_changeSelectionDialog->repository(), change); } GitSettings GitPlugin::settings() const diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index 0d6ad7fbdd5f412efedb67daf7b1d47c412a4ed6..bd2f6d1af40f344b47a236e8ffa6faf226e4177b 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -31,9 +31,9 @@ #define GITPLUGIN_H #include "settingspage.h" +#include "vcsbase/vcsbaseplugin.h" #include <coreplugin/editormanager/ieditorfactory.h> -#include <coreplugin/icorelistener.h> #include <extensionsystem/iplugin.h> #include <QtCore/QObject> @@ -49,7 +49,6 @@ QT_END_NAMESPACE namespace Core { class IEditorFactory; class ICore; -class IVersionControl; } namespace Utils { class ParameterAction; @@ -66,19 +65,7 @@ class GitSubmitEditor; struct CommitData; struct GitSettings; -// Just a proxy for GitPlugin -class CoreListener : public Core::ICoreListener -{ - Q_OBJECT -public: - CoreListener(GitPlugin *plugin) : m_plugin(plugin) { } - bool editorAboutToClose(Core::IEditor *editor); - bool coreAboutToClose() { return true; } -private: - GitPlugin *m_plugin; -}; - -class GitPlugin : public ExtensionSystem::IPlugin +class GitPlugin : public VCSBase::VCSBasePlugin { Q_OBJECT @@ -91,25 +78,19 @@ public: virtual bool initialize(const QStringList &arguments, QString *error_message); virtual void extensionsInitialized(); - QString getWorkingDirectory(); + GitVersionControl *gitVersionControl() const; GitSettings settings() const; void setSettings(const GitSettings &s); - GitClient *gitClient() const; - GitVersionControl *versionControl() const; - -public slots: - void updateActions(); - bool editorAboutToClose(Core::IEditor *editor); + GitClient *gitClient() const; private slots: void diffCurrentFile(); void diffCurrentProject(); void submitEditorDiff(const QStringList &unstaged, const QStringList &staged); void submitCurrentLog(); - void statusFile(); - void statusProject(); + void statusRepository(); void logFile(); void blameFile(); void logProject(); @@ -127,9 +108,12 @@ private slots: void pull(); void push(); +protected: + virtual void updateActions(VCSBase::VCSBasePlugin::ActionState); + virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor); + private: bool isCommitEditorOpen() const; - QFileInfo currentFile() const; Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd); void cleanCommitMessageFile(); @@ -137,8 +121,7 @@ private: Core::ICore *m_core; Utils::ParameterAction *m_diffAction; Utils::ParameterAction *m_diffProjectAction; - Utils::ParameterAction *m_statusAction; - Utils::ParameterAction *m_statusProjectAction; + QAction *m_statusRepositoryAction; Utils::ParameterAction *m_logAction; Utils::ParameterAction *m_blameAction; Utils::ParameterAction *m_logProjectAction; @@ -159,9 +142,9 @@ private: QAction *m_stashPopAction; QAction *m_stashListAction; QAction *m_branchListAction; + QAction *m_menuAction; GitClient *m_gitClient; - GitVersionControl *m_versionControl; ChangeSelectionDialog *m_changeSelectionDialog; QString m_submitRepository; QStringList m_submitOrigCommitFiles; diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp index c64a683bea0622f92a9ed46e3c3358e3159556f1..e9e8ec96026d466c2d077ea1d943c8fe81d3fc91 100644 --- a/src/plugins/git/gitversioncontrol.cpp +++ b/src/plugins/git/gitversioncontrol.cpp @@ -44,19 +44,6 @@ QString GitVersionControl::name() const return QLatin1String("git"); } -bool GitVersionControl::isEnabled() const -{ - return m_enabled; -} - -void GitVersionControl::setEnabled(bool enabled) -{ - if (m_enabled != enabled) { - m_enabled = enabled; - emit enabledChanged(m_enabled); - } -} - bool GitVersionControl::supportsOperation(Operation operation) const { bool rc = false; diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h index 44598000638800f3ad57de9da892ffff926221e6..fc4c1f7a2fdbd8fb8992b970d1dbcfb5e4e7dd60 100644 --- a/src/plugins/git/gitversioncontrol.h +++ b/src/plugins/git/gitversioncontrol.h @@ -46,9 +46,6 @@ public: virtual QString name() const; - virtual bool isEnabled() const; - virtual void setEnabled(bool enabled); - bool managesDirectory(const QString &directory) const; virtual QString findTopLevelForDirectory(const QString &directory) const; diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index a80d8f559734d6bb7d8a00230e398ac0974a5cde..8e1e55ea73d4f44b8b492fec03ee738e9b6994b2 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -152,15 +152,6 @@ static const char * const CMD_ID_SEPARATOR1 = "Perforce.Separator1"; static const char * const CMD_ID_SEPARATOR2 = "Perforce.Separator2"; static const char * const CMD_ID_SEPARATOR3 = "Perforce.Separator3"; -//// -// CoreListener -//// - -bool CoreListener::editorAboutToClose(Core::IEditor *editor) -{ - return m_plugin->editorAboutToClose(editor); -} - //// // PerforcePlugin //// @@ -168,6 +159,7 @@ bool CoreListener::editorAboutToClose(Core::IEditor *editor) PerforcePlugin *PerforcePlugin::m_perforcePluginInstance = NULL; PerforcePlugin::PerforcePlugin() : + VCSBase::VCSBasePlugin(QLatin1String(Constants::PERFORCESUBMITEDITOR_KIND)), m_editAction(0), m_addAction(0), m_deleteAction(0), @@ -190,8 +182,7 @@ PerforcePlugin::PerforcePlugin() : m_submitActionTriggered(false), m_diffSelectedFiles(0), m_undoAction(0), - m_redoAction(0), - m_versionControl(0) + m_redoAction(0) { } @@ -201,14 +192,13 @@ static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = { Perforce::Constants::C_PERFORCESUBMITEDITOR }; -bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMessage) +bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * errorMessage) { - Q_UNUSED(arguments) - Q_UNUSED(errorMessage) - typedef VCSBase::VCSEditorFactory<PerforceEditor> PerforceEditorFactory; typedef VCSBase::VCSSubmitEditorFactory<PerforceSubmitEditor> PerforceSubmitEditorFactory; + VCSBase::VCSBasePlugin::initialize(new PerforceVersionControl(this)); + Core::ICore *core = Core::ICore::instance(); if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.perforce/Perforce.mimetypes.xml"), errorMessage)) return false; @@ -227,11 +217,6 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess for (int i = 0; i < editorCount; i++) addAutoReleasedObject(new PerforceEditorFactory(editorParameters + i, this, describeSlot)); - m_versionControl = new PerforceVersionControl(this); - addAutoReleasedObject(m_versionControl); - - addAutoReleasedObject(new CoreListener(this)); - //register actions Core::ActionManager *am = Core::ICore::instance()->actionManager(); @@ -242,10 +227,7 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess am->createMenu(QLatin1String(CMD_ID_PERFORCE_MENU)); mperforce->menu()->setTitle(tr("&Perforce")); mtools->addMenu(mperforce); - if (QAction *ma = mperforce->menu()->menuAction()) { - ma->setEnabled(m_versionControl->isEnabled()); - connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool))); - } + m_menuAction = mperforce->menu()->menuAction(); QList<int> globalcontext; globalcontext << Core::Constants::C_GLOBAL_ID; @@ -397,24 +379,12 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess m_redoAction = new QAction(tr("&Redo"), this); command = am->registerAction(m_redoAction, Core::Constants::REDO, perforcesubmitcontext); - connect(core, SIGNAL(contextChanged(Core::IContext *)), - this, SLOT(updateActions())); - - connect(core->fileManager(), SIGNAL(currentFileChanged(const QString &)), - this, SLOT(updateActions())); - return true; } void PerforcePlugin::extensionsInitialized() { m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance(); - if (m_projectExplorer) { - connect(m_projectExplorer, - SIGNAL(currentProjectChanged(ProjectExplorer::Project*)), - this, SLOT(updateActions())); - } - updateActions(); } void PerforcePlugin::openCurrentFile() @@ -455,7 +425,7 @@ void PerforcePlugin::revertCurrentFile() fcb.setModifiedReload(true); PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); if (!result2.error) - m_versionControl->emitFilesChanged(QStringList(fileName)); + perforceVersionControl()->emitFilesChanged(QStringList(fileName)); } void PerforcePlugin::diffCurrentFile() @@ -519,7 +489,7 @@ void PerforcePlugin::updateCheckout(const QStringList &dirs) const PerforceResponse resp = runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); if (!dirs.empty()) foreach(const QString &dir, dirs) - m_versionControl->emitRepositoryChanged(dir); + perforceVersionControl()->emitRepositoryChanged(dir); } void PerforcePlugin::printOpenedFileList() @@ -680,8 +650,11 @@ void PerforcePlugin::filelog(const QString &fileName) } } -void PerforcePlugin::updateActions() +void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as) { + if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction)) + return; + const QString fileName = currentFileName(); const QString baseName = fileName.isEmpty() ? fileName : QFileInfo(fileName).fileName(); @@ -993,19 +966,16 @@ bool PerforcePlugin::isCommitEditorOpen() const return !m_commitMessageFileName.isEmpty(); } -bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor) +bool PerforcePlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor) { - if (!editor || !isCommitEditorOpen()) + if (!isCommitEditorOpen()) return true; - Core::ICore *core = Core::ICore::instance(); - Core::IFile *fileIFace = editor->file(); - if (!fileIFace) - return true; - const PerforceSubmitEditor *perforceEditor = qobject_cast<PerforceSubmitEditor *>(editor); - if (!perforceEditor) + Core::IFile *fileIFace = submitEditor->file(); + const PerforceSubmitEditor *perforceEditor = qobject_cast<PerforceSubmitEditor *>(submitEditor); + if (!fileIFace || !perforceEditor) return true; - QFileInfo editorFile(fileIFace->fileName()); - QFileInfo changeFile(m_commitMessageFileName); + const QFileInfo editorFile(fileIFace->fileName()); + const QFileInfo changeFile(m_commitMessageFileName); if (editorFile.absoluteFilePath() == changeFile.absoluteFilePath()) { // Prompt the user. Force a prompt unless submit was actually invoked (that // is, the editor was closed or shutdown). @@ -1025,9 +995,10 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor) m_settings.setPromptToSubmit(wantsPrompt); m_settings.toSettings(Core::ICore::instance()->settings()); } - core->fileManager()->blockFileChange(fileIFace); + Core::FileManager *fileManager = Core::ICore::instance()->fileManager(); + fileManager->blockFileChange(fileIFace); fileIFace->save(); - core->fileManager()->unblockFileChange(fileIFace); + fileManager->unblockFileChange(fileIFace); if (answer == VCSBase::VCSBaseSubmitEditor::SubmitConfirmed) { QFile commitMessageFile(m_commitMessageFileName); if (!commitMessageFile.open(QIODevice::ReadOnly|QIODevice::Text)) { @@ -1071,7 +1042,7 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor) const QString output = QString::fromLocal8Bit(proc.readAll()); VCSBase::VCSBaseOutputWindow::instance()->append(output); if (output.contains(QLatin1String("Out of date files must be resolved or reverted)"))) { - QMessageBox::warning(editor->widget(), tr("Pending change"), tr("Could not submit the change, because your workspace was out of date. Created a pending submit instead.")); + QMessageBox::warning(submitEditor->widget(), tr("Pending change"), tr("Could not submit the change, because your workspace was out of date. Created a pending submit instead.")); } QApplication::restoreOverrideCursor(); } @@ -1219,5 +1190,10 @@ PerforcePlugin *PerforcePlugin::perforcePluginInstance() return m_perforcePluginInstance; } +PerforceVersionControl *PerforcePlugin::perforceVersionControl() const +{ + return static_cast<PerforceVersionControl *>(versionControl()); +} + Q_EXPORT_PLUGIN(PerforcePlugin) diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h index 275903a9c595c60bd56c77465412c1799673c069..2aba09194c0c03df54e4a2bf7733698f468f786b 100644 --- a/src/plugins/perforce/perforceplugin.h +++ b/src/plugins/perforce/perforceplugin.h @@ -34,8 +34,7 @@ #include <coreplugin/editormanager/ieditorfactory.h> #include <coreplugin/iversioncontrol.h> -#include <coreplugin/icorelistener.h> -#include <extensionsystem/iplugin.h> +#include <vcsbase/vcsbaseplugin.h> #include <projectexplorer/projectexplorer.h> #include <QtCore/QObject> @@ -56,19 +55,6 @@ namespace Perforce { namespace Internal { 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 { @@ -78,7 +64,7 @@ struct PerforceResponse QString message; }; -class PerforcePlugin : public ExtensionSystem::IPlugin +class PerforcePlugin : public VCSBase::VCSBasePlugin { Q_OBJECT @@ -94,8 +80,6 @@ public: 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()); @@ -130,11 +114,14 @@ private slots: void filelogCurrentFile(); void filelog(); - void updateActions(); void submitCurrentLog(); void printPendingChanges(); void slotDiff(const QStringList &files); +protected: + virtual void updateActions(VCSBase::VCSBasePlugin::ActionState); + virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor); + private: QStringList environment() const; @@ -163,6 +150,7 @@ private: bool isCommitEditorOpen() const; void updateCheckout(const QStringList &dirs = QStringList()); + inline PerforceVersionControl *perforceVersionControl() const; ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer; @@ -191,12 +179,11 @@ private: QAction *m_undoAction; QAction *m_redoAction; - + QAction *m_menuAction; static PerforcePlugin *m_perforcePluginInstance; QString pendingChangesData(); - PerforceVersionControl *m_versionControl; PerforceSettings m_settings; }; diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp index ad915b2a2085f42ff63aec3e0da6fd8fc7d1d073..f5424082810328d52e7abcc168b5fb4ce4df4d78 100644 --- a/src/plugins/perforce/perforceversioncontrol.cpp +++ b/src/plugins/perforce/perforceversioncontrol.cpp @@ -38,25 +38,12 @@ PerforceVersionControl::PerforceVersionControl(PerforcePlugin *plugin) : m_plugin(plugin) { } - + QString PerforceVersionControl::name() const { return QLatin1String("perforce"); } -bool PerforceVersionControl::isEnabled() const -{ - return m_enabled; -} - -void PerforceVersionControl::setEnabled(bool enabled) -{ - if (m_enabled != enabled) { - m_enabled = enabled; - emit enabledChanged(m_enabled); - } -} - bool PerforceVersionControl::supportsOperation(Operation operation) const { bool rc = true; diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h index dd385061cbca5e80267a4ec43f54712381ca94bc..c6f5e1a4d6892b6c2f148697d1195578fc916e10 100644 --- a/src/plugins/perforce/perforceversioncontrol.h +++ b/src/plugins/perforce/perforceversioncontrol.h @@ -45,9 +45,6 @@ public: virtual QString name() const; - virtual bool isEnabled() const; - virtual void setEnabled(bool enabled); - bool managesDirectory(const QString &directory) const; virtual QString findTopLevelForDirectory(const QString &directory) const; @@ -59,9 +56,6 @@ public: void emitRepositoryChanged(const QString &s); void emitFilesChanged(const QStringList &l); -signals: - void enabledChanged(bool); - private: bool m_enabled; PerforcePlugin *m_plugin; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index c15c303e3aea1fb6e7f621034ee95a4552cd31cd..dd4020baaa16b1ca8e9b077f91ee732f1fd8f2ca 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1323,13 +1323,6 @@ void ProjectExplorerPlugin::setCurrent(Project *project, QString filePath, Node if (projectChanged) { if (debug) qDebug() << "ProjectExplorer - currentProjectChanged(" << (project ? project->name() : "0") << ")"; - // Enable the right VCS - if (const Core::IFile *projectFile = project ? project->file() : static_cast<const Core::IFile *>(0)) { - core->vcsManager()->setVCSEnabled(QFileInfo(projectFile->fileName()).absolutePath()); - } else { - core->vcsManager()->setAllVCSEnabled(); - } - emit currentProjectChanged(project); updateActions(); } diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp index ff0e0f1c81e872b85872d5990ded86f5089870ac..901b3f115cec7c13f9c5e9cf6cc63b4628948436 100644 --- a/src/plugins/subversion/subversioncontrol.cpp +++ b/src/plugins/subversion/subversioncontrol.cpp @@ -44,19 +44,6 @@ QString SubversionControl::name() const return QLatin1String("subversion"); } -bool SubversionControl::isEnabled() const -{ - return m_enabled; -} - -void SubversionControl::setEnabled(bool enabled) -{ - if (m_enabled != enabled) { - m_enabled = enabled; - emit enabledChanged(m_enabled); - } -} - bool SubversionControl::supportsOperation(Operation operation) const { bool rc = true; diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h index 325cfd10989bb9a4cb435d633c2d911125695852..6e1f0d3866116f147a5dacd8107bbe622f588990 100644 --- a/src/plugins/subversion/subversioncontrol.h +++ b/src/plugins/subversion/subversioncontrol.h @@ -45,9 +45,6 @@ public: explicit SubversionControl(SubversionPlugin *plugin); virtual QString name() const; - virtual bool isEnabled() const; - virtual void setEnabled(bool enabled); - virtual bool managesDirectory(const QString &directory) const; virtual QString findTopLevelForDirectory(const QString &directory) const; @@ -59,9 +56,6 @@ public: void emitRepositoryChanged(const QString &); void emitFilesChanged(const QStringList &); -signals: - void enabledChanged(bool); - private: bool m_enabled; SubversionPlugin *m_plugin; diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 0060e0239535c3ca1edee3e7e6a6675fa2ac1b90..7c479121f2f4d08ca37f353708c30258eefd69fb 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -180,8 +180,8 @@ static inline QStringList svnDirectories() SubversionPlugin *SubversionPlugin::m_subversionPluginInstance = 0; SubversionPlugin::SubversionPlugin() : + VCSBase::VCSBasePlugin(QLatin1String(Subversion::Constants::SUBVERSIONCOMMITEDITOR_KIND)), m_svnDirectories(svnDirectories()), - m_versionControl(0), m_projectExplorer(0), m_addAction(0), m_deleteAction(0), @@ -199,6 +199,7 @@ SubversionPlugin::SubversionPlugin() : m_submitDiffAction(0), m_submitUndoAction(0), m_submitRedoAction(0), + m_menuAction(0), m_submitActionTriggered(false) { } @@ -237,10 +238,8 @@ static inline Core::Command *createSeparator(QObject *parent, return ami->registerAction(tmpaction, id, globalcontext); } -bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMessage) +bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *errorMessage) { - Q_UNUSED(arguments) - typedef VCSBase::VCSSubmitEditorFactory<SubversionSubmitEditor> SubversionSubmitEditorFactory; typedef VCSBase::VCSEditorFactory<SubversionEditor> SubversionEditorFactory; using namespace Constants; @@ -248,19 +247,17 @@ bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMe using namespace Core::Constants; using namespace ExtensionSystem; + VCSBase::VCSBasePlugin::initialize(new SubversionControl(this)); + m_subversionPluginInstance = this; Core::ICore *core = Core::ICore::instance(); if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.subversion/Subversion.mimetypes.xml"), errorMessage)) return false; - m_versionControl = new SubversionControl(this); - addAutoReleasedObject(m_versionControl); - if (QSettings *settings = core->settings()) m_settings.fromSettings(settings); - addAutoReleasedObject(new CoreListener(this)); addAutoReleasedObject(new SettingsPage); addAutoReleasedObject(new SubversionSubmitEditorFactory(&submitParameters)); @@ -280,11 +277,7 @@ bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMe ami->createMenu(QLatin1String(CMD_ID_SUBVERSION_MENU)); subversionMenu->menu()->setTitle(tr("&Subversion")); toolsContainer->addMenu(subversionMenu); - if (QAction *ma = subversionMenu->menu()->menuAction()) { - ma->setEnabled(m_versionControl->isEnabled()); - connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool))); - } - + m_menuAction = subversionMenu->menu()->menuAction(); QList<int> globalcontext; globalcontext << core->uniqueIDManager()->uniqueIdentifier(C_GLOBAL); @@ -396,29 +389,21 @@ bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMe m_submitRedoAction = new QAction(tr("&Redo"), this); command = ami->registerAction(m_submitRedoAction, Core::Constants::REDO, svncommitcontext); - connect(Core::ICore::instance(), SIGNAL(contextChanged(Core::IContext *)), this, SLOT(updateActions())); - return true; } void SubversionPlugin::extensionsInitialized() { m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance(); - if (m_projectExplorer) { - connect(m_projectExplorer, - SIGNAL(currentProjectChanged(ProjectExplorer::Project*)), - m_subversionPluginInstance, SLOT(updateActions())); - } - updateActions(); } -bool SubversionPlugin::editorAboutToClose(Core::IEditor *iEditor) +bool SubversionPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor) { - if ( !iEditor || !isCommitEditorOpen() || qstrcmp(Constants::SUBVERSIONCOMMITEDITOR, iEditor->kind())) + if (!isCommitEditorOpen()) return true; - Core::IFile *fileIFace = iEditor->file(); - const SubversionSubmitEditor *editor = qobject_cast<SubversionSubmitEditor *>(iEditor); + Core::IFile *fileIFace = submitEditor->file(); + const SubversionSubmitEditor *editor = qobject_cast<SubversionSubmitEditor *>(submitEditor); if (!fileIFace || !editor) return true; @@ -511,8 +496,11 @@ SubversionSubmitEditor *SubversionPlugin::openSubversionSubmitEditor(const QStri return submitEditor; } -void SubversionPlugin::updateActions() +void SubversionPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as) { + if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction)) + return; + m_diffProjectAction->setEnabled(true); m_commitAllAction->setEnabled(true); m_statusAction->setEnabled(true); @@ -574,7 +562,7 @@ void SubversionPlugin::revertCurrentFile() const SubversionResponse revertResponse = runSvn(args, subversionShortTimeOut, true); if (!revertResponse.error) { fcb.setModifiedReload(true); - m_versionControl->emitFilesChanged(QStringList(file)); + subVersionControl()->emitFilesChanged(QStringList(file)); } } @@ -752,9 +740,10 @@ void SubversionPlugin::updateProject() args.push_back(QLatin1String(nonInteractiveOptionC)); args.append(topLevels); const SubversionResponse response = runSvn(args, subversionLongTimeOut, true); - if (!response.error) + if (!response.error) { foreach(const QString &repo, topLevels) - m_versionControl->emitRepositoryChanged(repo); + subVersionControl()->emitRepositoryChanged(repo); + } } void SubversionPlugin::annotateCurrentFile() @@ -1086,4 +1075,9 @@ QString SubversionPlugin::findTopLevelForDirectoryI(const QString &directory) co return QString(); } +SubversionControl *SubversionPlugin::subVersionControl() const +{ + return static_cast<SubversionControl *>(versionControl()); +} + Q_EXPORT_PLUGIN(SubversionPlugin) diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h index 6e3dab7e5d35235893bd2638fc755dfb01077589..0e6450b3ef3f9ccd8449dc1b66ba5563a64baed9 100644 --- a/src/plugins/subversion/subversionplugin.h +++ b/src/plugins/subversion/subversionplugin.h @@ -32,8 +32,7 @@ #include "subversionsettings.h" -#include <coreplugin/icorelistener.h> -#include <extensionsystem/iplugin.h> +#include <vcsbase/vcsbaseplugin.h> QT_BEGIN_NAMESPACE class QDir; @@ -43,6 +42,7 @@ QT_END_NAMESPACE namespace Core { class IVersionControl; + class IEditor; } namespace Utils { class ParameterAction; @@ -52,6 +52,10 @@ namespace ProjectExplorer { class ProjectExplorerPlugin; } +namespace VCSBase { + class VCSBaseSubmitEditor; +} + namespace Subversion { namespace Internal { @@ -67,7 +71,7 @@ struct SubversionResponse QString message; }; -class SubversionPlugin : public ExtensionSystem::IPlugin +class SubversionPlugin : public VCSBase::VCSBasePlugin { Q_OBJECT @@ -77,7 +81,6 @@ public: bool initialize(const QStringList &arguments, QString *error_message); void extensionsInitialized(); - bool editorAboutToClose(Core::IEditor *editor); void svnDiff(const QStringList &files, QString diffname = QString()); @@ -95,7 +98,6 @@ public: static SubversionPlugin *subversionPluginInstance(); private slots: - void updateActions(); void addCurrentFile(); void deleteCurrentFile(); void revertCurrentFile(); @@ -112,6 +114,10 @@ private slots: void submitCurrentLog(); void diffFiles(const QStringList &); +protected: + virtual void updateActions(VCSBase::VCSBasePlugin::ActionState); + virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor); + private: inline bool isCommitEditorOpen() const; QString currentFileName() const; @@ -128,11 +134,11 @@ private: void startCommit(const QStringList &files); bool commit(const QString &messageFile, const QStringList &subVersionFileList); void cleanCommitMessageFile(); + inline SubversionControl *subVersionControl() const; const QStringList m_svnDirectories; SubversionSettings m_settings; - SubversionControl *m_versionControl; QString m_commitMessageFileName; ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer; @@ -154,32 +160,12 @@ private: QAction *m_submitDiffAction; QAction *m_submitUndoAction; QAction *m_submitRedoAction; + QAction *m_menuAction; bool m_submitActionTriggered; static SubversionPlugin *m_subversionPluginInstance; }; -// Just a proxy for SubversionPlugin -class CoreListener : public Core::ICoreListener -{ - Q_OBJECT -public: - CoreListener(SubversionPlugin *plugin) : m_plugin(plugin) { } - - // Start commit when submit editor closes - bool editorAboutToClose(Core::IEditor *editor) { - return m_plugin->editorAboutToClose(editor); - } - - // TODO: how to handle that ??? - bool coreAboutToClose() { - return true; - } - -private: - SubversionPlugin *m_plugin; -}; - } // namespace Subversion } // namespace Internal diff --git a/src/plugins/vcsbase/basevcseditorfactory.cpp b/src/plugins/vcsbase/basevcseditorfactory.cpp index 775777e6e0f1b864d7dc7528df202fa418692f18..633d2e172278dc3eb1276feba22f5f2a3ea954dd 100644 --- a/src/plugins/vcsbase/basevcseditorfactory.cpp +++ b/src/plugins/vcsbase/basevcseditorfactory.cpp @@ -28,7 +28,6 @@ **************************************************************************/ #include "basevcseditorfactory.h" -#include "vcsbaseplugin.h" #include "vcsbaseeditor.h" #include <coreplugin/editormanager/editormanager.h> diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro index 45461211b95ec5489af859641f0c200aa3d0c66e..6dec3b25850bf7d8c6a263e6a8d558b15302cdda 100644 --- a/src/plugins/vcsbase/vcsbase.pro +++ b/src/plugins/vcsbase/vcsbase.pro @@ -5,6 +5,8 @@ include(../../qtcreatorplugin.pri) include(vcsbase_dependencies.pri) HEADERS += vcsbase_global.h \ vcsbaseconstants.h \ + vcsplugin.h \ + corelistener.h \ vcsbaseplugin.h \ baseannotationhighlighter.h \ diffhighlighter.h \ @@ -25,7 +27,9 @@ HEADERS += vcsbase_global.h \ basecheckoutwizardpage.h \ vcsbaseoutputwindow.h -SOURCES += vcsbaseplugin.cpp \ +SOURCES += vcsplugin.cpp \ + vcsbaseplugin.cpp \ + corelistener.cpp \ baseannotationhighlighter.cpp \ diffhighlighter.cpp \ vcsbasetextdocument.cpp \ diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 4536445054bfd337fd0fb0c53d8e099e8dad65a6..abd4287966a1dffa1504a8d872f1d1a2b90b9f12 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -630,5 +630,41 @@ bool VCSBaseEditor::gotoLineOfEditor(Core::IEditor *e, int lineNumber) return false; } +// Return source file or directory string depending on parameters +// ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file'). +QString VCSBaseEditor::getSource(const QString &workingDirectory, + const QString &fileName) +{ + if (fileName.isEmpty()) + return workingDirectory; + + QString rc = workingDirectory; + const QChar slash = QLatin1Char('/'); + if (!rc.isEmpty() && !(rc.endsWith(slash) || rc.endsWith(QLatin1Char('\\')))) + rc += slash; + rc += fileName; + return rc; +} + +QString VCSBaseEditor::getSource(const QString &workingDirectory, + const QStringList &fileNames) +{ + return fileNames.size() == 1 ? + getSource(workingDirectory, fileNames.front()) : + workingDirectory; +} + +QString VCSBaseEditor::getTitleId(const QString &workingDirectory, const QStringList &fileNames) +{ + switch (fileNames.size()) { + case 0: + return workingDirectory; + case 1: + return fileNames.front(); + default: + break; + } + return fileNames.join(QLatin1String(", ")); +} } // namespace VCSBase diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index 286f950cd62bac88e3b9fc6b80789bd68ff544fd..d272a4cba0c94b46fe720beca778dd880fb57c75 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -128,6 +128,15 @@ public: //Helper to go to line of editor if it is a text editor static bool gotoLineOfEditor(Core::IEditor *e, int lineNumber); + // Convenience functions to determine the source to pass on to a diff + // editor if one has a call consisting of working directory and file arguments. + // ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file'). + static QString getSource(const QString &workingDirectory, const QString &fileName); + static QString getSource(const QString &workingDirectory, const QStringList &fileNames); + // Convenience functions to determine an title/id to identify the editor + // from the arguments (','-joined arguments or directory). + static QString getTitleId(const QString &workingDirectory, const QStringList &fileNames); + signals: void describeRequested(const QString &source, const QString &change); diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index 911fc2580c70c2d55335588260ac97b78b1aad95..78c72de5657a20e0c8fc574fd1fd18e6460113ce 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -28,97 +28,420 @@ **************************************************************************/ #include "vcsbaseplugin.h" -#include "diffhighlighter.h" -#include "vcsbasesettingspage.h" -#include "nicknamedialog.h" -#include "vcsbaseoutputwindow.h" +#include "vcsbasesubmiteditor.h" +#include "vcsplugin.h" +#include "corelistener.h" #include <coreplugin/icore.h> -#include <coreplugin/coreconstants.h> -#include <coreplugin/uniqueidmanager.h> -#include <coreplugin/mimedatabase.h> +#include <coreplugin/ifile.h> +#include <coreplugin/iversioncontrol.h> +#include <coreplugin/filemanager.h> +#include <coreplugin/vcsmanager.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/project.h> +#include <utils/qtcassert.h> -#include <QtCore/QtPlugin> #include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QSharedData> + +#include <QtGui/QAction> + +enum { debug = 0 }; namespace VCSBase { + namespace Internal { -VCSBasePlugin *VCSBasePlugin::m_instance = 0; +// Internal state created by the state listener and +// VCSBasePluginState. + +struct State { + void clearFile(); + void clearProject(); + inline void clear(); + + bool equals(const State &rhs) const; -VCSBasePlugin::VCSBasePlugin() : - m_settingsPage(0), - m_nickNameModel(0) + inline bool hasFile() const { return !currentFile.isEmpty(); } + inline bool hasProject() const { return !currentProjectPath.isEmpty(); } + inline bool isEmpty() const { return !hasFile() && !hasProject(); } + + QString currentFile; + QString currentFileName; + QString currentFileDirectory; + QString currentFileTopLevel; + + QString currentProjectPath; + QString currentProjectName; + QString currentProjectTopLevel; +}; + +void State::clearFile() { - m_instance = this; + currentFile.clear(); + currentFileName.clear(); + currentFileDirectory.clear(); + currentFileTopLevel.clear(); } -VCSBasePlugin::~VCSBasePlugin() +void State::clearProject() { - m_instance = 0; + currentProjectPath.clear(); + currentProjectName.clear(); + currentProjectTopLevel.clear(); } -bool VCSBasePlugin::initialize(const QStringList &arguments, QString *errorMessage) +void State::clear() { - Q_UNUSED(arguments) - Q_UNUSED(errorMessage) + clearFile(); + clearProject(); +} + +bool State::equals(const State &rhs) const +{ + return currentFile == rhs.currentFile + && currentFileName == rhs.currentFileName + && currentFileTopLevel == rhs.currentFileTopLevel + && currentProjectPath == rhs.currentProjectPath + && currentProjectName == rhs.currentProjectName + && currentProjectTopLevel == rhs.currentProjectTopLevel; +} +QDebug operator<<(QDebug in, const State &state) +{ + QDebug nospace = in.nospace(); + nospace << "State: "; + if (state.isEmpty()) { + nospace << "<empty>"; + } else { + if (state.hasFile()) { + nospace << "File=" << state.currentFile + << ',' << state.currentFileTopLevel; + } else { + nospace << "<no file>"; + } + nospace << '\n'; + if (state.hasProject()) { + nospace << " Project=" << state.currentProjectName + << ',' << state.currentProjectPath + << ',' << state.currentProjectTopLevel; + + } else { + nospace << "<no project>"; + } + nospace << '\n'; + } + return in; +} + +// StateListener: Connects to the relevant signals, tries to find version +// controls and emits signals to the plugin instances. + +class StateListener : public QObject { + Q_OBJECT +public: + explicit StateListener(QObject *parent); + +signals: + void stateChanged(const VCSBase::Internal::State &s, Core::IVersionControl *vc); + +private slots: + void slotStateChanged(); +}; + +StateListener::StateListener(QObject *parent) : + QObject(parent) +{ Core::ICore *core = Core::ICore::instance(); - if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/vcsbase/VCSBase.mimetypes.xml"), errorMessage)) - return false; + connect(core, SIGNAL(contextChanged(Core::IContext *)), + this, SLOT(slotStateChanged())); + connect(core->fileManager(), SIGNAL(currentFileChanged(QString)), + this, SLOT(slotStateChanged())); - m_settingsPage = new VCSBaseSettingsPage; - addAutoReleasedObject(m_settingsPage); - addAutoReleasedObject(VCSBaseOutputWindow::instance()); - connect(m_settingsPage, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)), - this, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings))); - connect(m_settingsPage, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)), - this, SLOT(slotSettingsChanged())); - slotSettingsChanged(); - return true; + if (ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance()) + connect(pe, SIGNAL(currentProjectChanged(ProjectExplorer::Project*)), + this, SLOT(slotStateChanged())); } -void VCSBasePlugin::extensionsInitialized() +void StateListener::slotStateChanged() { + const ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance(); + const Core::ICore *core = Core::ICore::instance(); + Core::VCSManager *vcsManager = core->vcsManager(); + + // Get the current file. Are we on a temporary submit editor or something? Ignore. + State state; + state.currentFile = core->fileManager()->currentFile(); + if (!state.currentFile.isEmpty() && state.currentFile.startsWith(QDir::tempPath())) + state.currentFile.clear(); + // Get the file and its control. Do not use the file unless we find one + Core::IVersionControl *fileControl = 0; + if (!state.currentFile.isEmpty()) { + const QFileInfo fi(state.currentFile); + state.currentFileDirectory = fi.absolutePath(); + state.currentFileName = fi.fileName(); + fileControl = vcsManager->findVersionControlForDirectory(state.currentFileDirectory, + &state.currentFileTopLevel); + if (!fileControl) + state.clearFile(); + } + // Check for project, find the control + Core::IVersionControl *projectControl = 0; + if (const ProjectExplorer::Project *currentProject = pe->currentProject()) { + state.currentProjectPath = QFileInfo(currentProject->file()->fileName()).absolutePath(); + state.currentProjectName = currentProject->name(); + projectControl = vcsManager->findVersionControlForDirectory(state.currentProjectPath, + &state.currentProjectTopLevel); + if (projectControl) { + // If we have both, let the file's one take preference + if (fileControl && projectControl != fileControl) { + state.clearProject(); + } + } else { + state.clearProject(); // No control found + } + } + // Assemble state and emit signal. + Core::IVersionControl *vc = state.currentFile.isEmpty() ? projectControl : fileControl; + if (debug) + qDebug() << state << (vc ? vc->name() : QString(QLatin1String("No version control"))); + emit stateChanged(state, vc); } -VCSBasePlugin *VCSBasePlugin::instance() +} // namespace Internal + +class VCSBasePluginStateData : public QSharedData { +public: + Internal::State m_state; +}; + +VCSBasePluginState::VCSBasePluginState() : data(new VCSBasePluginStateData) { - return m_instance; } -VCSBaseSettings VCSBasePlugin::settings() const +VCSBasePluginState::VCSBasePluginState(const VCSBasePluginState &rhs) : data(rhs.data) { - return m_settingsPage->settings(); } -/* Delayed creation/update of the nick name model. */ -QStandardItemModel *VCSBasePlugin::nickNameModel() +VCSBasePluginState &VCSBasePluginState::operator=(const VCSBasePluginState &rhs) { - if (!m_nickNameModel) { - m_nickNameModel = NickNameDialog::createModel(this); - populateNickNameModel(); - } - return m_nickNameModel; + if (this != &rhs) + data.operator=(rhs.data); + return *this; +} + +VCSBasePluginState::~VCSBasePluginState() +{ +} + +QString VCSBasePluginState::currentFile() const +{ + return data->m_state.currentFile; +} + +QString VCSBasePluginState::currentFileName() const +{ + return data->m_state.currentFileName; +} + +QString VCSBasePluginState::currentFileTopLevel() const +{ + return data->m_state.currentFileTopLevel; +} + +QString VCSBasePluginState::currentFileDirectory() const +{ + return data->m_state.currentFileDirectory; +} + +QString VCSBasePluginState::relativeCurrentFile() const +{ + QTC_ASSERT(hasFile(), return QString()) + return QDir(data->m_state.currentFileTopLevel).relativeFilePath(data->m_state.currentFile); +} + +QString VCSBasePluginState::currentProjectPath() const +{ + return data->m_state.currentProjectPath; +} + +QString VCSBasePluginState::currentProjectName() const +{ + return data->m_state.currentProjectName; +} + +QString VCSBasePluginState::currentProjectTopLevel() const +{ + return data->m_state.currentProjectTopLevel; +} + +QStringList VCSBasePluginState::relativeCurrentProject() const +{ + QStringList rc; + QTC_ASSERT(hasProject(), return rc) + if (data->m_state.currentProjectTopLevel != data->m_state.currentProjectPath) + rc.append(QDir(data->m_state.currentProjectTopLevel).relativeFilePath(data->m_state.currentProjectPath)); + return rc; } -void VCSBasePlugin::populateNickNameModel() +bool VCSBasePluginState::hasTopLevel() const { - QString errorMessage; - if (!NickNameDialog::populateModelFromMailCapFile(settings().nickNameMailMap, - m_nickNameModel, - &errorMessage)) { - qWarning("%s", qPrintable(errorMessage)); + return data->m_state.hasFile() || data->m_state.hasProject(); +} + +QString VCSBasePluginState::topLevel() const +{ + return hasFile() ? data->m_state.currentFileTopLevel : data->m_state.currentProjectTopLevel; +} + +bool VCSBasePluginState::equals(const Internal::State &rhs) const +{ + return data->m_state.equals(rhs); +} + +bool VCSBasePluginState::equals(const VCSBasePluginState &rhs) const +{ + return equals(rhs.data->m_state); +} + +void VCSBasePluginState::clear() +{ + data->m_state.clear(); +} + +void VCSBasePluginState::setState(const Internal::State &s) +{ + data->m_state = s; +} + +bool VCSBasePluginState::isEmpty() const +{ + return data->m_state.isEmpty(); +} + +bool VCSBasePluginState::hasFile() const +{ + return data->m_state.hasFile(); +} + +bool VCSBasePluginState::hasProject() const +{ + return data->m_state.hasProject(); +} + +VCSBASE_EXPORT QDebug operator<<(QDebug in, const VCSBasePluginState &state) +{ + in << state.data->m_state; + return in; +} + +// VCSBasePlugin +struct VCSBasePluginPrivate { + explicit VCSBasePluginPrivate(const QString &submitEditorKind); + + const QString m_submitEditorKind; + Core::IVersionControl *m_versionControl; + VCSBasePluginState m_state; + int m_actionState; + + static Internal::StateListener *m_listener; +}; + +VCSBasePluginPrivate::VCSBasePluginPrivate(const QString &submitEditorKind) : + m_submitEditorKind(submitEditorKind), + m_versionControl(0), + m_actionState(-1) +{ +} + +Internal::StateListener *VCSBasePluginPrivate::m_listener = 0; + +VCSBasePlugin::VCSBasePlugin(const QString &submitEditorKind) : + d(new VCSBasePluginPrivate(submitEditorKind)) +{ +} + +VCSBasePlugin::~VCSBasePlugin() +{ + delete d; +} + +void VCSBasePlugin::initialize(Core::IVersionControl *vc) +{ + d->m_versionControl = vc; + addAutoReleasedObject(vc); + + Internal::VCSPlugin *plugin = Internal::VCSPlugin::instance(); + connect(plugin->coreListener(), SIGNAL(submitEditorAboutToClose(VCSBaseSubmitEditor*,bool*)), + this, SLOT(slotSubmitEditorAboutToClose(VCSBaseSubmitEditor*,bool*))); + // First time: create new listener + if (!VCSBasePluginPrivate::m_listener) + VCSBasePluginPrivate::m_listener = new Internal::StateListener(plugin); + connect(VCSBasePluginPrivate::m_listener, + SIGNAL(stateChanged(VCSBase::Internal::State, Core::IVersionControl*)), + this, + SLOT(slotStateChanged(VCSBase::Internal::State,Core::IVersionControl*))); +} + +void VCSBasePlugin::slotSubmitEditorAboutToClose(VCSBaseSubmitEditor *submitEditor, bool *result) +{ + if (debug) + qDebug() << this << d->m_submitEditorKind << "Closing submit editor" << submitEditor << submitEditor->kind(); + if (submitEditor->kind() == d->m_submitEditorKind) + *result = submitEditorAboutToClose(submitEditor); +} + +Core::IVersionControl *VCSBasePlugin::versionControl() const +{ + return d->m_versionControl; +} + +void VCSBasePlugin::slotStateChanged(const VCSBase::Internal::State &newInternalState, Core::IVersionControl *vc) +{ + if (vc == d->m_versionControl) { + // We are directly affected: Change state + if (!d->m_state.equals(newInternalState)) { + d->m_state.setState(newInternalState); + updateActions(VCSEnabled); } + } else { + // Some other VCS plugin or state changed: Reset us to empty state. + const ActionState newActionState = vc ? OtherVCSEnabled : NoVCSEnabled; + if (d->m_actionState != newActionState || !d->m_state.isEmpty()) { + d->m_actionState = newActionState; + const VCSBasePluginState emptyState; + d->m_state = emptyState; + updateActions(newActionState); + } + } } -void VCSBasePlugin::slotSettingsChanged() +const VCSBasePluginState &VCSBasePlugin::currentState() const { - if (m_nickNameModel) - populateNickNameModel(); + return d->m_state; +} + +bool VCSBasePlugin::enableMenuAction(ActionState as, QAction *menuAction) +{ + if (debug) + qDebug() << "enableMenuAction" << menuAction->text() << as; + switch (as) { + case VCSBase::VCSBasePlugin::NoVCSEnabled: + menuAction->setVisible(true); + menuAction->setEnabled(false); + return false; + case VCSBase::VCSBasePlugin::OtherVCSEnabled: + menuAction->setVisible(false); + return false; + case VCSBase::VCSBasePlugin::VCSEnabled: + menuAction->setVisible(true); + menuAction->setEnabled(true); + break; + } + return true; } -} // namespace Internal } // namespace VCSBase -Q_EXPORT_PLUGIN(VCSBase::Internal::VCSBasePlugin) +#include "vcsbaseplugin.moc" diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h index 136755955992eedb4b5523e443418943eb6ee1a9..e1d1d9bb618c0e70ba025efb2fe54d763ae22995 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.h +++ b/src/plugins/vcsbase/vcsbaseplugin.h @@ -30,56 +30,146 @@ #ifndef VCSBASEPLUGIN_H #define VCSBASEPLUGIN_H +#include "vcsbase_global.h" + #include <extensionsystem/iplugin.h> -#include <QtCore/QObject> +#include <QSharedDataPointer> QT_BEGIN_NAMESPACE -class QStandardItemModel; +class QAction; QT_END_NAMESPACE -namespace VCSBase { +namespace Core { + class IVersionControl; +} + +namespace VCSBase { namespace Internal { + struct State; +} + +class VCSBaseSubmitEditor; +struct VCSBasePluginPrivate; +class VCSBasePluginStateData; +class VCSBasePlugin; + +/* VCSBasePlugin and VCSBasePluginState: Provide a base class for + * VCS plugins. It mainly takes care of maintaining the + * VCS-relevant state of Qt Creator which is a tuple of + * + * 1) Current file and it's version system control/top level + * 2) Current project and it's version system control/top level + * + * (reflected in VCSBasePluginState). The plugin connects to the + * relevant change signals in Qt Creator and calls the virtual + * updateActions() for the plugins to update their menu actions + * according to the new state. This is done centrally to avoid + * single plugins repeatedly invoking searches/QFileInfo on files, + * etc. + * + * If current file/project are managed + * by different version controls, the project is discarded and only + * the current file is taken into account, allowing to do a diff + * also when the project of a file is not opened. + * + * When triggering an action, a copy of the state should be made to + * keep it, as it may rapidly change due to context changes, etc. + * + * The class also detects the VCS plugin submit editor closing and calls + * the virtual submitEditorAboutToClose() to trigger the submit process. */ + +class VCSBASE_EXPORT VCSBasePluginState +{ +public: + VCSBasePluginState(); + VCSBasePluginState(const VCSBasePluginState &); + VCSBasePluginState &operator=(const VCSBasePluginState &); + ~VCSBasePluginState(); + + void clear(); + + bool isEmpty() const; + bool hasFile() const; + bool hasProject() const; + bool hasTopLevel() const; + + // Current file. + QString currentFile() const; + QString currentFileName() const; + QString currentFileDirectory() const; + QString currentFileTopLevel() const; + // Convenience: Returns file relative to top level. + QString relativeCurrentFile() const; + + // Current project. + QString currentProjectPath() const; + QString currentProjectName() const; + QString currentProjectTopLevel() const; + /* Convenience: Returns project path relative to top level if it + * differs from top level (else empty()) as an argument list to do + * eg a 'vcs diff <args>' */ + QStringList relativeCurrentProject() const; + + // Top level directory for actions on the top level. Preferably + // the file one. + QString topLevel() const; + + bool equals(const VCSBasePluginState &rhs) const; + + friend VCSBASE_EXPORT QDebug operator<<(QDebug in, const VCSBasePluginState &state); -struct VCSBaseSettings; -class VCSBaseSettingsPage; +private: + friend class VCSBasePlugin; + bool equals(const Internal::State &s) const; + void setState(const Internal::State &s); -class VCSBasePlugin : public ExtensionSystem::IPlugin + QSharedDataPointer<VCSBasePluginStateData> data; +}; + +VCSBASE_EXPORT QDebug operator<<(QDebug in, const VCSBasePluginState &state); + +inline bool operator==(const VCSBasePluginState &s1, const VCSBasePluginState &s2) +{ return s1.equals(s2); } +inline bool operator!=(const VCSBasePluginState &s1, const VCSBasePluginState &s2) +{ return !s1.equals(s2); } + +class VCSBASE_EXPORT VCSBasePlugin : public ExtensionSystem::IPlugin { Q_OBJECT -public: - VCSBasePlugin(); - ~VCSBasePlugin(); +protected: + explicit VCSBasePlugin(const QString &submitEditorKind); - bool initialize(const QStringList &arguments, QString *error_message); + void initialize(Core::IVersionControl *vc); + Core::IVersionControl *versionControl() const; - void extensionsInitialized(); +public: + virtual ~VCSBasePlugin(); - static VCSBasePlugin *instance(); + const VCSBasePluginState ¤tState() const; - VCSBaseSettings settings() const; +protected: + enum ActionState { NoVCSEnabled, OtherVCSEnabled, VCSEnabled }; - // Model of user nick names used for the submit - // editor. Stored centrally here to achieve delayed - // initialization and updating on settings change. - QStandardItemModel *nickNameModel(); + // Implement to enable the plugin menu actions according to state. + virtual void updateActions(ActionState as) = 0; + // Implement to start the submit process. + virtual bool submitEditorAboutToClose(VCSBaseSubmitEditor *submitEditor) = 0; -signals: - void settingsChanged(const VCSBase::Internal::VCSBaseSettings& s); + // A helper to enable the VCS menu action according to state: + // NoVCSEnabled->(visible,disabled), OtherVCSEnabled->(invisible), else + // enabled. Returns whether actions should be set up further. + static bool enableMenuAction(ActionState as, QAction *in); private slots: - void slotSettingsChanged(); + void slotSubmitEditorAboutToClose(VCSBaseSubmitEditor *submitEditor, bool *result); + void slotStateChanged(const VCSBase::Internal::State &s, Core::IVersionControl *vc); private: - void populateNickNameModel(); - - static VCSBasePlugin *m_instance; - VCSBaseSettingsPage *m_settingsPage; - QStandardItemModel *m_nickNameModel; + VCSBasePluginPrivate *d; }; -} // namespace Internal } // namespace VCSBase #endif // VCSBASEPLUGIN_H diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 82efcb537b528c898924c014756a3d3e36753a3b..dba5cc254180574bbb6c784a1ffe0ae52528a471 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -29,7 +29,7 @@ #include "vcsbasesubmiteditor.h" #include "vcsbasesettings.h" -#include "vcsbaseplugin.h" +#include "vcsplugin.h" #include "nicknamedialog.h" #include "submiteditorfile.h" @@ -75,7 +75,7 @@ namespace VCSBase { static inline QString submitMessageCheckScript() { - return Internal::VCSBasePlugin::instance()->settings().submitMessageCheckScript; + return Internal::VCSPlugin::instance()->settings().submitMessageCheckScript; } struct VCSBaseSubmitEditorPrivate @@ -127,7 +127,7 @@ VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *pa connect(m_d->m_widget, SIGNAL(diffSelected(QStringList)), this, SLOT(slotDiffSelectedVCSFiles(QStringList))); connect(m_d->m_widget->descriptionEdit(), SIGNAL(textChanged()), this, SLOT(slotDescriptionChanged())); - const Internal::VCSBaseSettings settings = Internal::VCSBasePlugin::instance()->settings(); + const Internal::VCSBaseSettings settings = Internal::VCSPlugin::instance()->settings(); // Add additional context menu settings if (!settings.submitMessageCheckScript.isEmpty() || !settings.nickNameMailMap.isEmpty()) { QAction *sep = new QAction(this); @@ -152,7 +152,7 @@ VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *pa // wrapping. etc slotUpdateEditorSettings(settings); - connect(Internal::VCSBasePlugin::instance(), + connect(Internal::VCSPlugin::instance(), SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)), this, SLOT(slotUpdateEditorSettings(VCSBase::Internal::VCSBaseSettings))); @@ -199,7 +199,7 @@ void VCSBaseSubmitEditor::createUserFields(const QString &fieldConfigFile) if (fields.empty()) return; // Create a completer on user names - const QStandardItemModel *nickNameModel = Internal::VCSBasePlugin::instance()->nickNameModel(); + const QStandardItemModel *nickNameModel = Internal::VCSPlugin::instance()->nickNameModel(); QCompleter *completer = new QCompleter(Internal::NickNameDialog::nickNameList(nickNameModel), this); Utils::SubmitFieldWidget *fieldWidget = new Utils::SubmitFieldWidget; @@ -487,7 +487,7 @@ VCSBaseSubmitEditor::PromptSubmitResult QString VCSBaseSubmitEditor::promptForNickName() { if (!m_d->m_nickNameDialog) - m_d->m_nickNameDialog = new Internal::NickNameDialog(Internal::VCSBasePlugin::instance()->nickNameModel(), m_d->m_widget); + m_d->m_nickNameDialog = new Internal::NickNameDialog(Internal::VCSPlugin::instance()->nickNameModel(), m_d->m_widget); if (m_d->m_nickNameDialog->exec() == QDialog::Accepted) return m_d->m_nickNameDialog->nickName(); return QString();