Fix no newlines warnings. Patch by Peter Oberndorfer
[kdevelopdvcssupport.git] / shell / project.cpp
blob31cdcc0f19830e826e7b410abbd809a426955ba7
1 /* This file is part of the KDE project
2 Copyright 2001 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
3 Copyright 2002-2003 Roberto Raggi <roberto@kdevelop.org>
4 Copyright 2002 Simon Hausmann <hausmann@kde.org>
5 Copyright 2003 Jens Dagerbo <jens.dagerbo@swipnet.se>
6 Copyright 2003 Mario Scalas <mario.scalas@libero.it>
7 Copyright 2003-2004 Alexander Dymo <adymo@kdevelop.org>
8 Copyright 2006 Matt Rogers <mattr@kde.org>
9 Copyright 2007 Andreas Pakulat <apaku@gmx.de>
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Library General Public
13 License as published by the Free Software Foundation; either
14 version 2 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Library General Public License for more details.
21 You should have received a copy of the GNU Library General Public License
22 along with this library; see the file COPYING.LIB. If not, write to
23 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 Boston, MA 02110-1301, USA.
27 #include "project.h"
29 #include <QSet>
30 #include <QtGlobal>
31 #include <QFileInfo>
32 #include <QtDBus/QtDBus>
33 #include <QStandardItemModel>
35 #include <kconfig.h>
36 #include <kconfiggroup.h>
37 #include <klocale.h>
38 #include <kio/job.h>
39 #include <kio/netaccess.h>
40 #include <kio/global.h>
41 #include <kmessagebox.h>
42 #include <kio/jobclasses.h>
43 #include <ktemporaryfile.h>
44 #include <kdebug.h>
46 #include <project/interfaces/iprojectfilemanager.h>
47 #include <project/interfaces/ibuildsystemmanager.h>
48 #include <interfaces/iplugin.h>
49 #include <interfaces/iplugincontroller.h>
50 #include <interfaces/iruncontroller.h>
51 #include <project/importprojectjob.h>
52 #include <project/projectmodel.h>
53 #include <language/duchain/indexedstring.h>
55 #include "core.h"
56 #include "mainwindow.h"
57 #include "projectcontroller.h"
58 #include "uicontroller.h"
60 namespace KDevelop
63 class ProjectPrivate
65 public:
66 KUrl folder;
67 KUrl projectFileUrl;
68 KUrl developerFileUrl;
69 QString developerTempFile;
70 QString projectTempFile;
71 KTemporaryFile* tmp;
72 IPlugin* manager;
73 IPlugin* vcsPlugin;
74 ProjectFolderItem* topItem;
75 QString name;
76 KSharedConfig::Ptr m_cfg;
77 IProject *project;
78 QSet<KDevelop::IndexedString> fileSet;
80 QList<ProjectFileItem*> recurseFiles( ProjectBaseItem * projectItem )
82 QList<ProjectFileItem*> files;
83 if ( ProjectFolderItem * folder = projectItem->folder() )
85 QList<ProjectFolderItem*> folder_list = folder->folderList();
86 for ( QList<ProjectFolderItem*>::Iterator it = folder_list.begin(); it != folder_list.end(); ++it )
88 files += recurseFiles( ( *it ) );
91 QList<ProjectTargetItem*> target_list = folder->targetList();
92 for ( QList<ProjectTargetItem*>::Iterator it = target_list.begin(); it != target_list.end(); ++it )
94 files += recurseFiles( ( *it ) );
97 files += folder->fileList();
99 else if ( ProjectTargetItem * target = projectItem->target() )
101 files += target->fileList();
103 else if ( ProjectFileItem * file = projectItem->file() )
105 files.append( file );
107 return files;
110 QList<ProjectBaseItem*> itemsForUrlInternal( const KUrl& url, ProjectFolderItem* folder ) const
112 QList<ProjectBaseItem*> files;
113 if( !folder )
114 return files;
116 if( folder->url().equals( url, KUrl::CompareWithoutTrailingSlash ) )
118 files << folder;
121 // Check top level files
122 foreach( ProjectFileItem* file, folder->fileList() )
124 if( file->url() == url )
126 files << file;
130 // Check top level targets
131 foreach( ProjectTargetItem* target, folder->targetList() )
133 foreach( ProjectFileItem* file, target->fileList() )
135 if( file->url() == url )
137 files << file;
142 foreach( ProjectFolderItem* top, folder->folderList() )
144 files += itemsForUrlInternal( url, top );
146 return files;
148 QList<ProjectBaseItem*> itemsForUrl( const KUrl& url ) const
150 // TODO: This is moderately efficient, but could be much faster with a
151 // QHash<QString, ProjectFolderItem> member. Would it be worth it?
152 KUrl u = topItem->url();
153 if ( u.protocol() != url.protocol() || u.host() != url.host() )
154 return QList<ProjectBaseItem*>();
156 return itemsForUrlInternal( url, topItem );
160 void importDone( KJob* )
162 Core::self()->projectControllerInternal()->projectImportingFinished( project );
166 Project::Project( QObject *parent )
167 : IProject( parent )
168 , d( new ProjectPrivate )
170 QDBusConnection::sessionBus().registerObject( "/org/kdevelop/Project", this, QDBusConnection::ExportScriptableSlots );
172 d->project = this;
173 d->manager = 0;
174 d->topItem = 0;
175 d->tmp = 0;
176 d->vcsPlugin = 0;
179 Project::~Project()
181 delete d;
184 QString Project::name() const
186 return d->name;
189 QString Project::developerTempFile() const
191 return d->developerTempFile;
194 QString Project::projectTempFile() const
196 return d->projectTempFile;
199 KSharedConfig::Ptr Project::projectConfiguration() const
201 d->m_cfg->reparseConfiguration();
202 return d->m_cfg;
205 // void Project::setLocalFile( const KUrl& u )
206 // {
207 // d->localFile = u;
208 // }
210 // void Project::setGlobalFile( const KUrl& u )
211 // {
212 // d->globalFile = u;
213 // }
215 const KUrl Project::folder() const
217 return d->folder;
220 void Project::reloadModel()
222 ProjectModel* model = Core::self()->projectController()->projectModel();
223 model->removeRow( d->topItem->row() );
224 IProjectFileManager* iface = d->manager->extension<IProjectFileManager>();
225 if( iface )
227 d->topItem = iface->import( this );
228 if( !d->topItem )
230 KMessageBox::sorry( Core::self()->uiControllerInternal()->defaultMainWindow(),
231 i18n("Could not open project") );
232 return;
234 d->topItem->setIcon();
235 model->appendRow(d->topItem);
236 // model->insertRow( model->rowCount(), d->topItem );
237 ImportProjectJob* importJob = new ImportProjectJob( d->topItem, iface );
238 Core::self()->runController()->registerJob( importJob );
242 bool Project::open( const KUrl& projectFileUrl_ )
244 //Canonicalize the project url, because we do the same in many other cases with files,
245 //so we must canonicalize the project url too.
246 KUrl projectFileUrl = projectFileUrl_;
248 if ( projectFileUrl.isLocalFile() )
250 QString path = QFileInfo( projectFileUrl.toLocalFile() ).canonicalFilePath();
251 if ( !path.isEmpty() )
252 projectFileUrl.setPath( path );
255 KIO::StatJob* statJob = KIO::stat( projectFileUrl, KIO::HideProgressInfo );
256 if ( !statJob->exec() ) //be sync for right now
258 KMessageBox::sorry( Core::self()->uiControllerInternal()->defaultMainWindow(),
259 i18n( "Unable to load the project file %1",
260 projectFileUrl.pathOrUrl() ) );
261 return false;
264 d->projectFileUrl = projectFileUrl;
265 d->developerFileUrl = KUrl( projectFileUrl.directory( KUrl::AppendTrailingSlash ) );
266 d->developerFileUrl.addPath(".kdev4");
267 d->developerFileUrl.addPath( projectFileUrl.fileName() );
269 statJob = KIO::stat( d->developerFileUrl, KIO::HideProgressInfo );
270 if( !statJob->exec() )
272 KUrl dir = KUrl( projectFileUrl.directory( KUrl::AppendTrailingSlash ) + ".kdev4");
273 statJob = KIO::stat( dir, KIO::HideProgressInfo );
274 if( !statJob->exec() )
276 KIO::SimpleJob* mkdirJob = KIO::mkdir( dir );
277 if( !mkdirJob->exec() )
279 KMessageBox::sorry(
280 Core::self()->uiController()->activeMainWindow(),
281 i18n("Unable to create hidden dir (%1) for developer file",
282 dir.pathOrUrl() )
284 return false;
289 if( !KIO::NetAccess::download( d->projectFileUrl, d->projectTempFile,
290 Core::self()->uiController()->activeMainWindow() ) )
292 KMessageBox::sorry( Core::self()->uiController()->activeMainWindow(),
293 i18n("Unable to get project file: %1",
294 d->projectFileUrl.pathOrUrl() ) );
295 return false;
299 statJob = KIO::stat( d->developerFileUrl, KIO::HideProgressInfo );
300 if( !statJob->exec() || !KIO::NetAccess::download( d->developerFileUrl, d->developerTempFile,
301 Core::self()->uiController()->activeMainWindow() ) )
304 d->tmp = new KTemporaryFile();
305 d->tmp->open();
306 d->developerTempFile = d->tmp->fileName();
307 d->tmp->close();
310 kDebug() << "Creating KConfig object for project files" << d->developerTempFile << d->projectTempFile;
311 d->m_cfg = KSharedConfig::openConfig( d->developerTempFile );
312 d->m_cfg->addConfigSources( QStringList() << d->projectTempFile );
314 KConfigGroup projectGroup( d->m_cfg, "Project" );
316 d->name = projectGroup.readEntry( "Name", projectFileUrl.fileName() );
317 d->folder = projectFileUrl.directory( KUrl::AppendTrailingSlash );
319 QString managerSetting = projectGroup.readEntry( "Manager", "KDevGenericManager" );
321 //Get our importer
322 IPluginController* pluginManager = Core::self()->pluginController();
323 d->manager = pluginManager->pluginForExtension( "org.kdevelop.IProjectFileManager", managerSetting );
324 IProjectFileManager* iface = 0;
325 if ( d->manager )
326 iface = d->manager->extension<IProjectFileManager>();
327 else
329 KMessageBox::sorry( Core::self()->uiControllerInternal()->defaultMainWindow(),
330 i18n( "Could not load project management plugin %1.",
331 managerSetting ) );
332 d->manager = 0;
333 return false;
335 if ( d->manager && iface )
337 // ProjectModel* model = Core::self()->projectController()->projectModel();
338 d->topItem = iface->import( this );
339 if( !d->topItem )
341 KMessageBox::sorry( Core::self()->uiControllerInternal()->defaultMainWindow(),
342 i18n("Could not open project") );
343 return false;
345 d->topItem->setIcon();
346 // model->insertRow( model->rowCount(), d->topItem );
347 ImportProjectJob* importJob = new ImportProjectJob( d->topItem, iface );
348 connect( importJob, SIGNAL( result( KJob* ) ), this, SLOT( importDone( KJob* ) ) );
349 importJob->start(); //be asynchronous
351 else
353 KMessageBox::sorry( Core::self()->uiControllerInternal()->defaultMainWindow(),
354 i18n( "project importing plugin (%1) does not support the IProjectFileManager interface.", managerSetting ) );
355 delete d->manager;
356 d->manager = 0;
357 return false;
360 QString vcsPlugin = projectGroup.readEntry("VersionControlSupport", "");
361 if( !vcsPlugin.isEmpty() )
363 d->vcsPlugin = pluginManager->pluginForExtension( "org.kdevelop.IBasicVersionControl", vcsPlugin );
366 return true;
369 void Project::close()
371 // unloaded by project controller, depending on shared count
372 // KPluginInfo* pluginInfo = Core::self()->pluginController()->pluginInfo( d->manager );
373 // if ( pluginInfo )
374 // {
375 // Core::self()->pluginController()->unloadPlugin( pluginInfo->pluginName() );
376 // }
378 //the manager plugin will be deleted in the plugin controller, so just set
379 //the manager to zero.
380 // d->manager = 0;
381 Core::self()->projectController()->projectModel()->removeRow( d->topItem->row() );
383 if( d->tmp )
385 d->tmp->close();
388 if( !KIO::NetAccess::upload( d->developerTempFile, d->developerFileUrl,
389 Core::self()->uiController()->activeMainWindow() ) )
391 KMessageBox::sorry( Core::self()->uiController()->activeMainWindow(),
392 i18n("Could not store developer specific project configuration.\n"
393 "Attention: The project settings you changed will be lost."
394 ) );
396 delete d->tmp;
399 bool Project::inProject( const KUrl& url ) const
401 if( url.isLocalFile() && QFileInfo( url.path() ).isFile() )
402 return d->fileSet.contains( IndexedString( url ) );
403 return ( !d->itemsForUrl( url ).isEmpty() );
406 ProjectFileItem* Project::fileAt( int num ) const
408 QList<ProjectFileItem*> files;
409 if ( d->topItem )
410 files = d->recurseFiles( d->topItem );
412 if( !files.isEmpty() && num >= 0 && num < files.count() )
413 return files.at( num );
414 return 0;
417 QList<ProjectFileItem *> KDevelop::Project::files() const
419 QList<ProjectFileItem *> files;
420 if ( d->topItem )
421 files = d->recurseFiles( d->topItem );
422 return files;
425 QList<ProjectFileItem*> Project::filesForUrl(const KUrl& url) const
427 QList<ProjectFileItem*> items;
428 foreach(ProjectBaseItem* item, d->itemsForUrl( url ) )
430 if( item->type() == ProjectBaseItem::File )
431 items << dynamic_cast<ProjectFileItem*>( item );
433 return items;
436 QList<ProjectFolderItem*> Project::foldersForUrl(const KUrl& url) const
438 QList<ProjectFolderItem*> items;
439 foreach(ProjectBaseItem* item, d->itemsForUrl( url ) )
441 if( item->type() == ProjectBaseItem::Folder )
442 items << dynamic_cast<ProjectFolderItem*>( item );
444 return items;
447 int Project::fileCount() const
449 QList<ProjectFileItem*> files;
450 if ( d->topItem )
451 files = d->recurseFiles( d->topItem );
452 return files.count();
455 KUrl Project::relativeUrl( const KUrl& absolute ) const
457 kDebug() << "Creating relative url between: " << folder() << absolute;
458 return KUrl::relativeUrl( folder(), absolute );
461 KUrl Project::urlRelativeToProject( const KUrl & relativeUrl ) const
463 if ( KUrl::isRelativeUrl( relativeUrl.toLocalFile() ) )
464 return KUrl( folder(), relativeUrl.toLocalFile() );
466 return relativeUrl;
469 IProjectFileManager* Project::projectFileManager() const
471 return d->manager->extension<IProjectFileManager>();
474 IBuildSystemManager* Project::buildSystemManager() const
476 return d->manager->extension<IBuildSystemManager>();
479 IPlugin* Project::managerPlugin() const
481 return d->manager;
484 void Project::setManagerPlugin( IPlugin* manager )
486 d->manager = manager;
489 // PersistentHash * Project::persistentHash() const
490 // {
491 // return &d->persistentHash;
492 // }
494 KUrl Project::projectFileUrl() const
496 return d->projectFileUrl;
499 KUrl Project::developerFileUrl() const
501 return d->developerFileUrl;
504 ProjectFolderItem* Project::projectItem() const
506 return d->topItem;
509 IPlugin* Project::versionControlPlugin() const
511 return d->vcsPlugin;
515 void Project::addToFileSet( const IndexedString& file )
517 d->fileSet.insert( file );
520 void Project::removeFromFileSet( const IndexedString& file )
522 d->fileSet.remove( file );
525 QSet<IndexedString> Project::fileSet() const
527 return d->fileSet;
532 #include "project.moc"