/* === This file is part of Calamares - === * * Copyright 2015-2016, Teo Mrnjavac * Copyright 2019, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Calamares 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 General Public License * along with Calamares. If not, see . */ #include "DebugWindow.h" #include "ui_DebugWindow.h" #include "Branding.h" #include "modulesystem/Module.h" #include "modulesystem/ModuleManager.h" #include "utils/qjsonmodel.h" #include "GlobalStorage.h" #include "Job.h" #include "JobQueue.h" #include "utils/Logger.h" #include "utils/Retranslator.h" #ifdef WITH_PYTHONQT #include #include "ViewManager.h" #include "viewpages/PythonQtViewStep.h" #endif #include #include #include #include /** * @brief crash makes Calamares crash immediately. */ static void crash() { volatile int* a = nullptr; *a = 1; } /// @brief Print out the widget tree (names) in indented form. static void dumpWidgetTree( QDebug& deb, const QWidget* widget, int depth ) { if ( !widget ) return; deb << Logger::Continuation; for (int i = 0; i < depth; ++i ) deb << ' '; deb << widget->objectName(); for ( const auto* w : widget->findChildren( QString(), Qt::FindDirectChildrenOnly ) ) dumpWidgetTree( deb, w, depth+1 ); } namespace Calamares { DebugWindow::DebugWindow() : QWidget( nullptr ) , m_ui( new Ui::DebugWindow ) { m_ui->setupUi( this ); // GlobalStorage page QJsonModel* jsonModel = new QJsonModel( this ); m_ui->globalStorageView->setModel( jsonModel ); GlobalStorage* gs = JobQueue::instance()->globalStorage(); connect( gs, &GlobalStorage::changed, this, [ = ] { jsonModel->loadJson( QJsonDocument::fromVariant( gs->m ).toJson() ); m_ui->globalStorageView->expandAll(); } ); jsonModel->loadJson( QJsonDocument::fromVariant( gs->m ).toJson() ); m_ui->globalStorageView->expandAll(); // JobQueue page m_ui->jobQueueText->setReadOnly( true ); connect( JobQueue::instance(), &JobQueue::queueChanged, this, [ this ]( const JobList& jobs ) { QStringList text; for ( const auto &job : jobs ) { text.append( job->prettyName() ); } m_ui->jobQueueText->setText( text.join( '\n' ) ); } ); // Modules page QStringListModel* modulesModel = new QStringListModel( ModuleManager::instance()->loadedInstanceKeys() ); m_ui->modulesListView->setModel( modulesModel ); m_ui->modulesListView->setSelectionMode( QAbstractItemView::SingleSelection ); QJsonModel* moduleConfigModel = new QJsonModel( this ); m_ui->moduleConfigView->setModel( moduleConfigModel ); #ifdef WITH_PYTHONQT QPushButton* pythonConsoleButton = new QPushButton; pythonConsoleButton->setText( "Attach Python console" ); m_ui->modulesVerticalLayout->insertWidget( 1, pythonConsoleButton ); pythonConsoleButton->hide(); QObject::connect( pythonConsoleButton, &QPushButton::clicked, this, [ this, moduleConfigModel ] { QString moduleName = m_ui->modulesListView->currentIndex().data().toString(); Module* module = ModuleManager::instance()->moduleInstance( moduleName ); if ( module->interface() != Module::Interface::PythonQt || module->type() != Module::Type::View ) return; for ( ViewStep* step : ViewManager::instance()->viewSteps() ) { if ( step->moduleInstanceKey() == module->instanceKey() ) { PythonQtViewStep* pqvs = qobject_cast< PythonQtViewStep* >( step ); if ( pqvs ) { QWidget* consoleWindow = new QWidget; QWidget* console = pqvs->createScriptingConsole(); console->setParent( consoleWindow ); QVBoxLayout* layout = new QVBoxLayout; consoleWindow->setLayout( layout ); layout->addWidget( console ); QHBoxLayout* bottomLayout = new QHBoxLayout; layout->addLayout( bottomLayout ); QLabel* bottomLabel = new QLabel( consoleWindow ); bottomLayout->addWidget( bottomLabel ); QString line = QString( "Module: %1
" "Python class: %2" ) .arg( module->instanceKey() ) .arg( console->property( "classname" ).toString() ); bottomLabel->setText( line ); QPushButton* closeButton = new QPushButton( consoleWindow ); closeButton->setText( "&Close" ); QObject::connect( closeButton, &QPushButton::clicked, [ consoleWindow ] { consoleWindow->close(); } ); bottomLayout->addWidget( closeButton ); bottomLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); consoleWindow->setParent( this ); consoleWindow->setWindowFlags( Qt::Window ); consoleWindow->setWindowTitle( "Calamares Python console" ); consoleWindow->setAttribute( Qt::WA_DeleteOnClose, true ); consoleWindow->showNormal(); break; } } } } ); #endif connect( m_ui->modulesListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [ this, moduleConfigModel #ifdef WITH_PYTHONQT , pythonConsoleButton #endif ] { QString moduleName = m_ui->modulesListView->currentIndex().data().toString(); Module* module = ModuleManager::instance()->moduleInstance( moduleName ); if ( module ) { moduleConfigModel->loadJson( QJsonDocument::fromVariant( module->configurationMap() ).toJson() ); m_ui->moduleConfigView->expandAll(); m_ui->moduleTypeLabel->setText( module->typeString() ); m_ui->moduleInterfaceLabel->setText( module->interfaceString() ); #ifdef WITH_PYTHONQT pythonConsoleButton->setVisible( module->interface() == Module::Interface::PythonQt && module->type() == Module::Type::View ); #endif } } ); // Tools page connect( m_ui->crashButton, &QPushButton::clicked, this, [] { ::crash(); } ); connect( m_ui->reloadStylesheetButton, &QPushButton::clicked, []() { for ( auto* w : qApp->topLevelWidgets() ) { // Needs to match what's set in CalamaresWindow if ( w->objectName() == QStringLiteral( "mainApp" ) ) { w->setStyleSheet( Calamares::Branding::instance()->stylesheet() ); } } }); connect( m_ui->widgetTreeButton, &QPushButton::clicked, []() { for ( auto* w : qApp->topLevelWidgets() ) { auto deb = cDebug(); dumpWidgetTree( deb, w, 0 ); } }); CALAMARES_RETRANSLATE( m_ui->retranslateUi( this ); setWindowTitle( tr( "Debug information" ) ); ) } void DebugWindow::closeEvent( QCloseEvent* e ) { Q_UNUSED( e ) emit closed(); } } // namespace Calamares