diff --git a/vcs/dvcs/dvcsplugin.cpp b/vcs/dvcs/dvcsplugin.cpp index 239b073312..d0d4b1e451 100644 --- a/vcs/dvcs/dvcsplugin.cpp +++ b/vcs/dvcs/dvcsplugin.cpp @@ -1,263 +1,263 @@ /*************************************************************************** * This file was partly taken from KDevelop's cvs plugin * * Copyright 2007 Robert Gruber * * * * Adapted for DVCS (added templates) * * Copyright 2008 Evgeniy Ivanov * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #ifndef DVCS_PLUGIN_CC #define DVCS_PLUGIN_CC #include "dvcsplugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dvcsjob.h" #include "ui/dvcsmainview.h" #include "ui/dvcsgenericoutputview.h" #include "ui/importdialog.h" #include "ui/importmetadatawidget.h" #include "ui/logview.h" #include "ui/branchmanager.h" // #include "ui/commitmanager.h" #include "ui/revhistory/commitlogmodel.h" #include "ui/revhistory/commitView.h" #include #include #include #include #include namespace KDevelop { struct DistributedVersionControlPluginPrivate { explicit DistributedVersionControlPluginPrivate(DistributedVersionControlPlugin * pThis) : m_factory(new KDevDVCSViewFactory(pThis)) , m_common(new VcsPluginHelper(pThis, pThis)) {} KDevDVCSViewFactory* m_factory; std::auto_ptr m_common; }; //class DistributedVersionControlPlugin DistributedVersionControlPlugin::DistributedVersionControlPlugin(QObject *parent, KComponentData compData) : IPlugin(compData, parent) , d(new DistributedVersionControlPluginPrivate(this)) {} DistributedVersionControlPlugin::~DistributedVersionControlPlugin() { //TODO: Find out why this crashes on the svn tests delete d->m_factory; delete d; } // End: KDevelop::IBasicVersionControl // Begin: KDevelop::IDistributedVersionControl // End: KDevelop::IDistributedVersionControl KDevelop::VcsImportMetadataWidget* DistributedVersionControlPlugin::createImportMetadataWidget(QWidget* parent) { return new ImportMetadataWidget(parent); } KDevelop::ContextMenuExtension DistributedVersionControlPlugin::contextMenuExtension(Context* context) { d->m_common->setupFromContext(context); KUrl::List const & ctxUrlList = d->m_common->contextUrlList(); bool isWorkingDirectory = false; foreach(const KUrl &url, ctxUrlList) { if (isValidDirectory(url)) { isWorkingDirectory = true; break; } } if (!isWorkingDirectory) { // Not part of a repository return ContextMenuExtension(); } QMenu * menu = d->m_common->commonActions(); menu->addSeparator(); menu->addAction(KIcon("arrow-up-double"), i18n("Push"), this, SLOT(ctxPush())); menu->addAction(KIcon("arrow-down-double"), i18n("Pull"), this, SLOT(ctxPull())); menu->addAction(i18n("Branches..."), this, SLOT(ctxBranchManager()))->setEnabled(ctxUrlList.count()==1); - menu->addAction(i18n("Revision History"), this, SLOT(ctxRevHistory()))->setEnabled(ctxUrlList.count()==1); + menu->addAction(i18n("Revision Graph..."), this, SLOT(ctxRevHistory()))->setEnabled(ctxUrlList.count()==1); additionalMenuEntries(menu, ctxUrlList); ContextMenuExtension menuExt; menuExt.addAction(ContextMenuExtension::VcsGroup, menu->menuAction()); return menuExt; } void DistributedVersionControlPlugin::additionalMenuEntries(QMenu* /*menu*/, const KUrl::List& /*urls*/) {} void DistributedVersionControlPlugin::slotInit() { KUrl::List const & ctxUrlList = d->m_common->contextUrlList(); Q_ASSERT(!ctxUrlList.isEmpty()); KUrl url = ctxUrlList.front(); QFileInfo repoInfo = QFileInfo(url.toLocalFile()); if (repoInfo.isFile()) url = repoInfo.path(); ImportDialog dlg(this, url); dlg.exec(); } void DistributedVersionControlPlugin::ctxPush() { KUrl::List const & ctxUrlList = d->m_common->contextUrlList(); Q_ASSERT(!ctxUrlList.isEmpty()); VcsJob* job = push(ctxUrlList.front().toLocalFile(), VcsLocation()); connect(job, SIGNAL(result(KJob*)), this, SIGNAL(jobFinished(KJob*))); ICore::self()->runController()->registerJob(job); } void DistributedVersionControlPlugin::ctxPull() { KUrl::List const & ctxUrlList = d->m_common->contextUrlList(); Q_ASSERT(!ctxUrlList.isEmpty()); VcsJob* job = pull(VcsLocation(), ctxUrlList.front().toLocalFile()); connect(job, SIGNAL(result(KJob*)), this, SIGNAL(jobFinished(KJob*))); ICore::self()->runController()->registerJob(job); } static QString stripPathToDir(const QString &path) { return QFileInfo(path).absolutePath(); } void DistributedVersionControlPlugin::ctxBranchManager() { KUrl::List const & ctxUrlList = d->m_common->contextUrlList(); Q_ASSERT(!ctxUrlList.isEmpty()); ICore::self()->documentController()->saveAllDocuments(); BranchManager branchManager(stripPathToDir(ctxUrlList.front().toLocalFile()), this, core()->uiController()->activeMainWindow()); if(branchManager.isValid()) branchManager.exec(); else KMessageBox::error(0, i18n("Could not show the Branch Manager, current branch is unavailable.")); } // This is redundant with the normal VCS "history" action void DistributedVersionControlPlugin::ctxRevHistory() { KUrl::List const & ctxUrlList = d->m_common->contextUrlList(); Q_ASSERT(!ctxUrlList.isEmpty()); KDialog d; CommitLogModel* model = new CommitLogModel(this, ctxUrlList.first().toLocalFile(), &d); CommitView *revTree = new CommitView(&d); revTree->setModel(model); d.setButtons(KDialog::Close); d.setMainWidget(revTree); d.exec(); } KDevDVCSViewFactory * DistributedVersionControlPlugin::dvcsViewFactory() const { return d->m_factory; } KDevelop::DVcsJob* DistributedVersionControlPlugin::empty_cmd(KDevelop::OutputJob::OutputJobVerbosity verbosity) { DVcsJob* j = new DVcsJob(QDir(), this, verbosity); *j << "echo" << "command not implemented" << "-n"; return j; } QString DistributedVersionControlPlugin::curBranch(const KUrl& repo) { QString name; QScopedPointer job(currentBranch(repo)); if(job->exec() && job->status()==VcsJob::JobSucceeded) { name = job->fetchResults().toString(); } return name; } QStringList DistributedVersionControlPlugin::listBranches(const KUrl& repo) { QStringList branchlist; QScopedPointer job(branches(repo)); if(job->exec() && job->status()==VcsJob::JobSucceeded) { branchlist = job->fetchResults().toStringList(); } return branchlist; } } //----------------------------------------------------------------------------------- //class KDevDVCSViewFactory QWidget* KDevDVCSViewFactory::create(QWidget *parent) { return new DVCSmainView(m_plugin, parent); } Qt::DockWidgetArea KDevDVCSViewFactory::defaultPosition() { return Qt::BottomDockWidgetArea; } QString KDevDVCSViewFactory::id() const { return "org.kdevelop.DVCSview"; } #endif diff --git a/vcs/vcspluginhelper.cpp b/vcs/vcspluginhelper.cpp index fefe56c91e..ab2f1ce7b2 100644 --- a/vcs/vcspluginhelper.cpp +++ b/vcs/vcspluginhelper.cpp @@ -1,479 +1,479 @@ /*************************************************************************** * Copyright 2008 Andreas Pakulat * * Copyright 2010 Aleix Pol Gonzalez * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "vcspluginhelper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_KOMPARE #include #endif #include #include #include #include "vcsstatusinfo.h" #include #include #include #include "widgets/vcsdiffpatchsources.h" #include "widgets/flexibleaction.h" #include #include "vcsevent.h" #include #include #include #include #include namespace KDevelop { struct VcsPluginHelper::VcsPluginHelperPrivate { IPlugin * plugin; IBasicVersionControl * vcs; KUrl::List ctxUrls; KAction * commitAction; KAction * addAction; KAction * updateAction; KAction * historyAction; KAction * annotationAction; KAction * diffToBaseAction; KAction * revertAction; KAction * diffForRevAction; KAction * diffForRevGlobalAction; QPointer modificationTimer; void createActions(QObject * parent) { commitAction = new KAction(KIcon("svn-commit"), i18n("Commit..."), parent); updateAction = new KAction(KIcon("svn-update"), i18n("Update"), parent); addAction = new KAction(KIcon("list-add"), i18n("Add"), parent); diffToBaseAction = new KAction(KIcon("vcs_diff"), i18n("Show Differences..."), parent); revertAction = new KAction(KIcon("archive-remove"), i18n("Revert"), parent); historyAction = new KAction(KIcon("view-history"), i18n("History..."), parent); annotationAction = new KAction(KIcon("user-properties"), i18n("Annotation..."), parent); diffForRevAction = new KAction(KIcon("vcs_diff"), i18n("Show Diff..."), parent); diffForRevGlobalAction = new KAction(KIcon("vcs_diff"), i18n("Show Diff (all files)..."), parent); connect(commitAction, SIGNAL(triggered()), parent, SLOT(commit())); connect(addAction, SIGNAL(triggered()), parent, SLOT(add())); connect(updateAction, SIGNAL(triggered()), parent, SLOT(update())); connect(diffToBaseAction, SIGNAL(triggered()), parent, SLOT(diffToBase())); connect(revertAction, SIGNAL(triggered()), parent, SLOT(revert())); connect(historyAction, SIGNAL(triggered()), parent, SLOT(history())); connect(annotationAction, SIGNAL(triggered()), parent, SLOT(annotation())); connect(diffForRevAction, SIGNAL(triggered()), parent, SLOT(diffForRev())); connect(diffForRevGlobalAction, SIGNAL(triggered()), parent, SLOT(diffForRevGlobal())); } bool allLocalFiles(const KUrl::List& urls) { bool ret=true; foreach(const KUrl& url, urls) { QFileInfo info(url.toLocalFile()); ret &= info.isFile(); } return ret; } QMenu* createMenu() { bool allVersioned=true; foreach(const KUrl& url, ctxUrls) { allVersioned=allVersioned && vcs->isVersionControlled(url); if(!allVersioned) break; } QMenu* menu=new QMenu(vcs->name()); menu->setIcon(KIcon(ICore::self()->pluginController()->pluginInfo(plugin).icon())); menu->addAction(commitAction); menu->addAction(updateAction); menu->addSeparator(); menu->addAction(addAction); menu->addAction(revertAction); menu->addSeparator(); menu->addAction(historyAction); menu->addAction(annotationAction); menu->addAction(diffToBaseAction); addAction->setEnabled(!allVersioned); const bool singleVersionedFile = ctxUrls.count() == 1 && allVersioned; historyAction->setEnabled(singleVersionedFile); annotationAction->setEnabled(singleVersionedFile && allLocalFiles(ctxUrls)); diffToBaseAction->setEnabled(singleVersionedFile); commitAction->setEnabled(singleVersionedFile); return menu; } }; VcsPluginHelper::VcsPluginHelper(KDevelop::IPlugin* parent, KDevelop::IBasicVersionControl* vcs) : QObject(parent) , d(new VcsPluginHelperPrivate()) { Q_ASSERT(vcs); Q_ASSERT(parent); d->plugin = parent; d->vcs = vcs; d->createActions(this); } VcsPluginHelper::~VcsPluginHelper() {} void VcsPluginHelper::setupFromContext(Context* context) { d->ctxUrls.clear(); { KDevelop::ProjectItemContext* prjctx = dynamic_cast(context); if (prjctx) { foreach(KDevelop::ProjectBaseItem* item, prjctx->items()) { if(!item->target()) d->ctxUrls.append(item->url()); } } } { KDevelop::EditorContext* editctx = dynamic_cast(context); if (editctx) { d->ctxUrls.append(editctx->url()); } } { KDevelop::FileContext* filectx = dynamic_cast(context); if (filectx) { d->ctxUrls = filectx->urls(); } } } KUrl::List const & VcsPluginHelper::contextUrlList() { return d->ctxUrls; } QMenu* VcsPluginHelper::commonActions() { /* TODO: the following logic to determine which actions need to be enabled * or disabled does not work properly. What needs to be implemented is that * project items that are vc-controlled enable all except add, project * items that are not vc-controlled enable add action. For urls that cannot * be made into a project item, or if the project has no associated VC * plugin we need to check whether a VC controls the parent dir, if we have * one we assume the urls can be added but are not currently controlled. If * the url is already version controlled then just enable all except add */ return d->createMenu(); } #define EXECUTE_VCS_METHOD( method ) \ d->plugin->core()->runController()->registerJob( d->vcs-> method ( d->ctxUrls ) ) #define SINGLEURL_SETUP_VARS \ KDevelop::IBasicVersionControl* iface = d->vcs;\ const KUrl & url = d->ctxUrls.front(); void VcsPluginHelper::revert() { VcsJob* job=d->vcs->revert(d->ctxUrls); connect(job, SIGNAL(finished(KJob*)), SLOT(revertDone(KJob*))); foreach(const KUrl& url, d->ctxUrls) { IDocument* doc=ICore::self()->documentController()->documentForUrl(url); if(doc) { KTextEditor::ModificationInterface* modif=dynamic_cast(doc->textDocument()); modif->setModifiedOnDiskWarning(false); doc->textDocument()->setModified(false); } } job->setProperty("urls", d->ctxUrls); d->plugin->core()->runController()->registerJob(job); } void VcsPluginHelper::revertDone(KJob* job) { d->modificationTimer = new QTimer; d->modificationTimer->setInterval(100); connect(d->modificationTimer, SIGNAL(timeout()), SLOT(delayedModificationWarningOn())); d->modificationTimer->setProperty("urls", job->property("urls")); d->modificationTimer->start(); } void VcsPluginHelper::delayedModificationWarningOn() { KUrl::List urls = d->modificationTimer->property("urls").value(); foreach(const KUrl& url, urls) { IDocument* doc=ICore::self()->documentController()->documentForUrl(url); if(doc) { doc->reload(); KTextEditor::ModificationInterface* modif=dynamic_cast(doc->textDocument()); modif->setModifiedOnDiskWarning(true); } } d->modificationTimer->deleteLater(); } void VcsPluginHelper::diffJobFinished(KJob* job) { KDevelop::VcsJob* vcsjob = qobject_cast(job); Q_ASSERT(vcsjob); if (vcsjob->status() == KDevelop::VcsJob::JobSucceeded) { KDevelop::VcsDiff d = vcsjob->fetchResults().value(); if(d.isEmpty()) KMessageBox::information(ICore::self()->uiController()->activeMainWindow(), i18n("There are no differences."), i18n("VCS support")); else { VCSDiffPatchSource* patch=new VCSDiffPatchSource(d); showVcsDiff(patch); } } else { KMessageBox::error(ICore::self()->uiController()->activeMainWindow(), vcsjob->errorString(), i18n("Unable to get difference.")); } } void VcsPluginHelper::diffToBase() { SINGLEURL_SETUP_VARS ICore::self()->documentController()->saveAllDocuments(); VCSDiffPatchSource* patch =new VCSDiffPatchSource(new VCSStandardDiffUpdater(iface, url)); showVcsDiff(patch); } void VcsPluginHelper::diffForRev() { QAction* action = qobject_cast( sender() ); Q_ASSERT(action); Q_ASSERT(action->data().canConvert()); VcsRevision rev = action->data().value(); SINGLEURL_SETUP_VARS ICore::self()->documentController()->saveAllDocuments(); VcsRevision prev = KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Previous); KDevelop::VcsJob* job = iface->diff(url, prev, rev ); connect(job, SIGNAL(finished(KJob*)), this, SLOT(diffJobFinished(KJob*))); d->plugin->core()->runController()->registerJob(job); } void VcsPluginHelper::diffForRevGlobal() { for(int a = 0; a < d->ctxUrls.size(); ++a) { KUrl& url(d->ctxUrls[a]); IProject* project = ICore::self()->projectController()->findProjectForUrl( url ); if( project ) url = project->folder(); } diffForRev(); } void VcsPluginHelper::history(const VcsRevision& rev) { SINGLEURL_SETUP_VARS KDevelop::VcsJob *job = iface->log(url, rev, VcsRevision::createSpecialRevision( VcsRevision::Start )); KDialog* dlg = new KDialog(); dlg->setButtons(KDialog::Close); dlg->setCaption(i18n("%2 History (%1)", url.pathOrUrl(), iface->name())); KDevelop::VcsEventWidget* logWidget = new KDevelop::VcsEventWidget(url, job, dlg); dlg->setMainWidget(logWidget); dlg->show(); connect( dlg, SIGNAL(closeClicked()), job, SLOT(kill()) ); connect( dlg, SIGNAL(closeClicked()), dlg, SLOT(deleteLater()) ); } void VcsPluginHelper::annotation() { SINGLEURL_SETUP_VARS KDevelop::IDocument* doc = ICore::self()->documentController()->documentForUrl(url); if (!doc) doc = ICore::self()->documentController()->openDocument(url); if (doc && doc->textDocument()) { KDevelop::VcsJob* job = iface->annotate(url); if( !job ) { kWarning() << "Couldn't create annotate job for:" << url << "with iface:" << iface << dynamic_cast( iface ); return; } KTextEditor::AnnotationInterface* annotateiface = qobject_cast(doc->textDocument()); KTextEditor::AnnotationViewInterface* viewiface = qobject_cast(doc->textDocument()->activeView()); if (annotateiface && viewiface) { KDevelop::VcsAnnotationModel* model = new KDevelop::VcsAnnotationModel(job, url, doc->textDocument()); annotateiface->setAnnotationModel(model); viewiface->setAnnotationBorderVisible(true); connect(doc->textDocument()->activeView(), SIGNAL(annotationContextMenuAboutToShow(KTextEditor::View*,QMenu*,int)), this, SLOT(annotationContextMenuAboutToShow(KTextEditor::View*,QMenu*,int))); connect(doc->textDocument()->activeView(), SIGNAL(annotationBorderVisibilityChanged(KTextEditor::View*, bool)), SLOT(annotationVisibilityChange(KTextEditor::View*,QMenu*,int))); } else { KMessageBox::error(0, i18n("Cannot display annotations, missing interface KTextEditor::AnnotationInterface for the editor.")); delete job; } } else { KMessageBox::error(0, i18n("Cannot execute annotate action because the " "document was not found, or was not a text document:\n%1", url.pathOrUrl())); } } class CopyFunction : public AbstractFunction { public: CopyFunction(const QString& tocopy) : m_tocopy(tocopy) {} void operator()() { QApplication::clipboard()->setText(m_tocopy); } private: QString m_tocopy; }; class HistoryFunction : public AbstractFunction { public: HistoryFunction(VcsPluginHelper* helper, const VcsRevision& rev) : m_helper(helper), m_rev(rev) {} void operator()() { m_helper->history(m_rev); } private: VcsPluginHelper* m_helper; VcsRevision m_rev; }; void VcsPluginHelper::annotationContextMenuAboutToShow( KTextEditor::View* view, QMenu* menu, int line ) { KTextEditor::AnnotationInterface* annotateiface = qobject_cast(view->document()); VcsAnnotationModel* model = qobject_cast( annotateiface->annotationModel() ); Q_ASSERT(model); if(menu->actions().count()<3) { VcsRevision rev = model->revisionForLine(line); d->diffForRevAction->setData(QVariant::fromValue(rev)); d->diffForRevGlobalAction->setData(QVariant::fromValue(rev)); menu->addSeparator(); menu->addAction(d->diffForRevAction); menu->addAction(d->diffForRevGlobalAction); menu->addAction(new FlexibleAction(KIcon("edit-copy"), i18n("Copy Revision"), new CopyFunction(rev.revisionValue().toString()), menu)); - menu->addAction(new FlexibleAction(KIcon("view-history"), i18n("Revision History..."), new HistoryFunction(this, rev), menu)); + menu->addAction(new FlexibleAction(KIcon("view-history"), i18n("History..."), new HistoryFunction(this, rev), menu)); } } void VcsPluginHelper::annotationVisibilityChange(KTextEditor::View* view, QMenu* menu, int visible) { } void VcsPluginHelper::update() { EXECUTE_VCS_METHOD(update); } void VcsPluginHelper::add() { EXECUTE_VCS_METHOD(add); } void VcsPluginHelper::commit() { Q_ASSERT(!d->ctxUrls.isEmpty()); ICore::self()->documentController()->saveAllDocuments(); KUrl url = d->ctxUrls.first(); // We start the commit UI no matter whether there is real differences, as it can also be used to commit untracked files VCSCommitDiffPatchSource* patchSource = new VCSCommitDiffPatchSource(new VCSStandardDiffUpdater(d->vcs, url)); bool ret = showVcsDiff(patchSource); if(!ret) { VcsCommitDialog *commitDialog = new VcsCommitDialog(patchSource); commitDialog->setCommitCandidates(patchSource->infos()); commitDialog->exec(); } } } #include "vcspluginhelper.moc"