/* This file is part of KDevelop Copyright 2010 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "projectchangesmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(KDevelop::IProject*); using namespace KDevelop; ProjectChangesModel::ProjectChangesModel(QObject* parent) : VcsFileChangesModel(parent) { foreach(IProject* p, ICore::self()->projectController()->projects()) addProject(p); connect(ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), SLOT(addProject(KDevelop::IProject*))); connect(ICore::self()->projectController(), SIGNAL(projectClosing(KDevelop::IProject*)), SLOT(removeProject(KDevelop::IProject*))); connect(ICore::self()->documentController(), SIGNAL(documentSaved(KDevelop::IDocument*)), SLOT(documentSaved(KDevelop::IDocument*))); connect(ICore::self()->projectController()->projectModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(itemsAdded(QModelIndex,int,int))); connect(ICore::self()->runController(), SIGNAL(jobUnregistered(KJob*)), SLOT(jobUnregistered(KJob*))); } ProjectChangesModel::~ProjectChangesModel() {} void ProjectChangesModel::addProject(IProject* p) { QStandardItem* it = new QStandardItem(p->name()); it->setData(p->name(), ProjectChangesModel::ProjectNameRole); IPlugin* plugin = p->versionControlPlugin(); if(plugin) { IBasicVersionControl* vcs = plugin->extension(); KPluginInfo info = ICore::self()->pluginController()->pluginInfo(plugin); it->setIcon(KIcon(info.icon())); it->setToolTip(vcs->name()); reload(QList() << p); IBranchingVersionControl* branchingExtension = plugin->extension(); if(branchingExtension) { branchingExtension->registerRepositoryForCurrentBranchChanges(p->folder()); connect(plugin, SIGNAL(repositoryBranchChanged(KUrl)), this, SLOT(repositoryBranchChanged(KUrl))); repositoryBranchChanged(p->folder()); } } else { it->setEnabled(false); } appendRow(it); } void ProjectChangesModel::removeProject(IProject* p) { QStandardItem* it=projectItem(p); removeRow(it->row()); } QStandardItem* findItemChild(QStandardItem* parent, const QVariant& value, int role = Qt::DisplayRole) { for(int i=0; irowCount(); i++) { QStandardItem* curr=parent->child(i); if(curr->data(role) == value) return curr; } return 0; } QStandardItem* ProjectChangesModel::projectItem(IProject* p) const { return findItemChild(invisibleRootItem(), p->name(), ProjectChangesModel::ProjectNameRole); } void ProjectChangesModel::updateState(IProject* p, const KDevelop::VcsStatusInfo& status) { QStandardItem* pItem = projectItem(p); Q_ASSERT(pItem); VcsFileChangesModel::updateState(pItem, status); } void ProjectChangesModel::changes(IProject* project, const KUrl::List& urls, IBasicVersionControl::RecursionMode mode) { IPlugin* vcsplugin=project->versionControlPlugin(); IBasicVersionControl* vcs = vcsplugin ? vcsplugin->extension() : 0; if(vcs && vcs->isVersionControlled(urls.first())) { //TODO: filter? VcsJob* job=vcs->status(urls, mode); job->setProperty("urls", qVariantFromValue(urls)); job->setProperty("mode", qVariantFromValue(mode)); job->setProperty("project", qVariantFromValue(project)); connect(job, SIGNAL(finished(KJob*)), SLOT(statusReady(KJob*))); ICore::self()->runController()->registerJob(job); } } void ProjectChangesModel::statusReady(KJob* job) { VcsJob* status=static_cast(job); QList states = status->fetchResults().toList(); IProject* project = job->property("project").value(); if(!project) return; QSet foundUrls; foreach(const QVariant& state, states) { VcsStatusInfo st = state.value(); foundUrls += st.url(); updateState(project, st); } QStandardItem* itProject = projectItem(project); IBasicVersionControl::RecursionMode mode = IBasicVersionControl::RecursionMode(job->property("mode").toInt()); QSet uncertainUrls = urls(itProject).toSet().subtract(foundUrls); QList sourceUrls = job->property("urls").value(); foreach(const KUrl& url, sourceUrls) { if(url.isLocalFile() && QDir(url.toLocalFile()).exists()) { foreach(const KUrl& currentUrl, uncertainUrls) { if((mode == IBasicVersionControl::NonRecursive && currentUrl.upUrl().equals(url, KUrl::CompareWithoutTrailingSlash)) || (mode == IBasicVersionControl::Recursive && url.isParentOf(currentUrl)) ) { QStandardItem* fileItem = fileItemForUrl(itProject, currentUrl); itProject->removeRow(fileItem->row()); } } } } } void ProjectChangesModel::documentSaved(KDevelop::IDocument* document) { reload(KUrl::List() << document->url()); } void ProjectChangesModel::itemsAdded(const QModelIndex& parent, int start, int end) { ProjectModel* model=ICore::self()->projectController()->projectModel(); ProjectBaseItem* item=model->itemFromIndex(parent); if(!item) return; IProject* project=item->project(); if(!project) return; KUrl::List urls; for(int i=start; iitemFromIndex(idx); if(item->type()==ProjectBaseItem::File || item->type()==ProjectBaseItem::Folder || item->type()==ProjectBaseItem::BuildFolder) urls += item->path().toUrl(); } if(!urls.isEmpty()) changes(project, urls, KDevelop::IBasicVersionControl::NonRecursive); } void ProjectChangesModel::reload(const QList& projects) { foreach(IProject* project, projects) changes(project, project->folder(), KDevelop::IBasicVersionControl::Recursive); } void ProjectChangesModel::reload(const QList& urls) { foreach(const KUrl& url, urls) { IProject* project=ICore::self()->projectController()->findProjectForUrl(url); if(project) changes(project, url, KDevelop::IBasicVersionControl::NonRecursive); } } void ProjectChangesModel::reloadAll() { QList< IProject* > projects = ICore::self()->projectController()->projects(); reload(projects); } void ProjectChangesModel::jobUnregistered(KJob* job) { static QList readOnly = QList() << KDevelop::VcsJob::Add << KDevelop::VcsJob::Remove << KDevelop::VcsJob::Pull << KDevelop::VcsJob::Commit << KDevelop::VcsJob::Move << KDevelop::VcsJob::Copy << KDevelop::VcsJob::Revert ; VcsJob* vcsjob=dynamic_cast(job); if(vcsjob && readOnly.contains(vcsjob->type())) { reloadAll(); } } void ProjectChangesModel::repositoryBranchChanged(const KUrl& url) { IProject* project = ICore::self()->projectController()->findProjectForUrl(url); if(project) { IPlugin* v = project->versionControlPlugin(); Q_ASSERT(v); IBranchingVersionControl* branching = v->extension(); Q_ASSERT(branching); VcsJob* job = branching->currentBranch(url); connect(job, SIGNAL(resultsReady(KDevelop::VcsJob*)), SLOT(branchNameReady(KDevelop::VcsJob*))); job->setProperty("project", QVariant::fromValue(project)); ICore::self()->runController()->registerJob(job); } } void ProjectChangesModel::branchNameReady(VcsJob* job) { IProject* project = qobject_cast(job->property("project").value()); if(job->status()==VcsJob::JobSucceeded) { QString branchName = job->fetchResults().toString().isEmpty() ? i18n("no branch") : job->fetchResults().toString(); projectItem(project)->setText(i18nc("project name (branch name)", "%1 (%2)", project->name(), branchName)); } else { projectItem(project)->setText(project->name()); } reload(QList() << project); }