diff --git a/gui/page/spkpagesettings.cpp b/gui/page/spkpagesettings.cpp index a7ef719..1e48aa7 100644 --- a/gui/page/spkpagesettings.cpp +++ b/gui/page/spkpagesettings.cpp @@ -19,6 +19,9 @@ namespace SpkUi mMainArea->setWidget(mSettingsWidget); mMainArea->setWidgetResizable(true); + CFG->BindField("url/repo", &this->mRepoListUrl, + "https://d.store.deepinos.org.cn/store/server.list"); + SetupUi(); } @@ -50,20 +53,21 @@ namespace SpkUi ui->edtDownloadPath->setText(CFG->ReadField("dirs/download", "").toString()); ui->edtDownloadServers->setPlainText(CFG->ReadField("download/servers", "").toString()); ui->edtQssPath->setText(CFG->ReadField("internal/qss_path", "").toString()); + ui->edtRepoListUrl->setText(CFG->ReadField("url/repo", "").toString()); } void SpkPageSettings::SaveConfiguration() { auto ui = mSettingsUi; - auto settings = CFG; CFG->SetSettings("resource/concurrent", ui->spnConcurrentResDownloads->value()); - assert(CFG->SetField("url/api", ui->edtApiUrl->text())); - assert(CFG->SetField("url/res", ui->edtResourceUrl->text())); + CFG->SetField("url/api", ui->edtApiUrl->text()); + CFG->SetField("url/res", ui->edtResourceUrl->text()); CFG->SetSettings("dirs/cache", ui->edtResourceCachePath->text()); - assert(CFG->SetField("dirs/download", ui->edtDownloadPath->text())); - assert(CFG->SetField("download/servers", ui->edtDownloadServers->toPlainText())); + CFG->SetField("dirs/download", ui->edtDownloadPath->text()); + CFG->SetField("download/servers", ui->edtDownloadServers->toPlainText()); CFG->SetSettings("internal/qss_path", ui->edtQssPath->text()); + CFG->SetField("url/repo", ui->edtRepoListUrl->text()); } void SpkPageSettings::Activated() diff --git a/gui/page/spkpageuitest.cpp b/gui/page/spkpageuitest.cpp index be8554e..12db872 100644 --- a/gui/page/spkpageuitest.cpp +++ b/gui/page/spkpageuitest.cpp @@ -83,7 +83,7 @@ SpkUi::SpkPageUiTest::SpkPageUiTest(QWidget *parent) : QSplitter(parent) ShowPkgmgr = new QPushButton(this); ShowPkgmgr->setText("Show Install Menu"); - connect(ShowPkgmgr, &QPushButton::clicked, [](){ SpkPkgMgrBase::Instance()->ExecuteInstallation("", 0); }); + connect(ShowPkgmgr, &QPushButton::clicked, [=](){ SpkPkgMgrBase::Instance()->ExecuteInstallation(PopupText->text(), 0); }); SlideV = new QSlider(this); SlideV->setObjectName("spk_pg_qsstest_slider_v"); diff --git a/gui/page/ui/settings.ui b/gui/page/ui/settings.ui index 6aa46d2..725e4da 100644 --- a/gui/page/ui/settings.ui +++ b/gui/page/ui/settings.ui @@ -6,8 +6,8 @@ 0 0 - 501 - 699 + 581 + 896 @@ -61,41 +61,17 @@ - - - - - 0 - 0 - - - - - 0 - 80 - - - - - 16777215 - 150 - - - - - 100 - 100 - - - - download/servers + + + + Store API URL - - + + - Light/dark theme + Store resource URL @@ -106,75 +82,6 @@ - - - - true - - - gui/theme - - - - Auto - - - - - Always Light - - - - - Always Dark - - - - - - - - Store API URL - - - - - - - APT Repository - - - - - - - url/api - - - - - - - Server addresses are separated with two semicolons (;;). - - - 1 - - - Download servers - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - dirs/cache - - - @@ -182,23 +89,10 @@ - - - - - - - -1 - + + - Download path - - - - - - - Store resource URL + APT Repository @@ -255,6 +149,122 @@ + + + + Light/dark theme + + + + + + + dirs/cache + + + + + + + + 0 + 0 + + + + + 0 + 80 + + + + + 16777215 + 150 + + + + + 100 + 100 + + + + download/servers + + + + + + + true + + + gui/theme + + + + Auto + + + + + Always Light + + + + + Always Dark + + + + + + + + + + + -1 + + + Download path + + + + + + + Server addresses are separated with two semicolons (;;). + + + 1 + + + Download servers + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + url/api + + + + + + + APT Repository Source + + + + + + diff --git a/inc/page/spkpagesettings.h b/inc/page/spkpagesettings.h index 7485e46..af67861 100644 --- a/inc/page/spkpagesettings.h +++ b/inc/page/spkpagesettings.h @@ -22,11 +22,15 @@ namespace SpkUi virtual void Activated() override; + private slots: + private: QScrollArea *mMainArea; QVBoxLayout *mMainLay; QWidget *mSettingsWidget; Ui::SpkUiSettings *mSettingsUi; + QString mRepoListUrl; + }; } diff --git a/inc/pkgs/spkpkgmgrapt.h b/inc/pkgs/spkpkgmgrapt.h index d5576e8..68d16a2 100644 --- a/inc/pkgs/spkpkgmgrapt.h +++ b/inc/pkgs/spkpkgmgrapt.h @@ -2,8 +2,9 @@ #pragma once #include "spkpkgmgrbase.h" +#include -class SpkPkgMgrApt : public SpkPkgMgrBase +class SpkPkgMgrApt final : public SpkPkgMgrBase { Q_OBJECT @@ -21,10 +22,15 @@ class SpkPkgMgrApt : public SpkPkgMgrBase private: void CheckInstallerAvailability(); + private slots: + void InstallerExited(int, QProcess::ExitStatus); + private: QAction *mActAptitudeTerm, *mActAptTerm, *mActGdebi, *mActDeepinPkgInst; + QProcess mInstaller; + }; diff --git a/inc/pkgs/spkpkgmgrbase.h b/inc/pkgs/spkpkgmgrbase.h index 71d263d..d688cb7 100644 --- a/inc/pkgs/spkpkgmgrbase.h +++ b/inc/pkgs/spkpkgmgrbase.h @@ -20,8 +20,10 @@ class SpkPkgMgrBase : public QObject Q_ASSERT(mInstance == nullptr); mInstance = this; + mActOpen = new QAction(tr("Open package"), this); mActOpenDir = new QAction(tr("Open containing directory"), this); mMenu = new QMenu(tr("Package Actions")); + mMenu->addAction(mActOpen); mMenu->addAction(mActOpenDir); mMenu->setAttribute(Qt::WA_TranslucentBackground); mMenu->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint); @@ -47,9 +49,12 @@ class SpkPkgMgrBase : public QObject */ virtual PkgInstallResult ExecuteInstallation(QString pkgPath, int entryId) { + Q_UNUSED(entryId); auto item = mMenu->exec(QCursor::pos()); if(item == mActOpenDir) QDesktopServices::openUrl(QUrl(SpkUtils::CutPath(pkgPath))); + else if(item == mActOpen) + QDesktopServices::openUrl(QUrl(pkgPath)); return Ignored; } @@ -60,7 +65,11 @@ class SpkPkgMgrBase : public QObject */ virtual PkgInstallResult CliInstall(QString pkgPath) { - // TODO: print message + qInfo() << tr("Spark Store cannot install your package because no supported " + "packaging system has been found. You shall decide what you " + "want to do with the downloaded package.\n\n" + "File path:") + << pkgPath; return Ignored; } @@ -68,15 +77,15 @@ class SpkPkgMgrBase : public QObject static SpkPkgMgrBase *Instance() { return mInstance; } protected: - QAction *mActOpenDir, *mActDesc; + QAction *mActOpenDir, *mActOpen, *mActDesc; QMenu *mMenu; + int mCurrentItemId; ///< ID of currently installing download item private: static SpkPkgMgrBase *mInstance; signals: - void InstallationEnded(int entryId, - SpkPkgMgrBase::PkgInstallResult success, - QString message); - + void ReportInstallResult(int entryId, + SpkPkgMgrBase::PkgInstallResult result, + int exitCode); }; diff --git a/inc/pkgs/spkpkgmgrpacman.h b/inc/pkgs/spkpkgmgrpacman.h index 3bc689d..e648daf 100644 --- a/inc/pkgs/spkpkgmgrpacman.h +++ b/inc/pkgs/spkpkgmgrpacman.h @@ -3,7 +3,7 @@ #include "spkpkgmgrbase.h" -class SpkPkgMgrPacman : public SpkPkgMgrBase +class SpkPkgMgrPacman final : public SpkPkgMgrBase { Q_OBJECT diff --git a/inc/spkutils.h b/inc/spkutils.h index ef6c3cd..c18bb81 100644 --- a/inc/spkutils.h +++ b/inc/spkutils.h @@ -29,5 +29,7 @@ namespace SpkUtils QString BytesToSize(size_t s, int prec = 2); bool EnsureDirExists(QString path); - void FillWidget(QWidget* widget, QVariant val); + bool FindViableTerminal(); + + extern QPair AvailableTerminal; } diff --git a/resource/default_config b/resource/default_config index 3406ffb..4422b74 100644 --- a/resource/default_config +++ b/resource/default_config @@ -2,6 +2,7 @@ [url] api=https://store.deepinos.org/api/ res=http://img.store.deepinos.org.cn/ +repo=https://d.store.deepinos.org.cn/store/server.list [dirs] cache="*/.cache/spark-store/res/" diff --git a/src/pkgs/spkpkgmgrapt.cpp b/src/pkgs/spkpkgmgrapt.cpp index a2d648e..85d05d7 100644 --- a/src/pkgs/spkpkgmgrapt.cpp +++ b/src/pkgs/spkpkgmgrapt.cpp @@ -13,12 +13,16 @@ SpkPkgMgrApt::SpkPkgMgrApt(QObject *parent) : mActGdebi = new QAction(tr("GDebi"), this); mActDeepinPkgInst = new QAction(tr("Deepin Package Installer"), this); - mMenu->addAction(mActAptTerm); - mMenu->addAction(mActAptitudeTerm); - mMenu->addAction(mActGdebi); - mMenu->addAction(mActDeepinPkgInst); + mMenu->insertAction(mActOpen, mActAptTerm); + mMenu->insertAction(mActOpen, mActAptitudeTerm); + mMenu->insertAction(mActOpen, mActGdebi); + mMenu->insertAction(mActOpen, mActDeepinPkgInst); + mMenu->insertSeparator(mActOpen); mMenu->addSeparator(); mMenu->addAction(mActDesc); + + connect(&mInstaller, QOverload::of(&QProcess::finished), + this, &SpkPkgMgrApt::InstallerExited); } bool SpkPkgMgrApt::DetectRequirements() @@ -30,8 +34,63 @@ bool SpkPkgMgrApt::DetectRequirements() SpkPkgMgrBase::PkgInstallResult SpkPkgMgrApt::ExecuteInstallation(QString pkgPath, int entryId) { + static auto prompt = tr("\n\n================================\n" + "Press Enter to continue."); + + if(mInstaller.state() == QProcess::Running) + { + sNotify(tr("Please wait till the current installation finishes.")); + return Ignored; + } + mCurrentItemId = entryId; CheckInstallerAvailability(); - return SpkPkgMgrBase::ExecuteInstallation(pkgPath, entryId); + auto item = mMenu->exec(QCursor::pos()); + if(item == mActOpenDir) + { + QDesktopServices::openUrl(QUrl(SpkUtils::CutPath(pkgPath))); + return Ignored; + } + else if(item == mActOpen) + { + QDesktopServices::openUrl(QUrl(pkgPath)); + return Ignored; + } + else if(item == mActAptTerm) + { + mInstaller.setProgram(SpkUtils::AvailableTerminal.first); + mInstaller.setArguments({ SpkUtils::AvailableTerminal.second, "pkexec", + "bash", "-c", + QString("apt install '%1'; R=$?; read -p '%2'; exit $R") + .arg(pkgPath, prompt)}); + mInstaller.start(); + } + else if(item == mActAptitudeTerm) + { + mInstaller.setProgram(SpkUtils::AvailableTerminal.first); + mInstaller.setArguments({ SpkUtils::AvailableTerminal.second, "pkexec", + "bash", "-c", + QString("aptitude install '%1'; R=$?; read -p '%2'; exit $R") + .arg(pkgPath, prompt)}); + mInstaller.start(); + } + else if(item == mActGdebi) + { + mInstaller.setProgram("pkexec"); + mInstaller.setArguments({ "gdebi", "-n", pkgPath }); + mInstaller.start(); + } + else if(item == mActDeepinPkgInst) + { + mInstaller.setProgram("deepin-deb-installer"); + mInstaller.setArguments({ pkgPath }); + mInstaller.start(); + } + else + return Ignored; + + // Startup is very quick and we can risk blocking here a bit + mInstaller.waitForStarted(); + return mInstaller.state() == QProcess::Running ? Succeeded : Failed; } void SpkPkgMgrApt::CheckInstallerAvailability() @@ -41,4 +100,12 @@ void SpkPkgMgrApt::CheckInstallerAvailability() mActDeepinPkgInst->setEnabled(QFile::exists("/usr/bin/deepin-deb-installer")); } +void SpkPkgMgrApt::InstallerExited(int exitCode, QProcess::ExitStatus status) +{ + if(status == QProcess::NormalExit) + emit ReportInstallResult(mCurrentItemId, Succeeded, exitCode); + else + emit ReportInstallResult(mCurrentItemId, Failed, exitCode); +} + diff --git a/src/spkstore.cpp b/src/spkstore.cpp index 677b843..95cb9f3 100644 --- a/src/spkstore.cpp +++ b/src/spkstore.cpp @@ -8,6 +8,7 @@ #include "dtk/spkdtkplugin.h" #include "gitver.h" #include "spkmainwindow.h" +#include "spkmsgbox.h" #include "spkpopup.h" #include "spkstore.h" #include "spkutils.h" @@ -75,6 +76,13 @@ SpkStore::SpkStore(bool aCli, QString &aLogPath) mMainWindow = new SpkMainWindow; SpkUi::Popup = new SpkUi::SpkPopup(mMainWindow); + if(!SpkUtils::FindViableTerminal()) + SpkMsgBox::StaticExec(tr("Cannot find a terminal emulator on the system.\n" + "You will have to specify it in settings later in order\n" + "to use terminal for program output."), + tr("No Terminals Found"), + QMessageBox::Warning); + mMainWindow->show(); } diff --git a/src/spkutils.cpp b/src/spkutils.cpp index 47849d4..e877147 100644 --- a/src/spkutils.cpp +++ b/src/spkutils.cpp @@ -4,8 +4,11 @@ #include #include #include +#include #include "spkutils.h" +QPair SpkUtils::AvailableTerminal = {"", ""}; + void SpkUtils::VerifySingleRequest(QPointer aReply) { if(aReply.isNull()) @@ -112,7 +115,41 @@ bool SpkUtils::EnsureDirExists(QString path) return true; } -void SpkUtils::FillWidget(QWidget *widget, QVariant val) -{ +// From https://github.com/qt-creator/qt-creator/blob/18f1be58e7937af4f538fc0c47f660cf8c60bda2/src/libs/utils/consoleprocess.cpp +using StrStrPair = QPair; +Q_GLOBAL_STATIC_WITH_ARGS(QList, KnownTerminals, + ({ + {"x-terminal-emulator", "-e"}, + {"xdg-terminal ", ""}, + {"xterm", "-e"}, + {"aterm", "-e"}, + {"Eterm", "-e"}, + {"rxvt", "-e"}, + {"urxvt", "-e"}, + {"xfce4-terminal", "-x"}, + {"konsole", "-e "}, + {"gnome-terminal", "--"} + })); +bool SpkUtils::FindViableTerminal() +{ + auto dirs = qgetenv("PATH").split(':'); + QList searchDirs; + + for(auto &i : dirs) + searchDirs.append(QDir(i)); + + for(auto &i : *KnownTerminals) + { + for(auto &j : searchDirs) + { + if(j.exists(i.first)) + { + AvailableTerminal = i; + return true; + } + } + } + + return false; }