5
#include <qstringlist.h>
13
#include <kmessagebox.h>
18
#include <kfiledialog.h>
19
#include <kmainwindow.h>
20
#include <kparts/componentfactory.h>
22
#include <kapplication.h>
23
#include <kcmdlineargs.h>
26
#include <kstandarddirs.h>
27
#include <kio/netaccess.h>
28
#include <ktempfile.h>
30
#include <kstatusbar.h>
31
#include <kiconloader.h>
33
#include "kdevproject.h"
34
#include "kdevlanguagesupport.h"
35
#include "kdevplugin.h"
36
#include "kdevcreatefile.h"
37
#include "kdevversioncontrol.h"
43
#include "plugincontroller.h"
44
#include "partcontroller.h"
45
#include "codemodel.h"
46
#include "partselectwidget.h"
47
#include "languageselectwidget.h"
48
#include "generalinfowidget.h"
49
#include "projectsession.h"
52
#include "projectmanager.h"
54
QString ProjectInfo::sessionFile() const
56
QString sf = m_projectURL.path(-1);
57
sf.truncate(sf.length() - 8); // without ".kdevelop"
58
sf += "kdevses"; // suffix for a KDevelop session file
62
QString ProjectManager::projectDirectory( const QString& path, bool absolute ) {
65
KURL url(ProjectManager::getInstance()->projectFile(), path);
70
ProjectManager *ProjectManager::s_instance = 0;
72
ProjectManager::ProjectManager()
74
,m_pProjectSession(new ProjectSession)
78
ProjectManager::~ProjectManager()
80
delete m_pProjectSession;
84
ProjectManager *ProjectManager::getInstance()
87
s_instance = new ProjectManager;
91
void ProjectManager::createActions( KActionCollection* ac )
95
action = new KAction(i18n("&Open Project..."), "project_open", 0,
96
this, SLOT(slotOpenProject()),
98
action->setToolTip( i18n("Open project"));
99
action->setWhatsThis(i18n("<b>Open project</b><p>Opens a KDevelop3 or KDevelop2 project."));
101
m_openRecentProjectAction =
102
new KRecentFilesAction(i18n("Open &Recent Project"), 0,
103
this, SLOT(loadProject(const KURL &)),
104
ac, "project_open_recent");
105
m_openRecentProjectAction->setToolTip(i18n("Open recent project"));
106
m_openRecentProjectAction->setWhatsThis(i18n("<b>Open recent project</b><p>Opens recently opened project."));
107
m_openRecentProjectAction->loadEntries(kapp->config(), "RecentProjects");
109
m_closeProjectAction =
110
new KAction(i18n("C&lose Project"), "fileclose",0,
111
this, SLOT(closeProject()),
112
ac, "project_close");
113
m_closeProjectAction->setEnabled(false);
114
m_closeProjectAction->setToolTip(i18n("Close project"));
115
m_closeProjectAction->setWhatsThis(i18n("<b>Close project</b><p>Closes the current project."));
117
m_projectOptionsAction = new KAction(i18n("Project &Options"), "configure", 0,
118
this, SLOT(slotProjectOptions()),
119
ac, "project_options" );
120
m_projectOptionsAction->setToolTip(i18n("Project options"));
121
m_projectOptionsAction->setWhatsThis(i18n("<b>Project options</b><p>Lets you customize project options."));
122
m_projectOptionsAction->setEnabled(false);
125
void ProjectManager::slotOpenProject()
127
KConfig *config = kapp->config();
128
config->setGroup("General Options");
129
QString defaultProjectsDir = config->readPathEntry("DefaultProjectsDir", QDir::homeDirPath()+"/");
131
KURL url = KFileDialog::getOpenURL(defaultProjectsDir,
132
i18n("*.kdevelop|KDevelop 3 Project Files\n"
133
"*.kdevprj|KDevelop 2 Project Files"),
134
TopLevel::getInstance()->main(), i18n("Open Project") );
139
if (url.path().endsWith("kdevprj"))
140
loadKDevelop2Project( url );
145
void ProjectManager::slotProjectOptions()
147
KDialogBase dlg(KDialogBase::IconList, i18n("Project Options"),
148
KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, TopLevel::getInstance()->main(),
149
"project options dialog");
151
QVBox *box = dlg.addVBoxPage( i18n("General"), i18n("General"), BarIcon( "kdevelop", KIcon::SizeMedium ) );
152
GeneralInfoWidget *g = new GeneralInfoWidget(*API::getInstance()->projectDom(), box, "general informations widget");
153
connect (&dlg, SIGNAL(okClicked()), g, SLOT(accept()));
155
QVBox *vbox = dlg.addVBoxPage( i18n("Plugins"), i18n("Plugins"), BarIcon( "kdf", KIcon::SizeMedium ) );
156
PartSelectWidget *w = new PartSelectWidget(*API::getInstance()->projectDom(), vbox, "part selection widget");
157
connect( &dlg, SIGNAL(okClicked()), w, SLOT(accept()) );
158
connect( w, SIGNAL(accepted()), this, SLOT(loadLocalParts()) );
160
KConfig *config = kapp->config();
161
config->setGroup("Project Settings Dialog");
162
int height = config->readNumEntry( "Height", 600 );
163
int width = config->readNumEntry( "Width", 800 );
165
dlg.resize( width, height );
167
Core::getInstance()->doEmitProjectConfigWidget(&dlg);
172
config->setGroup("Project Settings Dialog");
173
config->writeEntry( "Height", dlg.size().height() );
174
config->writeEntry( "Width", dlg.size().width() );
177
void ProjectManager::loadSettings()
181
void ProjectManager::saveSettings()
183
KConfig *config = kapp->config();
187
config->setGroup("General Options");
188
config->writePathEntry("Last Project", ProjectManager::getInstance()->projectFile().url());
191
m_openRecentProjectAction->saveEntries(config, "RecentProjects");
194
void ProjectManager::loadDefaultProject()
196
KConfig *config = kapp->config();
197
config->setGroup("General Options");
198
QString project = config->readPathEntry("Last Project");
199
bool readProject = config->readBoolEntry("Read Last Project On Startup", true);
200
if (!project.isEmpty() && readProject)
202
loadProject(KURL(project));
206
bool ProjectManager::loadProject(const KURL &projectURL)
208
KURL url = projectURL;
213
if (url.isLocalFile())
215
QDir dir(url.path());
216
url.setPath(dir.canonicalPath());
219
// reopen the already opened project?
220
if( url.path() == projectFile().path() )
222
if (KMessageBox::questionYesNo(TopLevel::getInstance()->main(),
223
i18n("Are you sure you want to reopen the current project?"), QString::null, i18n("Reopen"), i18n("Do Not Reopen")) == KMessageBox::No)
227
TopLevel::getInstance()->main()->menuBar()->setEnabled( false );
228
kapp->setOverrideCursor( waitCursor );
230
if( projectLoaded() && !closeProject() )
232
m_openRecentProjectAction->setCurrentItem( -1 );
233
TopLevel::getInstance()->main()->menuBar()->setEnabled( true );
234
kapp->restoreOverrideCursor();
238
m_info = new ProjectInfo;
239
m_info->m_projectURL = url;
241
QTimer::singleShot( 0, this, SLOT(slotLoadProject()) );
243
// no one cares about this value
247
void ProjectManager::slotLoadProject( )
249
if( !loadProjectFile() )
251
m_openRecentProjectAction->removeURL(m_info->m_projectURL);
252
delete m_info; m_info = 0;
254
TopLevel::getInstance()->main()->menuBar()->setEnabled( true );
255
kapp->restoreOverrideCursor();
261
if( !loadLanguageSupport(m_info->m_language) ) {
262
delete m_info; m_info = 0;
263
TopLevel::getInstance()->main()->menuBar()->setEnabled( true );
264
kapp->restoreOverrideCursor();
268
if( !loadProjectPart() ) {
269
unloadLanguageSupport();
270
delete m_info; m_info = 0;
271
TopLevel::getInstance()->main()->menuBar()->setEnabled( true );
272
kapp->restoreOverrideCursor();
276
TopLevel::getInstance()->statusBar()->message( i18n("Changing plugin profile...") );
277
m_oldProfileName = PluginController::getInstance()->changeProfile(m_info->m_profileName);
279
TopLevel::getInstance()->statusBar()->message( i18n("Loading project plugins...") );
282
// shall we try to load a session file from network?? Probably not.
283
if (m_info->m_projectURL.isLocalFile())
285
// first restore the project session stored in a .kdevses file
286
if (!m_pProjectSession->restoreFromFile(m_info->sessionFile(), PluginController::getInstance()->loadedPlugins() ))
288
kdWarning() << i18n("error during restoring of the KDevelop session !") << endl;
292
m_openRecentProjectAction->addURL(projectFile());
294
m_closeProjectAction->setEnabled(true);
295
m_projectOptionsAction->setEnabled(true);
297
Core::getInstance()->doEmitProjectOpened();
299
TopLevel::getInstance()->main()->menuBar()->setEnabled( true );
300
kapp->restoreOverrideCursor();
302
TopLevel::getInstance()->statusBar()->message( i18n("Project loaded."), 3000 );
308
bool ProjectManager::closeProject( bool exiting )
310
if( !projectLoaded() )
313
// save the session if it is a local file
314
if (m_info->m_projectURL.isLocalFile())
316
m_pProjectSession->saveToFile(m_info->sessionFile(), PluginController::getInstance()->loadedPlugins() );
319
if ( !PartController::getInstance()->querySaveFiles() )
322
Core::getInstance()->doEmitProjectClosed();
324
PluginController::getInstance()->unloadProjectPlugins();
325
PluginController::getInstance()->changeProfile(m_oldProfileName);
326
unloadLanguageSupport();
329
/// @todo if this fails, user is screwed
332
API::getInstance()->setProjectDom(0);
333
API::getInstance()->codeModel()->wipeout();
338
m_closeProjectAction->setEnabled(false);
339
m_projectOptionsAction->setEnabled(false);
343
PartController::getInstance()->slotCloseAllWindows();
349
bool ProjectManager::loadProjectFile()
352
if (!KIO::NetAccess::download(m_info->m_projectURL, path, 0)) {
353
KMessageBox::sorry(TopLevel::getInstance()->main(),
354
i18n("Could not read project file: %1").arg(m_info->m_projectURL.prettyURL()));
359
if (!fin.open(IO_ReadOnly))
361
KMessageBox::sorry(TopLevel::getInstance()->main(),
362
i18n("Could not read project file: %1").arg(m_info->m_projectURL.prettyURL()));
366
int errorLine, errorCol;
368
if (!m_info->m_document.setContent(&fin, &errorMsg, &errorLine, &errorCol))
370
KMessageBox::sorry(TopLevel::getInstance()->main(),
371
i18n("This is not a valid project file.\n"
372
"XML error in line %1, column %2:\n%3")
373
.arg(errorLine).arg(errorCol).arg(errorMsg));
375
KIO::NetAccess::removeTempFile(path);
378
if (m_info->m_document.documentElement().nodeName() != "kdevelop")
380
KMessageBox::sorry(TopLevel::getInstance()->main(),
381
i18n("This is not a valid project file."));
383
KIO::NetAccess::removeTempFile(path);
388
KIO::NetAccess::removeTempFile(path);
390
API::getInstance()->setProjectDom(&m_info->m_document);
395
bool ProjectManager::saveProjectFile()
397
Q_ASSERT( API::getInstance()->projectDom() );
399
if (m_info->m_projectURL.isLocalFile()) {
400
QFile fout(m_info->m_projectURL.path());
401
if( !fout.open(IO_WriteOnly) ) {
402
KMessageBox::sorry(TopLevel::getInstance()->main(), i18n("Could not write the project file."));
406
QTextStream stream(&fout);
407
API::getInstance()->projectDom()->save(stream, 2);
410
KTempFile fout(QString::fromLatin1("kdevelop3"));
411
fout.setAutoDelete(true);
412
if (fout.status() != 0) {
413
KMessageBox::sorry(TopLevel::getInstance()->main(), i18n("Could not write the project file."));
416
API::getInstance()->projectDom()->save(*(fout.textStream()), 2);
418
KIO::NetAccess::upload(fout.name(), m_info->m_projectURL, 0);
424
static QString getAttribute(QDomElement elem, QString attr)
426
QDomElement el = elem.namedItem(attr).toElement();
427
return el.firstChild().toText().data();
430
static void getAttributeList(QDomElement elem, QString attr, QString tag, QStringList &list)
434
QDomElement el = elem.namedItem(attr).toElement();
435
QDomElement item = el.firstChild().toElement();
436
while (!item.isNull())
438
if (item.tagName() == tag)
439
list << item.firstChild().toText().data();
440
item = item.nextSibling().toElement();
444
void ProjectManager::getGeneralInfo()
446
QDomElement docEl = m_info->m_document.documentElement();
447
QDomElement generalEl = docEl.namedItem("general").toElement();
449
m_info->m_projectPlugin = getAttribute(generalEl, "projectmanagement");
450
m_info->m_vcsPlugin = getAttribute(generalEl, "versioncontrol");
451
m_info->m_language = getAttribute(generalEl, "primarylanguage");
453
getAttributeList(generalEl, "ignoreparts", "part", m_info->m_ignoreParts);
454
getAttributeList(generalEl, "keywords", "keyword", m_info->m_keywords);
456
//FIXME: adymo: workaround for those project templates without "profile" element
457
// m_info->m_profileName = getAttribute(generalEl, "profile");
458
QDomElement el = generalEl.namedItem("profile").toElement();
460
m_info->m_profileName = profileByAttributes(m_info->m_language, m_info->m_keywords);
462
m_info->m_profileName = el.firstChild().toText().data();
465
bool ProjectManager::loadProjectPart()
467
KService::Ptr projectService = KService::serviceByDesktopName(m_info->m_projectPlugin);
468
if (!projectService) {
469
// this is for backwards compatibility with pre-alpha6 projects
470
projectService = KService::serviceByDesktopName(m_info->m_projectPlugin.lower());
472
if (!projectService) {
473
KMessageBox::sorry(TopLevel::getInstance()->main(),
474
i18n("No project management plugin %1 found.")
475
.arg(m_info->m_projectPlugin));
479
KDevProject *projectPart = KParts::ComponentFactory
480
::createInstanceFromService< KDevProject >( projectService, API::getInstance(), 0,
481
PluginController::argumentsFromService( projectService ) );
482
if ( !projectPart ) {
483
KMessageBox::sorry(TopLevel::getInstance()->main(),
484
i18n("Could not create project management plugin %1.")
485
.arg(m_info->m_projectPlugin));
489
API::getInstance()->setProject( projectPart );
491
QDomDocument& dom = *API::getInstance()->projectDom();
492
QString path = DomUtil::readEntry(dom,"/general/projectdirectory", ".");
493
bool absolute = DomUtil::readBoolEntry(dom,"/general/absoluteprojectpath",false);
494
QString projectDir = projectDirectory( path, absolute );
495
kdDebug(9000) << "projectDir: " << projectDir << " projectName: " << m_info->m_projectURL.fileName() << endl;
497
projectPart->openProject(projectDir, m_info->m_projectURL.fileName());
499
PluginController::getInstance()->integratePart( projectPart );
504
void ProjectManager::unloadProjectPart()
506
KDevProject *projectPart = API::getInstance()->project();
507
if( !projectPart ) return;
508
PluginController::getInstance()->removePart( projectPart );
509
projectPart->closeProject();
511
API::getInstance()->setProject(0);
514
bool ProjectManager::loadLanguageSupport(const QString& lang)
516
kdDebug(9000) << "Looking for language support for " << lang << endl;
518
if (lang == m_info->m_activeLanguage)
520
kdDebug(9000) << "Language support already loaded" << endl;
524
KTrader::OfferList languageSupportOffers =
525
KTrader::self()->query(QString::fromLatin1("KDevelop/LanguageSupport"),
526
QString::fromLatin1("[X-KDevelop-Language] == '%1' and [X-KDevelop-Version] == %2").arg(lang).arg(KDEVELOP_PLUGIN_VERSION));
528
if (languageSupportOffers.isEmpty()) {
529
KMessageBox::sorry(TopLevel::getInstance()->main(),
530
i18n("No language plugin for %1 found.")
535
KService::Ptr languageSupportService = *languageSupportOffers.begin();
536
KDevLanguageSupport *langSupport = KParts::ComponentFactory
537
::createInstanceFromService<KDevLanguageSupport>( languageSupportService,
540
PluginController::argumentsFromService( languageSupportService ) );
542
if ( !langSupport ) {
543
KMessageBox::sorry(TopLevel::getInstance()->main(),
544
i18n("Could not create language plugin for %1.")
549
API::getInstance()->setLanguageSupport( langSupport );
550
PluginController::getInstance()->integratePart( langSupport );
551
m_info->m_activeLanguage = lang;
552
kdDebug(9000) << "Language support for " << lang << " successfully loaded." << endl;
556
void ProjectManager::unloadLanguageSupport()
558
KDevLanguageSupport *langSupport = API::getInstance()->languageSupport();
559
if( !langSupport ) return;
560
kdDebug(9000) << "Language support for " << langSupport->name() << " unloading..." << endl;
561
PluginController::getInstance()->removePart( langSupport );
563
API::getInstance()->setLanguageSupport(0);
566
void ProjectManager::loadLocalParts()
568
// Make sure to refresh load/ignore lists
571
PluginController::getInstance()->unloadPlugins( m_info->m_ignoreParts );
572
PluginController::getInstance()->loadProjectPlugins( m_info->m_ignoreParts );
573
PluginController::getInstance()->loadGlobalPlugins( m_info->m_ignoreParts );
576
KURL ProjectManager::projectFile() const
580
return m_info->m_projectURL;
583
bool ProjectManager::projectLoaded() const
588
ProjectSession* ProjectManager::projectSession() const
590
return m_pProjectSession;
593
bool ProjectManager::loadKDevelop2Project( const KURL & url )
595
if( !url.isValid() || !url.isLocalFile() ){
596
KMessageBox::sorry(0, i18n("Invalid URL."));
600
QString cmd = KGlobal::dirs()->findExe( "kdevprj2kdevelop" );
602
KMessageBox::sorry(0, i18n("You do not have 'kdevprj2kdevelop' installed."));
606
QFileInfo fileInfo( url.path() );
608
KShellProcess proc( "/bin/sh" );
609
proc.setWorkingDirectory( fileInfo.dirPath(true) );
610
proc << "perl" << cmd << KShellProcess::quote( url.path() );
611
proc.start( KProcess::Block );
613
QString projectFile = fileInfo.dirPath( true ) + "/" + fileInfo.baseName() + ".kdevelop";
614
return loadProject( KURL(projectFile) );
617
QString ProjectManager::profileByAttributes(const QString &language, const QStringList &keywords)
619
KConfig config(locate("data", "kdevelop/profiles/projectprofiles"));
620
config.setGroup(language);
622
QStringList profileKeywords = QStringList::split("/", "Empty");
623
if (config.hasKey("Keywords"))
624
profileKeywords = config.readListEntry("Keywords");
627
for (QStringList::const_iterator it = profileKeywords.constBegin();
628
it != profileKeywords.constEnd(); ++it)
630
if (keywords.contains(*it))
632
idx = profileKeywords.findIndex(*it);
637
QStringList profiles;
638
if (config.hasKey("Profiles"))
640
profiles = config.readListEntry("Profiles");
641
kdDebug() << "IDX: " << idx << " PROFILE: " << profiles[idx] << endl;
642
return profiles[idx];
647
#include "projectmanager.moc"