core.cpp 18.2 KB
Newer Older
1
/***************************************************************************
2 3
 *   Copyright 2007 Alexander Dymo <adymo@kdevelop.org>             *
 *   Copyright 2007 Kris Wong <kris.p.wong@gmail.com>               *
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *                                                                         *
 *   This program 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 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 Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/
#include "core.h"
Amilcar do Carmo Lucas's avatar
Amilcar do Carmo Lucas committed
21
#include "core_p.h"
22

23
#include <QApplication>
24

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
25
#include <KLocalizedString>
26

27
#include <language/backgroundparser/backgroundparser.h>
28
#include <language/duchain/duchain.h>
29

30
#include "mainwindow.h"
31
#include "sessioncontroller.h"
32 33 34 35 36 37
#include "uicontroller.h"
#include "plugincontroller.h"
#include "projectcontroller.h"
#include "partcontroller.h"
#include "languagecontroller.h"
#include "documentcontroller.h"
38
#include "runcontroller.h"
39
#include "session.h"
40
#include "documentationcontroller.h"
41
#include "sourceformattercontroller.h"
42
#include "progresswidget/progressmanager.h"
43
#include "selectioncontroller.h"
44
#include "debugcontroller.h"
45
#include "kdevplatform_version.h"
46
#include "workingsetcontroller.h"
47
#include "testcontroller.h"
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
48
#include "runtimecontroller.h"
Dāvis Mosāns's avatar
Dāvis Mosāns committed
49
#include "debug.h"
50

51 52
#include <csignal>

53
namespace {
54 55
void shutdownGracefully(int sig)
{
56 57
    static volatile std::sig_atomic_t handlingSignal = 0;

58 59
    if ( !handlingSignal ) {
        handlingSignal = 1;
Dāvis Mosāns's avatar
Dāvis Mosāns committed
60
        qCDebug(SHELL) << "signal " << sig << " received, shutting down gracefully";
61
        QCoreApplication* app = QCoreApplication::instance();
62
        if (auto* guiApp = qobject_cast<QApplication*>(app)) {
63 64 65 66
            guiApp->closeAllWindows();
        }
        app->quit();
        return;
67
    }
68 69 70 71

    // re-raise signal with default handler and trigger program termination
    std::signal(sig, SIG_DFL);
    std::raise(sig);
72 73 74 75 76 77 78 79 80 81 82 83 84 85
}

void installSignalHandler()
{
#ifdef SIGHUP
    std::signal(SIGHUP, shutdownGracefully);
#endif
#ifdef SIGINT
    std::signal(SIGINT, shutdownGracefully);
#endif
#ifdef SIGTERM
    std::signal(SIGTERM, shutdownGracefully);
#endif
}
86
}
87

88 89
namespace KDevelop {

90
Core *Core::m_self = nullptr;
91 92

KAboutData createAboutData()
93
{
94 95
    KAboutData aboutData( QStringLiteral("kdevplatform"),
                          i18n("KDevelop Platform"), QStringLiteral(KDEVPLATFORM_VERSION_STRING),
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
96
                          i18n("Development Platform for IDE-like Applications"),
97
                          KAboutLicense::LGPL_V2,
98
                          i18n("Copyright 2004-%1, The KDevelop developers", QStringLiteral("2020")),
99
                          QString(), QStringLiteral("https://www.kdevelop.org/"));
100 101 102 103

    aboutData.addAuthor( i18n("Andreas Pakulat"), i18n( "Architecture, VCS Support, Project Management Support, QMake Projectmanager" ), QStringLiteral("apaku@gmx.de") );
    aboutData.addAuthor( i18n("Alexander Dymo"), i18n( "Architecture, Sublime UI, Ruby support" ), QStringLiteral("adymo@kdevelop.org") );
    aboutData.addAuthor( i18n("David Nolden"), i18n( "Definition-Use Chain, C++ Support" ), QStringLiteral("david.nolden.kdevelop@art-master.de") );
104
    aboutData.addAuthor( i18n("Aleix Pol Gonzalez"), i18n( "CMake Support, Run Support, Kross Support" ), QStringLiteral("aleixpol@kde.org") );
105 106 107 108 109 110
    aboutData.addAuthor( i18n("Vladimir Prus"), i18n( "GDB integration" ), QStringLiteral("ghost@cs.msu.su") );
    aboutData.addAuthor( i18n("Hamish Rodda"), i18n( "Text editor integration, definition-use chain" ), QStringLiteral("rodda@kde.org") );

    aboutData.addCredit( i18n("Matt Rogers"), QString(), QStringLiteral("mattr@kde.org"));
    aboutData.addCredit( i18n("Cédric Pasteur"), i18n("astyle and indent support"), QStringLiteral("cedric.pasteur@free.fr") );
    aboutData.addCredit( i18n("Evgeniy Ivanov"), i18n("Distributed VCS, Git, Mercurial"), QStringLiteral("powerfox@kde.ru") );
111
    //Veritas is outside in playground currently.
Yuri Chornoivan's avatar
Yuri Chornoivan committed
112
    //aboutData.addCredit( i18n("Manuel Breugelmanns"), i18n( "Veritas, QTest integration"), "mbr.nxi@gmail.com" );
113 114 115
    aboutData.addCredit( i18n("Robert Gruber") , i18n( "SnippetPart, debugger and usability patches" ), QStringLiteral("rgruber@users.sourceforge.net") );
    aboutData.addCredit( i18n("Dukju Ahn"), i18n( "Subversion plugin, Custom Make Manager, Overall improvements" ), QStringLiteral("dukjuahn@gmail.com") );
    aboutData.addAuthor( i18n("Niko Sams"), i18n( "GDB integration, Webdevelopment Plugins" ), QStringLiteral("niko.sams@gmail.com") );
116 117 118
    aboutData.addAuthor( i18n("Milian Wolff"), i18n( "Generic manager, Webdevelopment Plugins, Snippets, Performance" ), QStringLiteral("mail@milianw.de") );
    aboutData.addAuthor( i18n("Kevin Funk"), i18n( "Co-maintainer, C++/Clang, QA, Windows Support, Performance, Website" ), QStringLiteral("kfunk@kde.org") );
    aboutData.addAuthor( i18n("Sven Brauch"), i18n( "Co-maintainer, AppImage, Python Support, User Interface improvements" ), QStringLiteral("svenbrauch@gmx.de") );
119
    aboutData.addAuthor( i18n("Friedrich W. H. Kossebau"), QString(), QStringLiteral("kossebau@kde.org") );
Andreas Pakulat's avatar
Andreas Pakulat committed
120

121 122
    return aboutData;
}
123

124
CorePrivate::CorePrivate(Core *core):
125
    m_aboutData( createAboutData() ), m_core(core), m_cleanedUp(false), m_shuttingDown(false)
126 127
{
}
128

129
bool CorePrivate::initialize(Core::Setup mode, const QString& session )
130 131
{
    m_mode=mode;
132 133 134

    qCDebug(SHELL) << "Creating controllers";

135
    if( !sessionController )
136
    {
137
        sessionController = new SessionController(m_core);
138
    }
139
    if( !workingSetController && !(mode & Core::NoUi) )
140
    {
141
        workingSetController = new WorkingSetController();
142
    }
Dāvis Mosāns's avatar
Dāvis Mosāns committed
143
    qCDebug(SHELL) << "Creating ui controller";
144
    if( !uiController )
145
    {
146
        uiController = new UiController(m_core);
147
    }
Dāvis Mosāns's avatar
Dāvis Mosāns committed
148
    qCDebug(SHELL) << "Creating plugin controller";
149 150 151

    if( !pluginController )
    {
152
        pluginController = new PluginController(m_core);
153 154 155 156 157 158
        const auto pluginInfos = pluginController->allPluginInfos();
        if (pluginInfos.isEmpty()) {
            QMessageBox::critical(nullptr,
                                  i18n("Could not find any plugins"),
                                  i18n("<p>Could not find any plugins during startup.<br/>"
                                  "Please make sure QT_PLUGIN_PATH is set correctly.</p>"
159
                                  "Refer to <a href=\"https://community.kde.org/Guidelines_and_HOWTOs/Build_from_source#Set_up_the_runtime_environment\">this article</a> for more information."),
160
                                  QMessageBox::Abort, QMessageBox::Abort);
Kevin Funk's avatar
Kevin Funk committed
161
            qCWarning(SHELL) << "Could not find any plugins, aborting";
162 163
            return false;
        }
164
    }
165 166
    if( !partController && !(mode & Core::NoUi))
    {
167
        partController = new PartController(m_core, uiController->defaultMainWindow());
168
    }
169 170 171

    if( !projectController )
    {
172
        projectController = new ProjectController(m_core);
173 174
    }

175
    if( !documentController )
176
    {
177
        documentController = new DocumentController(m_core);
178 179
    }

180
    if( !languageController )
181
    {
182 183 184
        // Must be initialized after documentController, because the background parser depends
        // on the document controller.
        languageController = new LanguageController(m_core);
185
    }
186

187 188 189
    if( !runController )
    {
        runController = new RunController(m_core);
190
    }
191

192
    if( !sourceFormatterController )
193 194
    {
        sourceFormatterController = new SourceFormatterController(m_core);
195
    }
196

Dāvis Mosāns's avatar
Dāvis Mosāns committed
197
    if ( !progressController)
198
    {
199
        progressController = ProgressManager::instance();
200 201
    }

202 203 204 205
    if( !selectionController )
    {
        selectionController = new SelectionController(m_core);
    }
206

207
    if( !documentationController && !(mode & Core::NoUi) )
208 209 210
    {
        documentationController = new DocumentationController(m_core);
    }
211

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
212 213 214 215 216
    if( !runtimeController )
    {
        runtimeController = new RuntimeController(m_core);
    }

217 218 219 220
    if( !debugController )
    {
        debugController = new DebugController(m_core);
    }
221 222 223 224 225 226

    if( !testController )
    {
        testController = new TestController(m_core);
    }

227 228 229
    qCDebug(SHELL) << "Done creating controllers";

    qCDebug(SHELL) << "Initializing controllers";
230

231 232
    sessionController->initialize( session );
    if( !sessionController->activeSessionLock() ) {
233 234
        return false;
    }
235

236 237
    // TODO: Is this early enough, or should we put the loading of the session into
    // the controller construct
238
    DUChain::initialize();
239

Kevin Funk's avatar
Kevin Funk committed
240
    if (!(mode & Core::NoUi)) {
241
        uiController->initialize();
Kevin Funk's avatar
Kevin Funk committed
242
    }
243
    languageController->initialize();
244 245 246 247 248 249
    languageController->backgroundParser()->suspend();
    // eventually resume the background parser once the project controller
    // has been initialized. At that point we know whether there are projects loading
    // which the background parser is handling internally to defer parse jobs
    QObject::connect(projectController.data(), &ProjectController::initialized,
                     m_core, [this]() {
250
                         languageController->backgroundParser()->resume();
251 252
                     });

Kevin Funk's avatar
Kevin Funk committed
253
    if (partController) {
254
        partController->initialize();
Kevin Funk's avatar
Kevin Funk committed
255
    }
256 257
    projectController->initialize();
    documentController->initialize();
258 259 260 261 262 263 264 265 266 267

    /* This is somewhat messy.  We want to load the areas before
        loading the plugins, so that when each plugin is loaded we
        know if an area wants some of the tool view from that plugin.
        OTOH, loading of areas creates documents, and some documents
        might require that a plugin is already loaded.
        Probably, the best approach would be to plugins to just add
        tool views to a list of available tool view, and then grab
        those tool views when loading an area.  */

268
    qCDebug(SHELL) << "Initializing plugin controller (loading session plugins)";
269
    pluginController->initialize();
270

271
    qCDebug(SHELL) << "Initializing working set controller";
272
    if(!(mode & Core::NoUi))
273
    {
274
        workingSetController->initialize();
275 276 277
        /* Need to do this after everything else is loaded.  It's too
            hard to restore position of views, and toolbars, and whatever
            that are not created yet.  */
278 279
        uiController->loadAllAreas(KSharedConfig::openConfig());
        uiController->defaultMainWindow()->show();
280
    }
281 282

    qCDebug(SHELL) << "Initializing remaining controllers";
283 284 285
    runController->initialize();
    sourceFormatterController->initialize();
    selectionController->initialize();
286
    if (documentationController) {
287
        documentationController->initialize();
288
    }
289 290 291
    debugController->initialize();
    testController->initialize();
    runtimeController->initialize();
292 293 294

    installSignalHandler();

295 296
    qCDebug(SHELL) << "Done initializing controllers";

297
    return true;
298 299 300
}
CorePrivate::~CorePrivate()
{
301 302 303 304 305 306 307 308 309 310 311 312 313
    delete selectionController.data();
    delete projectController.data();
    delete languageController.data();
    delete pluginController.data();
    delete uiController.data();
    delete partController.data();
    delete documentController.data();
    delete runController.data();
    delete sessionController.data();
    delete sourceFormatterController.data();
    delete documentationController.data();
    delete debugController.data();
    delete workingSetController.data();
314
    delete testController.data();
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
315
    delete runtimeController.data();
316 317 318 319 320 321 322 323 324 325 326 327 328 329

    selectionController.clear();
    projectController.clear();
    languageController.clear();
    pluginController.clear();
    uiController.clear();
    partController.clear();
    documentController.clear();
    runController.clear();
    sessionController.clear();
    sourceFormatterController.clear();
    documentationController.clear();
    debugController.clear();
    workingSetController.clear();
330
    testController.clear();
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
331
    runtimeController.clear();
332
}
333

334
bool Core::initialize(Setup mode, const QString& session)
335
{
336
    if (m_self)
337
        return true;
Kris Wong's avatar
Kris Wong committed
338

339
    m_self = new Core();
340
    bool ret = m_self->d->initialize(mode, session);
Dāvis Mosāns's avatar
Dāvis Mosāns committed
341

342 343
    if(ret)
        emit m_self->initializationCompleted();
Dāvis Mosāns's avatar
Dāvis Mosāns committed
344

345
    return ret;
346 347 348 349
}

Core *KDevelop::Core::self()
{
350
    return m_self;
351 352 353
}

Core::Core(QObject *parent)
Kris Wong's avatar
Kris Wong committed
354
    : ICore(parent)
355 356
{
    d = new CorePrivate(this);
357

358
    connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Core::shutdown);
359 360
}

361 362 363
Core::Core(CorePrivate* dd, QObject* parent)
: ICore(parent), d(dd)
{
364
    connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Core::shutdown);
365 366
}

367 368
Core::~Core()
{
Kevin Funk's avatar
Kevin Funk committed
369 370
    qCDebug(SHELL);

371
    //Cleanup already called before mass destruction of GUI
372
    delete d;
373
    m_self = nullptr;
374 375
}

376 377 378 379 380
Core::Setup Core::setupFlags() const
{
    return d->m_mode;
}

381 382
void Core::shutdown()
{
Kevin Funk's avatar
Kevin Funk committed
383 384
    qCDebug(SHELL);

385 386 387 388
    if (!d->m_shuttingDown) {
        cleanup();
        deleteLater();
    }
Kevin Funk's avatar
Kevin Funk committed
389 390

    qCDebug(SHELL) << "Shutdown done";
391 392
}

393 394 395 396 397
bool Core::shuttingDown() const
{
    return d->m_shuttingDown;
}

398 399
void Core::cleanup()
{
Kevin Funk's avatar
Kevin Funk committed
400 401
    qCDebug(SHELL);

402
    d->m_shuttingDown = true;
403 404
    emit aboutToShutdown();

405
    if (!d->m_cleanedUp) {
406
        // first of all: request stop of all background parser jobs
407 408 409
        d->languageController->backgroundParser()->abortAllJobs();
        d->languageController->backgroundParser()->suspend();

410 411
        d->debugController->cleanup();
        d->selectionController->cleanup();
412
        // Save the layout of the ui here, so run it first
413
        d->uiController->cleanup();
414 415

        if (d->workingSetController)
416
            d->workingSetController->cleanup();
417

418
        /* Must be called before projectController->cleanup(). */
419
        // Closes all documents (discards, as already saved if the user wished earlier)
420 421
        d->documentController->cleanup();
        d->runController->cleanup();
Kevin Funk's avatar
Kevin Funk committed
422 423 424
        if (d->partController) {
            d->partController->cleanup();
        }
425 426
        d->projectController->cleanup();
        d->sourceFormatterController->cleanup();
427 428 429

        // before unloading language plugins, we need to make sure all parse jobs are done
        d->languageController->backgroundParser()->waitForIdle();
430 431 432 433 434

        DUChain::self()->shutdown();

        // Only unload plugins after the DUChain shutdown to prevent issues with non-loaded factories for types
        // See: https://bugs.kde.org/show_bug.cgi?id=379669
435
        d->pluginController->cleanup();
436

437
        d->sessionController->cleanup();
438

439
        d->testController->cleanup();
440

441
        //Disable the functionality of the language controller
442
        d->languageController->cleanup();
443 444 445
    }

    d->m_cleanedUp = true;
446
    emit shutdownCompleted();
447 448
}

449
KAboutData Core::aboutData() const
450
{
451
    return d->m_aboutData;
452 453
}

454 455
IUiController *Core::uiController()
{
456
    return d->uiController.data();
457 458
}

459 460 461 462 463
ISession* Core::activeSession()
{
    return sessionController()->activeSession();
}

464 465 466 467 468
ISessionLock::Ptr Core::activeSessionLock()
{
    return sessionController()->activeSessionLock();
}

469
SessionController *Core::sessionController()
470
{
471
    return d->sessionController.data();
472 473
}

Kris Wong's avatar
Kris Wong committed
474 475
UiController *Core::uiControllerInternal()
{
476
    return d->uiController.data();
Kris Wong's avatar
Kris Wong committed
477 478 479
}

IPluginController *Core::pluginController()
480
{
481
    return d->pluginController.data();
482 483
}

Kris Wong's avatar
Kris Wong committed
484 485
PluginController *Core::pluginControllerInternal()
{
486
    return d->pluginController.data();
Kris Wong's avatar
Kris Wong committed
487 488 489
}

IProjectController *Core::projectController()
490
{
491
    return d->projectController.data();
492 493
}

Kris Wong's avatar
Kris Wong committed
494
ProjectController *Core::projectControllerInternal()
495
{
496
    return d->projectController.data();
497 498
}

499
IPartController *Core::partController()
500
{
501
    return d->partController.data();
502 503
}

504
PartController *Core::partControllerInternal()
505
{
506
    return d->partController.data();
507 508 509 510
}

ILanguageController *Core::languageController()
{
511
    return d->languageController.data();
512 513
}

Kris Wong's avatar
Kris Wong committed
514
LanguageController *Core::languageControllerInternal()
515
{
516
    return d->languageController.data();
517 518
}

Kris Wong's avatar
Kris Wong committed
519
IDocumentController *Core::documentController()
520
{
521
    return d->documentController.data();
522 523
}

Kris Wong's avatar
Kris Wong committed
524
DocumentController *Core::documentControllerInternal()
525
{
526
    return d->documentController.data();
527 528
}

529 530
IRunController *Core::runController()
{
531
    return d->runController.data();
532 533
}

534 535
RunController *Core::runControllerInternal()
{
536
    return d->runController.data();
537 538
}

539
ISourceFormatterController* Core::sourceFormatterController()
540
{
541
    return d->sourceFormatterController.data();
542
}
543

544 545
SourceFormatterController* Core::sourceFormatterControllerInternal()
{
546
    return d->sourceFormatterController.data();
547 548 549
}


550 551
ProgressManager *Core::progressController()
{
552
    return d->progressController.data();
553 554
}

555 556
ISelectionController* Core::selectionController()
{
557
    return d->selectionController.data();
558 559
}

560 561
IDocumentationController* Core::documentationController()
{
562
    return d->documentationController.data();
563 564
}

565 566
DocumentationController* Core::documentationControllerInternal()
{
567
    return d->documentationController.data();
568 569
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
570 571 572 573 574 575 576 577 578 579
IRuntimeController* Core::runtimeController()
{
    return d->runtimeController.data();
}

RuntimeController* Core::runtimeControllerInternal()
{
    return d->runtimeController.data();
}

580 581
IDebugController* Core::debugController()
{
582
    return d->debugController.data();
583 584 585 586
}

DebugController* Core::debugControllerInternal()
{
587
    return d->debugController.data();
588 589
}

590 591 592 593 594 595 596 597 598 599
ITestController* Core::testController()
{
    return d->testController.data();
}

TestController* Core::testControllerInternal()
{
    return d->testController.data();
}

600 601
WorkingSetController* Core::workingSetControllerInternal()
{
602
    return d->workingSetController.data();
603 604
}

605 606
QString Core::version()
{
607
    return QStringLiteral(KDEVPLATFORM_VERSION_STRING);
608 609
}

610
}
611