diff --git a/0001-branding-patch.patch b/0001-branding-patch.patch index 52f971918398b09213d77ef15a3668d76b8cf98c..f8d2e8cdd836a929e14889bad36a5acfee2a3cb0 100644 --- a/0001-branding-patch.patch +++ b/0001-branding-patch.patch @@ -122,7 +122,7 @@ index f4c50e629..f91d520cd 100644 - width: 200; height: 200 + id: background1 + source: "Slide1.png" -+ width: 980; height: 980 ++ width: 800; height: 800 fillMode: Image.PreserveAspectFit - anchors.centerIn: parent - } @@ -148,7 +148,7 @@ index f4c50e629..f91d520cd 100644 + Image { + id: background2 + source: "Slide2.png" -+ width: 980; height: 980 ++ width: 800; height: 800 + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter:parent.horizontalCenter + y:parent.height / 2 - height / 2 -25 @@ -161,7 +161,7 @@ index f4c50e629..f91d520cd 100644 + Image { + id: background3 + source: "Slide3.png" -+ width: 980; height: 980 ++ width: 800; height: 800 + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter:parent.horizontalCenter + y:parent.height / 2 - height / 2 -25 diff --git a/0006-modules-file.patch b/0006-modules-file.patch index d7473eaa46201d24be087139a7cadaada19487f9..a03be44e3f826ac106432fbb2adf9ef4cabd505a 100644 --- a/0006-modules-file.patch +++ b/0006-modules-file.patch @@ -36,7 +36,6 @@ Subject: [PATCH 4/4] modules Commit without .png, .svg, and .svgz files src/modules/unpackfs/main.py | 82 +- src/modules/unpackfs/unpackfs.conf | 12 +- src/modules/users/UsersPage.cpp | 2 +- - src/modules/users/page_usersetup.bak.ui | 710 ++++++++++++++++++ src/modules/users/page_usersetup.ui | 158 ++-- src/modules/users/users.conf | 2 +- src/modules/welcome/Config.cpp | 3 +- @@ -50,7 +49,6 @@ Subject: [PATCH 4/4] modules Commit without .png, .svg, and .svgz files mode change 100755 => 100644 src/modules/fstab/main.py mode change 100755 => 100644 src/modules/initramfscfg/encrypt_hook mode change 100755 => 100644 src/modules/initramfscfg/encrypt_hook_nokey - create mode 100644 src/modules/users/page_usersetup.bak.ui diff --git a/src/modules/bootloader/bootloader.conf b/src/modules/bootloader/bootloader.conf @@ -1324,722 +1322,6 @@ index 1ecc0eb..72fb3e0 100644 // Connect signals and slots ui->textBoxUserPassword->setText( config->userPassword() ); connect( ui->textBoxUserPassword, &QLineEdit::textChanged, config, &Config::setUserPassword ); -diff --git a/src/modules/users/page_usersetup.bak.ui b/src/modules/users/page_usersetup.bak.ui -new file mode 100644 -index 0000000..f808c89 ---- /dev/null -+++ b/src/modules/users/page_usersetup.bak.ui -@@ -0,0 +1,710 @@ -+ -+ -+ -+SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org> -+SPDX-License-Identifier: GPL-3.0-or-later -+ -+ Page_UserSetup -+ -+ -+ -+ 0 -+ 0 -+ 862 -+ 683 -+ -+ -+ -+ Form -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ QSizePolicy::Policy::Fixed -+ -+ -+ -+ 20 -+ 6 -+ -+ -+ -+ -+ -+ -+ -+ What is your name? -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ Your Full Name -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ 1 -+ 0 -+ -+ -+ -+ -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ QSizePolicy::Policy::Fixed -+ -+ -+ -+ 20 -+ 20 -+ -+ -+ -+ -+ -+ -+ -+ What name do you want to use to log in? -+ -+ -+ false -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ login -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ 1 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ -+ -+ -+ Qt::AlignmentFlag::AlignVCenter -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ QSizePolicy::Policy::Fixed -+ -+ -+ -+ 20 -+ 20 -+ -+ -+ -+ -+ -+ -+ -+ What is the name of this computer? -+ -+ -+ false -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ <small>This name will be used if you make the computer visible to others on a network.</small> -+ -+ -+ Computer Name -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ 1 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ -+ -+ -+ Qt::AlignmentFlag::AlignVCenter -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ QSizePolicy::Policy::Fixed -+ -+ -+ -+ 20 -+ 20 -+ -+ -+ -+ -+ -+ -+ -+ Choose a password to keep your account safe. -+ -+ -+ false -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ <small>Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals.</small> -+ -+ -+ QLineEdit::EchoMode::Password -+ -+ -+ Password -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ <small>Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals.</small> -+ -+ -+ QLineEdit::EchoMode::Password -+ -+ -+ Repeat Password -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ 1 -+ 0 -+ -+ -+ -+ -+ 100 -+ 0 -+ -+ -+ -+ -+ -+ -+ Qt::AlignmentFlag::AlignVCenter -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ QSizePolicy::Policy::Fixed -+ -+ -+ -+ 20 -+ 20 -+ -+ -+ -+ -+ -+ -+ -+ When this box is checked, password-strength checking is done and you will not be able to use a weak password. -+ -+ -+ Require strong passwords. -+ -+ -+ -+ -+ -+ -+ Log in automatically without asking for the password. -+ -+ -+ -+ -+ -+ -+ Use the same password for the administrator account. -+ -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ QSizePolicy::Policy::Fixed -+ -+ -+ -+ 20 -+ 20 -+ -+ -+ -+ -+ -+ -+ -+ Choose a password for the administrator account. -+ -+ -+ false -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ <small>Enter the same password twice, so that it can be checked for typing errors.</small> -+ -+ -+ QLineEdit::EchoMode::Password -+ -+ -+ Password -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 200 -+ 0 -+ -+ -+ -+ <small>Enter the same password twice, so that it can be checked for typing errors.</small> -+ -+ -+ QLineEdit::EchoMode::Password -+ -+ -+ Repeat Password -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ 0 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ -+ 24 -+ 24 -+ -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ 1 -+ 0 -+ -+ -+ -+ -+ 100 -+ 0 -+ -+ -+ -+ -+ -+ -+ Qt::AlignmentFlag::AlignVCenter -+ -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ QSizePolicy::Policy::Fixed -+ -+ -+ -+ 20 -+ 6 -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Use Active Directory -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Domain: -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Domain Administrator: -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Password: -+ -+ -+ -+ -+ -+ -+ QLineEdit::EchoMode::Password -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ IP Address (optional): -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Qt::Orientation::Vertical -+ -+ -+ -+ 20 -+ 1 -+ -+ -+ -+ -+ -+ -+ -+ -+ diff --git a/src/modules/users/page_usersetup.ui b/src/modules/users/page_usersetup.ui index 6e6e542..2a5ccd2 100644 --- a/src/modules/users/page_usersetup.ui diff --git a/0010-cDebugDelect.patch b/0010-cDebugDelect.patch new file mode 100644 index 0000000000000000000000000000000000000000..c5f63fef1df2e10c5603b4eaa39226486defbee3 --- /dev/null +++ b/0010-cDebugDelect.patch @@ -0,0 +1,400 @@ +From 662c8f4cdf8838d44f4a5b8be5455f840c0e314c Mon Sep 17 00:00:00 2001 +From: cui-gaoleng <562344211@qq.com> +Date: Tue, 19 Nov 2024 13:43:48 +0800 +Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E8=AF=95=E4=BF=A1=E6=81=AF=E5=92=8C?= + =?UTF-8?q?=E5=B7=B2=E6=B3=A8=E9=87=8A=E4=BB=A3=E7=A0=81=E5=88=A0=E9=99=A4?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + src/calamares/CalamaresWindow.cpp | 3 - + .../progresstree/ProgressTreeDelegate.cpp | 9 - + .../progresstree/ProgressTreeView.cpp | 2 - + src/libcalamares/CalamaresAbout.cpp | 1 - + .../modulesystem/CppJobModule.cpp | 4 - + src/modules/keyboard/KeyboardPage.cpp | 19 - + src/modules/keyboard/KeyboardPage.ui | 3 - + src/modules/locale/LocalePage.cpp | 20 +- + .../packagechooser/packagechooser.conf | 16 +- + src/modules/welcome/WelcomePage.cpp | 74 +- + 11 files changed, 7 insertions(+), 862 deletions(-) + +diff --git a/src/calamares/CalamaresWindow.cpp b/src/calamares/CalamaresWindow.cpp +index 4721cb9..4917f75 100644 +--- a/src/calamares/CalamaresWindow.cpp ++++ b/src/calamares/CalamaresWindow.cpp +@@ -440,7 +440,6 @@ CalamaresWindow::CalamaresWindow( QWidget* parent ) + int h = qBound( minimumSize.height(), windowDimensionToPixels( brandingSizes.second ), availableSize.height() ); + + cDebug() << Logger::SubEntry << "Proposed window size:" << w << h; +- //resize( availableSize.width(), availableSize.height() );//通用桌面大小作为窗口大小 + resize( w, h );//通用桌面大小作为窗口大小 + QWidget* baseWidget = this; + if ( !( branding->imagePath( ImageEntry::ProductWallpaper ).isEmpty() ) ) +@@ -519,8 +518,6 @@ CalamaresWindow::CalamaresWindow( QWidget* parent ) + Calamares::unmarginLayout( contentsLayout ); + baseWidget->setLayout( mainLayout ); + setStyleSheet( Calamares::Branding::instance()->stylesheet() ); +- cDebug()<<"<---------------------------WindowWindowSize-------------------------------------->"<size(); +- cDebug()<< "<--------------------sideBox->size()-------------------->"<< sideBox->size(); + this->setFixedSize(this->size()); + } + +diff --git a/src/calamares/progresstree/ProgressTreeDelegate.cpp b/src/calamares/progresstree/ProgressTreeDelegate.cpp +index 6d5f865..7541356 100644 +--- a/src/calamares/progresstree/ProgressTreeDelegate.cpp ++++ b/src/calamares/progresstree/ProgressTreeDelegate.cpp +@@ -53,9 +53,6 @@ static QString getTypeOfStep(const QString& stepString){ + + // 将地区枚举值转换为字符串 + QString countryString = QLocale::countryToString(country); +- // 输出当前语言 +- cDebug() << "-------------------------------------------当前系统语言:" << languageString; +- cDebug() << "-------------------------------------------当前系统地区:" << countryString; + if(contains(baseSetting1,stepString)){ + return "BaseSetting"; + } +@@ -145,7 +142,6 @@ paintViewStep( QPainter* painter, const QStyleOptionViewItem& option, const QMod + shrinkSteps++; + + QRectF boundingBox; +- cDebug() << "index.data().toString()" << index.data().toString(); + QString text; + if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"||!isVisable(index.data().toString())){ + text = ""; +@@ -179,7 +175,6 @@ ProgressTreeDelegate::sizeHint( const QStyleOptionViewItem& option, const QModel + } + + QFont font = qApp->font(); +- cDebug() << "ProgressTreeDelegate::sizeHint"; + + font.setPointSize( item_fontsize() ); + QFontMetrics fm( font ); +@@ -190,14 +185,12 @@ ProgressTreeDelegate::sizeHint( const QStyleOptionViewItem& option, const QModel + }else{ + return QSize( (Calamares::windowMinimumWidth*0.9)/3, height*2 ); + } +-// return QSize( option.rect.width(), height ); + + } + + void + ProgressTreeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const + { +- cDebug() << "ProgressTreeDelegate::paint----------"; + QStyleOptionViewItem opt = option; + + painter->save(); +@@ -209,11 +202,9 @@ ProgressTreeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti + QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackground ) ) ); + painter->setPen( QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarText ) ) ); + if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"){ +- cDebug() << "ProgressTreeDelegate::欢迎Welcome--------Nopaint----------"; + }else{ + paintViewStep( painter, opt, index ); + } +- //paintViewStep( painter, opt, index ); + + painter->restore(); + } +diff --git a/src/calamares/progresstree/ProgressTreeView.cpp b/src/calamares/progresstree/ProgressTreeView.cpp +index 29ee7ee..a9a15b8 100644 +--- a/src/calamares/progresstree/ProgressTreeView.cpp ++++ b/src/calamares/progresstree/ProgressTreeView.cpp +@@ -68,14 +68,12 @@ ProgressTreeView::setModel( QAbstractItemModel* model ) + void + ProgressTreeView::update() + { +- cDebug() << "update ---------------------"; + viewport()->update(); + } + + void + ProgressTreeView::updateVisibility(int currentStep) + { +- cDebug() << "int currentStep ------------------ " << currentStep; + // 在第一个步骤隐藏,其他步骤显示 + this->setVisible(currentStep > 0); + } + +diff --git a/src/libcalamares/CalamaresAbout.cpp b/src/libcalamares/CalamaresAbout.cpp +index 65a1b9d..595efc7 100644 +--- a/src/libcalamares/CalamaresAbout.cpp ++++ b/src/libcalamares/CalamaresAbout.cpp +@@ -65,7 +65,6 @@ Calamares::aboutString() + { + return substituteVersions( QCoreApplication::translate( "AboutData", s_header ) ) + aboutMaintainers() + + QCoreApplication::translate( "AboutData", s_footer ); +- // return aboutMaintainers()+ QCoreApplication::translate( "AboutData", s_footer ); + } + + const QString +diff --git a/src/libcalamaresui/modulesystem/CppJobModule.cpp b/src/libcalamaresui/modulesystem/CppJobModule.cpp +index c211006..b35a457 100644 +--- a/src/libcalamaresui/modulesystem/CppJobModule.cpp ++++ b/src/libcalamaresui/modulesystem/CppJobModule.cpp +@@ -53,10 +53,6 @@ CppJobModule::loadSelf() + cDebug() << "Could not load module:" << m_loader->errorString(); + return; + } +- // cDebug() << "CppJobModule loading self for instance" << instanceKey() +- // << "\nCppJobModule at address" << this +- // << "\nCalamares::PluginFactory at address" << pf +- // << "\nCppJob at address" << cppJob; + + cppJob->setModuleInstanceKey( instanceKey() ); + cppJob->setConfigurationMap( m_configurationMap ); +diff --git a/src/modules/keyboard/KeyboardPage.cpp b/src/modules/keyboard/KeyboardPage.cpp +index 3f06158..be60521 100644 +--- a/src/modules/keyboard/KeyboardPage.cpp ++++ b/src/modules/keyboard/KeyboardPage.cpp +@@ -48,9 +48,6 @@ KeyboardPage::KeyboardPage( Config* config, QWidget* parent ) + { + ui->setupUi( this ); + this->setContentsMargins(50,0,50,0); +- // Keyboard Preview +- // ui->KBPreviewLayout->addWidget( m_keyboardPreview ); +- + + { + auto* model = config->keyboardModels(); +@@ -93,27 +90,11 @@ KeyboardPage::KeyboardPage( Config* config, QWidget* parent ) + &QItemSelectionModel::currentChanged, + [ this ]( const QModelIndex& current ) + { m_config->keyboardLayouts()->setCurrentIndex( current.row() ); } ); +- // connect( config->keyboardLayouts(), +- // &KeyboardLayoutModel::currentIndexChanged, +- // [ this ]( int index ) +- // { +- // ui->layoutSelector->setCurrentIndex( m_config->keyboardLayouts()->index( index ) ); +- // m_keyboardPreview->setLayout( m_config->keyboardLayouts()->key( index ) ); +- // m_keyboardPreview->setVariant( +- // m_config->keyboardVariants()->key( m_config->keyboardVariants()->currentIndex() ) ); +- // } ); + + connect( ui->variantSelector->selectionModel(), + &QItemSelectionModel::currentChanged, + [ this ]( const QModelIndex& current ) + { m_config->keyboardVariants()->setCurrentIndex( current.row() ); } ); +- // connect( config->keyboardVariants(), +- // &KeyboardVariantsModel::currentIndexChanged, +- // [ this ]( int index ) +- // { +- // ui->variantSelector->setCurrentIndex( m_config->keyboardVariants()->index( index ) ); +- // m_keyboardPreview->setVariant( m_config->keyboardVariants()->key( index ) ); +- // } ); + + connect( ui->groupSelector, + QOverload< int >::of( &QComboBox::currentIndexChanged ), +diff --git a/src/modules/keyboard/KeyboardPage.ui b/src/modules/keyboard/KeyboardPage.ui +index 1d6afbf..70cfca3 100644 +--- a/src/modules/keyboard/KeyboardPage.ui ++++ b/src/modules/keyboard/KeyboardPage.ui +@@ -45,9 +45,6 @@ SPDX-License-Identifier: GPL-3.0-or-later + + + +- + + + +diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp +index 0568067..ed50574 100644 +--- a/src/modules/locale/LocalePage.cpp ++++ b/src/modules/locale/LocalePage.cpp +@@ -32,13 +32,6 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + { + QBoxLayout* mainLayout = new QVBoxLayout; + mainLayout->setContentsMargins(50,0,50,0); +- //QBoxLayout* tzwLayout = new QHBoxLayout; +- //m_tzWidget = new TimeZoneWidget( m_config->zonesModel(), this ); +- //tzwLayout->addStretch(); +- //tzwLayout->addWidget( m_tzWidget ); +- //tzwLayout->addStretch(); +- // Adjust for margins and spacing in this page +- //m_tzWidget->setMinimumHeight( m_tzWidget->minimumHeight() + 12 ); // 2 * spacing + + QBoxLayout* zoneAndRegionLayout = new QVBoxLayout; + m_regionLabel = new QLabel( this ); +@@ -90,7 +83,7 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + m_formatsChangeButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + formatsLayout->addWidget( m_formatsChangeButton ); + formatsLayout->addSpacing(20); +- //mainLayout->addLayout( tzwLayout ); ++ + mainLayout->addStretch(); + mainLayout->addLayout( zoneAndRegionLayout ); + mainLayout->addStretch(); +@@ -100,7 +93,7 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + mainLayout->addSpacing(20); + mainLayout->addLayout( timezoneLayout ); + mainLayout->addStretch(); +- //setMinimumWidth( m_tzWidget->width() ); ++ + setLayout( mainLayout ); + + m_localeChangeButton->hide(); +@@ -114,20 +107,15 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + zones->setRegion( location->region() ); + m_regionCombo->setModel( regions ); + m_zoneCombo->setModel( zones ); +- //m_tzWidget->setCurrentLocation( location ); ++ + locationChanged( location ); // doesn't inform TZ widget + } + + connect( config, &Config::currentLCStatusChanged, m_formatsLabel, &QLabel::setText ); + connect( config, &Config::currentLanguageStatusChanged, m_localeLabel, &QLabel::setText ); + connect( config, &Config::currentZoneChanged, m_timezoneLabel , &QLabel::setText); +- //connect( config, &Config::currentLocationChanged, m_tzWidget, &TimeZoneWidget::setCurrentLocation ); ++ + connect( config, &Config::currentLocationChanged, this, &LocalePage::locationChanged ); +- // connect( m_tzWidget, +- // &TimeZoneWidget::locationChanged, +- // config, +- // QOverload< const Calamares::Locale::TimeZoneData* >::of( &Config::setCurrentLocation ) ); +- + connect( m_regionCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::regionChanged ); + connect( m_zoneCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::zoneChanged ); + +diff --git a/src/modules/packagechooser/packagechooser.conf b/src/modules/packagechooser/packagechooser.conf +index e7b9b00..aa048e2 100644 +--- a/src/modules/packagechooser/packagechooser.conf ++++ b/src/modules/packagechooser/packagechooser.conf +@@ -157,11 +157,7 @@ items: + description[nl]: "Kies eventueel een desktop-omgeving uit deze lijst. Als u geen desktop-omgeving wenst te gebruiken, kies er dan geen. In dat geval start het systeem straks op in tekst-modus en kunt u later alsnog een desktop-omgeving installeren." + description[zh]: "请选择一个桌面环境。如果您不想安装桌面环境也没关系,您可以稍后再为系统安装桌面环境。" + screenshot: ":/images/Minimal-Install.png" +- # - id: kde +- # packages: [ kde-frameworks, kde-plasma, kde-gear ] +- # name: Plasma Desktop +- # description: "KDE Plasma Desktop, simple by default, a clean work area for real-world usage which intends to stay out of your way. Plasma is powerful when needed, enabling the user to create the workflow that makes them more effective to complete their tasks." +- # screenshot: ":/images/Plasma.png" ++ + - id: gnome + packages: [ checkpolicy, code, xorg-*, dejavu-fonts, liberation-fonts, gnu-*-fonts, google-*-fonts, adwaita-icon-theme, atk, atkmm, at-spi2-atk, at-spi2-core, baobab, abattis-cantarell-fonts, cheese, clutter, clutter-gst3, clutter-gtk, cogl, dconf, dconf-editor, devhelp, eog, epiphany, evince, evolution-data-server, file-roller, folks, gcab, gcr, gdk-pixbuf2, gdm, gedit, geocode-glib, gfbgraph, gjs, glib2, glibmm24, glib-networking, gmime30, gnome-autoar, gnome-backgrounds, gnome-bluetooth, gnome-builder, gnome-calculator, gnome-calendar, gnome-characters, gnome-clocks, gnome-color-manager, gnome-contacts, gnome-control-center, gnome-desktop3, gnome-disk-utility, gnome-font-viewer, gnome-getting-started-docs, gnome-initial-setup, gnome-keyring, gnome-logs, gnome-menus, gnome-music, gnome-online-accounts, gnome-online-miners, gnome-photos, gnome-remote-desktop, gnome-screenshot, gnome-session, gnome-settings-daemon, gnome-shell, gnome-shell-extensions, gnome-software, gnome-system-monitor, gnome-terminal, gnome-tour, gnome-user-docs, gnome-user-share, gnome-video-effects, gnome-weather, gobject-introspection, gom, grilo, grilo-plugins, gsettings-desktop-schemas, gsound, gspell, gssdp, gtk3, gtk4, gtk-doc, gtkmm30, gtksourceview4, gtk-vnc2, gupnp, gupnp-av, gupnp-dlna, gvfs, json-glib, libchamplain, libdazzle, libgdata, libgee, libgnomekbd, libgsf, libgtop2, libgweather, libgxps, libhandy, libmediaart, libnma, libnotify, libpeas, librsvg2, libsecret, libsigc++20, libsoup, mm-common, mutter, nautilus, orca, pango, pangomm, libphodav, python3-pyatspi, python3-gobject, rest, rygel, simple-scan, sushi, sysprof, tepl, totem, totem-pl-parser, tracker3, tracker3-miners, vala, vte291, yelp, yelp-tools, yelp-xsl, zenity, devstation-config, ibus-libpinyin ] + name: DevStation +@@ -169,13 +165,3 @@ items: + description: GNU Networked Object Modeling Environment Desktop + description[zh]: Devstation系统桌面 + screenshot: ":/images/gnome.png" +- #- id: ukui +- # packages: [ ukui ] +- # name: UKUI +- # description: Linux Desktop +- # screenshot: ":/images/UKUI.png" +- # - id: calamares +- # appdata: ../io.calamares.calamares.appdata.xml +- # screenshot: ":/images/calamares.png" +- # - id: kate +- # appstream: org.kde.kwrite.desktop +diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp +index 88f38c2..471187b 100644 +--- a/src/modules/welcome/WelcomePage.cpp ++++ b/src/modules/welcome/WelcomePage.cpp +@@ -91,21 +91,7 @@ WelcomePage::WelcomePage( Config* config, QWidget* parent ) + } + + void +-WelcomePage::init() +-{ +- //setup the url buttons +- // setupButton( WelcomePage::Button::Support, m_conf->supportUrl() ); +- // setupButton( WelcomePage::Button::KnownIssues, m_conf->knownIssuesUrl() ); +- // setupButton( WelcomePage::Button::ReleaseNotes, m_conf->releaseNotesUrl() ); +- // setupButton( WelcomePage::Button::Donate, m_conf->donateUrl() ); +- +- //language icon +- // auto icon = Calamares::Branding::instance()->image( m_conf->languageIcon(), QSize( 48, 48 ) ); +- // if ( !icon.isNull() ) +- // { +- // setLanguageIcon( icon ); +- // } +-} ++WelcomePage::init(){} + + void + WelcomePage::initLanguages() +@@ -125,57 +111,6 @@ WelcomePage::initLanguages() + &Config::setLocaleIndex ); + } + +-// void +-// WelcomePage::setupButton( Button role, const QString& url ) +-// { +-// QPushButton* button = nullptr; +-// Calamares::ImageType icon = Calamares::Information; +- +-// switch ( role ) +-// { +-// case Button::Donate: +-// button = ui->donateButton; +-// icon = Calamares::Donate; +-// break; +-// case Button::KnownIssues: +-// button = ui->knownIssuesButton; +-// icon = Calamares::Bugs; +-// break; +-// case Button::ReleaseNotes: +-// button = ui->releaseNotesButton; +-// icon = Calamares::Release; +-// break; +-// case Button::Support: +-// button = ui->supportButton; +-// icon = Calamares::Help; +-// break; +-// } +-// if ( !button ) +-// { +-// cWarning() << "Unknown button role" << smash( role ); +-// return; +-// } +- +-// if ( url.isEmpty() ) +-// { +-// button->hide(); +-// return; +-// } +- +-// QUrl u( url ); +-// if ( u.isValid() ) +-// { +-// auto size = 2 * QSize( Calamares::defaultFontHeight(), Calamares::defaultFontHeight() ); +-// button->setIcon( Calamares::defaultPixmap( icon, Calamares::Original, size ) ); +-// connect( button, &QPushButton::clicked, [ u ]() { QDesktopServices::openUrl( u ); } ); +-// } +-// else +-// { +-// cWarning() << "Welcome button" << smash( role ) << "URL" << url << "is invalid."; +-// button->hide(); +-// } +-// } +- + void + WelcomePage::focusInEvent( QFocusEvent* e ) + { +@@ -201,11 +136,6 @@ WelcomePage::externallySelectedLanguage( int row ) + } + } + +-// void +-// WelcomePage::setLanguageIcon( QPixmap i ) +-// { +-// ui->languageIcon->setPixmap( i ); +-// } + + void + WelcomePage::retranslate() +@@ -214,8 +144,6 @@ WelcomePage::retranslate() + + ui->mainText->setText( message.arg( Calamares::Branding::instance()->versionedName() ) ); + ui->retranslateUi( this ); +- // ui->supportButton->setText( +- // tr( "%1 Support", "@action" ).arg( Calamares::Branding::instance()->shortProductName() ) ); + } + + void + diff --git a/0011-fix-87-position-and-translate.patch b/0011-fix-87-position-and-translate.patch new file mode 100644 index 0000000000000000000000000000000000000000..0419506a4fc05c50217b96fc995c04c238e989b5 --- /dev/null +++ b/0011-fix-87-position-and-translate.patch @@ -0,0 +1,230 @@ +From 057721ec933fc439d9e9b9887dc69704cd49472e Mon Sep 17 00:00:00 2001 +From: cui-gaoleng <562344211@qq.com> +Date: Fri, 22 Nov 2024 12:14:08 +0800 +Subject: [PATCH] =?UTF-8?q?fix=20progress=20bar=20has=20been=20at=20the=20?= + =?UTF-8?q?87%=20position=20for=20a=20long=20time+=E4=B8=A4=E5=A4=84?= + =?UTF-8?q?=E7=B9=81=E4=BD=93=E7=BF=BB=E8=AF=91=E8=A1=A5=E9=BD=90?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + calamares.desktop | 2 +- + lang/calamares_zh_TW.ts | 6 +-- + src/modules/packages/main.py | 70 +++++++++++++++++++------------- + src/modules/packages/module.desc | 1 + + src/modules/unpackfs/main.py | 24 ++++++++--- + 5 files changed, 65 insertions(+), 38 deletions(-) + +diff --git a/calamares.desktop b/calamares.desktop +index 9a1416e..9d33495 100644 +--- a/calamares.desktop ++++ b/calamares.desktop +@@ -5,7 +5,7 @@ Name=Install System + GenericName=System Installer + Keywords=calamares;system;installer; + TryExec=calamares +-Exec=sh -c "pkexec calamares" ++Exec=sh -c "pkexec calamares -style Adwaita" + Comment=Calamares — System Installer + Icon=calamares + Terminal=false +diff --git a/lang/calamares_zh_TW.ts b/lang/calamares_zh_TW.ts +index 8689629..3cc473c 100644 +--- a/lang/calamares_zh_TW.ts ++++ b/lang/calamares_zh_TW.ts +@@ -613,9 +613,9 @@ The system will reboot or you can enter the debug mode for further investigation + + + +- &Debug ++ &Try Now + @button +- 調試(&D) ++ 立即試用(&D) + + + Do you really want to cancel the current install process? +@@ -4526,7 +4526,7 @@ Output: + + + language +- ++ 語言 + + + Open donations website +diff --git a/src/modules/packages/main.py b/src/modules/packages/main.py +index 8c165e8..1fbe276 100644 +--- a/src/modules/packages/main.py ++++ b/src/modules/packages/main.py +@@ -138,10 +138,11 @@ class PackageManager(metaclass=abc.ABCMeta): + self.install([packagedata], from_local=from_local, options=options) + else: + self.run(packagedata["pre-script"]) +- if isinstance(packagedata["package"], list): +- self.install(packagedata["package"], from_local=from_local, options=options) +- else: +- self.install([packagedata["package"]], from_local=from_local, options=options) ++ if "package" in packagedata: ++ if isinstance(packagedata["package"], list): ++ self.install(packagedata["package"], from_local=from_local, options=options) ++ else: ++ self.install([packagedata["package"]], from_local=from_local, options=options) + if isinstance(packagedata["post-script"], list): + for script in packagedata["post-script"]: + self.run(script) +@@ -787,41 +788,54 @@ def run_operations(pkgman, entry, options): + names (strings) or package information dictionaries with pre- + and post-scripts. + """ +- global group_packages, completed_packages, mode_packages +- +- if "source" in entry and entry["source"] == "packagechooser@packagechooser": +- handle_packagechooser(entry) ++ global group_packages, completed_packages, mode_packages, custom_status_message + + for key in entry.keys(): + package_list = subst_locale(entry[key]) ++ libcalamares.utils.warning(str(package_list)) + group_packages = len(package_list) + +- if key == "install": +- _change_mode(INSTALL) +- pkgman.operation_install(package_list, options=options) +- elif key == "try_install": ++ if key in ["install", "try_install", "localInstall"]: + _change_mode(INSTALL) +- pkgman.operation_try_install(package_list, options=options) +- elif key == "remove": +- _change_mode(REMOVE) +- pkgman.operation_remove(package_list, options=options) +- elif key == "try_remove": ++ for package in package_list: ++ custom_status_message = f"Installing package: {package}" ++ try: ++ if key == "localInstall": ++ pkgman.operation_install([package], from_local=True, options=options) ++ elif key == "try_install": ++ pkgman.operation_try_install([package], options=options) ++ else: ++ pkgman.operation_install([package], options=options) ++ except Exception as e: ++ libcalamares.utils.warning("Failed to install package {}: {}".format(package, str(e))) ++ ++ completed_packages += 1 ++ progress = completed_packages / total_packages ++ libcalamares.job.setprogress(progress) ++ libcalamares.utils.debug("Progress: {:.2f}, Package: {}".format(progress, package)) ++ elif key in ["remove", "try_remove"]: + _change_mode(REMOVE) +- pkgman.operation_try_remove(package_list, options=options) +- elif key == "localInstall": +- _change_mode(INSTALL) +- pkgman.operation_install(package_list, from_local=True, options=options) +- elif key == "source": +- libcalamares.utils.debug("Package-list from {!s}".format(entry[key])) ++ for package in package_list: ++ try: ++ if key == "remove": ++ pkgman.operation_remove([package], options=options) ++ elif key == "try_remove": ++ pkgman.operation_try_remove([package], options=options) ++ except Exception as e: ++ libcalamares.utils.warning("Failed to remove package {}: {}".format(package, str(e))) ++ ++ completed_packages += 1 ++ progress = completed_packages / total_packages ++ libcalamares.job.setprogress(progress) ++ libcalamares.utils.debug("Progress: {:.2f}, Package: {}".format(progress, package)) + else: + libcalamares.utils.warning("Unknown package-operation key {!s}".format(key)) +- completed_packages += len(package_list) +- libcalamares.job.setprogress(completed_packages * 1.0 / total_packages) +- libcalamares.utils.debug("Pretty name: {!s}, setting progress..".format(pretty_name())) + ++ if "source" in entry and entry["source"] == "packagechooser@packagechooser": ++ packagemeta = handle_packagechooser() ++ pkgman.operation_install([packagemeta], from_local=True, options=options) + group_packages = 0 +- _change_mode(None) +- ++ _change_mode(None) + + def run(): + """ +diff --git a/src/modules/packages/module.desc b/src/modules/packages/module.desc +index 3e3053b..9529af6 100644 +--- a/src/modules/packages/module.desc ++++ b/src/modules/packages/module.desc +@@ -5,3 +5,4 @@ type: "job" + name: "packages" + interface: "python" + script: "main.py" ++weight: 50 +diff --git a/src/modules/unpackfs/main.py b/src/modules/unpackfs/main.py +index 4148720..4c5518e 100644 +--- a/src/modules/unpackfs/main.py ++++ b/src/modules/unpackfs/main.py +@@ -26,6 +26,8 @@ import libcalamares + import platform + + import gettext ++ ++import libcalamares.utils + _ = gettext.translation("calamares-python", + localedir=libcalamares.utils.gettext_path(), + languages=libcalamares.utils.gettext_languages(), +@@ -263,6 +265,7 @@ def file_copy(source, entry, progress_cb): + progress_cb(num_files_copied, num_files_total_local) + try: + returncode = 0 ++ + arch = platform.machine() + + libcalamares.utils.host_env_process_output(["mkdir", "-p", entry.destination + "/etc/yum.repos.d/"], output_cb) +@@ -272,6 +275,7 @@ def file_copy(source, entry, progress_cb): + libcalamares.utils.host_env_process_output(["cp", "-af", "/etc/add_selinux_policy.sh", entry.destination + "/etc/add_selinux_policy.sh"], output_cb) + libcalamares.utils.host_env_process_output(["chmod", "+x", entry.destination + "/etc/add_selinux_policy.sh"], output_cb) + ++ completed_packages = 0 + if os.path.exists("/etc/yum.repos.d/local.repo"): + libcalamares.utils.host_env_process_output( + ["cp", "-af", "/etc/yum.repos.d/local.repo", entry.destination + "/etc/yum.repos.d/"], output_cb) +@@ -281,9 +285,13 @@ def file_copy(source, entry, progress_cb): + else: + packages = ["yum", "grub2", "grub2-efi-x64", "grub2-pc", "passwd", "sudo"] + +- libcalamares.utils.host_env_process_output( +- ["yum", "--installroot=" + entry.destination, "--disablerepo=*", "--enablerepo=local-repo", +- "--releasever=/", "--nogpgcheck", "--setopt=sslverify=0", "install", "-y"] + packages, output_cb) ++ for package in packages: ++ libcalamares.job.setprogress(completed_packages / len(packages)) ++ libcalamares.utils.host_env_process_output( ++ ["yum", "--installroot=" + entry.destination, "--disablerepo=*", "--enablerepo=local-repo", ++ "--releasever=/", "--nogpgcheck", "--setopt=sslverify=0", "install", "-y", package], output_cb) ++ completed_packages += 1 ++ libcalamares.job.setprogress(completed_packages / len(packages)) + else: + libcalamares.utils.host_env_process_output( + ["cp", "-af", "/etc/yum.repos.d/openEuler.repo", entry.destination + "/etc/yum.repos.d/"], output_cb) +@@ -292,9 +300,13 @@ def file_copy(source, entry, progress_cb): + else: + packages = ["yum", "grub2", "grub2-efi-x64", "grub2-pc", "passwd", "sudo"] + +- libcalamares.utils.host_env_process_output( +- ["yum", "--installroot=" + entry.destination, "--releasever=/", "--nogpgcheck", "--setopt=sslverify=0", +- "install", "-y"] + packages, output_cb) ++ for package in packages: ++ libcalamares.job.setprogress(completed_packages / len(packages)) ++ libcalamares.utils.host_env_process_output( ++ ["yum", "--installroot=" + entry.destination, "--releasever=/", "--nogpgcheck", "--setopt=sslverify=0", ++ "install", "-y", package], output_cb) ++ completed_packages += 1 ++ libcalamares.job.setprogress(completed_packages / len(packages)) + + libcalamares.utils.host_env_process_output(["rm", "-f", entry.destination + "/etc/shadow"], output_cb) + libcalamares.utils.host_env_process_output(["cp", "-af", "/etc/shadow", entry.destination + "/etc/shadow"], output_cb) +-- +2.43.0 + diff --git a/0012-replace-icon.patch b/0012-replace-icon.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a36c87799fdf9d9f22ebca94ba12c0e72f6cd1b --- /dev/null +++ b/0012-replace-icon.patch @@ -0,0 +1,29 @@ +From ec4ad9b45ba894afb73ae30ae6e8631fb701f1dd Mon Sep 17 00:00:00 2001 +From: cui-gaoleng <562344211@qq.com> +Date: Fri, 22 Nov 2024 12:44:38 +0800 +Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9B=BE=E6=A0=87=E9=85=8D?= + =?UTF-8?q?=E7=BD=AE?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + calamares.desktop | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/calamares.desktop b/calamares.desktop +index 9d33495..00c2368 100644 +--- a/calamares.desktop ++++ b/calamares.desktop +@@ -7,7 +7,7 @@ Keywords=calamares;system;installer; + TryExec=calamares + Exec=sh -c "pkexec calamares -style Adwaita" + Comment=Calamares — System Installer +-Icon=calamares ++Icon=/usr/share/calamares/branding/default/openEuler-icon.png + Terminal=false + StartupNotify=true + Categories=Qt;System; +-- +2.43.0 + diff --git a/0013-1230.patch b/0013-1230.patch new file mode 100644 index 0000000000000000000000000000000000000000..75ee73436323a6bf478946d9606fa90ec120389b --- /dev/null +++ b/0013-1230.patch @@ -0,0 +1,10764 @@ +From 9dd33a244e37407d18a5a8e3903ec9d4fd59cde9 Mon Sep 17 00:00:00 2001 +From: lizixin <2271170409@qq.com> +Date: Fri, 27 Dec 2024 19:27:11 +0800 +Subject: [PATCH] 1230 + +--- + CMakeLists.txt | 1 + + calamares.desktop | 10 +- + lang/calamares_zh_CN.ts | 2 +- + lang/tz_zh_CN.ts | 2626 +++++++++++++++++ + lang/tz_zh_TW.ts | 2626 +++++++++++++++++ + src/branding/default/show.qml | 6 +- + src/calamares/CMakeLists.txt | 134 +- + src/calamares/CalamaresApplication.cpp | 4 +- + src/calamares/DebugWindow.cpp | 530 ++-- + src/calamares/DebugWindow.h | 192 +- + src/calamares/VariantModel.cpp | 570 ++-- + src/calamares/VariantModel.h | 208 +- + src/calamares/calamares-navigation.qml | 166 +- + src/calamares/calamares-sidebar.qml | 250 +- + src/calamares/calamares.qrc | 20 +- + src/calamares/main.cpp | 308 +- + .../progresstree/ProgressTreeDelegate.cpp | 422 +-- + .../progresstree/ProgressTreeDelegate.h | 62 +- + .../progresstree/ProgressTreeView.cpp | 154 +- + src/calamares/progresstree/ProgressTreeView.h | 82 +- + src/calamares/test_conf.cpp | 218 +- + src/calamares/testmain.cpp | 1144 +++---- + src/libcalamares/CalamaresAbout.cpp | 1 + + .../modulesystem/CppJobModule.cpp | 4 + + src/modules/displaymanager/main.py | 10 + + src/modules/keyboard/KeyboardPage.cpp | 19 + + src/modules/keyboard/KeyboardPage.ui | 3 + + src/modules/locale/Config.cpp | 43 + + src/modules/locale/LocalePage.cpp | 20 +- + .../packagechooser/packagechooser.conf | 20 +- + src/modules/packagechooser/packagechooser.qrc | 5 - + src/modules/packages/main.py | 14 +- + src/modules/packages/packages.conf | 4 +- + src/modules/partition/core/DeviceList.cpp | 23 +- + src/modules/partition/jobs/ClearMountsJob.cpp | 51 +- + src/modules/unpackfs/main.py | 6 +- + src/modules/users/CreateUserJob.cpp | 18 + + src/modules/users/UsersPage.cpp | 102 + + src/modules/users/UsersPage.h | 15 + + src/modules/welcome/WelcomePage.cpp | 74 +- + src/modules/welcome/welcome.qrc | 1 - + 41 files changed, 7895 insertions(+), 2273 deletions(-) + create mode 100644 lang/tz_zh_CN.ts + create mode 100644 lang/tz_zh_TW.ts + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 19395d4..40ae7e0 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -744,3 +744,4 @@ set(CPACK_PACKAGE_DESCRIPTION + set(CPACK_PACKAGE_ICON "data/images/squid.png") + + include(CPack) ++ +diff --git a/calamares.desktop b/calamares.desktop +index 00c2368..b0d6c27 100644 +--- a/calamares.desktop ++++ b/calamares.desktop +@@ -7,7 +7,7 @@ Keywords=calamares;system;installer; + TryExec=calamares + Exec=sh -c "pkexec calamares -style Adwaita" + Comment=Calamares — System Installer +-Icon=/usr/share/calamares/branding/default/openEuler-icon.png ++Icon=/usr/share/applications/openEuler.png + Terminal=false + StartupNotify=true + Categories=Qt;System; +@@ -66,7 +66,7 @@ Icon[el]=calamares + GenericName[el]=Εγκατάσταση συστήματος + Comment[el]=Calamares — Εγκατάσταση συστήματος + Name[en_GB]=Install System +-Icon[en_GB]=calamares ++Icon[en_GB]=/usr/share/applications/openEuler.png + GenericName[en_GB]=System Installer + Comment[en_GB]=Calamares — System Installer + Name[eo]=Instali Sistemo +@@ -226,7 +226,7 @@ Icon[tr_TR]=calamares + GenericName[tr_TR]=Sistem Yükleyici + Comment[tr_TR]=Calamares — Sistem Yükleyici + Name[uk]=Встановити Систему +-Icon[uk]=calamares ++Icon[uk]=/usr/share/applications/openEuler.png + GenericName[uk]=Встановлювач системи + Comment[uk]=Calamares - Встановлювач системи + Name[vi]=Cài đặt hệ thống +@@ -234,10 +234,10 @@ Icon[vi]=calamares + GenericName[vi]=Bộ cài đặt hệ thống + Comment[vi]=Calamares — Bộ cài đặt hệ thống + Name[zh_CN]=安装系统 +-Icon[zh_CN]=calamares ++Icon[zh_CN]=/usr/share/applications/openEuler.png + GenericName[zh_CN]=系统安装程序 + Comment[zh_CN]=Calamares — 系统安装程序 + Name[zh_TW]=安裝系統 +-Icon[zh_TW]=calamares ++Icon[zh_TW]=/usr/share/applications/openEuler.png + GenericName[zh_TW]=系統安裝程式 + Comment[zh_TW]=Calamares ── 系統安裝程式 +diff --git a/lang/calamares_zh_CN.ts b/lang/calamares_zh_CN.ts +index 75ffe95..3479fd1 100644 +--- a/lang/calamares_zh_CN.ts ++++ b/lang/calamares_zh_CN.ts +@@ -1032,7 +1032,7 @@ The installer will quit and all changes will be lost. + + The timezone will be set to %1. + @info +- 设置时区为 %1. ++ 设置时区为 %1。 + + + The timezone whill be set to %1. +diff --git a/lang/tz_zh_CN.ts b/lang/tz_zh_CN.ts +new file mode 100644 +index 0000000..b154b93 +--- /dev/null ++++ b/lang/tz_zh_CN.ts +@@ -0,0 +1,2626 @@ ++ ++ ++ ++ ++ ++ QObject ++ ++ ++ Africa ++ tz_regions ++ 非洲 ++ ++ ++ ++ America ++ tz_regions ++ 美洲 ++ ++ ++ ++ Antarctica ++ tz_regions ++ 南极洲 ++ ++ ++ ++ Arctic ++ tz_regions ++ 北极 ++ ++ ++ ++ Asia ++ tz_regions ++ 亚洲 ++ ++ ++ ++ Atlantic ++ tz_regions ++ 大西洋 ++ ++ ++ ++ Australia ++ tz_regions ++ 澳大利亚 ++ ++ ++ ++ Europe ++ tz_regions ++ 欧洲 ++ ++ ++ ++ Indian ++ tz_regions ++ 印度 ++ ++ ++ ++ Pacific ++ tz_regions ++ 太平洋 ++ ++ ++ ++ Abidjan ++ tz_names ++ 阿比让 ++ ++ ++ ++ Accra ++ tz_names ++ 阿克拉 ++ ++ ++ ++ Adak ++ tz_names ++ 阿达克 ++ ++ ++ ++ Addis Ababa ++ tz_names ++ 亚的斯亚贝巴 ++ ++ ++ ++ Adelaide ++ tz_names ++ 阿德莱德 ++ ++ ++ ++ Aden ++ tz_names ++ 亚丁 ++ ++ ++ ++ Algiers ++ tz_names ++ 阿尔及尔 ++ ++ ++ ++ Almaty ++ tz_names ++ 阿拉木图 ++ ++ ++ ++ Amman ++ tz_names ++ 安曼 ++ ++ ++ ++ Amsterdam ++ tz_names ++ 阿姆斯特丹 ++ ++ ++ ++ Anadyr ++ tz_names ++ 阿纳迪尔 ++ ++ ++ ++ Anchorage ++ tz_names ++ 安克雷奇 ++ ++ ++ ++ Andorra ++ tz_names ++ 安道尔 ++ ++ ++ ++ Anguilla ++ tz_names ++ 安圭拉 ++ ++ ++ ++ Antananarivo ++ tz_names ++ 塔那那利佛 ++ ++ ++ ++ Antigua ++ tz_names ++ 安提瓜 ++ ++ ++ ++ Apia ++ tz_names ++ 阿皮亚 ++ ++ ++ ++ Aqtau ++ tz_names ++ 阿克托 ++ ++ ++ ++ Aqtobe ++ tz_names ++ 阿克托贝 ++ ++ ++ ++ Araguaina ++ tz_names ++ 阿拉瓜伊纳 ++ ++ ++ ++ Argentina/Buenos Aires ++ tz_names ++ 阿根廷/布宜诺斯艾利斯 ++ ++ ++ ++ Argentina/Catamarca ++ tz_names ++ 阿根廷/卡塔马卡 ++ ++ ++ ++ Argentina/Cordoba ++ tz_names ++ 阿根廷/科尔多瓦 ++ ++ ++ ++ Argentina/Jujuy ++ tz_names ++ 阿根廷/胡胡伊 ++ ++ ++ ++ Argentina/La Rioja ++ tz_names ++ 阿根廷/拉里奥哈 ++ ++ ++ ++ Argentina/Mendoza ++ tz_names ++ 阿根廷/门多萨 ++ ++ ++ ++ Argentina/Rio Gallegos ++ tz_names ++ 阿根廷/里奥加列戈斯 ++ ++ ++ ++ Argentina/Salta ++ tz_names ++ 阿根廷/萨尔塔 ++ ++ ++ ++ Argentina/San Juan ++ tz_names ++ 阿根廷/圣胡安 ++ ++ ++ ++ Argentina/San Luis ++ tz_names ++ 阿根廷/圣路易斯 ++ ++ ++ ++ Argentina/Tucuman ++ tz_names ++ 阿根廷/图库曼 ++ ++ ++ ++ Argentina/Ushuaia ++ tz_names ++ 阿根廷/乌斯怀亚 ++ ++ ++ ++ Aruba ++ tz_names ++ 阿鲁巴 ++ ++ ++ ++ Ashgabat ++ tz_names ++ 阿什哈巴德 ++ ++ ++ ++ Asmara ++ tz_names ++ 阿斯马拉 ++ ++ ++ ++ Astrakhan ++ tz_names ++ 阿斯特拉罕 ++ ++ ++ ++ Asuncion ++ tz_names ++ 亚松森 ++ ++ ++ ++ Athens ++ tz_names ++ 雅典 ++ ++ ++ ++ Atikokan ++ tz_names ++ 阿提科坎 ++ ++ ++ ++ Atyrau ++ tz_names ++ 阿特劳 ++ ++ ++ ++ Auckland ++ tz_names ++ 奥克兰 ++ ++ ++ ++ Azores ++ tz_names ++ 亚速尔群岛 ++ ++ ++ ++ Baghdad ++ tz_names ++ 巴格达 ++ ++ ++ ++ Bahia ++ tz_names ++ 巴伊亚 ++ ++ ++ ++ Bahia Banderas ++ tz_names ++ 巴伊亚·班德拉斯 ++ ++ ++ ++ Bahrain ++ tz_names ++ 巴林 ++ ++ ++ ++ Baku ++ tz_names ++ 巴库 ++ ++ ++ ++ Bamako ++ tz_names ++ 巴马科 ++ ++ ++ ++ Bangkok ++ tz_names ++ 曼谷 ++ ++ ++ ++ Bangui ++ tz_names ++ 班吉 ++ ++ ++ ++ Banjul ++ tz_names ++ 班珠尔 ++ ++ ++ ++ Barbados ++ tz_names ++ 巴巴多斯 ++ ++ ++ ++ Barnaul ++ tz_names ++ 巴尔瑙尔 ++ ++ ++ ++ Beirut ++ tz_names ++ 贝鲁特 ++ ++ ++ ++ Belem ++ tz_names ++ 贝伦 ++ ++ ++ ++ Belgrade ++ tz_names ++ 贝尔格莱德 ++ ++ ++ ++ Belize ++ tz_names ++ 伯利兹 ++ ++ ++ ++ Berlin ++ tz_names ++ 柏林 ++ ++ ++ ++ Bermuda ++ tz_names ++ 百慕大 ++ ++ ++ ++ Bishkek ++ tz_names ++ 比什凯克 ++ ++ ++ ++ Bissau ++ tz_names ++ 比绍 ++ ++ ++ ++ Blanc-Sablon ++ tz_names ++ 布兰克·萨布隆 ++ ++ ++ ++ Blantyre ++ tz_names ++ 布兰太尔 ++ ++ ++ ++ Boa Vista ++ tz_names ++ 博阿维斯塔 ++ ++ ++ ++ Bogota ++ tz_names ++ 波哥大 ++ ++ ++ ++ Boise ++ tz_names ++ 博伊西 ++ ++ ++ ++ Bougainville ++ tz_names ++ 布干维尔 ++ ++ ++ ++ Bratislava ++ tz_names ++ 布拉迪斯拉发 ++ ++ ++ ++ Brazzaville ++ tz_names ++ 布拉柴维尔 ++ ++ ++ ++ Brisbane ++ tz_names ++ 布里斯班 ++ ++ ++ ++ Broken Hill ++ tz_names ++ 布罗肯希尔 ++ ++ ++ ++ Brunei ++ tz_names ++ 文莱 ++ ++ ++ ++ Brussels ++ tz_names ++ 布鲁塞尔 ++ ++ ++ ++ Beijing ++ tz_names ++ 北京 ++ ++ ++ ++ Bucharest ++ tz_names ++ 布加勒斯特 ++ ++ ++ ++ Budapest ++ tz_names ++ 布达佩斯 ++ ++ ++ ++ Bujumbura ++ tz_names ++ 布琼布拉 ++ ++ ++ ++ Busingen ++ tz_names ++ 比辛根 ++ ++ ++ ++ Cairo ++ tz_names ++ 开罗 ++ ++ ++ ++ Cambridge Bay ++ tz_names ++ 剑桥湾 ++ ++ ++ ++ Campo Grande ++ tz_names ++ 坎波格兰德 ++ ++ ++ ++ Canary ++ tz_names ++ 加那利群岛 ++ ++ ++ ++ Cancun ++ tz_names ++ 坎昆 ++ ++ ++ ++ Cape Verde ++ tz_names ++ 佛得角 ++ ++ ++ ++ Caracas ++ tz_names ++ 加拉加斯 ++ ++ ++ ++ Casablanca ++ tz_names ++ 卡萨布兰卡 ++ ++ ++ ++ Casey ++ tz_names ++ 凯西 ++ ++ ++ ++ Cayenne ++ tz_names ++ 卡宴 ++ ++ ++ ++ Cayman ++ tz_names ++ 开曼群岛 ++ ++ ++ ++ Ceuta ++ tz_names ++ 休达 ++ ++ ++ ++ Chagos ++ tz_names ++ 查戈斯 ++ ++ ++ ++ Chatham ++ tz_names ++ 查塔姆 ++ ++ ++ ++ Chicago ++ tz_names ++ 芝加哥 ++ ++ ++ ++ Chihuahua ++ tz_names ++ 吉娃娃 ++ ++ ++ ++ Chisinau ++ tz_names ++ 基希讷乌 ++ ++ ++ ++ Chita ++ tz_names ++ 赤塔 ++ ++ ++ ++ Choibalsan ++ tz_names ++ 乔巴桑 ++ ++ ++ ++ Christmas ++ tz_names ++ 伯利恒 ++ ++ ++ ++ Chuuk ++ tz_names ++ 楚克 ++ ++ ++ ++ Cocos ++ tz_names ++ 科科斯 ++ ++ ++ ++ Colombo ++ tz_names ++ 科伦坡 ++ ++ ++ ++ Comoro ++ tz_names ++ 科摩罗 ++ ++ ++ ++ Conakry ++ tz_names ++ 科纳克里 ++ ++ ++ ++ Copenhagen ++ tz_names ++ 哥本哈根 ++ ++ ++ ++ Costa Rica ++ tz_names ++ 哥斯达黎加 ++ ++ ++ ++ Creston ++ tz_names ++ 克雷斯顿 ++ ++ ++ ++ Cuiaba ++ tz_names ++ 库亚巴 ++ ++ ++ ++ Curacao ++ tz_names ++ 库拉索 ++ ++ ++ ++ Currie ++ tz_names ++ 柯里 ++ ++ ++ ++ Dakar ++ tz_names ++ 达喀尔 ++ ++ ++ ++ Damascus ++ tz_names ++ 大马士革 ++ ++ ++ ++ Danmarkshavn ++ tz_names ++ 丹麦 ++ ++ ++ ++ Dar es Salaam ++ tz_names ++ 达累斯萨拉姆 ++ ++ ++ ++ Darwin ++ tz_names ++ 达尔文 ++ ++ ++ ++ Davis ++ tz_names ++ 戴维斯 ++ ++ ++ ++ Dawson ++ tz_names ++ 道森 ++ ++ ++ ++ Dawson Creek ++ tz_names ++ 道森溪 ++ ++ ++ ++ Denver ++ tz_names ++ 丹佛 ++ ++ ++ ++ Detroit ++ tz_names ++ 底特律 ++ ++ ++ ++ Dhaka ++ tz_names ++ 达卡 ++ ++ ++ ++ Dili ++ tz_names ++ 帝力 ++ ++ ++ ++ Djibouti ++ tz_names ++ 吉布提 ++ ++ ++ ++ Dominica ++ tz_names ++ 多米尼克 ++ ++ ++ ++ Douala ++ tz_names ++ 杜阿拉 ++ ++ ++ ++ Dubai ++ tz_names ++ 迪拜 ++ ++ ++ ++ Dublin ++ tz_names ++ 都柏林 ++ ++ ++ ++ DumontDUrville ++ tz_names ++ 杜蒙·杜维尔 ++ ++ ++ ++ Dushanbe ++ tz_names ++ 杜尚别 ++ ++ ++ ++ Easter ++ tz_names ++ 伊斯特迪 ++ ++ ++ ++ Edmonton ++ tz_names ++ 埃德蒙顿 ++ ++ ++ ++ Efate ++ tz_names ++ 埃法特岛 ++ ++ ++ ++ Eirunepe ++ tz_names ++ 埃鲁内佩 ++ ++ ++ ++ El Aaiun ++ tz_names ++ 阿尤恩 ++ ++ ++ ++ El Salvador ++ tz_names ++ 萨尔瓦多 ++ ++ ++ ++ Enderbury ++ tz_names ++ 恩德伯里 ++ ++ ++ ++ Eucla ++ tz_names ++ 尤克拉 ++ ++ ++ ++ Fakaofo ++ tz_names ++ 法考福 ++ ++ ++ ++ Famagusta ++ tz_names ++ 法马古斯塔 ++ ++ ++ ++ Faroe ++ tz_names ++ 法罗 ++ ++ ++ ++ Fiji ++ tz_names ++ 斐济 ++ ++ ++ ++ Fort Nelson ++ tz_names ++ 纳尔逊堡 ++ ++ ++ ++ Fortaleza ++ tz_names ++ 福塔莱萨 ++ ++ ++ ++ Freetown ++ tz_names ++ 弗里敦 ++ ++ ++ ++ Funafuti ++ tz_names ++ 富纳富提 ++ ++ ++ ++ Gaborone ++ tz_names ++ 哈博罗内 ++ ++ ++ ++ Galapagos ++ tz_names ++ 加拉帕戈斯群岛 ++ ++ ++ ++ Gambier ++ tz_names ++ 甘比尔 ++ ++ ++ ++ Gaza ++ tz_names ++ 加沙 ++ ++ ++ ++ Gibraltar ++ tz_names ++ 直布罗陀 ++ ++ ++ ++ Glace Bay ++ tz_names ++ 格莱斯湾 ++ ++ ++ ++ Godthab ++ tz_names ++ 戈德萨布 ++ ++ ++ ++ Goose Bay ++ tz_names ++ 鹅湾 ++ ++ ++ ++ Grand Turk ++ tz_names ++ 大特克 ++ ++ ++ ++ Grenada ++ tz_names ++ 格林纳达 ++ ++ ++ ++ Guadalcanal ++ tz_names ++ 瓜达尔卡纳尔岛 ++ ++ ++ ++ Guadeloupe ++ tz_names ++ 瓜德罗普岛 ++ ++ ++ ++ Guam ++ tz_names ++ 关岛 ++ ++ ++ ++ Guatemala ++ tz_names ++ 危地马拉 ++ ++ ++ ++ Guayaquil ++ tz_names ++ 瓜亚基尔 ++ ++ ++ ++ Guernsey ++ tz_names ++ 根西岛 ++ ++ ++ ++ Guyana ++ tz_names ++ 圭亚那 ++ ++ ++ ++ Halifax ++ tz_names ++ 哈利法克斯 ++ ++ ++ ++ Harare ++ tz_names ++ 哈拉雷 ++ ++ ++ ++ Havana ++ tz_names ++ 哈瓦那 ++ ++ ++ ++ Hebron ++ tz_names ++ 希伯伦 ++ ++ ++ ++ Helsinki ++ tz_names ++ 赫尔辛基 ++ ++ ++ ++ Hermosillo ++ tz_names ++ 埃莫西洛 ++ ++ ++ ++ Ho Chi Minh ++ tz_names ++ 胡志明 ++ ++ ++ ++ Hobart ++ tz_names ++ 霍巴特 ++ ++ ++ ++ Hong Kong(China) ++ tz_names ++ 香港(中国) ++ ++ ++ ++ Honolulu ++ tz_names ++ 檀香山 ++ ++ ++ ++ Hovd ++ tz_names ++ 科布多 ++ ++ ++ ++ Indiana/Indianapolis ++ tz_names ++ 印第安纳州/印第安纳波利斯 ++ ++ ++ ++ Indiana/Knox ++ tz_names ++ 印第安纳州/诺克斯 ++ ++ ++ ++ Indiana/Marengo ++ tz_names ++ 印度/马伦戈 ++ ++ ++ ++ Indiana/Petersburg ++ tz_names ++ 印第安纳州/彼得堡 ++ ++ ++ ++ Indiana/Tell City ++ tz_names ++ 印第安纳州/泰尔城 ++ ++ ++ ++ Indiana/Vevay ++ tz_names ++ 印度/沃韦 ++ ++ ++ ++ Indiana/Vincennes ++ tz_names ++ 印第安纳州/文森斯 ++ ++ ++ ++ Indiana/Winamac ++ tz_names ++ 印第安纳州/威纳马克 ++ ++ ++ ++ Inuvik ++ tz_names ++ 伊努维克 ++ ++ ++ ++ Iqaluit ++ tz_names ++ 伊魁特 ++ ++ ++ ++ Irkutsk ++ tz_names ++ 伊尔库茨克 ++ ++ ++ ++ Isle of Man ++ tz_names ++ 马恩岛 ++ ++ ++ ++ Istanbul ++ tz_names ++ 伊斯坦布尔 ++ ++ ++ ++ Jakarta ++ tz_names ++ 雅加达 ++ ++ ++ ++ Jamaica ++ tz_names ++ 牙买加 ++ ++ ++ ++ Jayapura ++ tz_names ++ 查亚普拉 ++ ++ ++ ++ Jersey ++ tz_names ++ 泽西岛 ++ ++ ++ ++ Jerusalem ++ tz_names ++ 耶路撒冷 ++ ++ ++ ++ Johannesburg ++ tz_names ++ 约翰内斯堡 ++ ++ ++ ++ Juba ++ tz_names ++ 朱巴 ++ ++ ++ ++ Juneau ++ tz_names ++ 朱诺 ++ ++ ++ ++ Kabul ++ tz_names ++ 喀布尔 ++ ++ ++ ++ Kaliningrad ++ tz_names ++ 加里宁格勒 ++ ++ ++ ++ Kamchatka ++ tz_names ++ 堪察加半岛 ++ ++ ++ ++ Kampala ++ tz_names ++ 坎帕拉 ++ ++ ++ ++ Karachi ++ tz_names ++ 卡拉奇 ++ ++ ++ ++ Kathmandu ++ tz_names ++ 加德满都 ++ ++ ++ ++ Kentucky/Louisville ++ tz_names ++ 肯塔基州/路易斯维尔 ++ ++ ++ ++ Kentucky/Monticello ++ tz_names ++ 肯塔基州/蒙蒂塞洛 ++ ++ ++ ++ Kerguelen ++ tz_names ++ 凯尔盖朗 ++ ++ ++ ++ Khandyga ++ tz_names ++ 坎代加 ++ ++ ++ ++ Khartoum ++ tz_names ++ 喀土穆 ++ ++ ++ ++ Kiev ++ tz_names ++ 基辅 ++ ++ ++ ++ Kigali ++ tz_names ++ 基加利 ++ ++ ++ ++ Kinshasa ++ tz_names ++ 金沙萨 ++ ++ ++ ++ Kiritimati ++ tz_names ++ 基里蒂马提斯 ++ ++ ++ ++ Kirov ++ tz_names ++ 基洛夫 ++ ++ ++ ++ Kolkata ++ tz_names ++ 加尔格达 ++ ++ ++ ++ Kosrae ++ tz_names ++ 科斯雷 ++ ++ ++ ++ Kralendijk ++ tz_names ++ 克罗地亚 ++ ++ ++ ++ Krasnoyarsk ++ tz_names ++ 克拉斯诺亚尔斯克 ++ ++ ++ ++ Kuala Lumpur ++ tz_names ++ 吉隆坡 ++ ++ ++ ++ Kuching ++ tz_names ++ 古晋 ++ ++ ++ ++ Kuwait ++ tz_names ++ 科威特 ++ ++ ++ ++ Kwajalein ++ tz_names ++ 夸贾林 ++ ++ ++ ++ La Paz ++ tz_names ++ 拉巴斯 ++ ++ ++ ++ Lagos ++ tz_names ++ 拉各斯 ++ ++ ++ ++ Libreville ++ tz_names ++ 利伯维尔 ++ ++ ++ ++ Lima ++ tz_names ++ 利马 ++ ++ ++ ++ Lindeman ++ tz_names ++ 林德曼 ++ ++ ++ ++ Lisbon ++ tz_names ++ 里斯本 ++ ++ ++ ++ Ljubljana ++ tz_names ++ 卢布尔雅那 ++ ++ ++ ++ Lome ++ tz_names ++ 多哥 ++ ++ ++ ++ London ++ tz_names ++ 伦敦 ++ ++ ++ ++ Longyearbyen ++ tz_names ++ 朗伊尔城 ++ ++ ++ ++ Lord Howe ++ tz_names ++ 豪勋爵 ++ ++ ++ ++ Los Angeles ++ tz_names ++ 洛杉矶 ++ ++ ++ ++ Lower Princes ++ tz_names ++ 圣马丁 ++ ++ ++ ++ Luanda ++ tz_names ++ 罗安达 ++ ++ ++ ++ Lubumbashi ++ tz_names ++ 卢本巴希 ++ ++ ++ ++ Lusaka ++ tz_names ++ 卢萨卡 ++ ++ ++ ++ Luxembourg ++ tz_names ++ 卢森堡 ++ ++ ++ ++ Macau(China) ++ tz_names ++ 澳门(中国) ++ ++ ++ ++ Maceio ++ tz_names ++ 马塞奥 ++ ++ ++ ++ Macquarie ++ tz_names ++ 麦格理 ++ ++ ++ ++ Madeira ++ tz_names ++ 马德拉 ++ ++ ++ ++ Madrid ++ tz_names ++ 马德里 ++ ++ ++ ++ Magadan ++ tz_names ++ 马加丹 ++ ++ ++ ++ Mahe ++ tz_names ++ 马埃 ++ ++ ++ ++ Majuro ++ tz_names ++ 马朱罗 ++ ++ ++ ++ Makassar ++ tz_names ++ 望加锡 ++ ++ ++ ++ Malabo ++ tz_names ++ 马拉博 ++ ++ ++ ++ Maldives ++ tz_names ++ 马尔代夫 ++ ++ ++ ++ Malta ++ tz_names ++ 马耳他 ++ ++ ++ ++ Managua ++ tz_names ++ 马那瓜 ++ ++ ++ ++ Manaus ++ tz_names ++ 马瑙斯 ++ ++ ++ ++ Manila ++ tz_names ++ 马尼拉 ++ ++ ++ ++ Maputo ++ tz_names ++ 马普托 ++ ++ ++ ++ Mariehamn ++ tz_names ++ 玛丽港 ++ ++ ++ ++ Marigot ++ tz_names ++ 马里戈 ++ ++ ++ ++ Marquesas ++ tz_names ++ 马克萨斯 ++ ++ ++ ++ Martinique ++ tz_names ++ 马提尼克岛 ++ ++ ++ ++ Maseru ++ tz_names ++ 马塞卢 ++ ++ ++ ++ Matamoros ++ tz_names ++ 马塔莫罗斯 ++ ++ ++ ++ Mauritius ++ tz_names ++ 毛里求斯 ++ ++ ++ ++ Mawson ++ tz_names ++ 莫森 ++ ++ ++ ++ Mayotte ++ tz_names ++ 马约特岛 ++ ++ ++ ++ Mazatlan ++ tz_names ++ 马萨特兰 ++ ++ ++ ++ Mbabane ++ tz_names ++ 姆巴巴内 ++ ++ ++ ++ McMurdo ++ tz_names ++ 麦克默多 ++ ++ ++ ++ Melbourne ++ tz_names ++ 墨尔本 ++ ++ ++ ++ Menominee ++ tz_names ++ 梅诺米尼 ++ ++ ++ ++ Merida ++ tz_names ++ 梅里达 ++ ++ ++ ++ Metlakatla ++ tz_names ++ 梅特拉卡特拉 ++ ++ ++ ++ Mexico City ++ tz_names ++ 墨西哥城 ++ ++ ++ ++ Midway ++ tz_names ++ 中途岛 ++ ++ ++ ++ Minsk ++ tz_names ++ 明斯克 ++ ++ ++ ++ Miquelon ++ tz_names ++ 密克隆 ++ ++ ++ ++ Mogadishu ++ tz_names ++ 摩加迪沙 ++ ++ ++ ++ Monaco ++ tz_names ++ 摩纳哥 ++ ++ ++ ++ Moncton ++ tz_names ++ 蒙克顿 ++ ++ ++ ++ Monrovia ++ tz_names ++ 蒙罗维亚 ++ ++ ++ ++ Monterrey ++ tz_names ++ 蒙特雷 ++ ++ ++ ++ Montevideo ++ tz_names ++ 蒙得维的亚 ++ ++ ++ ++ Montserrat ++ tz_names ++ 蒙特塞拉特 ++ ++ ++ ++ Moscow ++ tz_names ++ 莫斯科 ++ ++ ++ ++ Muscat ++ tz_names ++ 马斯喀特 ++ ++ ++ ++ Nairobi ++ tz_names ++ 内罗毕 ++ ++ ++ ++ Nassau ++ tz_names ++ 拿骚 ++ ++ ++ ++ Nauru ++ tz_names ++ 瑙鲁 ++ ++ ++ ++ Ndjamena ++ tz_names ++ 恩贾梅纳 ++ ++ ++ ++ New York ++ tz_names ++ 纽约 ++ ++ ++ ++ Niamey ++ tz_names ++ 尼亚美 ++ ++ ++ ++ Nicosia ++ tz_names ++ 尼科西亚 ++ ++ ++ ++ Nipigon ++ tz_names ++ 尼皮贡 ++ ++ ++ ++ Niue ++ tz_names ++ 纽埃 ++ ++ ++ ++ Nome ++ tz_names ++ 诺姆 ++ ++ ++ ++ Norfolk ++ tz_names ++ 诺福克 ++ ++ ++ ++ Noronha ++ tz_names ++ 诺罗尼亚 ++ ++ ++ ++ North Dakota/Beulah ++ tz_names ++ 北达科他州/比拉 ++ ++ ++ ++ North Dakota/Center ++ tz_names ++ 北达科他州/中心 ++ ++ ++ ++ North Dakota/New Salem ++ tz_names ++ 北达科他州/新塞勒姆 ++ ++ ++ ++ Nouakchott ++ tz_names ++ 努瓦克肖特 ++ ++ ++ ++ Noumea ++ tz_names ++ 努美阿 ++ ++ ++ ++ Novokuznetsk ++ tz_names ++ 新库兹涅茨克 ++ ++ ++ ++ Novosibirsk ++ tz_names ++ 新西伯利亚 ++ ++ ++ ++ Ojinaga ++ tz_names ++ 魁北克 ++ ++ ++ ++ Omsk ++ tz_names ++ 鄂木斯克 ++ ++ ++ ++ Oral ++ tz_names ++ 多拉 ++ ++ ++ ++ Oslo ++ tz_names ++ 奥斯陆 ++ ++ ++ ++ Ouagadougou ++ tz_names ++ 瓦加杜古 ++ ++ ++ ++ Pago Pago ++ tz_names ++ 帕果帕果 ++ ++ ++ ++ Palau ++ tz_names ++ 帕劳 ++ ++ ++ ++ Palmer ++ tz_names ++ 帕尔默 ++ ++ ++ ++ Panama ++ tz_names ++ 巴拿马 ++ ++ ++ ++ Pangnirtung ++ tz_names ++ 巴芬岛的旁涅唐 ++ ++ ++ ++ Paramaribo ++ tz_names ++ 帕拉马里博 ++ ++ ++ ++ Paris ++ tz_names ++ 巴黎 ++ ++ ++ ++ Perth ++ tz_names ++ 珀斯 ++ ++ ++ ++ Phnom Penh ++ tz_names ++ 金边 ++ ++ ++ ++ Phoenix ++ tz_names ++ 凤凰城 ++ ++ ++ ++ Pitcairn ++ tz_names ++ 皮特凯恩 ++ ++ ++ ++ Podgorica ++ tz_names ++ 波德戈里察 ++ ++ ++ ++ Pohnpei ++ tz_names ++ 波纳佩岛 ++ ++ ++ ++ Pontianak ++ tz_names ++ 坤甸 ++ ++ ++ ++ Port Moresby ++ tz_names ++ 莫尔兹比港 ++ ++ ++ ++ Port of Spain ++ tz_names ++ 西班牙港 ++ ++ ++ ++ Port-au-Prince ++ tz_names ++ 太子港 ++ ++ ++ ++ Porto Velho ++ tz_names ++ 维略港 ++ ++ ++ ++ Porto-Novo ++ tz_names ++ 波多诺伏 ++ ++ ++ ++ Prague ++ tz_names ++ 布拉格 ++ ++ ++ ++ Puerto Rico ++ tz_names ++ 波多黎各 ++ ++ ++ ++ Punta Arenas ++ tz_names ++ 蓬塔阿雷纳斯 ++ ++ ++ ++ Pyongyang ++ tz_names ++ 平壤 ++ ++ ++ ++ Qatar ++ tz_names ++ 卡塔尔 ++ ++ ++ ++ Qostanay ++ tz_names ++ 库斯塔 ++ ++ ++ ++ Qyzylorda ++ tz_names ++ 克孜勒奥尔达 ++ ++ ++ ++ Rainy River ++ tz_names ++ 雷尼河 ++ ++ ++ ++ Rankin Inlet ++ tz_names ++ 兰京海口 ++ ++ ++ ++ Rarotonga ++ tz_names ++ 拉罗汤加 ++ ++ ++ ++ Recife ++ tz_names ++ 累西腓 ++ ++ ++ ++ Regina ++ tz_names ++ 里贾纳 ++ ++ ++ ++ Resolute ++ tz_names ++ 雷索卢特 ++ ++ ++ ++ Reunion ++ tz_names ++ 留尼旺岛 ++ ++ ++ ++ Reykjavik ++ tz_names ++ 雷克雅未克 ++ ++ ++ ++ Riga ++ tz_names ++ 里加 ++ ++ ++ ++ Rio Branco ++ tz_names ++ 里奥·布兰科 ++ ++ ++ ++ Riyadh ++ tz_names ++ 利雅得 ++ ++ ++ ++ Rome ++ tz_names ++ 罗马 ++ ++ ++ ++ Rothera ++ tz_names ++ 罗瑟拉 ++ ++ ++ ++ Saipan ++ tz_names ++ 塞班岛 ++ ++ ++ ++ Sakhalin ++ tz_names ++ 萨哈林 ++ ++ ++ ++ Samara ++ tz_names ++ 萨马拉 ++ ++ ++ ++ Samarkand ++ tz_names ++ 撒马尔罕 ++ ++ ++ ++ San Marino ++ tz_names ++ 圣马力诺 ++ ++ ++ ++ Santarem ++ tz_names ++ 圣塔伦 ++ ++ ++ ++ Santiago ++ tz_names ++ 圣地亚哥 ++ ++ ++ ++ Santo Domingo ++ tz_names ++ 圣多明各 ++ ++ ++ ++ Sao Paulo ++ tz_names ++ 圣保罗 ++ ++ ++ ++ Sao Tome ++ tz_names ++ 圣多美 ++ ++ ++ ++ Sarajevo ++ tz_names ++ 萨拉热窝 ++ ++ ++ ++ Saratov ++ tz_names ++ 萨拉托夫 ++ ++ ++ ++ Scoresbysund ++ tz_names ++ 斯科斯比基金 ++ ++ ++ ++ Seoul ++ tz_names ++ 首尔 ++ ++ ++ ++ Shanghai ++ tz_names ++ 上海 ++ ++ ++ ++ Simferopol ++ tz_names ++ 辛菲罗波尔 ++ ++ ++ ++ Singapore ++ tz_names ++ 新加坡 ++ ++ ++ ++ Sitka ++ tz_names ++ 锡特卡 ++ ++ ++ ++ Skopje ++ tz_names ++ 斯科普里 ++ ++ ++ ++ Sofia ++ tz_names ++ 索菲亚 ++ ++ ++ ++ South Georgia ++ tz_names ++ 南乔治亚州 ++ ++ ++ ++ Srednekolymsk ++ tz_names ++ 雅库特 ++ ++ ++ ++ St Barthelemy ++ tz_names ++ 圣巴泰勒米 ++ ++ ++ ++ St Helena ++ tz_names ++ 圣赫勒拿 ++ ++ ++ ++ St Johns ++ tz_names ++ 圣约翰 ++ ++ ++ ++ St Kitts ++ tz_names ++ 圣基茨 ++ ++ ++ ++ St Lucia ++ tz_names ++ 圣卢西亚 ++ ++ ++ ++ St Thomas ++ tz_names ++ 圣托马斯 ++ ++ ++ ++ St Vincent ++ tz_names ++ 圣文森特 ++ ++ ++ ++ Stanley ++ tz_names ++ 斯坦利 ++ ++ ++ ++ Stockholm ++ tz_names ++ 斯德哥尔摩 ++ ++ ++ ++ Swift Current ++ tz_names ++ 斯威夫特卡伦特 ++ ++ ++ ++ Sydney ++ tz_names ++ 悉尼 ++ ++ ++ ++ Syowa ++ tz_names ++ 圣何塞 ++ ++ ++ ++ Tahiti ++ tz_names ++ 大溪地 ++ ++ ++ ++ Taipei(China) ++ tz_names ++ 台北(中国) ++ ++ ++ ++ Tallinn ++ tz_names ++ 塔林 ++ ++ ++ ++ Tarawa ++ tz_names ++ 塔拉瓦 ++ ++ ++ ++ Tashkent ++ tz_names ++ 塔什干 ++ ++ ++ ++ Tbilisi ++ tz_names ++ 第比利斯 ++ ++ ++ ++ Tegucigalpa ++ tz_names ++ 特古西加尔巴 ++ ++ ++ ++ Tehran ++ tz_names ++ 德黑兰 ++ ++ ++ ++ Thimphu ++ tz_names ++ 廷布 ++ ++ ++ ++ Thule ++ tz_names ++ 图勒 ++ ++ ++ ++ Thunder Bay ++ tz_names ++ 雷湾 ++ ++ ++ ++ Tijuana ++ tz_names ++ 蒂华纳 ++ ++ ++ ++ Tirane ++ tz_names ++ 地拉那 ++ ++ ++ ++ Tokyo ++ tz_names ++ 东京 ++ ++ ++ ++ Tomsk ++ tz_names ++ 托木斯克 ++ ++ ++ ++ Tongatapu ++ tz_names ++ 汤加塔布 ++ ++ ++ ++ Toronto ++ tz_names ++ 多伦多 ++ ++ ++ ++ Tortola ++ tz_names ++ 托托拉岛 ++ ++ ++ ++ Tripoli ++ tz_names ++ 的黎波里 ++ ++ ++ ++ Troll ++ tz_names ++ 特罗尔海坦 ++ ++ ++ ++ Tunis ++ tz_names ++ 突尼斯 ++ ++ ++ ++ Ulaanbaatar ++ tz_names ++ 乌兰巴托 ++ ++ ++ ++ Ulyanovsk ++ tz_names ++ 乌里扬诺夫斯克 ++ ++ ++ ++ Urumqi ++ tz_names ++ 乌鲁木齐 ++ ++ ++ ++ Ust-Nera ++ tz_names ++ 乌斯季挪拉 ++ ++ ++ ++ Uzhgorod ++ tz_names ++ 乌日哥罗德 ++ ++ ++ ++ Vaduz ++ tz_names ++ 瓦杜兹 ++ ++ ++ ++ Vancouver ++ tz_names ++ 温哥华 ++ ++ ++ ++ Vatican ++ tz_names ++ 梵蒂冈 ++ ++ ++ ++ Vienna ++ tz_names ++ 维也纳 ++ ++ ++ ++ Vientiane ++ tz_names ++ 万象 ++ ++ ++ ++ Vilnius ++ tz_names ++ 维尔纽斯 ++ ++ ++ ++ Vladivostok ++ tz_names ++ 符拉迪沃斯托克 ++ ++ ++ ++ Volgograd ++ tz_names ++ 伏尔加格勒 ++ ++ ++ ++ Vostok ++ tz_names ++ 沃斯托克 ++ ++ ++ ++ Wake ++ tz_names ++ 韦克 ++ ++ ++ ++ Wallis ++ tz_names ++ 沃利斯 ++ ++ ++ ++ Warsaw ++ tz_names ++ 华沙 ++ ++ ++ ++ Whitehorse ++ tz_names ++ 怀特霍斯 ++ ++ ++ ++ Windhoek ++ tz_names ++ 温得和克 ++ ++ ++ ++ Winnipeg ++ tz_names ++ 温尼伯 ++ ++ ++ ++ Yakutat ++ tz_names ++ 雅库特 ++ ++ ++ ++ Yakutsk ++ tz_names ++ 雅库茨克 ++ ++ ++ ++ Yangon ++ tz_names ++ 仰光 ++ ++ ++ ++ Yekaterinburg ++ tz_names ++ 叶卡捷琳堡 ++ ++ ++ ++ Yellowknife ++ tz_names ++ 耶洛奈夫 ++ ++ ++ ++ Yerevan ++ tz_names ++ 埃里温 ++ ++ ++ ++ Zagreb ++ tz_names ++ 萨格勒布 ++ ++ ++ ++ Zaporozhye ++ tz_names ++ 扎波罗热 ++ ++ ++ ++ Zurich ++ tz_names ++ 苏黎世 ++ ++ ++ +diff --git a/lang/tz_zh_TW.ts b/lang/tz_zh_TW.ts +new file mode 100644 +index 0000000..2713d37 +--- /dev/null ++++ b/lang/tz_zh_TW.ts +@@ -0,0 +1,2626 @@ ++ ++ ++ ++ ++ ++ QObject ++ ++ ++ Africa ++ tz_regions ++ 非洲 ++ ++ ++ ++ America ++ tz_regions ++ 美洲 ++ ++ ++ ++ Antarctica ++ tz_regions ++ 南極洲 ++ ++ ++ ++ Arctic ++ tz_regions ++ 北極 ++ ++ ++ ++ Asia ++ tz_regions ++ 亞洲 ++ ++ ++ ++ Atlantic ++ tz_regions ++ 大西洋 ++ ++ ++ ++ Australia ++ tz_regions ++ 澳大利亞 ++ ++ ++ ++ Europe ++ tz_regions ++ 歐洲 ++ ++ ++ ++ Indian ++ tz_regions ++ 印度 ++ ++ ++ ++ Pacific ++ tz_regions ++ 太平洋 ++ ++ ++ ++ Abidjan ++ tz_names ++ 阿必尚 ++ ++ ++ ++ Accra ++ tz_names ++ 阿克拉 ++ ++ ++ ++ Adak ++ tz_names ++ 阿達克 ++ ++ ++ ++ Addis Ababa ++ tz_names ++ 阿迪斯阿貝巴 ++ ++ ++ ++ Adelaide ++ tz_names ++ 阿德萊德 ++ ++ ++ ++ Aden ++ tz_names ++ 亞丁 ++ ++ ++ ++ Algiers ++ tz_names ++ 阿爾及爾 ++ ++ ++ ++ Almaty ++ tz_names ++ 阿拉木圖 ++ ++ ++ ++ Amman ++ tz_names ++ 安曼 ++ ++ ++ ++ Amsterdam ++ tz_names ++ 阿姆斯特丹 ++ ++ ++ ++ Anadyr ++ tz_names ++ 阿納迪爾 ++ ++ ++ ++ Anchorage ++ tz_names ++ 安克雷奇 ++ ++ ++ ++ Andorra ++ tz_names ++ 安道爾 ++ ++ ++ ++ Anguilla ++ tz_names ++ 安圭拉 ++ ++ ++ ++ Antananarivo ++ tz_names ++ 安塔那那利佛 ++ ++ ++ ++ Antigua ++ tz_names ++ 安提瓜 ++ ++ ++ ++ Apia ++ tz_names ++ 亞庇 ++ ++ ++ ++ Aqtau ++ tz_names ++ 阿克托 ++ ++ ++ ++ Aqtobe ++ tz_names ++ 阿克托貝 ++ ++ ++ ++ Araguaina ++ tz_names ++ 阿拉瓜伊納 ++ ++ ++ ++ Argentina/Buenos Aires ++ tz_names ++ 阿根廷/布宜諾賽勒斯 ++ ++ ++ ++ Argentina/Catamarca ++ tz_names ++ 阿根廷/卡塔馬卡 ++ ++ ++ ++ Argentina/Cordoba ++ tz_names ++ 阿根廷/科爾多瓦 ++ ++ ++ ++ Argentina/Jujuy ++ tz_names ++ 阿根廷/胡胡伊 ++ ++ ++ ++ Argentina/La Rioja ++ tz_names ++ 阿根廷/拉里奧哈 ++ ++ ++ ++ Argentina/Mendoza ++ tz_names ++ 阿根廷/門多薩 ++ ++ ++ ++ Argentina/Rio Gallegos ++ tz_names ++ 阿根廷/裏奧加列戈斯 ++ ++ ++ ++ Argentina/Salta ++ tz_names ++ 阿根廷/薩爾塔 ++ ++ ++ ++ Argentina/San Juan ++ tz_names ++ 阿根廷/聖胡安 ++ ++ ++ ++ Argentina/San Luis ++ tz_names ++ 阿根廷/聖路易斯 ++ ++ ++ ++ Argentina/Tucuman ++ tz_names ++ 阿根廷/圖庫曼 ++ ++ ++ ++ Argentina/Ushuaia ++ tz_names ++ 阿根廷/烏斯懷亞 ++ ++ ++ ++ Aruba ++ tz_names ++ 阿魯巴 ++ ++ ++ ++ Ashgabat ++ tz_names ++ 阿什哈巴德 ++ ++ ++ ++ Asmara ++ tz_names ++ 阿斯馬拉 ++ ++ ++ ++ Astrakhan ++ tz_names ++ 阿斯特拉罕 ++ ++ ++ ++ Asuncion ++ tz_names ++ 亞松森 ++ ++ ++ ++ Athens ++ tz_names ++ 雅典 ++ ++ ++ ++ Atikokan ++ tz_names ++ 阿提科坎 ++ ++ ++ ++ Atyrau ++ tz_names ++ 阿特勞 ++ ++ ++ ++ Auckland ++ tz_names ++ 奧克蘭 ++ ++ ++ ++ Azores ++ tz_names ++ 亞速爾群島 ++ ++ ++ ++ Baghdad ++ tz_names ++ 巴格達 ++ ++ ++ ++ Bahia ++ tz_names ++ 巴伊亞 ++ ++ ++ ++ Bahia Banderas ++ tz_names ++ 巴伊亞·班德拉斯 ++ ++ ++ ++ Bahrain ++ tz_names ++ 巴林 ++ ++ ++ ++ Baku ++ tz_names ++ 巴庫 ++ ++ ++ ++ Bamako ++ tz_names ++ 巴馬科 ++ ++ ++ ++ Bangkok ++ tz_names ++ 曼谷 ++ ++ ++ ++ Bangui ++ tz_names ++ 班基 ++ ++ ++ ++ Banjul ++ tz_names ++ 班竹 ++ ++ ++ ++ Barbados ++ tz_names ++ 巴巴多斯 ++ ++ ++ ++ Barnaul ++ tz_names ++ 巴爾瑙爾 ++ ++ ++ ++ Beirut ++ tz_names ++ 貝魯特 ++ ++ ++ ++ Belem ++ tz_names ++ 貝倫 ++ ++ ++ ++ Belgrade ++ tz_names ++ 貝爾格勒 ++ ++ ++ ++ Belize ++ tz_names ++ 貝裡斯 ++ ++ ++ ++ Berlin ++ tz_names ++ 柏林 ++ ++ ++ ++ Bermuda ++ tz_names ++ 百慕大 ++ ++ ++ ++ Bishkek ++ tz_names ++ 比什凱克 ++ ++ ++ ++ Bissau ++ tz_names ++ 比索 ++ ++ ++ ++ Beijing ++ tz_names ++ 北京 ++ ++ ++ ++ Blanc-Sablon ++ tz_names ++ 布蘭克·薩布隆 ++ ++ ++ ++ Blantyre ++ tz_names ++ 布蘭太爾 ++ ++ ++ ++ Boa Vista ++ tz_names ++ 博阿維斯塔 ++ ++ ++ ++ Bogota ++ tz_names ++ 波哥大 ++ ++ ++ ++ Boise ++ tz_names ++ 博伊西 ++ ++ ++ ++ Bougainville ++ tz_names ++ 布幹維爾 ++ ++ ++ ++ Bratislava ++ tz_names ++ 布拉提斯拉瓦 ++ ++ ++ ++ Brazzaville ++ tz_names ++ 布拉柴維爾 ++ ++ ++ ++ Brisbane ++ tz_names ++ 布里斯班 ++ ++ ++ ++ Broken Hill ++ tz_names ++ 布羅肯希爾 ++ ++ ++ ++ Brunei ++ tz_names ++ 汶萊 ++ ++ ++ ++ Brussels ++ tz_names ++ 布魯塞爾 ++ ++ ++ ++ Bucharest ++ tz_names ++ 布加勒斯特 ++ ++ ++ ++ Budapest ++ tz_names ++ 布達佩斯 ++ ++ ++ ++ Bujumbura ++ tz_names ++ 布松布拉 ++ ++ ++ ++ Busingen ++ tz_names ++ 匯流排 ++ ++ ++ ++ Cairo ++ tz_names ++ 開羅 ++ ++ ++ ++ Cambridge Bay ++ tz_names ++ 劍橋灣 ++ ++ ++ ++ Campo Grande ++ tz_names ++ 坎波格蘭德 ++ ++ ++ ++ Canary ++ tz_names ++ 加那利群島 ++ ++ ++ ++ Cancun ++ tz_names ++ 坎昆 ++ ++ ++ ++ Cape Verde ++ tz_names ++ 佛得角 ++ ++ ++ ++ Caracas ++ tz_names ++ 卡拉卡斯 ++ ++ ++ ++ Casablanca ++ tz_names ++ 卡薩布蘭卡 ++ ++ ++ ++ Casey ++ tz_names ++ 凱西 ++ ++ ++ ++ Cayenne ++ tz_names ++ 卡宴 ++ ++ ++ ++ Cayman ++ tz_names ++ 開曼群島 ++ ++ ++ ++ Ceuta ++ tz_names ++ 休達 ++ ++ ++ ++ Chagos ++ tz_names ++ 查戈斯 ++ ++ ++ ++ Chatham ++ tz_names ++ 查塔姆 ++ ++ ++ ++ Chicago ++ tz_names ++ 芝加哥 ++ ++ ++ ++ Chihuahua ++ tz_names ++ 吉娃娃 ++ ++ ++ ++ Chisinau ++ tz_names ++ 基希訥烏 ++ ++ ++ ++ Chita ++ tz_names ++ 赤塔 ++ ++ ++ ++ Choibalsan ++ tz_names ++ 喬巴桑 ++ ++ ++ ++ Christmas ++ tz_names ++ 耶誕節 ++ ++ ++ ++ Chuuk ++ tz_names ++ 楚克 ++ ++ ++ ++ Cocos ++ tz_names ++ 科科斯 ++ ++ ++ ++ Colombo ++ tz_names ++ 可倫坡 ++ ++ ++ ++ Comoro ++ tz_names ++ 科摩羅 ++ ++ ++ ++ Conakry ++ tz_names ++ 柯那克里 ++ ++ ++ ++ Copenhagen ++ tz_names ++ 哥本哈根 ++ ++ ++ ++ Costa Rica ++ tz_names ++ 哥斯大黎加 ++ ++ ++ ++ Creston ++ tz_names ++ 克雷斯頓 ++ ++ ++ ++ Cuiaba ++ tz_names ++ 庫亞巴 ++ ++ ++ ++ Curacao ++ tz_names ++ 庫拉索 ++ ++ ++ ++ Currie ++ tz_names ++ 柯裡 ++ ++ ++ ++ Dakar ++ tz_names ++ 達喀爾 ++ ++ ++ ++ Damascus ++ tz_names ++ 大馬士革 ++ ++ ++ ++ Danmarkshavn ++ tz_names ++ 丹麥 ++ ++ ++ ++ Dar es Salaam ++ tz_names ++ 沙蘭港 ++ ++ ++ ++ Darwin ++ tz_names ++ 達爾文 ++ ++ ++ ++ Davis ++ tz_names ++ 大衛斯 ++ ++ ++ ++ Dawson ++ tz_names ++ 道森 ++ ++ ++ ++ Dawson Creek ++ tz_names ++ 道森溪 ++ ++ ++ ++ Denver ++ tz_names ++ 丹佛 ++ ++ ++ ++ Detroit ++ tz_names ++ 底特律 ++ ++ ++ ++ Dhaka ++ tz_names ++ 達卡 ++ ++ ++ ++ Dili ++ tz_names ++ 帝利 ++ ++ ++ ++ Djibouti ++ tz_names ++ 吉佈提 ++ ++ ++ ++ Dominica ++ tz_names ++ 多明尼克 ++ ++ ++ ++ Douala ++ tz_names ++ 杜阿拉 ++ ++ ++ ++ Dubai ++ tz_names ++ 迪拜 ++ ++ ++ ++ Dublin ++ tz_names ++ 都柏林 ++ ++ ++ ++ DumontDUrville ++ tz_names ++ 杜蒙·杜維爾 ++ ++ ++ ++ Dushanbe ++ tz_names ++ 杜桑貝 ++ ++ ++ ++ Easter ++ tz_names ++ 復活節 ++ ++ ++ ++ Edmonton ++ tz_names ++ 埃德蒙頓 ++ ++ ++ ++ Efate ++ tz_names ++ 埃法特島 ++ ++ ++ ++ Eirunepe ++ tz_names ++ 埃魯內佩 ++ ++ ++ ++ El Aaiun ++ tz_names ++ 阿尤恩 ++ ++ ++ ++ El Salvador ++ tz_names ++ 薩爾瓦多 ++ ++ ++ ++ Enderbury ++ tz_names ++ 恩德伯裡 ++ ++ ++ ++ Eucla ++ tz_names ++ 尤克拉 ++ ++ ++ ++ Fakaofo ++ tz_names ++ 法攷福 ++ ++ ++ ++ Famagusta ++ tz_names ++ 法馬古斯塔 ++ ++ ++ ++ Faroe ++ tz_names ++ 法羅 ++ ++ ++ ++ Fiji ++ tz_names ++ 斐濟 ++ ++ ++ ++ Fort Nelson ++ tz_names ++ 納爾遜堡 ++ ++ ++ ++ Fortaleza ++ tz_names ++ 福塔雷薩 ++ ++ ++ ++ Freetown ++ tz_names ++ 弗裏敦 ++ ++ ++ ++ Funafuti ++ tz_names ++ 福納佛提 ++ ++ ++ ++ Gaborone ++ tz_names ++ 嘉柏隆里 ++ ++ ++ ++ Galapagos ++ tz_names ++ 加拉帕戈斯群島 ++ ++ ++ ++ Gambier ++ tz_names ++ 甘比爾 ++ ++ ++ ++ Gaza ++ tz_names ++ 加沙 ++ ++ ++ ++ Gibraltar ++ tz_names ++ 直布羅陀 ++ ++ ++ ++ Glace Bay ++ tz_names ++ 格萊斯灣 ++ ++ ++ ++ Godthab ++ tz_names ++ 戈德薩布 ++ ++ ++ ++ Goose Bay ++ tz_names ++ 鹅灣 ++ ++ ++ ++ Grand Turk ++ tz_names ++ 大特克 ++ ++ ++ ++ Grenada ++ tz_names ++ 格林伍德 ++ ++ ++ ++ Guadalcanal ++ tz_names ++ 瓜達爾卡納爾島 ++ ++ ++ ++ Guadeloupe ++ tz_names ++ 瓜德羅普島 ++ ++ ++ ++ Guam ++ tz_names ++ 關島 ++ ++ ++ ++ Guatemala ++ tz_names ++ 瓜地馬拉 ++ ++ ++ ++ Guayaquil ++ tz_names ++ 瓜亞基爾 ++ ++ ++ ++ Guernsey ++ tz_names ++ 根西島 ++ ++ ++ ++ Guyana ++ tz_names ++ 蓋亞那 ++ ++ ++ ++ Halifax ++ tz_names ++ 哈利法克斯 ++ ++ ++ ++ Harare ++ tz_names ++ 哈拉雷 ++ ++ ++ ++ Havana ++ tz_names ++ 哈瓦那 ++ ++ ++ ++ Hebron ++ tz_names ++ 希伯倫 ++ ++ ++ ++ Helsinki ++ tz_names ++ 赫爾辛基 ++ ++ ++ ++ Hermosillo ++ tz_names ++ 埃莫西洛 ++ ++ ++ ++ Ho Chi Minh ++ tz_names ++ 胡志明 ++ ++ ++ ++ Hobart ++ tz_names ++ 霍巴特 ++ ++ ++ ++ Hong Kong(China) ++ tz_names ++ 香港(中国) ++ ++ ++ ++ Honolulu ++ tz_names ++ 檀香山 ++ ++ ++ ++ Hovd ++ tz_names ++ 科布多 ++ ++ ++ ++ Indiana/Indianapolis ++ tz_names ++ 印第安那州/印弟安納波里斯 ++ ++ ++ ++ Indiana/Knox ++ tz_names ++ 印第安那州/諾克斯 ++ ++ ++ ++ Indiana/Marengo ++ tz_names ++ 印度/馬倫戈 ++ ++ ++ ++ Indiana/Petersburg ++ tz_names ++ 印第安那州/彼得堡 ++ ++ ++ ++ Indiana/Tell City ++ tz_names ++ 印第安那州/泰爾城 ++ ++ ++ ++ Indiana/Vevay ++ tz_names ++ 印度/沃韋 ++ ++ ++ ++ Indiana/Vincennes ++ tz_names ++ 印第安那州/文森斯 ++ ++ ++ ++ Indiana/Winamac ++ tz_names ++ 印第安那州/威納馬克 ++ ++ ++ ++ Inuvik ++ tz_names ++ 伊努維克 ++ ++ ++ ++ Iqaluit ++ tz_names ++ 伊魁特 ++ ++ ++ ++ Irkutsk ++ tz_names ++ 伊爾庫茨克 ++ ++ ++ ++ Isle of Man ++ tz_names ++ 曼島 ++ ++ ++ ++ Istanbul ++ tz_names ++ 蓋章 ++ ++ ++ ++ Jakarta ++ tz_names ++ 雅加達 ++ ++ ++ ++ Jamaica ++ tz_names ++ 牙買加 ++ ++ ++ ++ Jayapura ++ tz_names ++ 查亞普拉 ++ ++ ++ ++ Jersey ++ tz_names ++ 澤西島 ++ ++ ++ ++ Jerusalem ++ tz_names ++ 耶路撒冷 ++ ++ ++ ++ Johannesburg ++ tz_names ++ 約翰尼斯堡 ++ ++ ++ ++ Juba ++ tz_names ++ 朱巴 ++ ++ ++ ++ Juneau ++ tz_names ++ 朱諾 ++ ++ ++ ++ Kabul ++ tz_names ++ 喀布爾 ++ ++ ++ ++ Kaliningrad ++ tz_names ++ 加里寧格勒 ++ ++ ++ ++ Kamchatka ++ tz_names ++ 堪察加半島 ++ ++ ++ ++ Kampala ++ tz_names ++ 坎帕拉 ++ ++ ++ ++ Karachi ++ tz_names ++ 卡拉奇 ++ ++ ++ ++ Kathmandu ++ tz_names ++ 加德滿都 ++ ++ ++ ++ Kentucky/Louisville ++ tz_names ++ 肯塔基州/路易斯維爾 ++ ++ ++ ++ Kentucky/Monticello ++ tz_names ++ 肯塔基州/蒙蒂塞洛 ++ ++ ++ ++ Kerguelen ++ tz_names ++ 凱爾蓋朗 ++ ++ ++ ++ Khandyga ++ tz_names ++ 坎代加 ++ ++ ++ ++ Khartoum ++ tz_names ++ 喀土穆 ++ ++ ++ ++ Kiev ++ tz_names ++ 基輔 ++ ++ ++ ++ Kigali ++ tz_names ++ 吉佳利 ++ ++ ++ ++ Kinshasa ++ tz_names ++ 金夏沙 ++ ++ ++ ++ Kiritimati ++ tz_names ++ 基裏蒂馬提斯 ++ ++ ++ ++ Kirov ++ tz_names ++ 基洛夫 ++ ++ ++ ++ Kolkata ++ tz_names ++ 加爾格達 ++ ++ ++ ++ Kosrae ++ tz_names ++ 科斯雷 ++ ++ ++ ++ Kralendijk ++ tz_names ++ 克羅地亞 ++ ++ ++ ++ Krasnoyarsk ++ tz_names ++ 克拉斯諾亞爾斯克 ++ ++ ++ ++ Kuala Lumpur ++ tz_names ++ 吉隆玻 ++ ++ ++ ++ Kuching ++ tz_names ++ 古晋 ++ ++ ++ ++ Kuwait ++ tz_names ++ 科威特 ++ ++ ++ ++ Kwajalein ++ tz_names ++ 誇賈林 ++ ++ ++ ++ La Paz ++ tz_names ++ 拉巴斯 ++ ++ ++ ++ Lagos ++ tz_names ++ 拉各斯 ++ ++ ++ ++ Libreville ++ tz_names ++ 利伯維爾 ++ ++ ++ ++ Lima ++ tz_names ++ 利馬 ++ ++ ++ ++ Lindeman ++ tz_names ++ 林德曼 ++ ++ ++ ++ Lisbon ++ tz_names ++ 里斯本 ++ ++ ++ ++ Ljubljana ++ tz_names ++ 盧布亞納 ++ ++ ++ ++ Lome ++ tz_names ++ 多哥 ++ ++ ++ ++ London ++ tz_names ++ 倫敦 ++ ++ ++ ++ Longyearbyen ++ tz_names ++ 龍宜爾比恩 ++ ++ ++ ++ Lord Howe ++ tz_names ++ 豪勳爵 ++ ++ ++ ++ Los Angeles ++ tz_names ++ 洛杉磯 ++ ++ ++ ++ Lower Princes ++ tz_names ++ 聖馬丁 ++ ++ ++ ++ Luanda ++ tz_names ++ 魯安達 ++ ++ ++ ++ Lubumbashi ++ tz_names ++ 盧本巴希 ++ ++ ++ ++ Lusaka ++ tz_names ++ 路沙卡 ++ ++ ++ ++ Luxembourg ++ tz_names ++ 盧森堡 ++ ++ ++ ++ Macau ++ tz_names ++ 澳門(中国) ++ ++ ++ ++ Maceio ++ tz_names ++ 馬塞奧 ++ ++ ++ ++ Macquarie ++ tz_names ++ 麥格理 ++ ++ ++ ++ Madeira ++ tz_names ++ 馬德拉 ++ ++ ++ ++ Madrid ++ tz_names ++ 馬德里 ++ ++ ++ ++ Magadan ++ tz_names ++ 馬加丹 ++ ++ ++ ++ Mahe ++ tz_names ++ 馬埃 ++ ++ ++ ++ Majuro ++ tz_names ++ 麥哲魯 ++ ++ ++ ++ Makassar ++ tz_names ++ 望加錫 ++ ++ ++ ++ Malabo ++ tz_names ++ 馬拉博 ++ ++ ++ ++ Maldives ++ tz_names ++ 瑪律地夫 ++ ++ ++ ++ Malta ++ tz_names ++ 馬爾他 ++ ++ ++ ++ Managua ++ tz_names ++ 馬納瓜 ++ ++ ++ ++ Manaus ++ tz_names ++ 馬瑙斯 ++ ++ ++ ++ Manila ++ tz_names ++ 馬尼拉 ++ ++ ++ ++ Maputo ++ tz_names ++ 馬布多 ++ ++ ++ ++ Mariehamn ++ tz_names ++ 瑪麗港 ++ ++ ++ ++ Marigot ++ tz_names ++ 馬裏戈 ++ ++ ++ ++ Marquesas ++ tz_names ++ 馬克薩斯 ++ ++ ++ ++ Martinique ++ tz_names ++ 馬提尼克島 ++ ++ ++ ++ Maseru ++ tz_names ++ 馬塞魯 ++ ++ ++ ++ Matamoros ++ tz_names ++ 馬塔莫羅斯 ++ ++ ++ ++ Mauritius ++ tz_names ++ 模裡西斯 ++ ++ ++ ++ Mawson ++ tz_names ++ 莫森 ++ ++ ++ ++ Mayotte ++ tz_names ++ 馬約特島 ++ ++ ++ ++ Mazatlan ++ tz_names ++ 馬薩特蘭 ++ ++ ++ ++ Mbabane ++ tz_names ++ 姆巴班 ++ ++ ++ ++ McMurdo ++ tz_names ++ 麥克默多 ++ ++ ++ ++ Melbourne ++ tz_names ++ 墨爾本 ++ ++ ++ ++ Menominee ++ tz_names ++ 梅諾米尼 ++ ++ ++ ++ Merida ++ tz_names ++ 梅里達 ++ ++ ++ ++ Metlakatla ++ tz_names ++ 梅特拉卡特拉 ++ ++ ++ ++ Mexico City ++ tz_names ++ 墨西哥城 ++ ++ ++ ++ Midway ++ tz_names ++ 中途島 ++ ++ ++ ++ Minsk ++ tz_names ++ 明斯克 ++ ++ ++ ++ Miquelon ++ tz_names ++ 密克隆 ++ ++ ++ ++ Mogadishu ++ tz_names ++ 摩加迪休 ++ ++ ++ ++ Monaco ++ tz_names ++ 摩納哥 ++ ++ ++ ++ Moncton ++ tz_names ++ 蒙克頓 ++ ++ ++ ++ Monrovia ++ tz_names ++ 蒙羅維亞 ++ ++ ++ ++ Monterrey ++ tz_names ++ 蒙特雷 ++ ++ ++ ++ Montevideo ++ tz_names ++ 蒙特維多 ++ ++ ++ ++ Montserrat ++ tz_names ++ 蒙特塞拉特 ++ ++ ++ ++ Moscow ++ tz_names ++ 莫斯科 ++ ++ ++ ++ Muscat ++ tz_names ++ 馬斯喀特 ++ ++ ++ ++ Nairobi ++ tz_names ++ 奈洛比 ++ ++ ++ ++ Nassau ++ tz_names ++ 拿索 ++ ++ ++ ++ Nauru ++ tz_names ++ 瑙魯 ++ ++ ++ ++ Ndjamena ++ tz_names ++ 恩賈梅納 ++ ++ ++ ++ New York ++ tz_names ++ 紐約 ++ ++ ++ ++ Niamey ++ tz_names ++ 尼阿美 ++ ++ ++ ++ Nicosia ++ tz_names ++ 尼古西亞 ++ ++ ++ ++ Nipigon ++ tz_names ++ 尼皮貢 ++ ++ ++ ++ Niue ++ tz_names ++ 紐埃 ++ ++ ++ ++ Nome ++ tz_names ++ 諾姆 ++ ++ ++ ++ Norfolk ++ tz_names ++ 諾福克 ++ ++ ++ ++ Noronha ++ tz_names ++ 諾羅尼亞 ++ ++ ++ ++ North Dakota/Beulah ++ tz_names ++ 北達科他州/比拉 ++ ++ ++ ++ North Dakota/Center ++ tz_names ++ 北達科他州/中心 ++ ++ ++ ++ North Dakota/New Salem ++ tz_names ++ 北達科他州/新賽勒姆 ++ ++ ++ ++ Nouakchott ++ tz_names ++ 諾克少 ++ ++ ++ ++ Noumea ++ tz_names ++ 諾美亞 ++ ++ ++ ++ Novokuznetsk ++ tz_names ++ 新庫茲涅茨克 ++ ++ ++ ++ Novosibirsk ++ tz_names ++ 新西伯利亞 ++ ++ ++ ++ Ojinaga ++ tz_names ++ 魁北克 ++ ++ ++ ++ Omsk ++ tz_names ++ 鄂木斯克 ++ ++ ++ ++ Oral ++ tz_names ++ 朵拉 ++ ++ ++ ++ Oslo ++ tz_names ++ 奧斯陸 ++ ++ ++ ++ Ouagadougou ++ tz_names ++ 瓦加杜古 ++ ++ ++ ++ Pago Pago ++ tz_names ++ 帕果帕果 ++ ++ ++ ++ Palau ++ tz_names ++ 帕勞 ++ ++ ++ ++ Palmer ++ tz_names ++ 帕爾默 ++ ++ ++ ++ Panama ++ tz_names ++ 巴拿馬 ++ ++ ++ ++ Pangnirtung ++ tz_names ++ 巴芬島的旁涅唐 ++ ++ ++ ++ Paramaribo ++ tz_names ++ 巴拉馬利波 ++ ++ ++ ++ Paris ++ tz_names ++ 巴黎 ++ ++ ++ ++ Perth ++ tz_names ++ 珀斯 ++ ++ ++ ++ Phnom Penh ++ tz_names ++ 金邊 ++ ++ ++ ++ Phoenix ++ tz_names ++ 鳳凰城 ++ ++ ++ ++ Pitcairn ++ tz_names ++ 皮特凱恩 ++ ++ ++ ++ Podgorica ++ tz_names ++ 波德戈裡察 ++ ++ ++ ++ Pohnpei ++ tz_names ++ 波納佩島 ++ ++ ++ ++ Pontianak ++ tz_names ++ 坤甸 ++ ++ ++ ++ Port Moresby ++ tz_names ++ 莫爾斯貝港 ++ ++ ++ ++ Port of Spain ++ tz_names ++ 西班牙港 ++ ++ ++ ++ Port-au-Prince ++ tz_names ++ 太子港 ++ ++ ++ ++ Porto Velho ++ tz_names ++ 維略港 ++ ++ ++ ++ Porto-Novo ++ tz_names ++ 波多洛 ++ ++ ++ ++ Prague ++ tz_names ++ 布拉格 ++ ++ ++ ++ Puerto Rico ++ tz_names ++ 波多黎各 ++ ++ ++ ++ Punta Arenas ++ tz_names ++ 蓬塔阿雷納斯 ++ ++ ++ ++ Pyongyang ++ tz_names ++ 平壤 ++ ++ ++ ++ Qatar ++ tz_names ++ 卡塔爾 ++ ++ ++ ++ Qostanay ++ tz_names ++ 庫斯塔 ++ ++ ++ ++ Qyzylorda ++ tz_names ++ 克孜勒奧爾達 ++ ++ ++ ++ Rainy River ++ tz_names ++ 雷尼河 ++ ++ ++ ++ Rankin Inlet ++ tz_names ++ 蘭京海口 ++ ++ ++ ++ Rarotonga ++ tz_names ++ 拉羅湯加 ++ ++ ++ ++ Recife ++ tz_names ++ 累西腓 ++ ++ ++ ++ Regina ++ tz_names ++ 里賈納 ++ ++ ++ ++ Resolute ++ tz_names ++ 雷索盧特 ++ ++ ++ ++ Reunion ++ tz_names ++ 留尼旺島 ++ ++ ++ ++ Reykjavik ++ tz_names ++ 雷克雅維克 ++ ++ ++ ++ Riga ++ tz_names ++ 裏加 ++ ++ ++ ++ Rio Branco ++ tz_names ++ 裏奧·布蘭科 ++ ++ ++ ++ Riyadh ++ tz_names ++ 利雅德 ++ ++ ++ ++ Rome ++ tz_names ++ 羅馬 ++ ++ ++ ++ Rothera ++ tz_names ++ 羅瑟拉 ++ ++ ++ ++ Saipan ++ tz_names ++ 塞班島 ++ ++ ++ ++ Sakhalin ++ tz_names ++ 薩哈林 ++ ++ ++ ++ Samara ++ tz_names ++ 薩馬拉 ++ ++ ++ ++ Samarkand ++ tz_names ++ 撒馬爾罕 ++ ++ ++ ++ San Marino ++ tz_names ++ 聖馬利諾 ++ ++ ++ ++ Santarem ++ tz_names ++ 聖塔倫 ++ ++ ++ ++ Santiago ++ tz_names ++ 聖地牙哥 ++ ++ ++ ++ Santo Domingo ++ tz_names ++ 聖多明哥 ++ ++ ++ ++ Sao Paulo ++ tz_names ++ 聖保羅 ++ ++ ++ ++ Sao Tome ++ tz_names ++ 聖多美 ++ ++ ++ ++ Sarajevo ++ tz_names ++ 塞拉耶佛 ++ ++ ++ ++ Saratov ++ tz_names ++ 薩拉托夫 ++ ++ ++ ++ Scoresbysund ++ tz_names ++ 斯科斯比基金 ++ ++ ++ ++ Seoul ++ tz_names ++ 首爾 ++ ++ ++ ++ Shanghai ++ tz_names ++ 上海 ++ ++ ++ ++ Simferopol ++ tz_names ++ 辛菲羅波爾 ++ ++ ++ ++ Singapore ++ tz_names ++ 新加坡 ++ ++ ++ ++ Sitka ++ tz_names ++ 錫特卡 ++ ++ ++ ++ Skopje ++ tz_names ++ 斯高彼亞 ++ ++ ++ ++ Sofia ++ tz_names ++ 索菲亞 ++ ++ ++ ++ South Georgia ++ tz_names ++ 南喬治亞州 ++ ++ ++ ++ Srednekolymsk ++ tz_names ++ 雅庫特 ++ ++ ++ ++ St Barthelemy ++ tz_names ++ 聖巴泰勒米 ++ ++ ++ ++ St Helena ++ tz_names ++ 聖赫倫那 ++ ++ ++ ++ St Johns ++ tz_names ++ 聖約翰 ++ ++ ++ ++ St Kitts ++ tz_names ++ 聖基茨 ++ ++ ++ ++ St Lucia ++ tz_names ++ 聖盧西亞 ++ ++ ++ ++ St Thomas ++ tz_names ++ 聖托馬斯 ++ ++ ++ ++ St Vincent ++ tz_names ++ 聖文森特 ++ ++ ++ ++ Stanley ++ tz_names ++ 斯坦利 ++ ++ ++ ++ Stockholm ++ tz_names ++ 斯德哥爾摩 ++ ++ ++ ++ Swift Current ++ tz_names ++ 斯威夫特卡倫特 ++ ++ ++ ++ Sydney ++ tz_names ++ 雪梨 ++ ++ ++ ++ Syowa ++ tz_names ++ 聖約瑟 ++ ++ ++ ++ Tahiti ++ tz_names ++ 大溪地 ++ ++ ++ ++ Taipei(China) ++ tz_names ++ 臺北(中国) ++ ++ ++ ++ Tallinn ++ tz_names ++ 數位行 ++ ++ ++ ++ Tarawa ++ tz_names ++ 塔拉瓦 ++ ++ ++ ++ Tashkent ++ tz_names ++ 塔什干 ++ ++ ++ ++ Tbilisi ++ tz_names ++ 第比利斯 ++ ++ ++ ++ Tegucigalpa ++ tz_names ++ 德古西加巴 ++ ++ ++ ++ Tehran ++ tz_names ++ 德黑蘭 ++ ++ ++ ++ Thimphu ++ tz_names ++ 辛布 ++ ++ ++ ++ Thule ++ tz_names ++ 圖勒 ++ ++ ++ ++ Thunder Bay ++ tz_names ++ 雷灣 ++ ++ ++ ++ Tijuana ++ tz_names ++ 蒂華納 ++ ++ ++ ++ Tirane ++ tz_names ++ 地拉那 ++ ++ ++ ++ Tokyo ++ tz_names ++ 東京 ++ ++ ++ ++ Tomsk ++ tz_names ++ 托木斯克 ++ ++ ++ ++ Tongatapu ++ tz_names ++ 湯加塔布 ++ ++ ++ ++ Toronto ++ tz_names ++ 多倫多 ++ ++ ++ ++ Tortola ++ tz_names ++ 托托拉島 ++ ++ ++ ++ Tripoli ++ tz_names ++ 的黎波里 ++ ++ ++ ++ Troll ++ tz_names ++ 特羅爾海坦 ++ ++ ++ ++ Tunis ++ tz_names ++ 突尼斯 ++ ++ ++ ++ Ulaanbaatar ++ tz_names ++ 烏蘭巴托 ++ ++ ++ ++ Ulyanovsk ++ tz_names ++ 烏裡揚諾夫斯克 ++ ++ ++ ++ Urumqi ++ tz_names ++ 烏魯木齊 ++ ++ ++ ++ Ust-Nera ++ tz_names ++ 烏斯季挪拉 ++ ++ ++ ++ Uzhgorod ++ tz_names ++ 烏日哥羅德 ++ ++ ++ ++ Vaduz ++ tz_names ++ 瓦都茲 ++ ++ ++ ++ Vancouver ++ tz_names ++ 溫哥華 ++ ++ ++ ++ Vatican ++ tz_names ++ 梵蒂岡 ++ ++ ++ ++ Vienna ++ tz_names ++ 維也納 ++ ++ ++ ++ Vientiane ++ tz_names ++ 萬象 ++ ++ ++ ++ Vilnius ++ tz_names ++ 維爾紐斯 ++ ++ ++ ++ Vladivostok ++ tz_names ++ 符拉迪沃斯托克 ++ ++ ++ ++ Volgograd ++ tz_names ++ 伏爾加格勒 ++ ++ ++ ++ Vostok ++ tz_names ++ 沃斯托克 ++ ++ ++ ++ Wake ++ tz_names ++ 韋克 ++ ++ ++ ++ Wallis ++ tz_names ++ 沃利斯 ++ ++ ++ ++ Warsaw ++ tz_names ++ 華沙 ++ ++ ++ ++ Whitehorse ++ tz_names ++ 懷特霍斯 ++ ++ ++ ++ Windhoek ++ tz_names ++ 溫吐克 ++ ++ ++ ++ Winnipeg ++ tz_names ++ 溫尼伯 ++ ++ ++ ++ Yakutat ++ tz_names ++ 雅庫特 ++ ++ ++ ++ Yakutsk ++ tz_names ++ 亞庫次克 ++ ++ ++ ++ Yangon ++ tz_names ++ 仰光 ++ ++ ++ ++ Yekaterinburg ++ tz_names ++ 葉卡捷琳堡 ++ ++ ++ ++ Yellowknife ++ tz_names ++ 黃刀 ++ ++ ++ ++ Yerevan ++ tz_names ++ 葉里溫 ++ ++ ++ ++ Zagreb ++ tz_names ++ 札格雷布 ++ ++ ++ ++ Zaporozhye ++ tz_names ++ 紮波羅熱 ++ ++ ++ ++ Zurich ++ tz_names ++ 蘇黎世 ++ ++ ++ +diff --git a/src/branding/default/show.qml b/src/branding/default/show.qml +index f6223c0..f91d520 100644 +--- a/src/branding/default/show.qml ++++ b/src/branding/default/show.qml +@@ -33,7 +33,7 @@ Presentation + Image { + id: background1 + source: "Slide1.png" +- width: 800; height: 800 ++ width: 980; height: 980 + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter:parent.horizontalCenter + y:parent.height / 2 - height / 2 -25 +@@ -44,7 +44,7 @@ Presentation + Image { + id: background2 + source: "Slide2.png" +- width: 800; height: 800 ++ width: 980; height: 980 + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter:parent.horizontalCenter + y:parent.height / 2 - height / 2 -25 +@@ -55,7 +55,7 @@ Presentation + Image { + id: background3 + source: "Slide3.png" +- width: 800; height: 800 ++ width: 980; height: 980 + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter:parent.horizontalCenter + y:parent.height / 2 - height / 2 -25 +diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt +index 3be6b92..9f806c7 100644 +--- a/src/calamares/CMakeLists.txt ++++ b/src/calamares/CMakeLists.txt +@@ -1,67 +1,67 @@ +-# === This file is part of Calamares - === +-# +-# SPDX-FileCopyrightText: 2020 Adriaan de Groot +-# SPDX-License-Identifier: BSD-2-Clause +-# +- +-set(calamaresSources +- main.cpp +- CalamaresApplication.cpp +- CalamaresWindow.cpp +- DebugWindow.cpp +- VariantModel.cpp +- progresstree/ProgressTreeDelegate.cpp +- progresstree/ProgressTreeView.cpp +-) +- +-include_directories( +- ${CMAKE_SOURCE_DIR}/src/libcalamares +- ${CMAKE_SOURCE_DIR}/src/libcalamaresui +- ${CMAKE_BINARY_DIR}/src/libcalamares +- ${CMAKE_CURRENT_SOURCE_DIR} +-) +- +-### EXECUTABLE +-# +-# "calamares_bin" is the main application, not to be confused with +-# the target "calamares" which is the non-GUI library part. +-# +-# The calamares-i18n.cxx file -- full path in CALAMARES_TRANSLATIONS_SOURCE -- +-# is created as a target in the lang/ directory. This is compiled to a +-# library (it's just the result of a QRC compile). +-add_executable(calamares_bin ${calamaresSources} calamares.qrc) +-target_include_directories(calamares_bin PRIVATE ${CMAKE_SOURCE_DIR}) +-set_target_properties(calamares_bin PROPERTIES ENABLE_EXPORTS TRUE RUNTIME_OUTPUT_NAME calamares) +-calamares_automoc( calamares_bin ) +-calamares_autouic( calamares_bin ) +-calamares_autorcc( calamares_bin ) +- +-target_link_libraries( +- calamares_bin +- PRIVATE calamares calamaresui calamares-i18n kdsingleapplication ${qtname}::Core ${qtname}::Widgets +-) +-target_link_libraries(calamares_bin PRIVATE ${kfname}::CoreAddons) +-if(BUILD_CRASH_REPORTING) +- target_link_libraries(calamares_bin PRIVATE ${kfname}::Crash) +- target_compile_definitions(calamares_bin PRIVATE BUILD_CRASH_REPORTING) +-endif() +- +-install(TARGETS calamares_bin BUNDLE DESTINATION . RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +- +-install( +- FILES ${CMAKE_SOURCE_DIR}/data/images/squid.svg +- RENAME calamares.svg +- DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps +-) +- +-### TESTS +-# +-# +-if(BUILD_TESTING) +- # Don't install, these are just for enable_testing +- add_executable(loadmodule testmain.cpp) +- target_link_libraries(loadmodule PRIVATE ${qtname}::Core ${qtname}::Widgets calamares calamaresui) +- +- add_executable(test_conf test_conf.cpp) +- target_link_libraries(test_conf PUBLIC yamlcpp::yamlcpp ${qtname}::Core) +-endif() ++# === This file is part of Calamares - === ++# ++# SPDX-FileCopyrightText: 2020 Adriaan de Groot ++# SPDX-License-Identifier: BSD-2-Clause ++# ++ ++set(calamaresSources ++ main.cpp ++ CalamaresApplication.cpp ++ CalamaresWindow.cpp ++ DebugWindow.cpp ++ VariantModel.cpp ++ progresstree/ProgressTreeDelegate.cpp ++ progresstree/ProgressTreeView.cpp ++) ++ ++include_directories( ++ ${CMAKE_SOURCE_DIR}/src/libcalamares ++ ${CMAKE_SOURCE_DIR}/src/libcalamaresui ++ ${CMAKE_BINARY_DIR}/src/libcalamares ++ ${CMAKE_CURRENT_SOURCE_DIR} ++) ++ ++### EXECUTABLE ++# ++# "calamares_bin" is the main application, not to be confused with ++# the target "calamares" which is the non-GUI library part. ++# ++# The calamares-i18n.cxx file -- full path in CALAMARES_TRANSLATIONS_SOURCE -- ++# is created as a target in the lang/ directory. This is compiled to a ++# library (it's just the result of a QRC compile). ++add_executable(calamares_bin ${calamaresSources} calamares.qrc) ++target_include_directories(calamares_bin PRIVATE ${CMAKE_SOURCE_DIR}) ++set_target_properties(calamares_bin PROPERTIES ENABLE_EXPORTS TRUE RUNTIME_OUTPUT_NAME calamares) ++calamares_automoc( calamares_bin ) ++calamares_autouic( calamares_bin ) ++calamares_autorcc( calamares_bin ) ++ ++target_link_libraries( ++ calamares_bin ++ PRIVATE calamares calamaresui calamares-i18n kdsingleapplication ${qtname}::Core ${qtname}::Widgets ++) ++target_link_libraries(calamares_bin PRIVATE ${kfname}::CoreAddons) ++if(BUILD_CRASH_REPORTING) ++ target_link_libraries(calamares_bin PRIVATE ${kfname}::Crash) ++ target_compile_definitions(calamares_bin PRIVATE BUILD_CRASH_REPORTING) ++endif() ++ ++install(TARGETS calamares_bin BUNDLE DESTINATION . RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ++ ++install( ++ FILES ${CMAKE_SOURCE_DIR}/data/images/squid.svg ++ RENAME calamares.svg ++ DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps ++) ++ ++### TESTS ++# ++# ++if(BUILD_TESTING) ++ # Don't install, these are just for enable_testing ++ add_executable(loadmodule testmain.cpp) ++ target_link_libraries(loadmodule PRIVATE ${qtname}::Core ${qtname}::Widgets calamares calamaresui) ++ ++ add_executable(test_conf test_conf.cpp) ++ target_link_libraries(test_conf PUBLIC yamlcpp::yamlcpp ${qtname}::Core) ++endif() +diff --git a/src/calamares/CalamaresApplication.cpp b/src/calamares/CalamaresApplication.cpp +index a07edad..6b62fd6 100644 +--- a/src/calamares/CalamaresApplication.cpp ++++ b/src/calamares/CalamaresApplication.cpp +@@ -51,8 +51,8 @@ CalamaresApplication::CalamaresApplication( int& argc, char* argv[] ) + // directory -- where Calamares stores logs, for instance -- + // //, so we end up with ~/.cache/Calamares/calamares/ + // which is excessively squidly. +- // +- // setOrganizationName( QStringLiteral( CALAMARES_ORGANIZATION_NAME ) ); ++ ++ + setOrganizationDomain( QStringLiteral( CALAMARES_ORGANIZATION_DOMAIN ) ); + setApplicationName( QStringLiteral( CALAMARES_APPLICATION_NAME ) ); + setApplicationVersion( QStringLiteral( CALAMARES_VERSION ) ); +diff --git a/src/calamares/DebugWindow.cpp b/src/calamares/DebugWindow.cpp +index b28661e..69584b8 100644 +--- a/src/calamares/DebugWindow.cpp ++++ b/src/calamares/DebugWindow.cpp +@@ -1,265 +1,265 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac +- * SPDX-FileCopyrightText: 2019 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#include "DebugWindow.h" +-#include "ui_DebugWindow.h" +- +-#include "Branding.h" +-#include "CalamaresAbout.h" +-#include "CalamaresVersion.h" +-#include "GlobalStorage.h" +-#include "Job.h" +-#include "JobQueue.h" +-#include "Settings.h" +-#include "VariantModel.h" +-#include "modulesystem/Module.h" +-#include "modulesystem/ModuleManager.h" +-#include "utils/Gui.h" +-#include "utils/Logger.h" +-#include "utils/Paste.h" +-#include "utils/Retranslator.h" +-#include "widgets/TranslationFix.h" +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-/** +- * @brief crash makes Calamares crash immediately. +- */ +-static void +-crash() +-{ +- kill( getpid(), SIGTRAP ); +-} +- +-/// @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->metaObject()->className() << widget->objectName(); +- +- for ( const auto* w : widget->findChildren< QWidget* >( QString(), Qt::FindDirectChildrenOnly ) ) +- { +- dumpWidgetTree( deb, w, depth + 1 ); +- } +-} +- +-namespace Calamares +-{ +- +-DebugWindow::DebugWindow() +- : QWidget( nullptr ) +- , m_ui( new Ui::DebugWindow ) +- , m_globals( JobQueue::instance()->globalStorage()->data() ) +- , m_globals_model( std::make_unique< VariantModel >( &m_globals ) ) +- , m_module_model( std::make_unique< VariantModel >( &m_module ) ) +-{ +- GlobalStorage* gs = JobQueue::instance()->globalStorage(); +- +- m_ui->setupUi( this ); +- +- m_ui->globalStorageView->setModel( m_globals_model.get() ); +- m_ui->globalStorageView->expandAll(); +- +- // Do above when the GS changes, too +- connect( gs, +- &GlobalStorage::changed, +- this, +- [ = ] +- { +- m_globals = JobQueue::instance()->globalStorage()->data(); +- m_globals_model->reload(); +- m_ui->globalStorageView->expandAll(); +- } ); +- +- // JobQueue page +- m_ui->jobQueueText->setReadOnly( true ); +- connect( JobQueue::instance(), +- &JobQueue::queueChanged, +- this, +- [ this ]( const QStringList& jobs ) { m_ui->jobQueueText->setText( jobs.join( '\n' ) ); } ); +- +- // Modules page +- QStringList modulesKeys; +- for ( const auto& m : ModuleManager::instance()->loadedInstanceKeys() ) +- { +- modulesKeys << m.toString(); +- } +- +- QStringListModel* modulesModel = new QStringListModel( modulesKeys ); +- m_ui->modulesListView->setModel( modulesModel ); +- m_ui->modulesListView->setSelectionMode( QAbstractItemView::SingleSelection ); +- +- m_ui->moduleConfigView->setModel( m_module_model.get() ); +- +- connect( m_ui->modulesListView->selectionModel(), +- &QItemSelectionModel::selectionChanged, +- this, +- [ this ] +- { +- QString moduleName = m_ui->modulesListView->currentIndex().data().toString(); +- Module* module +- = ModuleManager::instance()->moduleInstance( ModuleSystem::InstanceKey::fromString( moduleName ) ); +- if ( module ) +- { +- m_module = module->configurationMap(); +- m_module_model->reload(); +- m_ui->moduleConfigView->expandAll(); +- m_ui->moduleTypeLabel->setText( module->typeString() ); +- m_ui->moduleInterfaceLabel->setText( module->interfaceString() ); +- } +- } ); +- +- // 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() ) +- { +- Logger::CDebug deb; +- dumpWidgetTree( deb, w, 0 ); +- } +- } ); +- +- // Send Log button only if it would be useful +- m_ui->sendLogButton->setVisible( Calamares::Paste::isEnabled() ); +- connect( m_ui->sendLogButton, &QPushButton::clicked, [ this ]() { Calamares::Paste::doLogUploadUI( this ); } ); +- +- CALAMARES_RETRANSLATE( m_ui->retranslateUi( this ); setWindowTitle( tr( "Debug Information", "@title" ) ); ); +-} +- +-void +-DebugWindow::closeEvent( QCloseEvent* e ) +-{ +- Q_UNUSED( e ) +- emit closed(); +-} +- +-DebugWindowManager::DebugWindowManager( QObject* parent ) +- : QObject( parent ) +-{ +-} +- +-bool +-DebugWindowManager::enabled() const +-{ +- const auto* s = Settings::instance(); +- return ( Logger::logLevel() >= Logger::LOGVERBOSE ) || ( s ? s->debugMode() : false ); +-} +- +-void +-DebugWindowManager::show( bool visible ) +-{ +- if ( !enabled() ) +- { +- visible = false; +- } +- if ( m_visible == visible ) +- { +- return; +- } +- +- if ( visible ) +- { +- m_debugWindow = new Calamares::DebugWindow(); +- m_debugWindow->show(); +- connect( m_debugWindow.data(), +- &Calamares::DebugWindow::closed, +- this, +- [ = ]() +- { +- m_debugWindow->deleteLater(); +- m_visible = false; +- emit visibleChanged( false ); +- } ); +- m_visible = true; +- emit visibleChanged( true ); +- } +- else +- { +- if ( m_debugWindow ) +- { +- m_debugWindow->deleteLater(); +- } +- m_visible = false; +- emit visibleChanged( false ); +- } +-} +- +-void +-DebugWindowManager::toggle() +-{ +- show( !m_visible ); +-} +- +-void +-DebugWindowManager::about() +-{ +- QString title = Calamares::Settings::instance()->isSetupMode() +- ? QCoreApplication::translate( "WelcomePage", "About %1 Setup", "@title" ) +- : QCoreApplication::translate( "WelcomePage", "About %1 Installer", "@title" ); +- QMessageBox mb( QMessageBox::Information, +- title.arg( CALAMARES_APPLICATION_NAME ), +- Calamares::aboutString().arg( Calamares::Branding::instance()->versionedName() ), +- QMessageBox::Ok, +- nullptr ); +- Calamares::fixButtonLabels( &mb ); +- mb.setStyleSheet( +- "QMessageBox {" +- "border: 1px solid hsl(240,2%,79%);" +- "border-radius: 5px;" +- "background-color: #FFFFFF;" // 设置对话框背景颜色 +- "}" +- ); +- mb.setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); +- mb.setIconPixmap( +- Calamares::defaultPixmap( Calamares::BigLogo,//Biglogo.svg +- Calamares::Original, +- QSize( 321/1.9, 297/2 ) ) ); +- QGridLayout* layout = reinterpret_cast< QGridLayout* >( mb.layout() ); +- if ( layout ) +- { +- layout->setColumnMinimumWidth( 2, Calamares::defaultFontHeight() * 24 ); +- } +- mb.exec(); +-} +- +-} // namespace Calamares ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac ++ * SPDX-FileCopyrightText: 2019 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#include "DebugWindow.h" ++#include "ui_DebugWindow.h" ++ ++#include "Branding.h" ++#include "CalamaresAbout.h" ++#include "CalamaresVersion.h" ++#include "GlobalStorage.h" ++#include "Job.h" ++#include "JobQueue.h" ++#include "Settings.h" ++#include "VariantModel.h" ++#include "modulesystem/Module.h" ++#include "modulesystem/ModuleManager.h" ++#include "utils/Gui.h" ++#include "utils/Logger.h" ++#include "utils/Paste.h" ++#include "utils/Retranslator.h" ++#include "widgets/TranslationFix.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/** ++ * @brief crash makes Calamares crash immediately. ++ */ ++static void ++crash() ++{ ++ kill( getpid(), SIGTRAP ); ++} ++ ++/// @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->metaObject()->className() << widget->objectName(); ++ ++ for ( const auto* w : widget->findChildren< QWidget* >( QString(), Qt::FindDirectChildrenOnly ) ) ++ { ++ dumpWidgetTree( deb, w, depth + 1 ); ++ } ++} ++ ++namespace Calamares ++{ ++ ++DebugWindow::DebugWindow() ++ : QWidget( nullptr ) ++ , m_ui( new Ui::DebugWindow ) ++ , m_globals( JobQueue::instance()->globalStorage()->data() ) ++ , m_globals_model( std::make_unique< VariantModel >( &m_globals ) ) ++ , m_module_model( std::make_unique< VariantModel >( &m_module ) ) ++{ ++ GlobalStorage* gs = JobQueue::instance()->globalStorage(); ++ ++ m_ui->setupUi( this ); ++ ++ m_ui->globalStorageView->setModel( m_globals_model.get() ); ++ m_ui->globalStorageView->expandAll(); ++ ++ // Do above when the GS changes, too ++ connect( gs, ++ &GlobalStorage::changed, ++ this, ++ [ = ] ++ { ++ m_globals = JobQueue::instance()->globalStorage()->data(); ++ m_globals_model->reload(); ++ m_ui->globalStorageView->expandAll(); ++ } ); ++ ++ // JobQueue page ++ m_ui->jobQueueText->setReadOnly( true ); ++ connect( JobQueue::instance(), ++ &JobQueue::queueChanged, ++ this, ++ [ this ]( const QStringList& jobs ) { m_ui->jobQueueText->setText( jobs.join( '\n' ) ); } ); ++ ++ // Modules page ++ QStringList modulesKeys; ++ for ( const auto& m : ModuleManager::instance()->loadedInstanceKeys() ) ++ { ++ modulesKeys << m.toString(); ++ } ++ ++ QStringListModel* modulesModel = new QStringListModel( modulesKeys ); ++ m_ui->modulesListView->setModel( modulesModel ); ++ m_ui->modulesListView->setSelectionMode( QAbstractItemView::SingleSelection ); ++ ++ m_ui->moduleConfigView->setModel( m_module_model.get() ); ++ ++ connect( m_ui->modulesListView->selectionModel(), ++ &QItemSelectionModel::selectionChanged, ++ this, ++ [ this ] ++ { ++ QString moduleName = m_ui->modulesListView->currentIndex().data().toString(); ++ Module* module ++ = ModuleManager::instance()->moduleInstance( ModuleSystem::InstanceKey::fromString( moduleName ) ); ++ if ( module ) ++ { ++ m_module = module->configurationMap(); ++ m_module_model->reload(); ++ m_ui->moduleConfigView->expandAll(); ++ m_ui->moduleTypeLabel->setText( module->typeString() ); ++ m_ui->moduleInterfaceLabel->setText( module->interfaceString() ); ++ } ++ } ); ++ ++ // 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() ) ++ { ++ Logger::CDebug deb; ++ dumpWidgetTree( deb, w, 0 ); ++ } ++ } ); ++ ++ // Send Log button only if it would be useful ++ m_ui->sendLogButton->setVisible( Calamares::Paste::isEnabled() ); ++ connect( m_ui->sendLogButton, &QPushButton::clicked, [ this ]() { Calamares::Paste::doLogUploadUI( this ); } ); ++ ++ CALAMARES_RETRANSLATE( m_ui->retranslateUi( this ); setWindowTitle( tr( "Debug Information", "@title" ) ); ); ++} ++ ++void ++DebugWindow::closeEvent( QCloseEvent* e ) ++{ ++ Q_UNUSED( e ) ++ emit closed(); ++} ++ ++DebugWindowManager::DebugWindowManager( QObject* parent ) ++ : QObject( parent ) ++{ ++} ++ ++bool ++DebugWindowManager::enabled() const ++{ ++ const auto* s = Settings::instance(); ++ return ( Logger::logLevel() >= Logger::LOGVERBOSE ) || ( s ? s->debugMode() : false ); ++} ++ ++void ++DebugWindowManager::show( bool visible ) ++{ ++ if ( !enabled() ) ++ { ++ visible = false; ++ } ++ if ( m_visible == visible ) ++ { ++ return; ++ } ++ ++ if ( visible ) ++ { ++ m_debugWindow = new Calamares::DebugWindow(); ++ m_debugWindow->show(); ++ connect( m_debugWindow.data(), ++ &Calamares::DebugWindow::closed, ++ this, ++ [ = ]() ++ { ++ m_debugWindow->deleteLater(); ++ m_visible = false; ++ emit visibleChanged( false ); ++ } ); ++ m_visible = true; ++ emit visibleChanged( true ); ++ } ++ else ++ { ++ if ( m_debugWindow ) ++ { ++ m_debugWindow->deleteLater(); ++ } ++ m_visible = false; ++ emit visibleChanged( false ); ++ } ++} ++ ++void ++DebugWindowManager::toggle() ++{ ++ show( !m_visible ); ++} ++ ++void ++DebugWindowManager::about() ++{ ++ QString title = Calamares::Settings::instance()->isSetupMode() ++ ? QCoreApplication::translate( "WelcomePage", "About %1 Setup", "@title" ) ++ : QCoreApplication::translate( "WelcomePage", "About %1 Installer", "@title" ); ++ QMessageBox mb( QMessageBox::Information, ++ title.arg( CALAMARES_APPLICATION_NAME ), ++ Calamares::aboutString().arg( Calamares::Branding::instance()->versionedName() ), ++ QMessageBox::Ok, ++ nullptr ); ++ Calamares::fixButtonLabels( &mb ); ++ mb.setStyleSheet( ++ "QMessageBox {" ++ "border: 1px solid hsl(240,2%,79%);" ++ "border-radius: 5px;" ++ "background-color: #FFFFFF;" // 设置对话框背景颜色 ++ "}" ++ ); ++ mb.setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); ++ mb.setIconPixmap( ++ Calamares::defaultPixmap( Calamares::BigLogo,//Biglogo.svg ++ Calamares::Original, ++ QSize( 321/1.9, 297/2 ) ) ); ++ QGridLayout* layout = reinterpret_cast< QGridLayout* >( mb.layout() ); ++ if ( layout ) ++ { ++ layout->setColumnMinimumWidth( 2, Calamares::defaultFontHeight() * 24 ); ++ } ++ mb.exec(); ++} ++ ++} // namespace Calamares +diff --git a/src/calamares/DebugWindow.h b/src/calamares/DebugWindow.h +index 83bfb08..9ed77e5 100644 +--- a/src/calamares/DebugWindow.h ++++ b/src/calamares/DebugWindow.h +@@ -1,96 +1,96 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2015 Teo Mrnjavac +- * SPDX-FileCopyrightText: 2019 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#ifndef CALAMARES_DEBUGWINDOW_H +-#define CALAMARES_DEBUGWINDOW_H +- +-#include "VariantModel.h" +- +-#include +-#include +-#include +- +-#include +- +-namespace Calamares +-{ +- +-// From the .ui file +-namespace Ui +-{ +-class DebugWindow; +-} // namespace Ui +- +-class DebugWindow : public QWidget +-{ +- Q_OBJECT +- +-public: +- explicit DebugWindow(); +- +-signals: +- void closed(); +- +-protected: +- void closeEvent( QCloseEvent* e ) override; +- +-private: +- Ui::DebugWindow* m_ui; +- QVariant m_globals; +- QVariant m_module; +- std::unique_ptr< VariantModel > m_globals_model; +- std::unique_ptr< VariantModel > m_module_model; +-}; +- +-/** @brief Manager for meta-windows (Debug and About windows) +- * +- * Only one DebugWindow is expected to be around. This class manages +- * (exactly one) DebugWindow and can create and destroy it as needed. +- * It is available to the Calamares panels as object `DebugWindow`. +- * +- * The about() method shows a modal pop-up about Calamares. +- */ +-class DebugWindowManager : public QObject +-{ +- Q_OBJECT +- +- /// @brief Proxy to Settings::debugMode() default @c false +- Q_PROPERTY( bool enabled READ enabled CONSTANT FINAL ) +- +- /** @brief Is the debug window visible? +- * +- * Writing @c true to this **may** make the debug window visible to +- * the user; only if debugMode() is on. +- */ +- Q_PROPERTY( bool visible READ visible WRITE show NOTIFY visibleChanged ) +- +-public: +- DebugWindowManager( QObject* parent = nullptr ); +- virtual ~DebugWindowManager() override = default; +- +-public Q_SLOTS: +- bool enabled() const; +- bool visible() const { return m_visible; } +- void show( bool visible ); +- void toggle(); +- +- void about(); +- +-signals: +- void visibleChanged( bool visible ); +- +-private: +- QPointer< DebugWindow > m_debugWindow; +- bool m_visible = false; +-}; +- +- +-} // namespace Calamares +-#endif ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2015 Teo Mrnjavac ++ * SPDX-FileCopyrightText: 2019 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#ifndef CALAMARES_DEBUGWINDOW_H ++#define CALAMARES_DEBUGWINDOW_H ++ ++#include "VariantModel.h" ++ ++#include ++#include ++#include ++ ++#include ++ ++namespace Calamares ++{ ++ ++// From the .ui file ++namespace Ui ++{ ++class DebugWindow; ++} // namespace Ui ++ ++class DebugWindow : public QWidget ++{ ++ Q_OBJECT ++ ++public: ++ explicit DebugWindow(); ++ ++signals: ++ void closed(); ++ ++protected: ++ void closeEvent( QCloseEvent* e ) override; ++ ++private: ++ Ui::DebugWindow* m_ui; ++ QVariant m_globals; ++ QVariant m_module; ++ std::unique_ptr< VariantModel > m_globals_model; ++ std::unique_ptr< VariantModel > m_module_model; ++}; ++ ++/** @brief Manager for meta-windows (Debug and About windows) ++ * ++ * Only one DebugWindow is expected to be around. This class manages ++ * (exactly one) DebugWindow and can create and destroy it as needed. ++ * It is available to the Calamares panels as object `DebugWindow`. ++ * ++ * The about() method shows a modal pop-up about Calamares. ++ */ ++class DebugWindowManager : public QObject ++{ ++ Q_OBJECT ++ ++ /// @brief Proxy to Settings::debugMode() default @c false ++ Q_PROPERTY( bool enabled READ enabled CONSTANT FINAL ) ++ ++ /** @brief Is the debug window visible? ++ * ++ * Writing @c true to this **may** make the debug window visible to ++ * the user; only if debugMode() is on. ++ */ ++ Q_PROPERTY( bool visible READ visible WRITE show NOTIFY visibleChanged ) ++ ++public: ++ DebugWindowManager( QObject* parent = nullptr ); ++ virtual ~DebugWindowManager() override = default; ++ ++public Q_SLOTS: ++ bool enabled() const; ++ bool visible() const { return m_visible; } ++ void show( bool visible ); ++ void toggle(); ++ ++ void about(); ++ ++signals: ++ void visibleChanged( bool visible ); ++ ++private: ++ QPointer< DebugWindow > m_debugWindow; ++ bool m_visible = false; ++}; ++ ++ ++} // namespace Calamares ++#endif +diff --git a/src/calamares/VariantModel.cpp b/src/calamares/VariantModel.cpp +index da4f556..6d175d5 100644 +--- a/src/calamares/VariantModel.cpp ++++ b/src/calamares/VariantModel.cpp +@@ -1,285 +1,285 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2019 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#include "VariantModel.h" +- +-#include "compat/Variant.h" +- +-static bool +-isMapLike( const QVariant& item ) +-{ +- return item.canConvert< QVariantMap >(); +-} +- +-static bool +-isListLike( const QVariant& item ) +-{ +- return item.canConvert< QVariantList >() && !( Calamares::typeOf( item ) == Calamares::StringVariantType ); +-} +- +-static void +-overallLength( const QVariant& item, quintptr& c, quintptr parent, VariantModel::IndexVector* skiplist ) +-{ +- if ( skiplist ) +- { +- skiplist->append( parent ); +- } +- +- parent = c++; +- if ( isMapLike( item ) ) +- { +- for ( const auto& subitem : item.toMap() ) +- { +- overallLength( subitem, c, parent, skiplist ); +- } +- } +- else if ( isListLike( item ) ) +- { +- for ( const auto& subitem : item.toList() ) +- { +- overallLength( subitem, c, parent, skiplist ); +- } +- } +-} +- +-static quintptr +-findNth( const VariantModel::IndexVector& skiplist, quintptr value, int n ) +-{ +- constexpr const quintptr invalid_index = static_cast< quintptr >( -1 ); +- +- if ( n < 0 ) +- { +- return invalid_index; +- } +- +- int index = static_cast< int >( value ); +- while ( ( n >= 0 ) && ( index < skiplist.count() ) ) +- { +- if ( skiplist[ index ] == value ) +- { +- if ( --n < 0 ) +- { +- // It's bigger than 0 +- return static_cast< quintptr >( index ); +- } +- } +- index++; +- } +- return invalid_index; +-} +- +- +-VariantModel::VariantModel( const QVariant* p ) +- : m_p( p ) +-{ +- reload(); +-} +- +-VariantModel::~VariantModel() {} +- +-void +-VariantModel::reload() +-{ +- constexpr const quintptr invalid_index = static_cast< quintptr >( -1 ); +- +- quintptr x = 0; +- m_rows.clear(); // Start over +- if ( m_rows.capacity() < 64 ) +- { +- m_rows.reserve( 64 ); // Start reasonably-sized +- } +- overallLength( *m_p, x, invalid_index, &m_rows ); +-} +- +-int +-VariantModel::columnCount( const QModelIndex& ) const +-{ +- return 2; +-} +- +-int +-VariantModel::rowCount( const QModelIndex& index ) const +-{ +- quintptr p = index.isValid() ? index.internalId() : 0; +- return m_rows.count( p ); +-} +- +-QModelIndex +-VariantModel::index( int row, int column, const QModelIndex& parent ) const +-{ +- quintptr p = 0; +- +- if ( parent.isValid() ) +- { +- if ( inRange( parent ) ) +- { +- p = parent.internalId(); +- } +- } +- +- return createIndex( row, column, findNth( m_rows, p, row ) ); +-} +- +-static inline quintptr +-deref( const VariantModel::IndexVector& v, quintptr i ) +-{ +- return v[ static_cast< int >( i ) ]; +-} +- +-QModelIndex +-VariantModel::parent( const QModelIndex& index ) const +-{ +- if ( !index.isValid() || !inRange( index ) ) +- { +- return QModelIndex(); +- } +- +- quintptr p = deref( m_rows, index.internalId() ); +- if ( p == 0 ) +- { +- return QModelIndex(); +- } +- +- if ( !inRange( p ) ) +- { +- return QModelIndex(); +- } +- quintptr p_pid = deref( m_rows, p ); +- int row = 0; +- for ( int i = static_cast< int >( p_pid ); i < static_cast< int >( p ); ++i ) +- { +- if ( m_rows[ i ] == p_pid ) +- { +- row++; +- } +- } +- +- return createIndex( row, index.column(), p ); +-} +- +-QVariant +-VariantModel::data( const QModelIndex& index, int role ) const +-{ +- if ( role != Qt::DisplayRole ) +- { +- return QVariant(); +- } +- +- if ( !index.isValid() ) +- { +- return QVariant(); +- } +- +- if ( ( index.column() < 0 ) || ( index.column() > 1 ) ) +- { +- return QVariant(); +- } +- +- if ( !inRange( index ) ) +- { +- return QVariant(); +- } +- +- const QVariant thing = underlying( parent( index ) ); +- +- if ( !thing.isValid() ) +- { +- return QVariant(); +- } +- +- if ( isMapLike( thing ) ) +- { +- QVariantMap the_map = thing.toMap(); +- const auto key = the_map.keys().at( index.row() ); +- if ( index.column() == 0 ) +- { +- return key; +- } +- else +- { +- return the_map[ key ]; +- } +- } +- else if ( isListLike( thing ) ) +- { +- if ( index.column() == 0 ) +- { +- return index.row(); +- } +- else +- { +- QVariantList the_list = thing.toList(); +- return the_list.at( index.row() ); +- } +- } +- else +- { +- if ( index.column() == 0 ) +- { +- return QVariant(); +- } +- else +- { +- return thing; +- } +- } +-} +- +-QVariant +-VariantModel::headerData( int section, Qt::Orientation orientation, int role ) const +-{ +- if ( role != Qt::DisplayRole ) +- { +- return QVariant(); +- } +- +- if ( orientation == Qt::Horizontal ) +- { +- if ( section == 0 ) +- { +- return tr( "Key", "Column header for key/value" ); +- } +- else if ( section == 1 ) +- { +- return tr( "Value", "Column header for key/value" ); +- } +- else +- { +- return QVariant(); +- } +- } +- else +- { +- return QVariant(); +- } +-} +- +-const QVariant +-VariantModel::underlying( const QModelIndex& index ) const +-{ +- if ( !index.isValid() ) +- { +- return *m_p; +- } +- +- const auto& thing = underlying( parent( index ) ); +- if ( isMapLike( thing ) ) +- { +- const auto& the_map = thing.toMap(); +- return the_map[ the_map.keys()[ index.row() ] ]; +- } +- else if ( isListLike( thing ) ) +- { +- return thing.toList()[ index.row() ]; +- } +- else +- { +- return thing; +- } +-} ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2019 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#include "VariantModel.h" ++ ++#include "compat/Variant.h" ++ ++static bool ++isMapLike( const QVariant& item ) ++{ ++ return item.canConvert< QVariantMap >(); ++} ++ ++static bool ++isListLike( const QVariant& item ) ++{ ++ return item.canConvert< QVariantList >() && !( Calamares::typeOf( item ) == Calamares::StringVariantType ); ++} ++ ++static void ++overallLength( const QVariant& item, quintptr& c, quintptr parent, VariantModel::IndexVector* skiplist ) ++{ ++ if ( skiplist ) ++ { ++ skiplist->append( parent ); ++ } ++ ++ parent = c++; ++ if ( isMapLike( item ) ) ++ { ++ for ( const auto& subitem : item.toMap() ) ++ { ++ overallLength( subitem, c, parent, skiplist ); ++ } ++ } ++ else if ( isListLike( item ) ) ++ { ++ for ( const auto& subitem : item.toList() ) ++ { ++ overallLength( subitem, c, parent, skiplist ); ++ } ++ } ++} ++ ++static quintptr ++findNth( const VariantModel::IndexVector& skiplist, quintptr value, int n ) ++{ ++ constexpr const quintptr invalid_index = static_cast< quintptr >( -1 ); ++ ++ if ( n < 0 ) ++ { ++ return invalid_index; ++ } ++ ++ int index = static_cast< int >( value ); ++ while ( ( n >= 0 ) && ( index < skiplist.count() ) ) ++ { ++ if ( skiplist[ index ] == value ) ++ { ++ if ( --n < 0 ) ++ { ++ // It's bigger than 0 ++ return static_cast< quintptr >( index ); ++ } ++ } ++ index++; ++ } ++ return invalid_index; ++} ++ ++ ++VariantModel::VariantModel( const QVariant* p ) ++ : m_p( p ) ++{ ++ reload(); ++} ++ ++VariantModel::~VariantModel() {} ++ ++void ++VariantModel::reload() ++{ ++ constexpr const quintptr invalid_index = static_cast< quintptr >( -1 ); ++ ++ quintptr x = 0; ++ m_rows.clear(); // Start over ++ if ( m_rows.capacity() < 64 ) ++ { ++ m_rows.reserve( 64 ); // Start reasonably-sized ++ } ++ overallLength( *m_p, x, invalid_index, &m_rows ); ++} ++ ++int ++VariantModel::columnCount( const QModelIndex& ) const ++{ ++ return 2; ++} ++ ++int ++VariantModel::rowCount( const QModelIndex& index ) const ++{ ++ quintptr p = index.isValid() ? index.internalId() : 0; ++ return m_rows.count( p ); ++} ++ ++QModelIndex ++VariantModel::index( int row, int column, const QModelIndex& parent ) const ++{ ++ quintptr p = 0; ++ ++ if ( parent.isValid() ) ++ { ++ if ( inRange( parent ) ) ++ { ++ p = parent.internalId(); ++ } ++ } ++ ++ return createIndex( row, column, findNth( m_rows, p, row ) ); ++} ++ ++static inline quintptr ++deref( const VariantModel::IndexVector& v, quintptr i ) ++{ ++ return v[ static_cast< int >( i ) ]; ++} ++ ++QModelIndex ++VariantModel::parent( const QModelIndex& index ) const ++{ ++ if ( !index.isValid() || !inRange( index ) ) ++ { ++ return QModelIndex(); ++ } ++ ++ quintptr p = deref( m_rows, index.internalId() ); ++ if ( p == 0 ) ++ { ++ return QModelIndex(); ++ } ++ ++ if ( !inRange( p ) ) ++ { ++ return QModelIndex(); ++ } ++ quintptr p_pid = deref( m_rows, p ); ++ int row = 0; ++ for ( int i = static_cast< int >( p_pid ); i < static_cast< int >( p ); ++i ) ++ { ++ if ( m_rows[ i ] == p_pid ) ++ { ++ row++; ++ } ++ } ++ ++ return createIndex( row, index.column(), p ); ++} ++ ++QVariant ++VariantModel::data( const QModelIndex& index, int role ) const ++{ ++ if ( role != Qt::DisplayRole ) ++ { ++ return QVariant(); ++ } ++ ++ if ( !index.isValid() ) ++ { ++ return QVariant(); ++ } ++ ++ if ( ( index.column() < 0 ) || ( index.column() > 1 ) ) ++ { ++ return QVariant(); ++ } ++ ++ if ( !inRange( index ) ) ++ { ++ return QVariant(); ++ } ++ ++ const QVariant thing = underlying( parent( index ) ); ++ ++ if ( !thing.isValid() ) ++ { ++ return QVariant(); ++ } ++ ++ if ( isMapLike( thing ) ) ++ { ++ QVariantMap the_map = thing.toMap(); ++ const auto key = the_map.keys().at( index.row() ); ++ if ( index.column() == 0 ) ++ { ++ return key; ++ } ++ else ++ { ++ return the_map[ key ]; ++ } ++ } ++ else if ( isListLike( thing ) ) ++ { ++ if ( index.column() == 0 ) ++ { ++ return index.row(); ++ } ++ else ++ { ++ QVariantList the_list = thing.toList(); ++ return the_list.at( index.row() ); ++ } ++ } ++ else ++ { ++ if ( index.column() == 0 ) ++ { ++ return QVariant(); ++ } ++ else ++ { ++ return thing; ++ } ++ } ++} ++ ++QVariant ++VariantModel::headerData( int section, Qt::Orientation orientation, int role ) const ++{ ++ if ( role != Qt::DisplayRole ) ++ { ++ return QVariant(); ++ } ++ ++ if ( orientation == Qt::Horizontal ) ++ { ++ if ( section == 0 ) ++ { ++ return tr( "Key", "Column header for key/value" ); ++ } ++ else if ( section == 1 ) ++ { ++ return tr( "Value", "Column header for key/value" ); ++ } ++ else ++ { ++ return QVariant(); ++ } ++ } ++ else ++ { ++ return QVariant(); ++ } ++} ++ ++const QVariant ++VariantModel::underlying( const QModelIndex& index ) const ++{ ++ if ( !index.isValid() ) ++ { ++ return *m_p; ++ } ++ ++ const auto& thing = underlying( parent( index ) ); ++ if ( isMapLike( thing ) ) ++ { ++ const auto& the_map = thing.toMap(); ++ return the_map[ the_map.keys()[ index.row() ] ]; ++ } ++ else if ( isListLike( thing ) ) ++ { ++ return thing.toList()[ index.row() ]; ++ } ++ else ++ { ++ return thing; ++ } ++} +diff --git a/src/calamares/VariantModel.h b/src/calamares/VariantModel.h +index 9d33231..4e47a93 100644 +--- a/src/calamares/VariantModel.h ++++ b/src/calamares/VariantModel.h +@@ -1,104 +1,104 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2019 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#ifndef VARIANTMODEL_H +-#define VARIANTMODEL_H +- +-#include +-#include +-#include +- +-/** @brief A model that operates directly on a QVariant +- * +- * A VariantModel operates directly on an underlying +- * QVariant, treating QVariantMap and QVariantList as +- * nodes with multiple children. In general, putting +- * a QVariantMap into a QVariant and passing that into +- * the model will get you a tree-like model of the +- * VariantMap's data structure. +- * +- * Take care of object lifetimes and that the underlying +- * QVariant does not change during use. If the QVariant +- * **does** change, call reload() to re-build the internal +- * representation of the tree. +- */ +-class VariantModel : public QAbstractItemModel +-{ +- Q_OBJECT +-public: +- /** @brief Auxiliary data +- * +- * The nodes of the tree are enumerated into a vector +- * (of length equal to the number of nodes in the tree + 1) +- * which are used to do index and parent calculations. +- */ +- using IndexVector = QVector< quintptr >; +- +- /** @brief Constructor +- * +- * The QVariant's lifetime is **not** affected by the model, +- * so take care that the QVariant lives at least as long as +- * the model). Also, don't change the QVariant underneath the model. +- */ +- VariantModel( const QVariant* p ); +- +- ~VariantModel() override; +- +- /** @brief Re-build the internal tree +- * +- * Call this when the underlying variant is changed, which +- * might impact how the tree is laid out. +- */ +- void reload(); +- +- int columnCount( const QModelIndex& index ) const override; +- int rowCount( const QModelIndex& index ) const override; +- +- QModelIndex index( int row, int column, const QModelIndex& parent ) const override; +- QModelIndex parent( const QModelIndex& index ) const override; +- QVariant data( const QModelIndex& index, int role ) const override; +- QVariant headerData( int section, Qt::Orientation orientation, int role ) const override; +- +-private: +- const QVariant* const m_p; +- +- /** @brief Tree representation of the variant. +- * +- * At index 0 in the vector , we store -1 to indicate the root. +- * +- * Then we enumerate all the elements in the tree (by traversing +- * the variant and using QVariantMap and QVariantList as having +- * children, and everything else being a leaf node) and at the index +- * for a child, store the index of its parent. This means that direct +- * children of the root store a 0 in their indexes, children of the first +- * child of the root store a 1, and we can "pointer chase" from an index +- * through parents back to index 0. +- * +- * Because of this structure, the value stored at index i must be +- * less than i (except for index 0, which is special). This makes it +- * slightly easier to search for a given value *p*, because we can start +- * at index *p* (or even *p+1*). +- * +- * Given an index *i* into the vector corresponding to a child, we know the +- * parent, but can also count which row this child should have, by counting +- * *other* indexes before *i* with the same parent (and by the ordering +- * of values, we can start counting at index *parent-index*). +- * +- */ +- IndexVector m_rows; +- +- /// @brief Implementation of walking an index through the variant-tree +- const QVariant underlying( const QModelIndex& index ) const; +- +- /// @brief Helpers for range-checking +- inline bool inRange( quintptr p ) const { return p < static_cast< quintptr >( m_rows.count() ); } +- inline bool inRange( const QModelIndex& index ) const { return inRange( index.internalId() ); } +-}; +- +-#endif ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2019 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#ifndef VARIANTMODEL_H ++#define VARIANTMODEL_H ++ ++#include ++#include ++#include ++ ++/** @brief A model that operates directly on a QVariant ++ * ++ * A VariantModel operates directly on an underlying ++ * QVariant, treating QVariantMap and QVariantList as ++ * nodes with multiple children. In general, putting ++ * a QVariantMap into a QVariant and passing that into ++ * the model will get you a tree-like model of the ++ * VariantMap's data structure. ++ * ++ * Take care of object lifetimes and that the underlying ++ * QVariant does not change during use. If the QVariant ++ * **does** change, call reload() to re-build the internal ++ * representation of the tree. ++ */ ++class VariantModel : public QAbstractItemModel ++{ ++ Q_OBJECT ++public: ++ /** @brief Auxiliary data ++ * ++ * The nodes of the tree are enumerated into a vector ++ * (of length equal to the number of nodes in the tree + 1) ++ * which are used to do index and parent calculations. ++ */ ++ using IndexVector = QVector< quintptr >; ++ ++ /** @brief Constructor ++ * ++ * The QVariant's lifetime is **not** affected by the model, ++ * so take care that the QVariant lives at least as long as ++ * the model). Also, don't change the QVariant underneath the model. ++ */ ++ VariantModel( const QVariant* p ); ++ ++ ~VariantModel() override; ++ ++ /** @brief Re-build the internal tree ++ * ++ * Call this when the underlying variant is changed, which ++ * might impact how the tree is laid out. ++ */ ++ void reload(); ++ ++ int columnCount( const QModelIndex& index ) const override; ++ int rowCount( const QModelIndex& index ) const override; ++ ++ QModelIndex index( int row, int column, const QModelIndex& parent ) const override; ++ QModelIndex parent( const QModelIndex& index ) const override; ++ QVariant data( const QModelIndex& index, int role ) const override; ++ QVariant headerData( int section, Qt::Orientation orientation, int role ) const override; ++ ++private: ++ const QVariant* const m_p; ++ ++ /** @brief Tree representation of the variant. ++ * ++ * At index 0 in the vector , we store -1 to indicate the root. ++ * ++ * Then we enumerate all the elements in the tree (by traversing ++ * the variant and using QVariantMap and QVariantList as having ++ * children, and everything else being a leaf node) and at the index ++ * for a child, store the index of its parent. This means that direct ++ * children of the root store a 0 in their indexes, children of the first ++ * child of the root store a 1, and we can "pointer chase" from an index ++ * through parents back to index 0. ++ * ++ * Because of this structure, the value stored at index i must be ++ * less than i (except for index 0, which is special). This makes it ++ * slightly easier to search for a given value *p*, because we can start ++ * at index *p* (or even *p+1*). ++ * ++ * Given an index *i* into the vector corresponding to a child, we know the ++ * parent, but can also count which row this child should have, by counting ++ * *other* indexes before *i* with the same parent (and by the ordering ++ * of values, we can start counting at index *parent-index*). ++ * ++ */ ++ IndexVector m_rows; ++ ++ /// @brief Implementation of walking an index through the variant-tree ++ const QVariant underlying( const QModelIndex& index ) const; ++ ++ /// @brief Helpers for range-checking ++ inline bool inRange( quintptr p ) const { return p < static_cast< quintptr >( m_rows.count() ); } ++ inline bool inRange( const QModelIndex& index ) const { return inRange( index.internalId() ); } ++}; ++ ++#endif +diff --git a/src/calamares/calamares-navigation.qml b/src/calamares/calamares-navigation.qml +index becc1b4..58c233d 100644 +--- a/src/calamares/calamares-navigation.qml ++++ b/src/calamares/calamares-navigation.qml +@@ -1,83 +1,83 @@ +-/* Sample of QML navigation. +- +- SPDX-FileCopyrightText: 2020 Adriaan de Groot +- SPDX-License-Identifier: GPL-3.0-or-later +- +- +- The navigation panel is generally "horizontal" in layout, with +- buttons for next and previous; this particular one copies +- the layout and size of the widgets panel. +-*/ +-import io.calamares.ui 1.0 +-import io.calamares.core 1.0 +- +-import QtQuick 2.3 +-import QtQuick.Controls 2.10 +-import QtQuick.Layouts 1.3 +- +-Rectangle { +- id: navigationBar; +- color: Branding.styleString( Branding.SidebarBackground ); +- height: 48; +- +- RowLayout { +- id: buttonBar +- anchors.fill: parent; +- +- Item +- { +- Layout.fillWidth: true; +- } +- +- Button +- { +- text: ViewManager.backLabel; +- icon.name: ViewManager.backIcon; +- +- enabled: ViewManager.backEnabled; +- visible: ViewManager.backAndNextVisible; +- onClicked: { ViewManager.back(); } +- } +- Button +- { +- text: ViewManager.nextLabel; +- icon.name: ViewManager.nextIcon; +- +- enabled: ViewManager.nextEnabled; +- visible: ViewManager.backAndNextVisible; +- onClicked: { ViewManager.next(); } +- // This margin goes in the "next" button, because the "quit" +- // button can vanish and we want to keep the margin to +- // the next-thing-in-the-navigation-panel around. +- Layout.rightMargin: 3 * buttonBar.spacing; +- } +- Button +- { +- Layout.rightMargin: 2 * buttonBar.spacing +- text: ViewManager.quitLabel; +- icon.name: ViewManager.quitIcon; +- +- ToolTip.visible: hovered +- ToolTip.timeout: 5000 +- ToolTip.delay: 1000 +- ToolTip.text: ViewManager.quitTooltip; +- +- /* +- * The ViewManager has settings -- user-controlled via the +- * branding component, and party based on program state -- +- * whether the quit button should be enabled and visible. +- * +- * QML navigation *should* follow this pattern, but can also +- * add other qualifications. For instance, you may have a +- * "finished" module that handles quit in its own way, and +- * want to hide the quit button then. The ViewManager has a +- * current step and a total count, so compare them: +- * +- * visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1); +- */ +- enabled: ViewManager.quitEnabled; +- visible: ViewManager.quitVisible; +- onClicked: { ViewManager.quit(); } +- } +- } +-} ++/* Sample of QML navigation. ++ ++ SPDX-FileCopyrightText: 2020 Adriaan de Groot ++ SPDX-License-Identifier: GPL-3.0-or-later ++ ++ ++ The navigation panel is generally "horizontal" in layout, with ++ buttons for next and previous; this particular one copies ++ the layout and size of the widgets panel. ++*/ ++import io.calamares.ui 1.0 ++import io.calamares.core 1.0 ++ ++import QtQuick 2.3 ++import QtQuick.Controls 2.10 ++import QtQuick.Layouts 1.3 ++ ++Rectangle { ++ id: navigationBar; ++ color: Branding.styleString( Branding.SidebarBackground ); ++ height: 48; ++ ++ RowLayout { ++ id: buttonBar ++ anchors.fill: parent; ++ ++ Item ++ { ++ Layout.fillWidth: true; ++ } ++ ++ Button ++ { ++ text: ViewManager.backLabel; ++ icon.name: ViewManager.backIcon; ++ ++ enabled: ViewManager.backEnabled; ++ visible: ViewManager.backAndNextVisible; ++ onClicked: { ViewManager.back(); } ++ } ++ Button ++ { ++ text: ViewManager.nextLabel; ++ icon.name: ViewManager.nextIcon; ++ ++ enabled: ViewManager.nextEnabled; ++ visible: ViewManager.backAndNextVisible; ++ onClicked: { ViewManager.next(); } ++ // This margin goes in the "next" button, because the "quit" ++ // button can vanish and we want to keep the margin to ++ // the next-thing-in-the-navigation-panel around. ++ Layout.rightMargin: 3 * buttonBar.spacing; ++ } ++ Button ++ { ++ Layout.rightMargin: 2 * buttonBar.spacing ++ text: ViewManager.quitLabel; ++ icon.name: ViewManager.quitIcon; ++ ++ ToolTip.visible: hovered ++ ToolTip.timeout: 5000 ++ ToolTip.delay: 1000 ++ ToolTip.text: ViewManager.quitTooltip; ++ ++ /* ++ * The ViewManager has settings -- user-controlled via the ++ * branding component, and party based on program state -- ++ * whether the quit button should be enabled and visible. ++ * ++ * QML navigation *should* follow this pattern, but can also ++ * add other qualifications. For instance, you may have a ++ * "finished" module that handles quit in its own way, and ++ * want to hide the quit button then. The ViewManager has a ++ * current step and a total count, so compare them: ++ * ++ * visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1); ++ */ ++ enabled: ViewManager.quitEnabled; ++ visible: ViewManager.quitVisible; ++ onClicked: { ViewManager.quit(); } ++ } ++ } ++} +diff --git a/src/calamares/calamares-sidebar.qml b/src/calamares/calamares-sidebar.qml +index 4780823..3a75d95 100644 +--- a/src/calamares/calamares-sidebar.qml ++++ b/src/calamares/calamares-sidebar.qml +@@ -1,125 +1,125 @@ +-/* Sample of QML progress tree. +- +- SPDX-FileCopyrightText: 2020 Adriaan de Groot +- SPDX-FileCopyrightText: 2021 Anke Boersma +- SPDX-License-Identifier: GPL-3.0-or-later +- +- +- The progress tree (actually a list) is generally "vertical" in layout, +- with the steps going "down", but it could also be a more compact +- horizontal layout with suitable branding settings. +- +- This example emulates the layout and size of the widgets progress tree. +-*/ +-import io.calamares.ui 1.0 +-import io.calamares.core 1.0 +- +-import QtQuick 2.3 +-import QtQuick.Layouts 1.3 +- +-Rectangle { +- id: sideBar; +- color: Branding.styleString( Branding.SidebarBackground ); +- anchors.fill: parent; +- +- ColumnLayout { +- anchors.fill: parent; +- spacing: 0; +- +- Image { +- Layout.topMargin: 12; +- Layout.bottomMargin: 12; +- Layout.alignment: Qt.AlignHCenter | Qt.AlignTop +- id: logo; +- width: 80; +- height: width; // square +- source: "file:/" + Branding.imagePath(Branding.ProductLogo); +- sourceSize.width: width; +- sourceSize.height: height; +- } +- +- Repeater { +- model: ViewManager +- Rectangle { +- Layout.leftMargin: 6; +- Layout.rightMargin: 6; +- Layout.fillWidth: true; +- height: 35; +- radius: 6; +- color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground ); +- +- Text { +- anchors.verticalCenter: parent.verticalCenter; +- anchors.horizontalCenter: parent.horizontalCenter; +- color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextCurrent : Branding.SidebarText ); +- text: display; +- } +- } +- } +- +- Item { +- Layout.fillHeight: true; +- } +- +- Rectangle { +- id: metaArea +- Layout.fillWidth: true; +- height: 35 +- Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom +- color: Branding.styleString( Branding.SidebarBackground ); +- visible: true; +- +- Rectangle { +- id: aboutArea +- height: 35 +- width: parent.width / 2; +- anchors.left: parent.left +- color: Branding.styleString( Branding.SidebarBackgroundCurrent ); +- visible: true; +- +- MouseArea { +- id: mouseAreaAbout +- anchors.fill: parent; +- cursorShape: Qt.PointingHandCursor +- hoverEnabled: true +- Text { +- anchors.verticalCenter: parent.verticalCenter; +- anchors.horizontalCenter: parent.horizontalCenter; +- x: parent.x + 4; +- text: qsTr("About") +- color: Branding.styleString( Branding.SidebarTextCurrent ); +- font.pointSize : 9 +- } +- +- onClicked: debug.about() +- } +- } +- +- Rectangle { +- id: debugArea +- height: 35 +- width: parent.width / 2; +- anchors.right: parent.right +- color: Branding.styleString( Branding.SidebarBackgroundCurrent ); +- visible: debug.enabled +- +- MouseArea { +- id: mouseAreaDebug +- anchors.fill: parent; +- cursorShape: Qt.PointingHandCursor +- hoverEnabled: true +- Text { +- anchors.verticalCenter: parent.verticalCenter; +- anchors.horizontalCenter: parent.horizontalCenter; +- x: parent.x + 4; +- text: qsTr("Debug") +- color: Branding.styleString( Branding.SidebarTextCurrent ); +- font.pointSize : 9 +- } +- +- onClicked: debug.toggle() +- } +- } +- } +- } +-} ++/* Sample of QML progress tree. ++ ++ SPDX-FileCopyrightText: 2020 Adriaan de Groot ++ SPDX-FileCopyrightText: 2021 Anke Boersma ++ SPDX-License-Identifier: GPL-3.0-or-later ++ ++ ++ The progress tree (actually a list) is generally "vertical" in layout, ++ with the steps going "down", but it could also be a more compact ++ horizontal layout with suitable branding settings. ++ ++ This example emulates the layout and size of the widgets progress tree. ++*/ ++import io.calamares.ui 1.0 ++import io.calamares.core 1.0 ++ ++import QtQuick 2.3 ++import QtQuick.Layouts 1.3 ++ ++Rectangle { ++ id: sideBar; ++ color: Branding.styleString( Branding.SidebarBackground ); ++ anchors.fill: parent; ++ ++ ColumnLayout { ++ anchors.fill: parent; ++ spacing: 0; ++ ++ Image { ++ Layout.topMargin: 12; ++ Layout.bottomMargin: 12; ++ Layout.alignment: Qt.AlignHCenter | Qt.AlignTop ++ id: logo; ++ width: 80; ++ height: width; // square ++ source: "file:/" + Branding.imagePath(Branding.ProductLogo); ++ sourceSize.width: width; ++ sourceSize.height: height; ++ } ++ ++ Repeater { ++ model: ViewManager ++ Rectangle { ++ Layout.leftMargin: 6; ++ Layout.rightMargin: 6; ++ Layout.fillWidth: true; ++ height: 35; ++ radius: 6; ++ color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground ); ++ ++ Text { ++ anchors.verticalCenter: parent.verticalCenter; ++ anchors.horizontalCenter: parent.horizontalCenter; ++ color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextCurrent : Branding.SidebarText ); ++ text: display; ++ } ++ } ++ } ++ ++ Item { ++ Layout.fillHeight: true; ++ } ++ ++ Rectangle { ++ id: metaArea ++ Layout.fillWidth: true; ++ height: 35 ++ Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom ++ color: Branding.styleString( Branding.SidebarBackground ); ++ visible: true; ++ ++ Rectangle { ++ id: aboutArea ++ height: 35 ++ width: parent.width / 2; ++ anchors.left: parent.left ++ color: Branding.styleString( Branding.SidebarBackgroundCurrent ); ++ visible: true; ++ ++ MouseArea { ++ id: mouseAreaAbout ++ anchors.fill: parent; ++ cursorShape: Qt.PointingHandCursor ++ hoverEnabled: true ++ Text { ++ anchors.verticalCenter: parent.verticalCenter; ++ anchors.horizontalCenter: parent.horizontalCenter; ++ x: parent.x + 4; ++ text: qsTr("About") ++ color: Branding.styleString( Branding.SidebarTextCurrent ); ++ font.pointSize : 9 ++ } ++ ++ onClicked: debug.about() ++ } ++ } ++ ++ Rectangle { ++ id: debugArea ++ height: 35 ++ width: parent.width / 2; ++ anchors.right: parent.right ++ color: Branding.styleString( Branding.SidebarBackgroundCurrent ); ++ visible: debug.enabled ++ ++ MouseArea { ++ id: mouseAreaDebug ++ anchors.fill: parent; ++ cursorShape: Qt.PointingHandCursor ++ hoverEnabled: true ++ Text { ++ anchors.verticalCenter: parent.verticalCenter; ++ anchors.horizontalCenter: parent.horizontalCenter; ++ x: parent.x + 4; ++ text: qsTr("Debug") ++ color: Branding.styleString( Branding.SidebarTextCurrent ); ++ font.pointSize : 9 ++ } ++ ++ onClicked: debug.toggle() ++ } ++ } ++ } ++ } ++} +diff --git a/src/calamares/calamares.qrc b/src/calamares/calamares.qrc +index 5733ea0..8517bad 100644 +--- a/src/calamares/calamares.qrc ++++ b/src/calamares/calamares.qrc +@@ -1,10 +1,10 @@ +- +- +- +- +- calamares-sidebar.qml +- calamares-navigation.qml +- +- ++ ++ ++ ++ ++ calamares-sidebar.qml ++ calamares-navigation.qml ++ ++ +diff --git a/src/calamares/main.cpp b/src/calamares/main.cpp +index e0491e5..af1b13a 100644 +--- a/src/calamares/main.cpp ++++ b/src/calamares/main.cpp +@@ -1,154 +1,154 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2014 Teo Mrnjavac +- * SPDX-FileCopyrightText: 2017-2020 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#include "CalamaresApplication.h" +- +-#include "Settings.h" +-#include "utils/Dirs.h" +-#include "utils/Logger.h" +-#include "utils/Retranslator.h" +- +-// From 3rdparty/ +-#include "kdsingleapplication.h" +- +-#include +-#ifdef BUILD_CRASH_REPORTING +-#include +-#endif +- +-#include +-#include +-#include +- +-#include +- +-/** @brief Gets debug-level from -D command-line-option +- * +- * If unset, use LOGERROR (corresponding to -D1), although +- * effectively -D2 is the lowest level you can set for +- * logging-to-the-console, and everything always gets +- * logged to the session file). +- */ +-static unsigned int +-debug_level( QCommandLineParser& parser, QCommandLineOption& levelOption ) +-{ +- if ( !parser.isSet( levelOption ) ) +- { +- return Logger::LOGERROR; +- } +- +- bool ok = true; +- int l = parser.value( levelOption ).toInt( &ok ); +- if ( !ok || ( l < 0 ) ) +- { +- return Logger::LOGVERBOSE; +- } +- else +- { +- return static_cast< unsigned int >( l ); // l >= 0 +- } +-} +- +-/** @brief Handles the command-line arguments +- * +- * Sets up internals for Calamares based on command-line arguments like `-D`, +- * `-d`, etc. Returns @c true if this is a *debug* run, i.e. if the `-d` +- * command-line flag is given, @c false otherwise. +- */ +-static bool +-handle_args( CalamaresApplication& a ) +-{ +- QCommandLineOption debugOption( QStringList { "d", "debug" }, +- "Also look in current directory for configuration. Implies -D8." ); +- QCommandLineOption debugLevelOption( +- QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8).", "level" ); +- QCommandLineOption debugTxOption( QStringList { "T", "debug-translation" }, +- "Also look in the current directory for translation." ); +- +- QCommandLineOption configOption( +- QStringList { "c", "config" }, "Configuration directory to use, for testing purposes.", "config" ); +- QCommandLineOption xdgOption( QStringList { "X", "xdg-config" }, "Use XDG_{CONFIG,DATA}_DIRS as well." ); +- +- QCommandLineParser parser; +- parser.setApplicationDescription( "Distribution-independent installer framework" ); +- parser.addHelpOption(); +- parser.addVersionOption(); +- +- parser.addOption( debugOption ); +- parser.addOption( debugLevelOption ); +- parser.addOption( configOption ); +- parser.addOption( xdgOption ); +- parser.addOption( debugTxOption ); +- +- parser.process( a ); +- +- Logger::setupLogLevel( parser.isSet( debugOption ) ? Logger::LOGVERBOSE : debug_level( parser, debugLevelOption ) ); +- if ( parser.isSet( configOption ) ) +- { +- Calamares::setAppDataDir( QDir( parser.value( configOption ) ) ); +- } +- if ( parser.isSet( xdgOption ) ) +- { +- Calamares::setXdgDirs(); +- } +- Calamares::setAllowLocalTranslation( parser.isSet( debugOption ) || parser.isSet( debugTxOption ) ); +- +- return parser.isSet( debugOption ); +-} +- +-int +-main( int argc, char* argv[] ) +-{ +-#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) +- // Not needed in Qt6 +- QApplication::setAttribute( Qt::AA_EnableHighDpiScaling ); +-#endif +- CalamaresApplication a( argc, argv ); +- +- KAboutData aboutData( "calamares", +- "Calamares", +- a.applicationVersion(), +- "The universal system installer", +- KAboutLicense::GPL_V3, +- QString(), +- QString(), +- "https://calamares.io", +- "https://github.com/calamares/calamares/issues" ); +- KAboutData::setApplicationData( aboutData ); +- a.setApplicationDisplayName( QString() ); // To avoid putting an extra "Calamares/" into the log-file +- +-#ifdef BUILD_CRASH_REPORTING +- KCrash::initialize(); +- // KCrash::setCrashHandler(); +- KCrash::setDrKonqiEnabled( true ); +- KCrash::setFlags( KCrash::SaferDialog | KCrash::AlwaysDirectly ); +-#endif +- +- std::unique_ptr< KDSingleApplication > possiblyUnique; +- const bool is_debug = handle_args( a ); +- if ( !is_debug ) +- { +- possiblyUnique = std::make_unique< KDSingleApplication >(); +- if ( !possiblyUnique->isPrimaryInstance() ) +- { +- qCritical() << "Calamares is already running."; +- return 87; // EUSERS on Linux +- } +- } +- +- Calamares::Settings::init( is_debug ); +- if ( !Calamares::Settings::instance() || !Calamares::Settings::instance()->isValid() ) +- { +- qCritical() << "Calamares has invalid settings, shutting down."; +- return 78; // EX_CONFIG on FreeBSD +- } +- a.init(); +- return a.exec(); +-} ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2014 Teo Mrnjavac ++ * SPDX-FileCopyrightText: 2017-2020 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#include "CalamaresApplication.h" ++ ++#include "Settings.h" ++#include "utils/Dirs.h" ++#include "utils/Logger.h" ++#include "utils/Retranslator.h" ++ ++// From 3rdparty/ ++#include "kdsingleapplication.h" ++ ++#include ++#ifdef BUILD_CRASH_REPORTING ++#include ++#endif ++ ++#include ++#include ++#include ++ ++#include ++ ++/** @brief Gets debug-level from -D command-line-option ++ * ++ * If unset, use LOGERROR (corresponding to -D1), although ++ * effectively -D2 is the lowest level you can set for ++ * logging-to-the-console, and everything always gets ++ * logged to the session file). ++ */ ++static unsigned int ++debug_level( QCommandLineParser& parser, QCommandLineOption& levelOption ) ++{ ++ if ( !parser.isSet( levelOption ) ) ++ { ++ return Logger::LOGERROR; ++ } ++ ++ bool ok = true; ++ int l = parser.value( levelOption ).toInt( &ok ); ++ if ( !ok || ( l < 0 ) ) ++ { ++ return Logger::LOGVERBOSE; ++ } ++ else ++ { ++ return static_cast< unsigned int >( l ); // l >= 0 ++ } ++} ++ ++/** @brief Handles the command-line arguments ++ * ++ * Sets up internals for Calamares based on command-line arguments like `-D`, ++ * `-d`, etc. Returns @c true if this is a *debug* run, i.e. if the `-d` ++ * command-line flag is given, @c false otherwise. ++ */ ++static bool ++handle_args( CalamaresApplication& a ) ++{ ++ QCommandLineOption debugOption( QStringList { "d", "debug" }, ++ "Also look in current directory for configuration. Implies -D8." ); ++ QCommandLineOption debugLevelOption( ++ QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8).", "level" ); ++ QCommandLineOption debugTxOption( QStringList { "T", "debug-translation" }, ++ "Also look in the current directory for translation." ); ++ ++ QCommandLineOption configOption( ++ QStringList { "c", "config" }, "Configuration directory to use, for testing purposes.", "config" ); ++ QCommandLineOption xdgOption( QStringList { "X", "xdg-config" }, "Use XDG_{CONFIG,DATA}_DIRS as well." ); ++ ++ QCommandLineParser parser; ++ parser.setApplicationDescription( "Distribution-independent installer framework" ); ++ parser.addHelpOption(); ++ parser.addVersionOption(); ++ ++ parser.addOption( debugOption ); ++ parser.addOption( debugLevelOption ); ++ parser.addOption( configOption ); ++ parser.addOption( xdgOption ); ++ parser.addOption( debugTxOption ); ++ ++ parser.process( a ); ++ ++ Logger::setupLogLevel( parser.isSet( debugOption ) ? Logger::LOGVERBOSE : debug_level( parser, debugLevelOption ) ); ++ if ( parser.isSet( configOption ) ) ++ { ++ Calamares::setAppDataDir( QDir( parser.value( configOption ) ) ); ++ } ++ if ( parser.isSet( xdgOption ) ) ++ { ++ Calamares::setXdgDirs(); ++ } ++ Calamares::setAllowLocalTranslation( parser.isSet( debugOption ) || parser.isSet( debugTxOption ) ); ++ ++ return parser.isSet( debugOption ); ++} ++ ++int ++main( int argc, char* argv[] ) ++{ ++#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) ++ // Not needed in Qt6 ++ QApplication::setAttribute( Qt::AA_EnableHighDpiScaling ); ++#endif ++ CalamaresApplication a( argc, argv ); ++ ++ KAboutData aboutData( "calamares", ++ "Calamares", ++ a.applicationVersion(), ++ "The universal system installer", ++ KAboutLicense::GPL_V3, ++ QString(), ++ QString(), ++ "https://calamares.io", ++ "https://github.com/calamares/calamares/issues" ); ++ KAboutData::setApplicationData( aboutData ); ++ a.setApplicationDisplayName( QString() ); // To avoid putting an extra "Calamares/" into the log-file ++ ++#ifdef BUILD_CRASH_REPORTING ++ KCrash::initialize(); ++ // KCrash::setCrashHandler(); ++ KCrash::setDrKonqiEnabled( true ); ++ KCrash::setFlags( KCrash::SaferDialog | KCrash::AlwaysDirectly ); ++#endif ++ ++ std::unique_ptr< KDSingleApplication > possiblyUnique; ++ const bool is_debug = handle_args( a ); ++ if ( !is_debug ) ++ { ++ possiblyUnique = std::make_unique< KDSingleApplication >(); ++ if ( !possiblyUnique->isPrimaryInstance() ) ++ { ++ qCritical() << "Calamares is already running."; ++ return 87; // EUSERS on Linux ++ } ++ } ++ ++ Calamares::Settings::init( is_debug ); ++ if ( !Calamares::Settings::instance() || !Calamares::Settings::instance()->isValid() ) ++ { ++ qCritical() << "Calamares has invalid settings, shutting down."; ++ return 78; // EX_CONFIG on FreeBSD ++ } ++ a.init(); ++ return a.exec(); ++} +diff --git a/src/calamares/progresstree/ProgressTreeDelegate.cpp b/src/calamares/progresstree/ProgressTreeDelegate.cpp +index f0a2470..5b988d6 100644 +--- a/src/calamares/progresstree/ProgressTreeDelegate.cpp ++++ b/src/calamares/progresstree/ProgressTreeDelegate.cpp +@@ -1,210 +1,212 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac +- * SPDX-FileCopyrightText: 2017 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#include "ProgressTreeDelegate.h" +- +-#include "Branding.h" +-#include "CalamaresApplication.h" +-#include "CalamaresWindow.h" +-#include "ViewManager.h" +-#include "utils/Gui.h" +-#include "utils/Logger.h" +- +-#include +-#include +-static constexpr int const item_margin = 8; +-static inline int +-item_fontsize() +-{ +- return Calamares::defaultFontSize(); +-} +-static bool contains(const std::vector& vec,const QString& value){ +- for(const QString& v : vec){ +- if(v==value){ +- return true; +- } +- } +- return false; +-} +-static QString getTypeOfStep(const QString& stepString){ +- std::vector baseSetting1 = {"Location","Keyboard"}; +- std::vector userSetting1 = {"Users","Packages"}; +- std::vector installSteps1 = {"Partitions","Summary","Install","Finish"}; +- std::vector baseSetting2 = {"位置","键盘"}; +- std::vector userSetting2 = {"用户","桌面"}; +- std::vector installSteps2 = {"分区","摘要","安装","结束"}; +- std::vector baseSetting3 = {"位置", "鍵盤"}; +- std::vector userSetting3 = {"使用者", "軟體包"}; +- std::vector installSteps3 = {"分割區", "總覽", "安裝", "完成"}; +- // 获取当前系统的语言设置 +- QLocale locale; +- QLocale::Language lang = locale.language(); +- +- // 将语言枚举值转换为字符串 +- QString languageString = QLocale::languageToString(lang); +- QLocale::Country country = locale.country(); +- +- // 将地区枚举值转换为字符串 +- QString countryString = QLocale::countryToString(country); +- if(contains(baseSetting1,stepString)){ +- return "BaseSetting"; +- } +- if(contains(userSetting1,stepString)){ +- return "UserSetting"; +- } +- if(contains(installSteps1,stepString)){ +- return "InstallSetting"; +- } +- if(contains(baseSetting2,stepString) && countryString=="China"){ +- return "基础设置"; +- } +- if(contains(userSetting2,stepString) && countryString=="China"){ +- return "用户设置"; +- } +- if(contains(installSteps2,stepString) && countryString=="China"){ +- return "安装设置"; +- } +- if (contains(baseSetting3, stepString) && countryString=="Taiwan") { +- return "基礎設定"; +- } +- if (contains(userSetting3, stepString) && countryString=="Taiwan"){ +- return "使用者設定"; +- } +- if (contains(installSteps3, stepString) && countryString=="Taiwan") { +- return "安裝設定"; +- } +- return 0; +-} +-static int getTypeOfStep(int val){ +- if(val<=1){ +- return 1; +- } +- else if(val<=3){ +- return 2; +- } +- else if(val<=8){ +- return 3; +- } +- else{ +- return 0; +- } +-} +-static bool isVisable(const QString& stepString){ +- std::vector installSteps = {"鍵盤", "軟體包", "總覽", "安裝", "完成", +- "Keyboard","Packages","Summary","Install","Finish", +- "键盘","桌面","摘要","安装","结束"}; +- return !contains(installSteps, stepString); +-} +-static void +-paintViewStep( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) +-{ +- QRect textRect = option.rect.adjusted( item_margin, item_margin, -item_margin, -item_margin ); +- QFont font = qApp->font(); +- font.setPointSize( item_fontsize() ); +- font.setBold( false ); +- painter->setFont( font ); +- +- int CurrentTypeOfStep = getTypeOfStep(index.data( Calamares::ViewManager::ProgressTreeItemCurrentIndex ).toInt()); +- int TypeOfStep = getTypeOfStep(index.row()); +- if ( CurrentTypeOfStep == TypeOfStep ) +- { +- painter->setPen( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarTextCurrent ) ); +- QString textHighlight +- = Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackgroundCurrent ); +- if ( textHighlight.isEmpty() ) +- { +- painter->setBrush( CalamaresApplication::instance()->mainWindow()->palette().window() ); +- } +- else +- { +- painter->setBrush( QColor( textHighlight ) ); +- } +- } +- +- // Draw the text at least once. If it doesn't fit, then shrink the font +- // being used by 1 pt on each iteration, up to a maximum of maximumShrink +- // times. On each loop, we'll have to blank out the rectangle again, so this +- // is an expensive (in terms of drawing operations) thing to do. +- // +- // (The loop uses <= because the counter is incremented at the start). +- static constexpr int const maximumShrink = 4; +- int shrinkSteps = 0; +- do +- { +- +- shrinkSteps++; +- +- QRectF boundingBox; +- QString text; +- if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"||!isVisable(index.data().toString())){ +- text = ""; +- }else{ +- text = getTypeOfStep(index.data().toString()); +- painter->fillRect( option.rect, painter->brush().color() ); +- } +- painter->drawText( +- textRect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, text, &boundingBox ); +- +- // The extra check here is to avoid the changing-font-size if we're not going to use +- // it in the next iteration of the loop anyway. +- if ( ( shrinkSteps <= maximumShrink ) && ( boundingBox.width() > textRect.width() ) ) +- { +- font.setPointSize( item_fontsize() ); +- painter->setFont( font ); +- } +- else +- { +- break; // It fits +- } +- } while ( shrinkSteps <= maximumShrink ); +-} +- +-QSize +-ProgressTreeDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const +-{ +- if ( !index.isValid() ) +- { +- return option.rect.size(); +- } +- +- QFont font = qApp->font(); +- +- font.setPointSize( item_fontsize() ); +- QFontMetrics fm( font ); +- int height = fm.height(); +- height += 2 * item_margin; +- if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"||!isVisable(index.data().toString())){ +- return QSize( 0, 0 ); +- }else{ +- return QSize( (Calamares::windowMinimumWidth*0.9)/3, height*2 ); +- } +- +-} +- +-void +-ProgressTreeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +-{ +- QStyleOptionViewItem opt = option; +- +- painter->save(); +- +- initStyleOption( &opt, index ); +- opt.text.clear(); +- +- painter->setBrush( +- QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackground ) ) ); +- painter->setPen( QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarText ) ) ); +- if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"){ +- }else{ +- paintViewStep( painter, opt, index ); +- } +- +- painter->restore(); +-} ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac ++ * SPDX-FileCopyrightText: 2017 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#include "ProgressTreeDelegate.h" ++ ++#include "Branding.h" ++#include "CalamaresApplication.h" ++#include "CalamaresWindow.h" ++#include "ViewManager.h" ++#include "utils/Gui.h" ++#include "utils/Logger.h" ++ ++#include ++#include ++static constexpr int const item_margin = 8; ++static inline int ++item_fontsize() ++{ ++ return Calamares::defaultFontSize(); ++} ++static bool contains(const std::vector& vec,const QString& value){ ++ for(const QString& v : vec){ ++ if(v==value){ ++ return true; ++ } ++ } ++ return false; ++} ++static QString getTypeOfStep(const QString& stepString){ ++ std::vector baseSetting1 = {"Location","Keyboard"}; ++ std::vector userSetting1 = {"Users","Packages"}; ++ std::vector installSteps1 = {"Partitions","Summary","Install","Finish"}; ++ std::vector baseSetting2 = {"位置","键盘"}; ++ std::vector userSetting2 = {"用户","桌面"}; ++ std::vector installSteps2 = {"分区","摘要","安装","结束"}; ++ std::vector baseSetting3 = {"位置", "鍵盤"}; ++ std::vector userSetting3 = {"使用者", "軟體包"}; ++ std::vector installSteps3 = {"分割區", "總覽", "安裝", "完成"}; ++ // 获取当前系统的语言设置 ++ QLocale locale; ++ QLocale::Language lang = locale.language(); ++ ++ // 将语言枚举值转换为字符串 ++ QString languageString = QLocale::languageToString(lang); ++ QLocale::Country country = locale.country(); ++ ++ // 将地区枚举值转换为字符串 ++ QString countryString = QLocale::countryToString(country); ++ // 输出当前语言 ++ if(contains(baseSetting1,stepString)){ ++ return "BaseSetting"; ++ } ++ if(contains(userSetting1,stepString)){ ++ return "UserSetting"; ++ } ++ if(contains(installSteps1,stepString)){ ++ return "InstallSetting"; ++ } ++ if(contains(baseSetting2,stepString) && countryString=="China"){ ++ return "基础设置"; ++ } ++ if(contains(userSetting2,stepString) && countryString=="China"){ ++ return "用户设置"; ++ } ++ if(contains(installSteps2,stepString) && countryString=="China"){ ++ return "安装设置"; ++ } ++ if (contains(baseSetting3, stepString) && countryString=="Taiwan") { ++ return "基礎設定"; ++ } ++ if (contains(userSetting3, stepString) && countryString=="Taiwan"){ ++ return "使用者設定"; ++ } ++ if (contains(installSteps3, stepString) && countryString=="Taiwan") { ++ return "安裝設定"; ++ } ++ return 0; ++} ++static int getTypeOfStep(int val){ ++ if(val<=1){ ++ return 1; ++ } ++ else if(val<=3){ ++ return 2; ++ } ++ else if(val<=8){ ++ return 3; ++ } ++ else{ ++ return 0; ++ } ++} ++static bool isVisable(const QString& stepString){ ++ std::vector installSteps = {"鍵盤", "軟體包", "總覽", "安裝", "完成", ++ "Keyboard","Packages","Summary","Install","Finish", ++ "键盘","桌面","摘要","安装","结束"}; ++ return !contains(installSteps, stepString); ++} ++static void ++paintViewStep( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) ++{ ++ QRect textRect = option.rect.adjusted( item_margin, item_margin, -item_margin, -item_margin ); ++ QFont font = qApp->font(); ++ font.setPointSize( item_fontsize() ); ++ font.setBold( false ); ++ painter->setFont( font ); ++ ++ int CurrentTypeOfStep = getTypeOfStep(index.data( Calamares::ViewManager::ProgressTreeItemCurrentIndex ).toInt()); ++ int TypeOfStep = getTypeOfStep(index.row()); ++ if ( CurrentTypeOfStep == TypeOfStep ) ++ { ++ painter->setPen( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarTextCurrent ) ); ++ QString textHighlight ++ = Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackgroundCurrent ); ++ if ( textHighlight.isEmpty() ) ++ { ++ painter->setBrush( CalamaresApplication::instance()->mainWindow()->palette().window() ); ++ } ++ else ++ { ++ painter->setBrush( QColor( textHighlight ) ); ++ } ++ } ++ ++ // Draw the text at least once. If it doesn't fit, then shrink the font ++ // being used by 1 pt on each iteration, up to a maximum of maximumShrink ++ // times. On each loop, we'll have to blank out the rectangle again, so this ++ // is an expensive (in terms of drawing operations) thing to do. ++ // ++ // (The loop uses <= because the counter is incremented at the start). ++ static constexpr int const maximumShrink = 4; ++ int shrinkSteps = 0; ++ do ++ { ++ ++ shrinkSteps++; ++ ++ QRectF boundingBox; ++ QString text; ++ if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"||!isVisable(index.data().toString())){ ++ text = ""; ++ }else{ ++ text = getTypeOfStep(index.data().toString()); ++ painter->fillRect( option.rect, painter->brush().color() ); ++ } ++ painter->drawText( ++ textRect, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, text, &boundingBox ); ++ ++ // The extra check here is to avoid the changing-font-size if we're not going to use ++ // it in the next iteration of the loop anyway. ++ if ( ( shrinkSteps <= maximumShrink ) && ( boundingBox.width() > textRect.width() ) ) ++ { ++ font.setPointSize( item_fontsize() ); ++ painter->setFont( font ); ++ } ++ else ++ { ++ break; // It fits ++ } ++ } while ( shrinkSteps <= maximumShrink ); ++} ++ ++QSize ++ProgressTreeDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const ++{ ++ if ( !index.isValid() ) ++ { ++ return option.rect.size(); ++ } ++ ++ QFont font = qApp->font(); ++ ++ font.setPointSize( item_fontsize() ); ++ QFontMetrics fm( font ); ++ int height = fm.height(); ++ height += 2 * item_margin; ++ if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"||!isVisable(index.data().toString())){ ++ return QSize( 0, 0 ); ++ }else{ ++ return QSize( (Calamares::windowMinimumWidth*0.9)/3, height*2 ); ++ } ++ ++} ++ ++void ++ProgressTreeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const ++{ ++ QStyleOptionViewItem opt = option; ++ ++ painter->save(); ++ ++ initStyleOption( &opt, index ); ++ opt.text.clear(); ++ ++ painter->setBrush( ++ QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackground ) ) ); ++ painter->setPen( QColor( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarText ) ) ); ++ if(index.data().toString()=="欢迎" || index.data().toString()=="Welcome"){ ++ ++ }else{ ++ paintViewStep( painter, opt, index ); ++ } ++ ++ painter->restore(); ++} +diff --git a/src/calamares/progresstree/ProgressTreeDelegate.h b/src/calamares/progresstree/ProgressTreeDelegate.h +index d5a5abc..af4fef9 100644 +--- a/src/calamares/progresstree/ProgressTreeDelegate.h ++++ b/src/calamares/progresstree/ProgressTreeDelegate.h +@@ -1,31 +1,31 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac +- * SPDX-FileCopyrightText: 2019 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#ifndef PROGRESSTREEDELEGATE_H +-#define PROGRESSTREEDELEGATE_H +- +-#include +- +-/** +- * @brief The ProgressTreeDelegate class customizes the look and feel of the +- * ProgressTreeView elements. +- * @see ProgressTreeView +- */ +-class ProgressTreeDelegate : public QStyledItemDelegate +-{ +-public: +- using QStyledItemDelegate::QStyledItemDelegate; +- +-protected: +- QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const override; +- void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override; +-}; +- +-#endif // PROGRESSTREEDELEGATE_H ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac ++ * SPDX-FileCopyrightText: 2019 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#ifndef PROGRESSTREEDELEGATE_H ++#define PROGRESSTREEDELEGATE_H ++ ++#include ++ ++/** ++ * @brief The ProgressTreeDelegate class customizes the look and feel of the ++ * ProgressTreeView elements. ++ * @see ProgressTreeView ++ */ ++class ProgressTreeDelegate : public QStyledItemDelegate ++{ ++public: ++ using QStyledItemDelegate::QStyledItemDelegate; ++ ++protected: ++ QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const override; ++ void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override; ++}; ++ ++#endif // PROGRESSTREEDELEGATE_H +diff --git a/src/calamares/progresstree/ProgressTreeView.cpp b/src/calamares/progresstree/ProgressTreeView.cpp +index cdbafeb..5ea761c 100644 +--- a/src/calamares/progresstree/ProgressTreeView.cpp ++++ b/src/calamares/progresstree/ProgressTreeView.cpp +@@ -1,79 +1,75 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2014 Teo Mrnjavac +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#include "ProgressTreeView.h" +- +-#include "ProgressTreeDelegate.h" +- +-#include "Branding.h" +-#include "ViewManager.h" +-#include "utils/Logger.h" +- +-ProgressTreeView::ProgressTreeView( QWidget* parent ) +- : QListView( parent ) +-{ +- this->setObjectName( "sidebarMenuApp" ); +- setFrameShape( QFrame::NoFrame ); +- setContentsMargins( 0, 0, 0, 0 ); +- +- setFlow(QListView::LeftToRight);// +- setSelectionMode( QAbstractItemView::NoSelection ); +- setDragDropMode( QAbstractItemView::NoDragDrop ); +- setAcceptDrops( false ); +-// setVisible( false); +- +- setItemDelegate( new ProgressTreeDelegate( this ) ); +- +- QPalette plt = palette(); +- plt.setColor( QPalette::Base, +- Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackground ) ); +- setPalette( plt ); +-// connect(parent, SIGNAL(currentStepChanged(int)), this, SLOT(updateVisibility(int))); +- connect( Calamares::ViewManager::instance(), +- &Calamares::ViewManager::currentStepChanged, +- this, +- &ProgressTreeView::updateVisibility, +- Qt::UniqueConnection ); +-// connect(viewManager, &ViewManager::currentStepChanged, this, &ProgressTreeView::updateVisibility); +-} +- +- +-ProgressTreeView::~ProgressTreeView() {} +- +- +- +-void +-ProgressTreeView::setModel( QAbstractItemModel* model ) +-{ +- if ( ProgressTreeView::model() ) +- { +- return; +- } +- +- QListView::setModel( model ); +- +- connect( Calamares::ViewManager::instance(), +- &Calamares::ViewManager::currentStepChanged, +- this, +- &ProgressTreeView::update, +- Qt::UniqueConnection ); +-} +- +-void +-ProgressTreeView::update() +-{ +- viewport()->update(); +-} +- +-void +-ProgressTreeView::updateVisibility(int currentStep) +-{ +- // 在第一个步骤隐藏,其他步骤显示 +- this->setVisible(currentStep > 0); +-} ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2014 Teo Mrnjavac ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#include "ProgressTreeView.h" ++ ++#include "ProgressTreeDelegate.h" ++ ++#include "Branding.h" ++#include "ViewManager.h" ++#include "utils/Logger.h" ++ ++ProgressTreeView::ProgressTreeView( QWidget* parent ) ++ : QListView( parent ) ++{ ++ this->setObjectName( "sidebarMenuApp" ); ++ setFrameShape( QFrame::NoFrame ); ++ setContentsMargins( 0, 0, 0, 0 ); ++ ++ setFlow(QListView::LeftToRight); ++ setSelectionMode( QAbstractItemView::NoSelection ); ++ setDragDropMode( QAbstractItemView::NoDragDrop ); ++ setAcceptDrops( false ); ++ ++ setItemDelegate( new ProgressTreeDelegate( this ) ); ++ ++ QPalette plt = palette(); ++ plt.setColor( QPalette::Base, ++ Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarBackground ) ); ++ setPalette( plt ); ++ connect( Calamares::ViewManager::instance(), ++ &Calamares::ViewManager::currentStepChanged, ++ this, ++ &ProgressTreeView::updateVisibility, ++ Qt::UniqueConnection ); ++} ++ ++ ++ProgressTreeView::~ProgressTreeView() {} ++ ++ ++ ++void ++ProgressTreeView::setModel( QAbstractItemModel* model ) ++{ ++ if ( ProgressTreeView::model() ) ++ { ++ return; ++ } ++ ++ QListView::setModel( model ); ++ ++ connect( Calamares::ViewManager::instance(), ++ &Calamares::ViewManager::currentStepChanged, ++ this, ++ &ProgressTreeView::update, ++ Qt::UniqueConnection ); ++} ++ ++void ++ProgressTreeView::update() ++{ ++ viewport()->update(); ++} ++ ++void ++ProgressTreeView::updateVisibility(int currentStep) ++{ ++ this->setVisible(currentStep > 0); ++} +diff --git a/src/calamares/progresstree/ProgressTreeView.h b/src/calamares/progresstree/ProgressTreeView.h +index 11491e4..b02b9ce 100644 +--- a/src/calamares/progresstree/ProgressTreeView.h ++++ b/src/calamares/progresstree/ProgressTreeView.h +@@ -1,41 +1,41 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2014 Teo Mrnjavac +- * SPDX-FileCopyrightText: 2017 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-#ifndef PROGRESSTREEVIEW_H +-#define PROGRESSTREEVIEW_H +- +-#include +-#include "utils/Logger.h" +- +-/** +- * @brief Displays progress through the list of (visible) steps +- * +- * The ProgressTreeView class is a modified QListView which displays the +- * available view steps and the user's progress through them. +- * Since Calamares doesn't support "sub steps", it isn't really a tree. +- */ +-class ProgressTreeView : public QListView +-{ +- Q_OBJECT +-public: +- explicit ProgressTreeView( QWidget* parent = nullptr ); +- ~ProgressTreeView() override; +- +- /** +- * @brief setModel assigns a model to this view. +- */ +- void setModel( QAbstractItemModel* model ) override; +- +-public Q_SLOTS: +- void update(); +- void updateVisibility(int currentStep); +-}; +- +-#endif // PROGRESSTREEVIEW_H ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2014 Teo Mrnjavac ++ * SPDX-FileCopyrightText: 2017 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++#ifndef PROGRESSTREEVIEW_H ++#define PROGRESSTREEVIEW_H ++ ++#include ++#include "utils/Logger.h" ++ ++/** ++ * @brief Displays progress through the list of (visible) steps ++ * ++ * The ProgressTreeView class is a modified QListView which displays the ++ * available view steps and the user's progress through them. ++ * Since Calamares doesn't support "sub steps", it isn't really a tree. ++ */ ++class ProgressTreeView : public QListView ++{ ++ Q_OBJECT ++public: ++ explicit ProgressTreeView( QWidget* parent = nullptr ); ++ ~ProgressTreeView() override; ++ ++ /** ++ * @brief setModel assigns a model to this view. ++ */ ++ void setModel( QAbstractItemModel* model ) override; ++ ++public Q_SLOTS: ++ void update(); ++ void updateVisibility(int currentStep); ++}; ++ ++#endif // PROGRESSTREEVIEW_H +diff --git a/src/calamares/test_conf.cpp b/src/calamares/test_conf.cpp +index 73b19aa..81f4e36 100644 +--- a/src/calamares/test_conf.cpp ++++ b/src/calamares/test_conf.cpp +@@ -1,109 +1,109 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-/** +- * This is a test-application that just checks the YAML config-file +- * shipped with each module for correctness -- well, for parseability. +- */ +- +-#include "utils/Yaml.h" +- +-#include +-#include +- +-#include +- +-#include +-#include +- +-using std::cerr; +- +-static const char usage[] = "Usage: test_conf [-v] [-b] ...\n"; +- +-int +-main( int argc, char** argv ) +-{ +- bool verbose = false; +- bool bytes = false; +- +- int opt; +- while ( ( opt = getopt( argc, argv, "vb" ) ) != -1 ) +- { +- switch ( opt ) +- { +- case 'v': +- verbose = true; +- break; +- case 'b': +- bytes = true; +- break; +- default: /* '?' */ +- cerr << usage; +- return 1; +- } +- } +- +- if ( optind >= argc ) +- { +- cerr << usage; +- return 1; +- } +- +- const char* filename = argv[ optind ]; +- try +- { +- YAML::Node doc; +- if ( bytes ) +- { +- QFile f( filename ); +- if ( f.open( QFile::ReadOnly | QFile::Text ) ) +- { +- doc = YAML::Load( f.readAll().constData() ); +- } +- } +- else +- { +- doc = YAML::LoadFile( filename ); +- } +- +- if ( doc.IsNull() ) +- { +- // Special case: empty config files are valid, +- // but aren't a map. For the example configs, +- // this is still an error. +- cerr << "WARNING:" << filename << '\n'; +- cerr << "WARNING: empty YAML\n"; +- return 1; +- } +- +- if ( !doc.IsMap() ) +- { +- cerr << "WARNING:" << filename << '\n'; +- cerr << "WARNING: not-a-YAML-map (type=" << doc.Type() << ")\n"; +- return 1; +- } +- +- if ( verbose ) +- { +- cerr << "Keys:\n"; +- for ( auto i = doc.begin(); i != doc.end(); ++i ) +- { +- cerr << i->first.as< std::string >() << '\n'; +- } +- } +- } +- catch ( YAML::Exception& e ) +- { +- cerr << "WARNING:" << filename << '\n'; +- cerr << "WARNING: YAML parser error " << e.what() << '\n'; +- return 1; +- } +- +- return 0; +-} ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++/** ++ * This is a test-application that just checks the YAML config-file ++ * shipped with each module for correctness -- well, for parseability. ++ */ ++ ++#include "utils/Yaml.h" ++ ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++using std::cerr; ++ ++static const char usage[] = "Usage: test_conf [-v] [-b] ...\n"; ++ ++int ++main( int argc, char** argv ) ++{ ++ bool verbose = false; ++ bool bytes = false; ++ ++ int opt; ++ while ( ( opt = getopt( argc, argv, "vb" ) ) != -1 ) ++ { ++ switch ( opt ) ++ { ++ case 'v': ++ verbose = true; ++ break; ++ case 'b': ++ bytes = true; ++ break; ++ default: /* '?' */ ++ cerr << usage; ++ return 1; ++ } ++ } ++ ++ if ( optind >= argc ) ++ { ++ cerr << usage; ++ return 1; ++ } ++ ++ const char* filename = argv[ optind ]; ++ try ++ { ++ YAML::Node doc; ++ if ( bytes ) ++ { ++ QFile f( filename ); ++ if ( f.open( QFile::ReadOnly | QFile::Text ) ) ++ { ++ doc = YAML::Load( f.readAll().constData() ); ++ } ++ } ++ else ++ { ++ doc = YAML::LoadFile( filename ); ++ } ++ ++ if ( doc.IsNull() ) ++ { ++ // Special case: empty config files are valid, ++ // but aren't a map. For the example configs, ++ // this is still an error. ++ cerr << "WARNING:" << filename << '\n'; ++ cerr << "WARNING: empty YAML\n"; ++ return 1; ++ } ++ ++ if ( !doc.IsMap() ) ++ { ++ cerr << "WARNING:" << filename << '\n'; ++ cerr << "WARNING: not-a-YAML-map (type=" << doc.Type() << ")\n"; ++ return 1; ++ } ++ ++ if ( verbose ) ++ { ++ cerr << "Keys:\n"; ++ for ( auto i = doc.begin(); i != doc.end(); ++i ) ++ { ++ cerr << i->first.as< std::string >() << '\n'; ++ } ++ } ++ } ++ catch ( YAML::Exception& e ) ++ { ++ cerr << "WARNING:" << filename << '\n'; ++ cerr << "WARNING: YAML parser error " << e.what() << '\n'; ++ return 1; ++ } ++ ++ return 0; ++} +diff --git a/src/calamares/testmain.cpp b/src/calamares/testmain.cpp +index c25bc51..7ab15c9 100644 +--- a/src/calamares/testmain.cpp ++++ b/src/calamares/testmain.cpp +@@ -1,572 +1,572 @@ +-/* === This file is part of Calamares - === +- * +- * SPDX-FileCopyrightText: 2018 Adriaan de Groot +- * SPDX-License-Identifier: GPL-3.0-or-later +- * +- * Calamares is Free Software: see the License-Identifier above. +- * +- */ +- +-/* +- * This executable loads and runs a Calamares Python module +- * within a C++ application, in order to test the different +- * bindings. +- */ +- +-#include "Branding.h" +-#include "CppJob.h" +-#include "GlobalStorage.h" +-#include "Job.h" +-#include "JobQueue.h" +-#include "Settings.h" +-#include "ViewManager.h" +-#include "modulesystem/Module.h" +-#include "modulesystem/ModuleManager.h" +-#include "modulesystem/ViewModule.h" +-#include "utils/Logger.h" +-#include "utils/Retranslator.h" +-#include "utils/System.h" +-#include "utils/Yaml.h" +-#include "viewpages/ExecutionViewStep.h" +- +-// Optional features of Calamares +-// - Python support with pybind11 +-// - Python support with older Boost implementation +-// - QML support +-#ifdef WITH_PYTHON +-#ifdef WITH_PYBIND11 +-#include "python/PythonJob.h" +-#else +-#include "PythonJob.h" +-#endif +-#endif +-#ifdef WITH_QML +-#include "utils/Qml.h" +-#endif +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-struct ModuleConfig +-{ +- QString moduleName() const { return m_module; } +- QString configFile() const { return m_jobConfig; } +- QString language() const { return m_language; } +- QString globalConfigFile() const { return m_globalConfig; } +- +- QString m_module; +- QString m_jobConfig; +- QString m_globalConfig; +- QString m_settingsConfig; +- QString m_language; +- QString m_branding; +- bool m_ui; +- bool m_pythonInjection; +-}; +- +-static ModuleConfig +-handle_args( QCoreApplication& a ) +-{ +- QCommandLineOption debugLevelOption( +- QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8), ignored.", "level" ); +- QCommandLineOption settingsOption( { QStringLiteral( "S" ), QStringLiteral( "settings" ) }, +- QStringLiteral( "Settings.conf document" ), +- QString( "settings.conf" ) ); +- QCommandLineOption globalOption( { QStringLiteral( "g" ), QStringLiteral( "global" ) }, +- QStringLiteral( "Global storage settings document" ), +- "global.yaml" ); +- QCommandLineOption jobOption( +- { QStringLiteral( "j" ), QStringLiteral( "job" ) }, QStringLiteral( "Job settings document" ), "job.yaml" ); +- QCommandLineOption langOption( { QStringLiteral( "l" ), QStringLiteral( "language" ) }, +- QStringLiteral( "Language (global)" ), +- "languagecode" ); +- QCommandLineOption brandOption( { QStringLiteral( "b" ), QStringLiteral( "branding" ) }, +- QStringLiteral( "Branding directory" ), +- "path/to/branding.desc", +- "src/branding/default/branding.desc" ); +- QCommandLineOption uiOption( { QStringLiteral( "U" ), QStringLiteral( "ui" ) }, QStringLiteral( "Enable UI" ) ); +- QCommandLineOption slideshowOption( { QStringLiteral( "s" ), QStringLiteral( "slideshow" ) }, +- QStringLiteral( "Run slideshow module" ) ); +- QCommandLineParser parser; +- parser.setApplicationDescription( "Calamares module tester" ); +- parser.addHelpOption(); +- parser.addVersionOption(); +- +- parser.addOption( debugLevelOption ); +- parser.addOption( settingsOption ); +- parser.addOption( globalOption ); +- parser.addOption( jobOption ); +- parser.addOption( langOption ); +- parser.addOption( brandOption ); +- parser.addOption( uiOption ); +- parser.addOption( slideshowOption ); +-#ifdef WITH_PYTHON +- QCommandLineOption pythonOption( { QStringLiteral( "P" ), QStringLiteral( "no-injected-python" ) }, +- QStringLiteral( "Do not disable potentially-harmful Python commands" ) ); +- parser.addOption( pythonOption ); +-#endif +- +- parser.addPositionalArgument( "module", "Path or name of module to run." ); +- parser.addPositionalArgument( "job.yaml", "Path of job settings document to use.", "[job.yaml]" ); +- +- parser.process( a ); +- +- const QStringList args = parser.positionalArguments(); +- if ( args.isEmpty() && !parser.isSet( slideshowOption ) ) +- { +- cError() << "Missing path.\n"; +- parser.showHelp(); +- } +- else if ( args.size() > 2 ) +- { +- cError() << "More than one path.\n"; +- parser.showHelp(); +- } +- else +- { +- QString jobSettings( parser.value( jobOption ) ); +- if ( jobSettings.isEmpty() && ( args.size() == 2 ) ) +- { +- jobSettings = args.at( 1 ); +- } +- +- bool pythonInjection = true; +-#ifdef WITH_PYTHON +- if ( parser.isSet( pythonOption ) ) +- { +- pythonInjection = false; +- } +-#endif +- return ModuleConfig { parser.isSet( slideshowOption ) ? QStringLiteral( "-" ) : args.first(), +- jobSettings, +- parser.value( globalOption ), +- parser.value( settingsOption ), +- parser.value( langOption ), +- parser.value( brandOption ), +- parser.isSet( slideshowOption ) || parser.isSet( uiOption ), +- pythonInjection }; +- } +-} +- +-/** @brief Bogus Job for --slideshow option +- * +- * Generally one would use DummyCppJob for this kind of dummy +- * job, but that class lives in a module so isn't available +- * in this test application. +- * +- * This bogus job just sleeps for 3. +- */ +-class ExecViewJob : public Calamares::CppJob +-{ +-public: +- explicit ExecViewJob( const QString& name, unsigned long t = 3 ) +- : m_name( name ) +- , m_delay( t ) +- { +- } +- ~ExecViewJob() override; +- +- QString prettyName() const override { return m_name; } +- +- Calamares::JobResult exec() override +- { +- QThread::sleep( m_delay ); +- return Calamares::JobResult::ok(); +- } +- +- void setConfigurationMap( const QVariantMap& ) override {} +- +-private: +- QString m_name; +- unsigned long m_delay; +-}; +- +-ExecViewJob::~ExecViewJob() {} +- +-/** @brief Bogus module for --slideshow option +- * +- * Normally the slideshow -- displayed by ExecutionViewStep -- is not +- * associated with any particular module in the Calamares configuration. +- * It is added internally by the module manager. For the module-loader +- * testing application, we need something that pretends to be the +- * module for the ExecutionViewStep. +- */ +-class ExecViewModule : public Calamares::Module +-{ +-public: +- ExecViewModule(); +- ~ExecViewModule() override; +- +- void loadSelf() override; +- +- virtual Calamares::ModuleSystem::Type type() const override; +- virtual Calamares::ModuleSystem::Interface interface() const override; +- +- virtual Calamares::JobList jobs() const override; +- +-protected: +- void initFrom( const Calamares::ModuleSystem::Descriptor& ) override; +-}; +- +-ExecViewModule::ExecViewModule() +- : Calamares::Module() +-{ +- // Normally the module-loader gives the module an instance key +- // (out of the settings file, or the descriptor of the module). +- // We don't have one, so build one -- this gives us "execView@execView". +- QVariantMap m; +- const QString execView = QStringLiteral( "execView" ); +- m.insert( "name", execView ); +- Calamares::Module::initFrom( Calamares::ModuleSystem::Descriptor::fromDescriptorData( m, execView ), execView ); +-} +- +-ExecViewModule::~ExecViewModule() {} +- +-void +-ExecViewModule::initFrom( const Calamares::ModuleSystem::Descriptor& ) +-{ +-} +- +-void +-ExecViewModule::loadSelf() +-{ +- auto* viewStep = new Calamares::ExecutionViewStep(); +- viewStep->setModuleInstanceKey( instanceKey() ); +- viewStep->setConfigurationMap( m_configurationMap ); +- viewStep->appendJobModuleInstanceKey( instanceKey() ); +- Calamares::ViewManager::instance()->addViewStep( viewStep ); +- m_loaded = true; +-} +- +-Calamares::Module::Type +-ExecViewModule::type() const +-{ +- return Module::Type::View; +-} +- +-Calamares::Module::Interface +-ExecViewModule::interface() const +-{ +- return Module::Interface::QtPlugin; +-} +- +-Calamares::JobList +-ExecViewModule::jobs() const +-{ +- Calamares::JobList l; +- const auto* gs = Calamares::JobQueue::instance()->globalStorage(); +- if ( gs && gs->contains( "jobs" ) ) +- { +- QVariantList joblist = gs->value( "jobs" ).toList(); +- for ( const auto& jd : joblist ) +- { +- QVariantMap jobdescription = jd.toMap(); +- if ( jobdescription.contains( "name" ) && jobdescription.contains( "delay" ) ) +- { +- l.append( Calamares::job_ptr( new ExecViewJob( jobdescription.value( "name" ).toString(), +- jobdescription.value( "delay" ).toULongLong() ) ) ); +- } +- } +- } +- if ( l.count() > 0 ) +- { +- return l; +- } +- +- l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "step 1" ) ) ) ); +- l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "step two" ) ) ) ); +- l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "locking mutexes" ), 20 ) ) ); +- l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "unlocking mutexes" ), 1 ) ) ); +- for ( const QString& s : QStringList { "Harder", "Better", "Faster", "Stronger" } ) +- { +- l.append( Calamares::job_ptr( new ExecViewJob( s, 0 ) ) ); +- } +- l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "cleaning up" ), 20 ) ) ); +- return l; +-} +- +-static Calamares::Module* +-load_module( const ModuleConfig& moduleConfig ) +-{ +- QString moduleName = moduleConfig.moduleName(); +- if ( moduleName == "-" ) +- { +- return new ExecViewModule; +- } +- +- QFileInfo fi; // This is kept around to hold the path of the module descriptor +- +- bool ok = false; +- QVariantMap descriptor; +- +- QStringList moduleDirectories { "./", "src/modules/", "modules/", CMAKE_INSTALL_FULL_LIBDIR "/calamares/modules/" }; +- for ( const QString& prefix : qAsConst( moduleDirectories ) ) +- { +- // Could be a complete path, eg. src/modules/dummycpp/module.desc +- fi = QFileInfo( prefix + moduleName ); +- if ( fi.exists() && fi.isFile() ) +- { +- descriptor = Calamares::YAML::load( fi, &ok ); +- } +- if ( ok ) +- { +- break; +- } +- +- // Could be a path without module.desc +- fi = QFileInfo( prefix + moduleName ); +- if ( fi.exists() && fi.isDir() ) +- { +- fi = QFileInfo( prefix + moduleName + "/module.desc" ); +- if ( fi.exists() && fi.isFile() ) +- { +- descriptor = Calamares::YAML::load( fi, &ok ); +- } +- if ( ok ) +- { +- break; +- } +- else +- { +- if ( !fi.exists() ) +- { +- cDebug() << "Expected a descriptor file" << fi.path(); +- } +- else +- { +- cDebug() << "Read descriptor" << fi.path() << "and it was empty."; +- } +- } +- } +- } +- +- if ( !ok ) +- { +- cWarning() << "No suitable module descriptor found in" << Logger::DebugList( moduleDirectories ); +- return nullptr; +- } +- +- QString name = descriptor.value( "name" ).toString(); +- if ( name.isEmpty() ) +- { +- cWarning() << "No name found in module descriptor" << fi.absoluteFilePath(); +- return nullptr; +- } +- +- QString moduleDirectory = fi.absolutePath(); +- QString configFile( moduleConfig.configFile().isEmpty() ? moduleDirectory + '/' + name + ".conf" +- : moduleConfig.configFile() ); +- +- cDebug() << Logger::SubEntry << "Module" << moduleName << "job-configuration:" << configFile; +- +- Calamares::Module* module = Calamares::moduleFromDescriptor( +- Calamares::ModuleSystem::Descriptor::fromDescriptorData( descriptor, fi.absoluteFilePath() ), +- name, +- configFile, +- moduleDirectory ); +- +- return module; +-} +- +-static bool +-is_ui_option( const char* s ) +-{ +- return !qstrcmp( s, "--ui" ) || !qstrcmp( s, "-U" ); +-} +- +-static bool +-is_slideshow_option( const char* s ) +-{ +- return !qstrcmp( s, "--slideshow" ) || !qstrcmp( s, "-s" ); +-} +- +-/** @brief Create the right kind of QApplication +- * +- * Does primitive parsing of argv[] to find the --ui option and returns +- * a UI-enabled application if it does. +- * +- * @p argc must be a reference (to main's argc) because the QCoreApplication +- * constructors take a reference as well, and that would otherwise be a +- * reference to a temporary. +- */ +-QCoreApplication* +-createApplication( int& argc, char* argv[] ) +-{ +- for ( int i = 1; i < argc; ++i ) +- { +- if ( is_slideshow_option( argv[ i ] ) || is_ui_option( argv[ i ] ) ) +- { +- auto* aw = new QApplication( argc, argv ); +- aw->setQuitOnLastWindowClosed( true ); +- return aw; +- } +- } +- return new QCoreApplication( argc, argv ); +-} +- +-#ifdef WITH_PYTHON +-static const char pythonPreScript[] = R"%( +-# This is Python code executed by Python modules *before* the +-# script file (e.g. main.py) is executed. +-# +-# Calls to suprocess methods that execute something are +-# suppressed and logged -- scripts should really be using libcalamares +-# methods instead. +-_calamares_subprocess = __import__("subprocess", globals(), locals(), [], 0) +-import sys +-import libcalamares +-class fake_subprocess(object): +- PIPE = object() +- STDOUT = object() +- STDERR = object() +- class CompletedProcess(object): +- returncode = 0 +- stdout = "" +- stderr = "" +- @staticmethod +- def call(*args, **kwargs): +- libcalamares.utils.debug("subprocess.call(%r,%r) X ignored" % (args, kwargs)) +- return 0 +- @staticmethod +- def check_call(*args, **kwargs): +- libcalamares.utils.debug("subprocess.check_call(%r,%r) X ignored" % (args, kwargs)) +- return 0 +- # This is a 3.5-and-later method, is supposed to return a CompletedProcess +- @staticmethod +- def run(*args, **kwargs): +- libcalamares.utils.debug("subprocess.run(%r,%r) X ignored" % (args, kwargs)) +- return fake_subprocess.CompletedProcess() +-for attr in ("CalledProcessError",): +- setattr(fake_subprocess,attr,getattr(_calamares_subprocess,attr)) +-sys.modules["subprocess"] = fake_subprocess +-libcalamares.utils.debug('pre-script for testing purposes injected') +- +-)%"; +-#endif +- +-int +-main( int argc, char* argv[] ) +-{ +- QCoreApplication* application = createApplication( argc, argv ); +- +- Logger::setupLogLevel( Logger::LOGVERBOSE ); +- +- ModuleConfig module = handle_args( *application ); +- if ( module.moduleName().isEmpty() ) +- { +- return 1; +- } +- +- std::unique_ptr< Calamares::Settings > settings_p( Calamares::Settings::init( module.m_settingsConfig ) ); +- std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) ); +- std::unique_ptr< Calamares::System > system_p( new Calamares::System( settings_p->doChroot() ) ); +- +- QMainWindow* mainWindow = nullptr; +- +- auto* gs = jobqueue_p->globalStorage(); +- if ( !module.globalConfigFile().isEmpty() ) +- { +- gs->loadYaml( module.globalConfigFile() ); +- } +- if ( !module.language().isEmpty() ) +- { +- QVariantMap vm; +- vm.insert( "LANG", module.language() ); +- gs->insert( "localeConf", vm ); +- } +- +-#ifdef WITH_PYTHON +- if ( module.m_pythonInjection ) +- { +-#ifdef WITH_PYBIND11 +- Calamares::Python::Job::setInjectedPreScript( pythonPreScript ); +-#else +- // Old Boost approach +- Calamares::PythonJob::setInjectedPreScript( pythonPreScript ); +-#endif +- } +-#endif +-#ifdef WITH_QML +- Calamares::initQmlModulesDir(); // don't care if failed +-#endif +- +- cDebug() << "Calamares module-loader testing" << module.moduleName(); +- Calamares::Module* m = load_module( module ); +- if ( !m ) +- { +- cError() << "Could not load module" << module.moduleName(); +- return 1; +- } +- +- cDebug() << Logger::SubEntry << "got" << m->name() << m->typeString() << m->interfaceString(); +- if ( m->type() == Calamares::Module::Type::View ) +- { +- // If we forgot the --ui, any ViewModule will core dump as it +- // tries to create the widget **which won't be used anyway**. +- // +- // To avoid that crash, re-create the QApplication, now with GUI +- if ( !qobject_cast< QApplication* >( application ) ) +- { +- auto* replace_app = new QApplication( argc, argv ); +- replace_app->setQuitOnLastWindowClosed( true ); +- application = replace_app; +- } +- mainWindow = module.m_ui ? new QMainWindow() : nullptr; +- if ( mainWindow ) +- { +- mainWindow->installEventFilter( Calamares::Retranslator::instance() ); +- } +- +- (void)new Calamares::Branding( module.m_branding ); +- auto* modulemanager = new Calamares::ModuleManager( QStringList(), nullptr ); +- (void)Calamares::ViewManager::instance( mainWindow ); +- modulemanager->addModule( m ); +- } +- +- if ( !m->isLoaded() ) +- { +- m->loadSelf(); +- } +- +- if ( !m->isLoaded() ) +- { +- cError() << "Module" << module.moduleName() << "could not be loaded."; +- return 1; +- } +- +- if ( mainWindow ) +- { +- auto* vm = Calamares::ViewManager::instance(); +- vm->onInitComplete(); +- QWidget* w = vm->currentStep()->widget(); +- w->setParent( mainWindow ); +- mainWindow->setCentralWidget( w ); +- w->show(); +- mainWindow->show(); +- return application->exec(); +- } +- +- using TR = Logger::DebugRow< const char*, const QString >; +- +- cDebug() << Logger::SubEntry << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() ) +- << TR( "interface", m->interfaceString() ); +- +- Calamares::JobQueue::instance()->enqueue( 100, m->jobs() ); +- +- QObject::connect( Calamares::JobQueue::instance(), +- &Calamares::JobQueue::finished, +- [ application ]() +- { QTimer::singleShot( std::chrono::seconds( 3 ), application, &QApplication::quit ); } ); +- QTimer::singleShot( 0, []() { Calamares::JobQueue::instance()->start(); } ); +- +- return application->exec(); +-} ++/* === This file is part of Calamares - === ++ * ++ * SPDX-FileCopyrightText: 2018 Adriaan de Groot ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ * ++ * Calamares is Free Software: see the License-Identifier above. ++ * ++ */ ++ ++/* ++ * This executable loads and runs a Calamares Python module ++ * within a C++ application, in order to test the different ++ * bindings. ++ */ ++ ++#include "Branding.h" ++#include "CppJob.h" ++#include "GlobalStorage.h" ++#include "Job.h" ++#include "JobQueue.h" ++#include "Settings.h" ++#include "ViewManager.h" ++#include "modulesystem/Module.h" ++#include "modulesystem/ModuleManager.h" ++#include "modulesystem/ViewModule.h" ++#include "utils/Logger.h" ++#include "utils/Retranslator.h" ++#include "utils/System.h" ++#include "utils/Yaml.h" ++#include "viewpages/ExecutionViewStep.h" ++ ++// Optional features of Calamares ++// - Python support with pybind11 ++// - Python support with older Boost implementation ++// - QML support ++#ifdef WITH_PYTHON ++#ifdef WITH_PYBIND11 ++#include "python/PythonJob.h" ++#else ++#include "PythonJob.h" ++#endif ++#endif ++#ifdef WITH_QML ++#include "utils/Qml.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct ModuleConfig ++{ ++ QString moduleName() const { return m_module; } ++ QString configFile() const { return m_jobConfig; } ++ QString language() const { return m_language; } ++ QString globalConfigFile() const { return m_globalConfig; } ++ ++ QString m_module; ++ QString m_jobConfig; ++ QString m_globalConfig; ++ QString m_settingsConfig; ++ QString m_language; ++ QString m_branding; ++ bool m_ui; ++ bool m_pythonInjection; ++}; ++ ++static ModuleConfig ++handle_args( QCoreApplication& a ) ++{ ++ QCommandLineOption debugLevelOption( ++ QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8), ignored.", "level" ); ++ QCommandLineOption settingsOption( { QStringLiteral( "S" ), QStringLiteral( "settings" ) }, ++ QStringLiteral( "Settings.conf document" ), ++ QString( "settings.conf" ) ); ++ QCommandLineOption globalOption( { QStringLiteral( "g" ), QStringLiteral( "global" ) }, ++ QStringLiteral( "Global storage settings document" ), ++ "global.yaml" ); ++ QCommandLineOption jobOption( ++ { QStringLiteral( "j" ), QStringLiteral( "job" ) }, QStringLiteral( "Job settings document" ), "job.yaml" ); ++ QCommandLineOption langOption( { QStringLiteral( "l" ), QStringLiteral( "language" ) }, ++ QStringLiteral( "Language (global)" ), ++ "languagecode" ); ++ QCommandLineOption brandOption( { QStringLiteral( "b" ), QStringLiteral( "branding" ) }, ++ QStringLiteral( "Branding directory" ), ++ "path/to/branding.desc", ++ "src/branding/default/branding.desc" ); ++ QCommandLineOption uiOption( { QStringLiteral( "U" ), QStringLiteral( "ui" ) }, QStringLiteral( "Enable UI" ) ); ++ QCommandLineOption slideshowOption( { QStringLiteral( "s" ), QStringLiteral( "slideshow" ) }, ++ QStringLiteral( "Run slideshow module" ) ); ++ QCommandLineParser parser; ++ parser.setApplicationDescription( "Calamares module tester" ); ++ parser.addHelpOption(); ++ parser.addVersionOption(); ++ ++ parser.addOption( debugLevelOption ); ++ parser.addOption( settingsOption ); ++ parser.addOption( globalOption ); ++ parser.addOption( jobOption ); ++ parser.addOption( langOption ); ++ parser.addOption( brandOption ); ++ parser.addOption( uiOption ); ++ parser.addOption( slideshowOption ); ++#ifdef WITH_PYTHON ++ QCommandLineOption pythonOption( { QStringLiteral( "P" ), QStringLiteral( "no-injected-python" ) }, ++ QStringLiteral( "Do not disable potentially-harmful Python commands" ) ); ++ parser.addOption( pythonOption ); ++#endif ++ ++ parser.addPositionalArgument( "module", "Path or name of module to run." ); ++ parser.addPositionalArgument( "job.yaml", "Path of job settings document to use.", "[job.yaml]" ); ++ ++ parser.process( a ); ++ ++ const QStringList args = parser.positionalArguments(); ++ if ( args.isEmpty() && !parser.isSet( slideshowOption ) ) ++ { ++ cError() << "Missing path.\n"; ++ parser.showHelp(); ++ } ++ else if ( args.size() > 2 ) ++ { ++ cError() << "More than one path.\n"; ++ parser.showHelp(); ++ } ++ else ++ { ++ QString jobSettings( parser.value( jobOption ) ); ++ if ( jobSettings.isEmpty() && ( args.size() == 2 ) ) ++ { ++ jobSettings = args.at( 1 ); ++ } ++ ++ bool pythonInjection = true; ++#ifdef WITH_PYTHON ++ if ( parser.isSet( pythonOption ) ) ++ { ++ pythonInjection = false; ++ } ++#endif ++ return ModuleConfig { parser.isSet( slideshowOption ) ? QStringLiteral( "-" ) : args.first(), ++ jobSettings, ++ parser.value( globalOption ), ++ parser.value( settingsOption ), ++ parser.value( langOption ), ++ parser.value( brandOption ), ++ parser.isSet( slideshowOption ) || parser.isSet( uiOption ), ++ pythonInjection }; ++ } ++} ++ ++/** @brief Bogus Job for --slideshow option ++ * ++ * Generally one would use DummyCppJob for this kind of dummy ++ * job, but that class lives in a module so isn't available ++ * in this test application. ++ * ++ * This bogus job just sleeps for 3. ++ */ ++class ExecViewJob : public Calamares::CppJob ++{ ++public: ++ explicit ExecViewJob( const QString& name, unsigned long t = 3 ) ++ : m_name( name ) ++ , m_delay( t ) ++ { ++ } ++ ~ExecViewJob() override; ++ ++ QString prettyName() const override { return m_name; } ++ ++ Calamares::JobResult exec() override ++ { ++ QThread::sleep( m_delay ); ++ return Calamares::JobResult::ok(); ++ } ++ ++ void setConfigurationMap( const QVariantMap& ) override {} ++ ++private: ++ QString m_name; ++ unsigned long m_delay; ++}; ++ ++ExecViewJob::~ExecViewJob() {} ++ ++/** @brief Bogus module for --slideshow option ++ * ++ * Normally the slideshow -- displayed by ExecutionViewStep -- is not ++ * associated with any particular module in the Calamares configuration. ++ * It is added internally by the module manager. For the module-loader ++ * testing application, we need something that pretends to be the ++ * module for the ExecutionViewStep. ++ */ ++class ExecViewModule : public Calamares::Module ++{ ++public: ++ ExecViewModule(); ++ ~ExecViewModule() override; ++ ++ void loadSelf() override; ++ ++ virtual Calamares::ModuleSystem::Type type() const override; ++ virtual Calamares::ModuleSystem::Interface interface() const override; ++ ++ virtual Calamares::JobList jobs() const override; ++ ++protected: ++ void initFrom( const Calamares::ModuleSystem::Descriptor& ) override; ++}; ++ ++ExecViewModule::ExecViewModule() ++ : Calamares::Module() ++{ ++ // Normally the module-loader gives the module an instance key ++ // (out of the settings file, or the descriptor of the module). ++ // We don't have one, so build one -- this gives us "execView@execView". ++ QVariantMap m; ++ const QString execView = QStringLiteral( "execView" ); ++ m.insert( "name", execView ); ++ Calamares::Module::initFrom( Calamares::ModuleSystem::Descriptor::fromDescriptorData( m, execView ), execView ); ++} ++ ++ExecViewModule::~ExecViewModule() {} ++ ++void ++ExecViewModule::initFrom( const Calamares::ModuleSystem::Descriptor& ) ++{ ++} ++ ++void ++ExecViewModule::loadSelf() ++{ ++ auto* viewStep = new Calamares::ExecutionViewStep(); ++ viewStep->setModuleInstanceKey( instanceKey() ); ++ viewStep->setConfigurationMap( m_configurationMap ); ++ viewStep->appendJobModuleInstanceKey( instanceKey() ); ++ Calamares::ViewManager::instance()->addViewStep( viewStep ); ++ m_loaded = true; ++} ++ ++Calamares::Module::Type ++ExecViewModule::type() const ++{ ++ return Module::Type::View; ++} ++ ++Calamares::Module::Interface ++ExecViewModule::interface() const ++{ ++ return Module::Interface::QtPlugin; ++} ++ ++Calamares::JobList ++ExecViewModule::jobs() const ++{ ++ Calamares::JobList l; ++ const auto* gs = Calamares::JobQueue::instance()->globalStorage(); ++ if ( gs && gs->contains( "jobs" ) ) ++ { ++ QVariantList joblist = gs->value( "jobs" ).toList(); ++ for ( const auto& jd : joblist ) ++ { ++ QVariantMap jobdescription = jd.toMap(); ++ if ( jobdescription.contains( "name" ) && jobdescription.contains( "delay" ) ) ++ { ++ l.append( Calamares::job_ptr( new ExecViewJob( jobdescription.value( "name" ).toString(), ++ jobdescription.value( "delay" ).toULongLong() ) ) ); ++ } ++ } ++ } ++ if ( l.count() > 0 ) ++ { ++ return l; ++ } ++ ++ l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "step 1" ) ) ) ); ++ l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "step two" ) ) ) ); ++ l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "locking mutexes" ), 20 ) ) ); ++ l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "unlocking mutexes" ), 1 ) ) ); ++ for ( const QString& s : QStringList { "Harder", "Better", "Faster", "Stronger" } ) ++ { ++ l.append( Calamares::job_ptr( new ExecViewJob( s, 0 ) ) ); ++ } ++ l.append( Calamares::job_ptr( new ExecViewJob( QStringLiteral( "cleaning up" ), 20 ) ) ); ++ return l; ++} ++ ++static Calamares::Module* ++load_module( const ModuleConfig& moduleConfig ) ++{ ++ QString moduleName = moduleConfig.moduleName(); ++ if ( moduleName == "-" ) ++ { ++ return new ExecViewModule; ++ } ++ ++ QFileInfo fi; // This is kept around to hold the path of the module descriptor ++ ++ bool ok = false; ++ QVariantMap descriptor; ++ ++ QStringList moduleDirectories { "./", "src/modules/", "modules/", CMAKE_INSTALL_FULL_LIBDIR "/calamares/modules/" }; ++ for ( const QString& prefix : qAsConst( moduleDirectories ) ) ++ { ++ // Could be a complete path, eg. src/modules/dummycpp/module.desc ++ fi = QFileInfo( prefix + moduleName ); ++ if ( fi.exists() && fi.isFile() ) ++ { ++ descriptor = Calamares::YAML::load( fi, &ok ); ++ } ++ if ( ok ) ++ { ++ break; ++ } ++ ++ // Could be a path without module.desc ++ fi = QFileInfo( prefix + moduleName ); ++ if ( fi.exists() && fi.isDir() ) ++ { ++ fi = QFileInfo( prefix + moduleName + "/module.desc" ); ++ if ( fi.exists() && fi.isFile() ) ++ { ++ descriptor = Calamares::YAML::load( fi, &ok ); ++ } ++ if ( ok ) ++ { ++ break; ++ } ++ else ++ { ++ if ( !fi.exists() ) ++ { ++ cDebug() << "Expected a descriptor file" << fi.path(); ++ } ++ else ++ { ++ cDebug() << "Read descriptor" << fi.path() << "and it was empty."; ++ } ++ } ++ } ++ } ++ ++ if ( !ok ) ++ { ++ cWarning() << "No suitable module descriptor found in" << Logger::DebugList( moduleDirectories ); ++ return nullptr; ++ } ++ ++ QString name = descriptor.value( "name" ).toString(); ++ if ( name.isEmpty() ) ++ { ++ cWarning() << "No name found in module descriptor" << fi.absoluteFilePath(); ++ return nullptr; ++ } ++ ++ QString moduleDirectory = fi.absolutePath(); ++ QString configFile( moduleConfig.configFile().isEmpty() ? moduleDirectory + '/' + name + ".conf" ++ : moduleConfig.configFile() ); ++ ++ cDebug() << Logger::SubEntry << "Module" << moduleName << "job-configuration:" << configFile; ++ ++ Calamares::Module* module = Calamares::moduleFromDescriptor( ++ Calamares::ModuleSystem::Descriptor::fromDescriptorData( descriptor, fi.absoluteFilePath() ), ++ name, ++ configFile, ++ moduleDirectory ); ++ ++ return module; ++} ++ ++static bool ++is_ui_option( const char* s ) ++{ ++ return !qstrcmp( s, "--ui" ) || !qstrcmp( s, "-U" ); ++} ++ ++static bool ++is_slideshow_option( const char* s ) ++{ ++ return !qstrcmp( s, "--slideshow" ) || !qstrcmp( s, "-s" ); ++} ++ ++/** @brief Create the right kind of QApplication ++ * ++ * Does primitive parsing of argv[] to find the --ui option and returns ++ * a UI-enabled application if it does. ++ * ++ * @p argc must be a reference (to main's argc) because the QCoreApplication ++ * constructors take a reference as well, and that would otherwise be a ++ * reference to a temporary. ++ */ ++QCoreApplication* ++createApplication( int& argc, char* argv[] ) ++{ ++ for ( int i = 1; i < argc; ++i ) ++ { ++ if ( is_slideshow_option( argv[ i ] ) || is_ui_option( argv[ i ] ) ) ++ { ++ auto* aw = new QApplication( argc, argv ); ++ aw->setQuitOnLastWindowClosed( true ); ++ return aw; ++ } ++ } ++ return new QCoreApplication( argc, argv ); ++} ++ ++#ifdef WITH_PYTHON ++static const char pythonPreScript[] = R"%( ++# This is Python code executed by Python modules *before* the ++# script file (e.g. main.py) is executed. ++# ++# Calls to suprocess methods that execute something are ++# suppressed and logged -- scripts should really be using libcalamares ++# methods instead. ++_calamares_subprocess = __import__("subprocess", globals(), locals(), [], 0) ++import sys ++import libcalamares ++class fake_subprocess(object): ++ PIPE = object() ++ STDOUT = object() ++ STDERR = object() ++ class CompletedProcess(object): ++ returncode = 0 ++ stdout = "" ++ stderr = "" ++ @staticmethod ++ def call(*args, **kwargs): ++ libcalamares.utils.debug("subprocess.call(%r,%r) X ignored" % (args, kwargs)) ++ return 0 ++ @staticmethod ++ def check_call(*args, **kwargs): ++ libcalamares.utils.debug("subprocess.check_call(%r,%r) X ignored" % (args, kwargs)) ++ return 0 ++ # This is a 3.5-and-later method, is supposed to return a CompletedProcess ++ @staticmethod ++ def run(*args, **kwargs): ++ libcalamares.utils.debug("subprocess.run(%r,%r) X ignored" % (args, kwargs)) ++ return fake_subprocess.CompletedProcess() ++for attr in ("CalledProcessError",): ++ setattr(fake_subprocess,attr,getattr(_calamares_subprocess,attr)) ++sys.modules["subprocess"] = fake_subprocess ++libcalamares.utils.debug('pre-script for testing purposes injected') ++ ++)%"; ++#endif ++ ++int ++main( int argc, char* argv[] ) ++{ ++ QCoreApplication* application = createApplication( argc, argv ); ++ ++ Logger::setupLogLevel( Logger::LOGVERBOSE ); ++ ++ ModuleConfig module = handle_args( *application ); ++ if ( module.moduleName().isEmpty() ) ++ { ++ return 1; ++ } ++ ++ std::unique_ptr< Calamares::Settings > settings_p( Calamares::Settings::init( module.m_settingsConfig ) ); ++ std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) ); ++ std::unique_ptr< Calamares::System > system_p( new Calamares::System( settings_p->doChroot() ) ); ++ ++ QMainWindow* mainWindow = nullptr; ++ ++ auto* gs = jobqueue_p->globalStorage(); ++ if ( !module.globalConfigFile().isEmpty() ) ++ { ++ gs->loadYaml( module.globalConfigFile() ); ++ } ++ if ( !module.language().isEmpty() ) ++ { ++ QVariantMap vm; ++ vm.insert( "LANG", module.language() ); ++ gs->insert( "localeConf", vm ); ++ } ++ ++#ifdef WITH_PYTHON ++ if ( module.m_pythonInjection ) ++ { ++#ifdef WITH_PYBIND11 ++ Calamares::Python::Job::setInjectedPreScript( pythonPreScript ); ++#else ++ // Old Boost approach ++ Calamares::PythonJob::setInjectedPreScript( pythonPreScript ); ++#endif ++ } ++#endif ++#ifdef WITH_QML ++ Calamares::initQmlModulesDir(); // don't care if failed ++#endif ++ ++ cDebug() << "Calamares module-loader testing" << module.moduleName(); ++ Calamares::Module* m = load_module( module ); ++ if ( !m ) ++ { ++ cError() << "Could not load module" << module.moduleName(); ++ return 1; ++ } ++ ++ cDebug() << Logger::SubEntry << "got" << m->name() << m->typeString() << m->interfaceString(); ++ if ( m->type() == Calamares::Module::Type::View ) ++ { ++ // If we forgot the --ui, any ViewModule will core dump as it ++ // tries to create the widget **which won't be used anyway**. ++ // ++ // To avoid that crash, re-create the QApplication, now with GUI ++ if ( !qobject_cast< QApplication* >( application ) ) ++ { ++ auto* replace_app = new QApplication( argc, argv ); ++ replace_app->setQuitOnLastWindowClosed( true ); ++ application = replace_app; ++ } ++ mainWindow = module.m_ui ? new QMainWindow() : nullptr; ++ if ( mainWindow ) ++ { ++ mainWindow->installEventFilter( Calamares::Retranslator::instance() ); ++ } ++ ++ (void)new Calamares::Branding( module.m_branding ); ++ auto* modulemanager = new Calamares::ModuleManager( QStringList(), nullptr ); ++ (void)Calamares::ViewManager::instance( mainWindow ); ++ modulemanager->addModule( m ); ++ } ++ ++ if ( !m->isLoaded() ) ++ { ++ m->loadSelf(); ++ } ++ ++ if ( !m->isLoaded() ) ++ { ++ cError() << "Module" << module.moduleName() << "could not be loaded."; ++ return 1; ++ } ++ ++ if ( mainWindow ) ++ { ++ auto* vm = Calamares::ViewManager::instance(); ++ vm->onInitComplete(); ++ QWidget* w = vm->currentStep()->widget(); ++ w->setParent( mainWindow ); ++ mainWindow->setCentralWidget( w ); ++ w->show(); ++ mainWindow->show(); ++ return application->exec(); ++ } ++ ++ using TR = Logger::DebugRow< const char*, const QString >; ++ ++ cDebug() << Logger::SubEntry << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() ) ++ << TR( "interface", m->interfaceString() ); ++ ++ Calamares::JobQueue::instance()->enqueue( 100, m->jobs() ); ++ ++ QObject::connect( Calamares::JobQueue::instance(), ++ &Calamares::JobQueue::finished, ++ [ application ]() ++ { QTimer::singleShot( std::chrono::seconds( 3 ), application, &QApplication::quit ); } ); ++ QTimer::singleShot( 0, []() { Calamares::JobQueue::instance()->start(); } ); ++ ++ return application->exec(); ++} +diff --git a/src/libcalamares/CalamaresAbout.cpp b/src/libcalamares/CalamaresAbout.cpp +index 595efc7..65a1b9d 100644 +--- a/src/libcalamares/CalamaresAbout.cpp ++++ b/src/libcalamares/CalamaresAbout.cpp +@@ -65,6 +65,7 @@ Calamares::aboutString() + { + return substituteVersions( QCoreApplication::translate( "AboutData", s_header ) ) + aboutMaintainers() + + QCoreApplication::translate( "AboutData", s_footer ); ++ // return aboutMaintainers()+ QCoreApplication::translate( "AboutData", s_footer ); + } + + const QString +diff --git a/src/libcalamaresui/modulesystem/CppJobModule.cpp b/src/libcalamaresui/modulesystem/CppJobModule.cpp +index b35a457..c211006 100644 +--- a/src/libcalamaresui/modulesystem/CppJobModule.cpp ++++ b/src/libcalamaresui/modulesystem/CppJobModule.cpp +@@ -53,6 +53,10 @@ CppJobModule::loadSelf() + cDebug() << "Could not load module:" << m_loader->errorString(); + return; + } ++ // cDebug() << "CppJobModule loading self for instance" << instanceKey() ++ // << "\nCppJobModule at address" << this ++ // << "\nCalamares::PluginFactory at address" << pf ++ // << "\nCppJob at address" << cppJob; + + cppJob->setModuleInstanceKey( instanceKey() ); + cppJob->setConfigurationMap( m_configurationMap ); +diff --git a/src/modules/displaymanager/main.py b/src/modules/displaymanager/main.py +index 6ca279e..02fec0f 100644 +--- a/src/modules/displaymanager/main.py ++++ b/src/modules/displaymanager/main.py +@@ -410,6 +410,11 @@ class DMgdm(DisplayManager): + if self.config is None: + raise ValueError( "No config file for GDM has been set." ) + ++ ++ libcalamares.utils.target_env_call( ++ ['hostnamectl', 'set-hostname', username] ++ ) ++ + # Systems with GDM as Desktop Manager + gdm_conf_path = os.path.join(self.root_mount_point, self.config) + +@@ -571,6 +576,11 @@ class DMlightdm(DisplayManager): + # Ideally, we should use configparser for the ini conf file, + # but we just do a simple text replacement for now, as it + # worksforme(tm) ++ ++ libcalamares.utils.target_env_call( ++ ['hostnamectl', 'set-hostname', username] ++ ) ++ + lightdm_conf_path = os.path.join( + self.root_mount_point, "etc/lightdm/lightdm.conf" + ) +diff --git a/src/modules/keyboard/KeyboardPage.cpp b/src/modules/keyboard/KeyboardPage.cpp +index be60521..3f06158 100644 +--- a/src/modules/keyboard/KeyboardPage.cpp ++++ b/src/modules/keyboard/KeyboardPage.cpp +@@ -48,6 +48,9 @@ KeyboardPage::KeyboardPage( Config* config, QWidget* parent ) + { + ui->setupUi( this ); + this->setContentsMargins(50,0,50,0); ++ // Keyboard Preview ++ // ui->KBPreviewLayout->addWidget( m_keyboardPreview ); ++ + + { + auto* model = config->keyboardModels(); +@@ -90,11 +93,27 @@ KeyboardPage::KeyboardPage( Config* config, QWidget* parent ) + &QItemSelectionModel::currentChanged, + [ this ]( const QModelIndex& current ) + { m_config->keyboardLayouts()->setCurrentIndex( current.row() ); } ); ++ // connect( config->keyboardLayouts(), ++ // &KeyboardLayoutModel::currentIndexChanged, ++ // [ this ]( int index ) ++ // { ++ // ui->layoutSelector->setCurrentIndex( m_config->keyboardLayouts()->index( index ) ); ++ // m_keyboardPreview->setLayout( m_config->keyboardLayouts()->key( index ) ); ++ // m_keyboardPreview->setVariant( ++ // m_config->keyboardVariants()->key( m_config->keyboardVariants()->currentIndex() ) ); ++ // } ); + + connect( ui->variantSelector->selectionModel(), + &QItemSelectionModel::currentChanged, + [ this ]( const QModelIndex& current ) + { m_config->keyboardVariants()->setCurrentIndex( current.row() ); } ); ++ // connect( config->keyboardVariants(), ++ // &KeyboardVariantsModel::currentIndexChanged, ++ // [ this ]( int index ) ++ // { ++ // ui->variantSelector->setCurrentIndex( m_config->keyboardVariants()->index( index ) ); ++ // m_keyboardPreview->setVariant( m_config->keyboardVariants()->key( index ) ); ++ // } ); + + connect( ui->groupSelector, + QOverload< int >::of( &QComboBox::currentIndexChanged ), +diff --git a/src/modules/keyboard/KeyboardPage.ui b/src/modules/keyboard/KeyboardPage.ui +index 70cfca3..1d6afbf 100644 +--- a/src/modules/keyboard/KeyboardPage.ui ++++ b/src/modules/keyboard/KeyboardPage.ui +@@ -45,6 +45,9 @@ SPDX-License-Identifier: GPL-3.0-or-later + + + ++ + + + +diff --git a/src/modules/locale/Config.cpp b/src/modules/locale/Config.cpp +index 0d70ff3..fbcbf48 100644 +--- a/src/modules/locale/Config.cpp ++++ b/src/modules/locale/Config.cpp +@@ -426,6 +426,33 @@ Config::currentLCStatus() const + .arg( localeLabel( m_selectedLocaleConfiguration.lc_numeric ) ); + } + ++ ++static QString ++getTranRes(QString& filePath,QString& keyWord) { ++ QFile file(filePath); ++ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { ++ qDebug() << "无法打开文件"; ++ return QString(); ++ } ++ ++ QTextStream in(&file); ++ QString currentLine; ++ QString resLine; ++ ++ while (!in.atEnd()) { ++ currentLine = in.readLine(); ++ if (currentLine.contains(keyWord, Qt::CaseInsensitive)) { ++ in.readLine(); ++ resLine = in.readLine(); ++ file.close(); ++ return resLine.trimmed().replace("","").replace("",""); ++ } ++ } ++ ++ return keyWord; ++} ++ ++ + QString + Config::currentTimeZoneStatus() const + { +@@ -434,6 +461,22 @@ Config::currentTimeZoneStatus() const + { + zone = "Hong Kong(China)"; + } ++ ++ ++ zone.replace("_"," "); ++ QString translationFile = ""; ++ if( m_selectedLocaleConfiguration.language() == "zh_CN.utf8"){ ++ translationFile = "tz_zh_CN.ts"; ++ } else if( m_selectedLocaleConfiguration.language() == "zh_TW.utf8"){ ++ translationFile="tz_zh_TW.ts"; ++ } ++ ++ QString transFilePath = QStringLiteral("/usr/share/calamares/") + translationFile; ++ cDebug() << "transFilePath" << transFilePath; ++ if(translationFile != ""){ ++ zone = getTranRes(transFilePath, zone); ++ } ++ + return tr("The timezone will be set to %1.","@info") + .arg( zone ); + } +diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp +index ed50574..0568067 100644 +--- a/src/modules/locale/LocalePage.cpp ++++ b/src/modules/locale/LocalePage.cpp +@@ -32,6 +32,13 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + { + QBoxLayout* mainLayout = new QVBoxLayout; + mainLayout->setContentsMargins(50,0,50,0); ++ //QBoxLayout* tzwLayout = new QHBoxLayout; ++ //m_tzWidget = new TimeZoneWidget( m_config->zonesModel(), this ); ++ //tzwLayout->addStretch(); ++ //tzwLayout->addWidget( m_tzWidget ); ++ //tzwLayout->addStretch(); ++ // Adjust for margins and spacing in this page ++ //m_tzWidget->setMinimumHeight( m_tzWidget->minimumHeight() + 12 ); // 2 * spacing + + QBoxLayout* zoneAndRegionLayout = new QVBoxLayout; + m_regionLabel = new QLabel( this ); +@@ -83,7 +90,7 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + m_formatsChangeButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + formatsLayout->addWidget( m_formatsChangeButton ); + formatsLayout->addSpacing(20); +- ++ //mainLayout->addLayout( tzwLayout ); + mainLayout->addStretch(); + mainLayout->addLayout( zoneAndRegionLayout ); + mainLayout->addStretch(); +@@ -93,7 +100,7 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + mainLayout->addSpacing(20); + mainLayout->addLayout( timezoneLayout ); + mainLayout->addStretch(); +- ++ //setMinimumWidth( m_tzWidget->width() ); + setLayout( mainLayout ); + + m_localeChangeButton->hide(); +@@ -107,15 +114,20 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) + zones->setRegion( location->region() ); + m_regionCombo->setModel( regions ); + m_zoneCombo->setModel( zones ); +- ++ //m_tzWidget->setCurrentLocation( location ); + locationChanged( location ); // doesn't inform TZ widget + } + + connect( config, &Config::currentLCStatusChanged, m_formatsLabel, &QLabel::setText ); + connect( config, &Config::currentLanguageStatusChanged, m_localeLabel, &QLabel::setText ); + connect( config, &Config::currentZoneChanged, m_timezoneLabel , &QLabel::setText); +- ++ //connect( config, &Config::currentLocationChanged, m_tzWidget, &TimeZoneWidget::setCurrentLocation ); + connect( config, &Config::currentLocationChanged, this, &LocalePage::locationChanged ); ++ // connect( m_tzWidget, ++ // &TimeZoneWidget::locationChanged, ++ // config, ++ // QOverload< const Calamares::Locale::TimeZoneData* >::of( &Config::setCurrentLocation ) ); ++ + connect( m_regionCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::regionChanged ); + connect( m_zoneCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::zoneChanged ); + +diff --git a/src/modules/packagechooser/packagechooser.conf b/src/modules/packagechooser/packagechooser.conf +index aa048e2..3f35638 100644 +--- a/src/modules/packagechooser/packagechooser.conf ++++ b/src/modules/packagechooser/packagechooser.conf +@@ -147,6 +147,8 @@ labels: + # + # An item for AppStream may also contain an *id* and a *screenshot* + # key which will override the data from AppStream. ++# liberation-fonts, gnu-*-fonts, google-*-fonts, adwaita-icon-theme, atk, atkmm, at-spi2-atk, at-spi2-core, baobab, abattis-cantarell-fonts, cheese, clutter, clutter-gst3, clutter-gtk, cogl, dconf, dconf-editor, devhelp, eog, epiphany, evince, evolution-data-server, file-roller, folks, gcab, gcr, gdk-pixbuf2, gdm, gedit, geocode-glib, gfbgraph, gjs, glib2, glibmm24, glib-networking, gmime30, gnome-autoar, gnome-backgrounds, gnome-bluetooth, gnome-builder, gnome-calculator, gnome-calendar, gnome-characters, gnome-clocks, gnome-color-manager, gnome-contacts, gnome-control-center, gnome-desktop3, gnome-disk-utility, gnome-font-viewer, gnome-getting-started-docs, gnome-initial-setup, gnome-keyring, gnome-logs, gnome-menus, gnome-music, gnome-online-accounts, gnome-online-miners, gnome-photos, gnome-remote-desktop, gnome-screenshot, gnome-session, gnome-settings-daemon, gnome-shell, gnome-shell-extensions, gnome-software, gnome-system-monitor, gnome-terminal, gnome-tour, gnome-user-docs, gnome-user-share, gnome-video-effects, gnome-weather, gobject-introspection, gom, grilo, grilo-plugins, gsettings-desktop-schemas, gsound, gspell, gssdp, gtk3, gtk4, gtk-doc, gtkmm30, gtksourceview4, gtk-vnc2, gupnp, gupnp-av, gupnp-dlna, gvfs, json-glib, libchamplain, libdazzle, libgdata, libgee, libgnomekbd, libgsf, libgtop2, libgweather, libgxps, libhandy, libmediaart, libnma, libnotify, libpeas, librsvg2, libsecret, libsigc++20, libsoup, mm-common, mutter, nautilus, orca, pango, pangomm, libphodav, python3-pyatspi, python3-gobject, rest, rygel, simple-scan, sushi, sysprof, tepl, totem, totem-pl-parser, tracker3, tracker3-miners, vala, vte291, yelp, yelp-tools, yelp-xsl, zenity, devstation-config, ibus-libpinyin ] ++ + items: + - id: "" + # packages: [] # This item installs no packages +@@ -157,11 +159,25 @@ items: + description[nl]: "Kies eventueel een desktop-omgeving uit deze lijst. Als u geen desktop-omgeving wenst te gebruiken, kies er dan geen. In dat geval start het systeem straks op in tekst-modus en kunt u later alsnog een desktop-omgeving installeren." + description[zh]: "请选择一个桌面环境。如果您不想安装桌面环境也没关系,您可以稍后再为系统安装桌面环境。" + screenshot: ":/images/Minimal-Install.png" +- ++ # - id: kde ++ # packages: [ kde-frameworks, kde-plasma, kde-gear ] ++ # name: Plasma Desktop ++ # description: "KDE Plasma Desktop, simple by default, a clean work area for real-world usage which intends to stay out of your way. Plasma is powerful when needed, enabling the user to create the workflow that makes them more effective to complete their tasks." ++ # screenshot: ":/images/Plasma.png" + - id: gnome +- packages: [ checkpolicy, code, xorg-*, dejavu-fonts, liberation-fonts, gnu-*-fonts, google-*-fonts, adwaita-icon-theme, atk, atkmm, at-spi2-atk, at-spi2-core, baobab, abattis-cantarell-fonts, cheese, clutter, clutter-gst3, clutter-gtk, cogl, dconf, dconf-editor, devhelp, eog, epiphany, evince, evolution-data-server, file-roller, folks, gcab, gcr, gdk-pixbuf2, gdm, gedit, geocode-glib, gfbgraph, gjs, glib2, glibmm24, glib-networking, gmime30, gnome-autoar, gnome-backgrounds, gnome-bluetooth, gnome-builder, gnome-calculator, gnome-calendar, gnome-characters, gnome-clocks, gnome-color-manager, gnome-contacts, gnome-control-center, gnome-desktop3, gnome-disk-utility, gnome-font-viewer, gnome-getting-started-docs, gnome-initial-setup, gnome-keyring, gnome-logs, gnome-menus, gnome-music, gnome-online-accounts, gnome-online-miners, gnome-photos, gnome-remote-desktop, gnome-screenshot, gnome-session, gnome-settings-daemon, gnome-shell, gnome-shell-extensions, gnome-software, gnome-system-monitor, gnome-terminal, gnome-tour, gnome-user-docs, gnome-user-share, gnome-video-effects, gnome-weather, gobject-introspection, gom, grilo, grilo-plugins, gsettings-desktop-schemas, gsound, gspell, gssdp, gtk3, gtk4, gtk-doc, gtkmm30, gtksourceview4, gtk-vnc2, gupnp, gupnp-av, gupnp-dlna, gvfs, json-glib, libchamplain, libdazzle, libgdata, libgee, libgnomekbd, libgsf, libgtop2, libgweather, libgxps, libhandy, libmediaart, libnma, libnotify, libpeas, librsvg2, libsecret, libsigc++20, libsoup, mm-common, mutter, nautilus, orca, pango, pangomm, libphodav, python3-pyatspi, python3-gobject, rest, rygel, simple-scan, sushi, sysprof, tepl, totem, totem-pl-parser, tracker3, tracker3-miners, vala, vte291, yelp, yelp-tools, yelp-xsl, zenity, devstation-config, ibus-libpinyin ] ++ packages: [ checkpolicy, code, dejavu-fonts, liberation-fonts, gnome-shell, gnome-session, gnome-terminal, gnome-software, gnome-menus, nautilus, xdg-utils, google-droid-sans-fonts, google-noto-fonts-common, google-noto-sans-arabic-vf-fonts, google-noto-sans-armenian-vf-fonts, google-noto-sans-bengali-vf-fonts, google-noto-sans-canadian-aboriginal-vf-fonts, google-noto-sans-cherokee-vf-fonts, google-noto-sans-devanagari-vf-fonts, google-noto-sans-ethiopic-vf-fonts, google-noto-sans-georgian-vf-fonts, google-noto-sans-hebrew-vf-fonts, google-noto-sans-kannada-vf-fonts, google-noto-sans-khmer-vf-fonts, google-noto-sans-lao-vf-fonts, google-noto-sans-math-fonts, google-noto-sans-mono-vf-fonts, google-noto-sans-sinhala-vf-fonts, google-noto-sans-symbols2-fonts, google-noto-sans-symbols-vf-fonts, google-noto-sans-tamil-vf-fonts, google-noto-sans-thaana-vf-fonts, google-noto-sans-thai-vf-fonts, google-noto-sans-vf-fonts, google-noto-serif-armenian-vf-fonts, google-noto-serif-ethiopic-vf-fonts, google-noto-serif-georgian-vf-fonts, google-noto-serif-gujarati-vf-fonts, google-noto-serif-gurmukhi-vf-fonts, google-noto-serif-hebrew-vf-fonts, google-noto-serif-kannada-vf-fonts, google-noto-serif-khmer-vf-fonts, google-noto-serif-lao-vf-fonts, google-noto-serif-sinhala-vf-fonts, google-noto-serif-tamil-vf-fonts, google-noto-serif-thai-vf-fonts, google-noto-serif-vf-fonts, gdm, ibus-libpinyin, webp-pixbuf-loader, firefox, devstation-config, wqy-zenhei-fonts ] + name: DevStation + name[zh]: DevStation + description: GNU Networked Object Modeling Environment Desktop + description[zh]: Devstation系统桌面 + screenshot: ":/images/gnome.png" ++ #- id: ukui ++ # packages: [ ukui ] ++ # name: UKUI ++ # description: Linux Desktop ++ # screenshot: ":/images/UKUI.png" ++ # - id: calamares ++ # appdata: ../io.calamares.calamares.appdata.xml ++ # screenshot: ":/images/calamares.png" ++ # - id: kate ++ # appstream: org.kde.kwrite.desktop +diff --git a/src/modules/packagechooser/packagechooser.qrc b/src/modules/packagechooser/packagechooser.qrc +index 2f76726..b5c4a9c 100644 +--- a/src/modules/packagechooser/packagechooser.qrc ++++ b/src/modules/packagechooser/packagechooser.qrc +@@ -1,12 +1,7 @@ + + + images/no-selection.png +- images/calamares.png +- + images/gnome.png +- +- +- + images/Minimal-Install.png + + +diff --git a/src/modules/packages/main.py b/src/modules/packages/main.py +index 1fbe276..2c6e6ad 100644 +--- a/src/modules/packages/main.py ++++ b/src/modules/packages/main.py +@@ -756,7 +756,7 @@ def subst_locale_orig(plist): + return ret + + +-def handle_packagechooser(entry): ++def handle_packagechooser(): + """ + Handle special logic for entries with source "packagechooser@packagechooser". + Modifies the entry to include specific pre- and post-scripts. +@@ -764,13 +764,11 @@ def handle_packagechooser(entry): + :param entry: dict + The operation entry to process. + """ +- if "install" in entry: +- item = { +- "package": entry["install"], +- "pre-script": "", +- "post-script": ["/bin/bash /etc/add_selinux_policy.sh", "systemctl enable gdm", "systemctl set-default graphical.target"] +- } +- entry["install"] = [item] ++ item = { ++ "pre-script": "", ++ "post-script": ["/bin/bash /etc/add_selinux_policy.sh", "systemctl enable gdm", "systemctl set-default graphical.target"] ++ } ++ return item + + + def run_operations(pkgman, entry, options): +diff --git a/src/modules/packages/packages.conf b/src/modules/packages/packages.conf +index 490c289..31e51c2 100644 +--- a/src/modules/packages/packages.conf ++++ b/src/modules/packages/packages.conf +@@ -215,7 +215,7 @@ operations: + - coreutils + - efibootmgr + - shim +- - java-11-openjdk-devel ++ - java-21-openjdk-devel + - vim + - gdb + - perf +@@ -229,5 +229,3 @@ operations: + options: + - --nogpgcheck + - --setopt=sslverify=0 +- - --disablerepo=* +- - --enablerepo=local-repo +diff --git a/src/modules/partition/core/DeviceList.cpp b/src/modules/partition/core/DeviceList.cpp +index 16723c7..1885949 100644 +--- a/src/modules/partition/core/DeviceList.cpp ++++ b/src/modules/partition/core/DeviceList.cpp +@@ -43,6 +43,17 @@ hasRootPartition( Device* device ) + return false; + } + ++/** ++ * Does the given @p device path should point to a device ++ */ ++static bool ++isValidDevice(const QString& devicePath) ++{ ++ auto result = Calamares::System::runCommand({ "blkid", devicePath }, std::chrono::seconds(30)); ++ ++ return result.getExitCode() == 0 && !result.getOutput().isEmpty(); ++} ++ + /** @brief Check if @p path holds an iso9660 filesystem + * + * The @p path should point to a device; blkid is used to check the FS type. +@@ -187,7 +198,17 @@ getDevices( DeviceType which ) + } + else + { +- ++it; ++ const QString devicePath = (*it)->deviceNode(); ++ ++ if (!isValidDevice(devicePath)) ++ { ++ cDebug() << Logger::SubEntry << "Skipping device due to blkid failure: " << devicePath; ++ it = removeInAllModes(devices, it); ++ } ++ else ++ { ++ ++it; ++ } + } + } + cDebug() << Logger::SubEntry << "there are" << devices.count() << "devices left."; +diff --git a/src/modules/partition/jobs/ClearMountsJob.cpp b/src/modules/partition/jobs/ClearMountsJob.cpp +index ce1355b..d36c4e5 100644 +--- a/src/modules/partition/jobs/ClearMountsJob.cpp ++++ b/src/modules/partition/jobs/ClearMountsJob.cpp +@@ -260,7 +260,7 @@ STATICTEST MessageAndPath + tryUmount( const QString& partPath ) + { + QProcess process; +- process.start( "umount", { partPath } ); ++ process.start( "umount", { "-l", partPath } ); + process.waitForFinished(); + if ( process.exitCode() == 0 ) + { +@@ -317,6 +317,51 @@ tryCryptoClose( const QString& mapperPath ) + return {}; + } + ++STATICTEST MessageAndPath ++tryClearLVM(const QString& LVMPath) ++{ ++ tryUmount( LVMPath ); ++ ++ QProcess process; ++ process.start( "dmsetup", {"remove", LVMPath } ); ++ process.waitForFinished(); ++ if ( process.exitCode() == 0 ) ++ { ++ return { QT_TRANSLATE_NOOP( "ClearMountsJob", "Successfully removed LVM %1." ), LVMPath }; ++ } ++ return {}; ++} ++ ++STATICTEST MessageAndPath ++mpathClear(const QString& deviceName) ++{ ++ QString devicePath = "/dev/" + deviceName; ++ QProcess process; ++ process.start("multipath", { "-ll", devicePath } ); ++ process.waitForFinished(); ++ if( process.exitCode() == 0 ) ++ { ++ QStringList multiPathLines = QString::fromLocal8Bit( process.readAllStandardOutput() ).split( '\n' ); ++ QStringList firstLines = multiPathLines.first().split(' '); ++ QString mpath = firstLines.first(); ++ return tryClearLVM("/dev/mapper/" + mpath); ++ } ++ return {}; ++} ++ ++STATICTEST MessageAndPath ++diskClear(const QString& diskPath) ++{ ++ QString devicePath = "/dev/" + diskPath; ++ QProcess process; ++ process.start( "wipefs", { "-af", devicePath } ); ++ process.waitForFinished(); ++ if( process.exitCode() == 0 ) ++ { ++ return { QT_TRANSLATE_NOOP( "ClearMountsJob", "Successfully cleared %1." ), diskPath }; ++ } ++ return {}; ++} + STATICTEST MessageAndPath + tryVGDisable( const QString& vgName ) + { +@@ -380,12 +425,14 @@ ClearMountsJob::exec() + QList< MessageAndPath > goodNews; + + apply( getCryptoDevices( m_mapperExceptions ), tryCryptoClose, goodNews ); +- apply( getLVMVolumes(), tryUmount, goodNews ); ++ apply( getLVMVolumes(), tryClearLVM, goodNews ); + apply( getPVGroups( deviceName ), tryVGDisable, goodNews ); + + apply( getCryptoDevices( m_mapperExceptions ), tryCryptoClose, goodNews ); + apply( getPartitionsForDevice( deviceName ), tryUmount, goodNews ); + apply( getSwapsForDevice( m_deviceNode ), tryClearSwap, goodNews ); ++ diskClear(deviceName); ++ mpathClear(deviceName); + + Calamares::JobResult ok = Calamares::JobResult::ok(); + ok.setMessage( tr( "Cleared all mounts for %1" ).arg( m_deviceNode ) ); +diff --git a/src/modules/unpackfs/main.py b/src/modules/unpackfs/main.py +index 4c5518e..7db5f2e 100644 +--- a/src/modules/unpackfs/main.py ++++ b/src/modules/unpackfs/main.py +@@ -207,7 +207,7 @@ def file_copy(source, entry, progress_cb): + # `source` *must* end with '/' otherwise a directory named after the source + # will be created in `dest`: ie if `source` is "/foo/bar" and `dest` is + # "/dest", then files will be copied in "/dest/bar". +- if not source.endswith("/") and not os.path.isfile(source): ++ if source and not source.endswith("/") and not os.path.isfile(source): + source += "/" + + num_files_total_local = 0 +@@ -395,8 +395,6 @@ class UnpackOperation: + for entry in self.entries: + status = _("Starting to unpack {}").format(entry.source) + libcalamares.job.setprogress( ( 1.0 * complete ) / len(self.entries) ) +- entry.do_mount(source_mount_path) +- entry.do_count() # Fill in the entry.total + + self.report_progress() + error_msg = self.unpack_image(entry, entry.mountPoint) +@@ -437,7 +435,7 @@ class UnpackOperation: + + return file_copy(source, entry, progress_cb) + finally: +- if not entry.is_file(): ++ if imgmountdir and not entry.is_file() and os.path.isdir(imgmountdir): + subprocess.check_call(["umount", "-l", imgmountdir]) + + +diff --git a/src/modules/users/CreateUserJob.cpp b/src/modules/users/CreateUserJob.cpp +index 4e36c50..9699141 100644 +--- a/src/modules/users/CreateUserJob.cpp ++++ b/src/modules/users/CreateUserJob.cpp +@@ -79,6 +79,23 @@ createUser( const QString& loginName, const QString& fullName, const QString& sh + return Calamares::JobResult::ok(); + } + ++static Calamares::JobResult ++config_root_bash(const QString& loginName) ++{ ++ QStringList copyBashFilesCommand; ++ copyBashFilesCommand << "cp" ++ << QString("/home/%1/.bashrc").arg(loginName) ++ << QString("/home/%1/.bash_profile").arg(loginName) ++ << "/root/"; ++ auto commandResult = Calamares::System::instance()->targetEnvCommand( copyBashFilesCommand ); ++ if ( commandResult.getExitCode() ) ++ { ++ cError() << "copy bash config file failed" << commandResult.getExitCode(); ++ return commandResult.explainProcess( copyBashFilesCommand, std::chrono::seconds( 10 ) /* bogus timeout */ ); ++ } ++ return Calamares::JobResult::ok(); ++} ++ + static Calamares::JobResult + setUserGroups( const QString& loginName, const QStringList& groups ) + { +@@ -155,6 +172,7 @@ CreateUserJob::exec() + QString userGroup = QString( "%1:%2" ).arg( m_config->loginName() ).arg( m_config->loginName() ); + QString homeDir = QString( "/home/%1" ).arg( m_config->loginName() ); + auto commandResult = Calamares::System::instance()->targetEnvCommand( { "chown", "-R", userGroup, homeDir } ); ++ config_root_bash(m_config->loginName()); + if ( commandResult.getExitCode() ) + { + cError() << "chown failed" << commandResult.getExitCode(); +diff --git a/src/modules/users/UsersPage.cpp b/src/modules/users/UsersPage.cpp +index 72fb3e0..a4edddf 100644 +--- a/src/modules/users/UsersPage.cpp ++++ b/src/modules/users/UsersPage.cpp +@@ -31,6 +31,9 @@ + #include + #include + #include ++#include ++#include ++#include + + /** @brief Add an error message and pixmap to a label. */ + static inline void +@@ -83,6 +86,105 @@ UsersPage::UsersPage( Config* config, QWidget* parent ) + { + ui->setupUi( this ); + this->setContentsMargins(50,15,50,0); ++ ++ ++ //初始化参数 ++ userPassword=false; ++ userVertifyPassword=false; ++ rootPassword=false; ++ rootVertifyPassword=false; ++ ++ userButton=new QPushButton(); ++ userVertifyButton=new QPushButton(); ++ rootButton=new QPushButton(); ++ rootVertifyButton=new QPushButton(); ++ ++ hIcon = QIcon(imagePath + "password-hide.png"); ++ sIcon = QIcon(imagePath + "password-show.png"); ++ userButton->setIcon(hIcon); ++ userVertifyButton->setIcon(hIcon); ++ rootButton->setIcon(hIcon); ++ rootVertifyButton->setIcon(hIcon); ++ ++ userButton->setCursor(Qt::PointingHandCursor); ++ userButton->setStyleSheet("QPushButton:hover {background-color:transparent;border-style:outset;}"); ++ userButton->setWindowFlags(Qt::FramelessWindowHint); ++ userButton->setFlat(true); ++ ++ userVertifyButton->setCursor(Qt::PointingHandCursor); ++ userVertifyButton->setStyleSheet("QPushButton:hover {background-color:transparent;border-style:outset;}"); ++ userVertifyButton->setWindowFlags(Qt::FramelessWindowHint); ++ userVertifyButton->setFlat(true); ++ ++ rootButton->setCursor(Qt::PointingHandCursor); ++ rootButton->setStyleSheet("QPushButton:hover {background-color:transparent;border-style:outset;}"); ++ rootButton->setWindowFlags(Qt::FramelessWindowHint); ++ rootButton->setFlat(true); ++ ++ rootVertifyButton->setCursor(Qt::PointingHandCursor); ++ rootVertifyButton->setStyleSheet("QPushButton:hover {background-color:transparent;border-style:outset;}"); ++ rootVertifyButton->setWindowFlags(Qt::FramelessWindowHint); ++ rootVertifyButton->setFlat(true); ++ ++ QWidgetAction* userPasswordAction = new QWidgetAction(ui->textBoxUserPassword); ++ QWidgetAction* userVerifiedPasswordAction = new QWidgetAction(ui->textBoxUserVerifiedPassword); ++ QWidgetAction* rootPasswordAction = new QWidgetAction(ui->textBoxRootPassword); ++ QWidgetAction* rootVerifiedPasswordAction = new QWidgetAction(ui->textBoxVerifiedRootPassword); ++ ++ userPasswordAction->setDefaultWidget(userButton); ++ ui->textBoxUserPassword->addAction(userPasswordAction,QLineEdit::TrailingPosition); ++ userVerifiedPasswordAction->setDefaultWidget(userVertifyButton); ++ ui->textBoxUserVerifiedPassword->addAction(userVerifiedPasswordAction,QLineEdit::TrailingPosition); ++ rootPasswordAction->setDefaultWidget(rootButton); ++ ui->textBoxRootPassword->addAction(rootPasswordAction,QLineEdit::TrailingPosition); ++ rootVerifiedPasswordAction->setDefaultWidget(rootVertifyButton); ++ ui->textBoxVerifiedRootPassword->addAction(rootVerifiedPasswordAction,QLineEdit::TrailingPosition); ++ ++ connect( ++ userButton, ++ &QPushButton::clicked, ++ [this] ( ) { ++ userPassword =! userPassword; ++ if(userPassword){ ++ userButton->setIcon(sIcon); ++ ui->textBoxUserPassword->setEchoMode(QLineEdit::Normal); ++ } else { ++ userButton->setIcon(hIcon); ++ ui->textBoxUserPassword->setEchoMode(QLineEdit::Password); ++ } ++ }); ++ connect(userVertifyButton,&QPushButton::clicked, [this](){ ++ userVertifyPassword =! userVertifyPassword; ++ if(userVertifyPassword){ ++ userVertifyButton->setIcon(sIcon); ++ ui->textBoxUserVerifiedPassword->setEchoMode(QLineEdit::Normal); ++ } else { ++ userVertifyButton->setIcon(hIcon); ++ ui->textBoxUserVerifiedPassword->setEchoMode(QLineEdit::Password); ++ } ++ }); ++ connect(rootButton,&QPushButton::clicked, [this](){ ++ rootPassword =! rootPassword; ++ if(rootPassword){ ++ rootButton->setIcon(sIcon); ++ ui->textBoxRootPassword->setEchoMode(QLineEdit::Normal); ++ } else { ++ rootButton->setIcon(hIcon); ++ ui->textBoxRootPassword->setEchoMode(QLineEdit::Password); ++ } ++ }); ++ connect(rootVertifyButton,&QPushButton::clicked, [this](){ ++ rootVertifyPassword =! rootVertifyPassword; ++ if(rootVertifyPassword){ ++ rootVertifyButton->setIcon(sIcon); ++ ui->textBoxVerifiedRootPassword->setEchoMode(QLineEdit::Normal); ++ } else { ++ rootVertifyButton->setIcon(hIcon); ++ ui->textBoxVerifiedRootPassword->setEchoMode(QLineEdit::Password); ++ } ++ }); ++ ++ + // Connect signals and slots + ui->textBoxUserPassword->setText( config->userPassword() ); + connect( ui->textBoxUserPassword, &QLineEdit::textChanged, config, &Config::setUserPassword ); +diff --git a/src/modules/users/UsersPage.h b/src/modules/users/UsersPage.h +index 379176a..fcee0f0 100644 +--- a/src/modules/users/UsersPage.h ++++ b/src/modules/users/UsersPage.h +@@ -17,6 +17,10 @@ + #define USERSPAGE_H + + #include ++#include ++#include ++#include ++ + + class Config; + +@@ -51,6 +55,17 @@ private: + + Ui::Page_UserSetup* ui; + Config* m_config; ++ bool userPassword; ++ bool userVertifyPassword; ++ bool rootPassword; ++ bool rootVertifyPassword; ++ QIcon hIcon; ++ QIcon sIcon; ++ QPushButton* userButton; ++ QPushButton* userVertifyButton; ++ QPushButton* rootButton; ++ QPushButton* rootVertifyButton; ++ QString imagePath="/usr/share/calamares/branding/default/"; + }; + + #endif // USERSPAGE_H +diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp +index 471187b..88f38c2 100644 +--- a/src/modules/welcome/WelcomePage.cpp ++++ b/src/modules/welcome/WelcomePage.cpp +@@ -91,7 +91,21 @@ WelcomePage::WelcomePage( Config* config, QWidget* parent ) + } + + void +-WelcomePage::init(){} ++WelcomePage::init() ++{ ++ //setup the url buttons ++ // setupButton( WelcomePage::Button::Support, m_conf->supportUrl() ); ++ // setupButton( WelcomePage::Button::KnownIssues, m_conf->knownIssuesUrl() ); ++ // setupButton( WelcomePage::Button::ReleaseNotes, m_conf->releaseNotesUrl() ); ++ // setupButton( WelcomePage::Button::Donate, m_conf->donateUrl() ); ++ ++ //language icon ++ // auto icon = Calamares::Branding::instance()->image( m_conf->languageIcon(), QSize( 48, 48 ) ); ++ // if ( !icon.isNull() ) ++ // { ++ // setLanguageIcon( icon ); ++ // } ++} + + void + WelcomePage::initLanguages() +@@ -111,6 +125,57 @@ WelcomePage::initLanguages() + &Config::setLocaleIndex ); + } + ++// void ++// WelcomePage::setupButton( Button role, const QString& url ) ++// { ++// QPushButton* button = nullptr; ++// Calamares::ImageType icon = Calamares::Information; ++ ++// switch ( role ) ++// { ++// case Button::Donate: ++// button = ui->donateButton; ++// icon = Calamares::Donate; ++// break; ++// case Button::KnownIssues: ++// button = ui->knownIssuesButton; ++// icon = Calamares::Bugs; ++// break; ++// case Button::ReleaseNotes: ++// button = ui->releaseNotesButton; ++// icon = Calamares::Release; ++// break; ++// case Button::Support: ++// button = ui->supportButton; ++// icon = Calamares::Help; ++// break; ++// } ++// if ( !button ) ++// { ++// cWarning() << "Unknown button role" << smash( role ); ++// return; ++// } ++ ++// if ( url.isEmpty() ) ++// { ++// button->hide(); ++// return; ++// } ++ ++// QUrl u( url ); ++// if ( u.isValid() ) ++// { ++// auto size = 2 * QSize( Calamares::defaultFontHeight(), Calamares::defaultFontHeight() ); ++// button->setIcon( Calamares::defaultPixmap( icon, Calamares::Original, size ) ); ++// connect( button, &QPushButton::clicked, [ u ]() { QDesktopServices::openUrl( u ); } ); ++// } ++// else ++// { ++// cWarning() << "Welcome button" << smash( role ) << "URL" << url << "is invalid."; ++// button->hide(); ++// } ++// } ++ + void + WelcomePage::focusInEvent( QFocusEvent* e ) + { +@@ -136,6 +201,11 @@ WelcomePage::externallySelectedLanguage( int row ) + } + } + ++// void ++// WelcomePage::setLanguageIcon( QPixmap i ) ++// { ++// ui->languageIcon->setPixmap( i ); ++// } + + void + WelcomePage::retranslate() +@@ -144,6 +214,8 @@ WelcomePage::retranslate() + + ui->mainText->setText( message.arg( Calamares::Branding::instance()->versionedName() ) ); + ui->retranslateUi( this ); ++ // ui->supportButton->setText( ++ // tr( "%1 Support", "@action" ).arg( Calamares::Branding::instance()->shortProductName() ) ); + } + + void +diff --git a/src/modules/welcome/welcome.qrc b/src/modules/welcome/welcome.qrc +index d338d73..7182a4d 100644 +--- a/src/modules/welcome/welcome.qrc ++++ b/src/modules/welcome/welcome.qrc +@@ -1,6 +1,5 @@ + + +- + WelcomePage.cpp + language-icon-128px.png + language-icon-48px.png +-- +2.46.0 + diff --git a/calamares.spec b/calamares.spec index 6c3665908cacebcd7e3fb62acc7ea3beba080243..d36c5bd389fa626fec69d4b4b8b55f3e28b1a333 100644 --- a/calamares.spec +++ b/calamares.spec @@ -2,7 +2,7 @@ Name: calamares Version: 3.3.7 -Release: 1 +Release: 2 Summary: Installer from a live CD/DVD/USB to disk License: GPL-3.0-or-later @@ -38,7 +38,9 @@ Source16: information.svgz Source17: openEuler.png Source18: openEulerWord-blus.png Source19: openEulerWord.png - +Source20: openEuler-icon.png +Source21: password-hide.png +Source22: password-show.png # patch Patch0: 0001-branding-patch.patch Patch1: 0002-lang.patch @@ -49,6 +51,11 @@ Patch5: 0006-modules-file.patch Patch6: 0007-root.patch Patch7: 0008-progromTree.patch Patch8: 0009-qss.patch +Patch9: 0010-cDebugDelect.patch +Patch10: 0011-fix-87-position-and-translate.patch +Patch11: 0012-replace-icon.patch +Patch12: 0013-1230.patch + # Calamares is only supported where live images (and GRUB) are. (#1171380) # This list matches the arches where grub2-efi is used to boot the system ExclusiveArch: %{ix86} x86_64 aarch64 riscv64 @@ -213,6 +220,7 @@ mkdir -p %{_builddir}/calamares-3.3.7/data/images install -Dm 0644 %{SOURCE8} %{_builddir}/calamares-3.3.7/data/images/Biglogo.svgz install -Dm 0644 %{SOURCE9} %{_builddir}/calamares-3.3.7/data/images/Biglogo.svg install -Dm 0644 %{SOURCE16} %{_builddir}/calamares-3.3.7/data/images/information.svgz + mkdir -p %{_builddir}/calamares-3.3.7/src/modules/packagechooser/images install -Dm 0644 %{SOURCE10} %{_builddir}/calamares-3.3.7/src/branding/default/Biglogo.png install -Dm 0644 %{SOURCE11} %{_builddir}/calamares-3.3.7/src/modules/packagechooser/images/Minimal-Install.png @@ -226,11 +234,14 @@ install -Dm 0644 %{SOURCE15} %{_builddir}/calamares-3.3.7/src/branding/default/S install -Dm 0644 %{SOURCE17} %{_builddir}/calamares-3.3.7/src/branding/default/openEuler.png install -Dm 0644 %{SOURCE18} %{_builddir}/calamares-3.3.7/src/branding/default/openEulerWord-blus.png install -Dm 0644 %{SOURCE19} %{_builddir}/calamares-3.3.7/src/branding/default/openEulerWord.png +install -Dm 0644 %{SOURCE20} %{_builddir}/calamares-3.3.7/src/branding/default/openEuler-icon.png +install -Dm 0644 %{SOURCE21} %{_builddir}/calamares-3.3.7/src/branding/default/password-hide.png +install -Dm 0644 %{SOURCE22} %{_builddir}/calamares-3.3.7/src/branding/default/password-show.png %build mkdir build cd build cmake .. -DINSTALL_CONFIG=ON -make -j 2 +make -j %install cd build @@ -261,7 +272,6 @@ mkdir -p %{buildroot}/data/images install -Dm 0644 %{SOURCE8} %{buildroot}/data/images/Biglogo.svgz install -Dm 0644 %{SOURCE9} %{buildroot}/data/images/Biglogo.svg install -Dm 0644 %{SOURCE16} %{buildroot}/data/images/information.svgz - # calamares模块图片目录 mkdir -p %{buildroot}%{_datadir}/calamares/modules/packagechooser/images install -Dm 0644 %{SOURCE10} %{buildroot}%{_datadir}/calamares/branding/default/Biglogo.png @@ -276,7 +286,9 @@ install -Dm 0644 %{SOURCE15} %{buildroot}%{_datadir}/calamares/branding/default/ install -Dm 0644 %{SOURCE17} %{buildroot}%{_datadir}/calamares/branding/default/openEuler.png install -Dm 0644 %{SOURCE18} %{buildroot}%{_datadir}/calamares/branding/default/openEulerWord-blus.png install -Dm 0644 %{SOURCE19} %{buildroot}%{_datadir}/calamares/branding/default/openEulerWord.png - +install -Dm 0644 %{SOURCE20} %{buildroot}%{_datadir}/calamares/branding/default/openEuler-icon.png +install -Dm 0644 %{SOURCE21} %{_builddir}/calamares-3.3.7/src/branding/default/password-hide.png +install -Dm 0644 %{SOURCE22} %{_builddir}/calamares-3.3.7/src/branding/default/password-show.png %files %doc AUTHORS %license LICENSES/* @@ -313,7 +325,7 @@ install -Dm 0644 %{SOURCE19} %{buildroot}%{_datadir}/calamares/branding/default/ %{_datadir}/calamares/branding/default/openEulerWord-blus.png %{_datadir}/calamares/branding/default/openEulerWord.png %{_datadir}/calamares/branding/default/openEuler.png - +%{_datadir}/calamares/branding/default/openEuler-icon.png %files libs %{_libdir}/libcalamares.so.* %{_libdir}/libcalamaresui.so.* @@ -335,5 +347,8 @@ cd %{_builddir} || exit 0 rm -rf %{buildroot} %changelog +* Fri Dec 27 2024 Li Zixin - 3.3.7-2 +- 新增修改磁盘分区、中英文翻译、修复root bash等问题的patch + * Wed Oct 9 2024 Li Ping - 3.3.7-1 - Initial package diff --git a/openEuler-icon.png b/openEuler-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..db2afafdd36eabdd5c5fd083d9bc00aff9911e6c Binary files /dev/null and b/openEuler-icon.png differ diff --git a/password-hide.png b/password-hide.png new file mode 100644 index 0000000000000000000000000000000000000000..424b4feb99d3f66926d22b36f32949da45ed0819 Binary files /dev/null and b/password-hide.png differ diff --git a/password-show.png b/password-show.png new file mode 100644 index 0000000000000000000000000000000000000000..2ff2c6717fa8e188177d52d924d7dd5068bfb372 Binary files /dev/null and b/password-show.png differ