OSDN Git Service

Merge branch 'master' into requirements-checking
[alterlinux/alterlinux-calamares.git] / src / calamares / CalamaresApplication.cpp
1 /* === This file is part of Calamares - <https://github.com/calamares> ===
2  *
3  *   Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
4  *   Copyright 2018, Adriaan de Groot <groot@kde.org>
5  *
6  *   Calamares is free software: you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation, either version 3 of the License, or
9  *   (at your option) any later version.
10  *
11  *   Calamares is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with Calamares. If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <QDesktopWidget>
20 #include "CalamaresApplication.h"
21
22 #include "CalamaresConfig.h"
23 #include "CalamaresWindow.h"
24 #include "CalamaresVersion.h"
25 #include "progresstree/ProgressTreeView.h"
26 #include "progresstree/ProgressTreeModel.h"
27
28 #include "modulesystem/ModuleManager.h"
29 #include "utils/CalamaresUtilsGui.h"
30 #include "utils/CalamaresUtilsSystem.h"
31 #include "utils/Logger.h"
32 #include "JobQueue.h"
33 #include "Branding.h"
34 #include "Settings.h"
35 #include "viewpages/ViewStep.h"
36 #include "ViewManager.h"
37
38 #include <QDir>
39 #include <QFileInfo>
40
41
42 CalamaresApplication::CalamaresApplication( int& argc, char* argv[] )
43     : QApplication( argc, argv )
44     , m_mainwindow( nullptr )
45     , m_moduleManager( nullptr )
46     , m_debugMode( false )
47 {
48     // Setting the organization name makes the default cache
49     // directory -- where Calamares stores logs, for instance --
50     // <org>/<app>/, so we end up with ~/.cache/Calamares/calamares/
51     // which is excessively squidly.
52     //
53     // setOrganizationName( QStringLiteral( CALAMARES_ORGANIZATION_NAME ) );
54     setOrganizationDomain( QStringLiteral( CALAMARES_ORGANIZATION_DOMAIN ) );
55     setApplicationName( QStringLiteral( CALAMARES_APPLICATION_NAME ) );
56     setApplicationVersion( QStringLiteral( CALAMARES_VERSION ) );
57
58     cDebug() << "Calamares version:" << CALAMARES_VERSION;
59
60     CalamaresUtils::installTranslator( QLocale::system(), QString(), this );
61
62     QFont f = font();
63
64     cDebug() << "Default font size" << f.pointSize() << ';' << f.pixelSize() << "px";
65     CalamaresUtils::setDefaultFontSize( f.pointSize() );
66
67     cDebug() << "Available languages:" << QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';' );
68 }
69
70
71 void
72 CalamaresApplication::init()
73 {
74     Logger::setupLogfile();
75
76     setQuitOnLastWindowClosed( false );
77
78     initQmlPath();
79     initSettings();
80     initBranding();
81
82     setWindowIcon( QIcon( Calamares::Branding::instance()->
83                           imagePath( Calamares::Branding::ProductIcon ) ) );
84
85     cDebug() << "STARTUP: initQmlPath, initSettings, initBranding done";
86
87     initModuleManager(); //also shows main window
88
89     cDebug() << "STARTUP: initModuleManager: module init started";
90 }
91
92
93 CalamaresApplication::~CalamaresApplication()
94 {
95     cDebug( Logger::LOGVERBOSE ) << "Shutting down Calamares...";
96
97 //    if ( JobQueue::instance() )
98 //        JobQueue::instance()->stop();
99
100 //    delete m_mainwindow;
101
102 //    delete JobQueue::instance();
103
104     cDebug( Logger::LOGVERBOSE ) << "Finished shutdown.";
105 }
106
107
108 CalamaresApplication*
109 CalamaresApplication::instance()
110 {
111     return qobject_cast< CalamaresApplication* >( QApplication::instance() );
112 }
113
114
115 void
116 CalamaresApplication::setDebug( bool enabled )
117 {
118     m_debugMode = enabled;
119 }
120
121
122 bool
123 CalamaresApplication::isDebug()
124 {
125     return m_debugMode;
126 }
127
128
129 CalamaresWindow*
130 CalamaresApplication::mainWindow()
131 {
132     return m_mainwindow;
133 }
134
135
136 static QStringList
137 qmlDirCandidates( bool assumeBuilddir )
138 {
139     static const char QML[] = "qml";
140
141     QStringList qmlDirs;
142     if ( CalamaresUtils::isAppDataDirOverridden() )
143         qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
144     else
145     {
146         if ( assumeBuilddir )
147             qmlDirs << QDir::current().absoluteFilePath( "src/qml" );  // In build-dir
148         if ( CalamaresUtils::haveExtraDirs() )
149             for ( auto s : CalamaresUtils::extraDataDirs() )
150                 qmlDirs << ( s + QML );
151         qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
152     }
153
154     return qmlDirs;
155 }
156
157
158 static QStringList
159 settingsFileCandidates( bool assumeBuilddir )
160 {
161     static const char settings[] = "settings.conf";
162
163     QStringList settingsPaths;
164     if ( CalamaresUtils::isAppDataDirOverridden() )
165         settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
166     else
167     {
168         if ( assumeBuilddir )
169             settingsPaths << QDir::current().absoluteFilePath( settings );
170         if ( CalamaresUtils::haveExtraDirs() )
171             for ( auto s : CalamaresUtils::extraConfigDirs() )
172                 settingsPaths << ( s + settings );
173         settingsPaths << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf";  // String concat
174         settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
175     }
176
177     return settingsPaths;
178 }
179
180
181 static QStringList
182 brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
183 {
184     QStringList brandingPaths;
185     if ( CalamaresUtils::isAppDataDirOverridden() )
186         brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename );
187     else
188     {
189         if ( assumeBuilddir )
190             brandingPaths << ( QDir::currentPath() + QStringLiteral( "/src/" ) + brandingFilename );
191         if ( CalamaresUtils::haveExtraDirs() )
192             for ( auto s : CalamaresUtils::extraDataDirs() )
193                 brandingPaths << ( s + brandingFilename );
194         brandingPaths << QDir( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/" ).absoluteFilePath( brandingFilename );
195         brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename);
196     }
197
198     return brandingPaths;
199 }
200
201
202 void
203 CalamaresApplication::initQmlPath()
204 {
205     QDir importPath;  // Right now, current-dir
206     QStringList qmlDirCandidatesByPriority = qmlDirCandidates( isDebug() );
207     bool found = false;
208
209     foreach ( const QString& path, qmlDirCandidatesByPriority )
210     {
211         QDir dir( path );
212         if ( dir.exists() && dir.isReadable() )
213         {
214             importPath = dir;
215             found = true;
216             break;
217         }
218     }
219
220     if ( !found || !importPath.exists() || !importPath.isReadable() )
221     {
222         cError() << "Cowardly refusing to continue startup without a QML directory."
223             << Logger::DebugList( qmlDirCandidatesByPriority );
224         if ( CalamaresUtils::isAppDataDirOverridden() )
225             cError() << "FATAL: explicitly configured application data directory is missing qml/";
226         else
227             cError() << "FATAL: none of the expected QML paths exist.";
228         ::exit( EXIT_FAILURE );
229     }
230
231     cDebug() << "Using Calamares QML directory" << importPath.absolutePath();
232     CalamaresUtils::setQmlModulesDir( importPath );
233 }
234
235
236 void
237 CalamaresApplication::initSettings()
238 {
239     QStringList settingsFileCandidatesByPriority = settingsFileCandidates( isDebug() );
240
241     QFileInfo settingsFile;
242     bool found = false;
243
244     foreach ( const QString& path, settingsFileCandidatesByPriority )
245     {
246         QFileInfo pathFi( path );
247         if ( pathFi.exists() && pathFi.isReadable() )
248         {
249             settingsFile = pathFi;
250             found = true;
251             break;
252         }
253     }
254
255     if ( !found || !settingsFile.exists() || !settingsFile.isReadable() )
256     {
257         cError() << "Cowardly refusing to continue startup without settings."
258             << Logger::DebugList( settingsFileCandidatesByPriority );
259         if ( CalamaresUtils::isAppDataDirOverridden() )
260             cError() << "FATAL: explicitly configured application data directory is missing settings.conf";
261         else
262             cError() << "FATAL: none of the expected configuration file paths exist.";
263         ::exit( EXIT_FAILURE );
264     }
265
266     new Calamares::Settings( settingsFile.absoluteFilePath(), isDebug(), this );
267 }
268
269
270 void
271 CalamaresApplication::initBranding()
272 {
273     QString brandingComponentName = Calamares::Settings::instance()->brandingComponentName();
274     if ( brandingComponentName.simplified().isEmpty() )
275     {
276         cError() << "FATAL: branding component not set in settings.conf";
277         ::exit( EXIT_FAILURE );
278     }
279
280     QString brandingDescriptorSubpath = QString( "branding/%1/branding.desc" ).arg( brandingComponentName );
281     QStringList brandingFileCandidatesByPriority = brandingFileCandidates( isDebug(), brandingDescriptorSubpath);
282
283     QFileInfo brandingFile;
284     bool found = false;
285
286     foreach ( const QString& path, brandingFileCandidatesByPriority )
287     {
288         QFileInfo pathFi( path );
289         if ( pathFi.exists() && pathFi.isReadable() )
290         {
291             brandingFile = pathFi;
292             found = true;
293             break;
294         }
295     }
296
297     if ( !found || !brandingFile.exists() || !brandingFile.isReadable() )
298     {
299         cError() << "Cowardly refusing to continue startup without branding."
300             << Logger::DebugList( brandingFileCandidatesByPriority );
301         if ( CalamaresUtils::isAppDataDirOverridden() )
302             cError() << "FATAL: explicitly configured application data directory is missing" << brandingComponentName;
303         else
304             cError() << "FATAL: none of the expected branding descriptor file paths exist.";
305         ::exit( EXIT_FAILURE );
306     }
307
308     new Calamares::Branding( brandingFile.absoluteFilePath(), this );
309 }
310
311
312 void
313 CalamaresApplication::initModuleManager()
314 {
315     m_moduleManager = new Calamares::ModuleManager(
316         Calamares::Settings::instance()->modulesSearchPaths(), this );
317     connect( m_moduleManager, &Calamares::ModuleManager::initDone,
318              this,            &CalamaresApplication::initView );
319     m_moduleManager->init();
320 }
321
322
323 void
324 CalamaresApplication::initView()
325 {
326     cDebug() << "STARTUP: initModuleManager: all modules init done";
327     initJobQueue();
328     cDebug() << "STARTUP: initJobQueue done";
329
330     m_mainwindow = new CalamaresWindow(); //also creates ViewManager
331
332     connect( m_moduleManager, &Calamares::ModuleManager::modulesLoaded,
333              this, &CalamaresApplication::initViewSteps );
334     connect( m_moduleManager, &Calamares::ModuleManager::modulesFailed,
335              this, &CalamaresApplication::initFailed );
336
337     m_moduleManager->loadModules();
338
339     m_mainwindow->move(
340         this->desktop()->availableGeometry().center() -
341         m_mainwindow->rect().center() );
342
343     cDebug() << "STARTUP: CalamaresWindow created; loadModules started";
344 }
345
346
347 void
348 CalamaresApplication::initViewSteps()
349 {
350     cDebug() << "STARTUP: loadModules for all modules done";
351     m_moduleManager->checkRequirements();
352     if ( Calamares::Branding::instance()->windowMaximize() )
353     {
354         m_mainwindow->setWindowFlag( Qt::FramelessWindowHint );
355         m_mainwindow->showMaximized();
356     }
357     else
358         m_mainwindow->show();
359
360     ProgressTreeModel* m = new ProgressTreeModel( nullptr );
361     ProgressTreeView::instance()->setModel( m );
362     cDebug() << "STARTUP: Window now visible and ProgressTreeView populated";
363 }
364
365 void
366 CalamaresApplication::initFailed(const QStringList& l)
367 {
368     cError() << "STARTUP: failed modules are" << l;
369     m_mainwindow->show();
370 }
371
372 void
373 CalamaresApplication::initJobQueue()
374 {
375     Calamares::JobQueue* jobQueue = new Calamares::JobQueue( this );
376     new CalamaresUtils::System( Calamares::Settings::instance()->doChroot(), this );
377     Calamares::Branding::instance()->setGlobals( jobQueue->globalStorage() );
378 }