summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ui/qt5/CMakeLists.txt2
-rw-r--r--ui/qt5/horizon.qrc1
-rw-r--r--ui/qt5/horizonwizard.cc2
-rw-r--r--ui/qt5/pkgcustom.cc58
-rw-r--r--ui/qt5/pkgcustom.hh29
-rw-r--r--ui/qt5/pkgmodel.cc296
-rw-r--r--ui/qt5/pkgmodel.hh76
-rw-r--r--ui/qt5/resources/packages.txt62
8 files changed, 526 insertions, 0 deletions
diff --git a/ui/qt5/CMakeLists.txt b/ui/qt5/CMakeLists.txt
index 23f269b..b286915 100644
--- a/ui/qt5/CMakeLists.txt
+++ b/ui/qt5/CMakeLists.txt
@@ -19,6 +19,8 @@ set(UI_SOURCES
datetimepage.cc
hostnamepage.cc
pkgsimple.cc
+ pkgmodel.cc
+ pkgcustom.cc
pkgdefaults.cc
bootpage.cc
rootpwpage.cc
diff --git a/ui/qt5/horizon.qrc b/ui/qt5/horizon.qrc
index 58272c1..709cdc2 100644
--- a/ui/qt5/horizon.qrc
+++ b/ui/qt5/horizon.qrc
@@ -33,5 +33,6 @@
</qresource>
<qresource prefix="/">
<file alias="horizon-256.png">../../assets/horizon-256.png</file>
+ <file alias="packages.txt">resources/packages.txt</file>
</qresource>
</RCC>
diff --git a/ui/qt5/horizonwizard.cc b/ui/qt5/horizonwizard.cc
index a71b824..ccf6b8f 100644
--- a/ui/qt5/horizonwizard.cc
+++ b/ui/qt5/horizonwizard.cc
@@ -48,6 +48,7 @@ extern "C" {
#include "datetimepage.hh"
#include "hostnamepage.hh"
#include "pkgsimple.hh"
+#include "pkgcustom.hh"
#include "pkgdefaults.hh"
#include "bootpage.hh"
#include "rootpwpage.hh"
@@ -207,6 +208,7 @@ HorizonWizard::HorizonWizard(QWidget *parent) : QWizard(parent) {
setPage(Page_DateTime, new DateTimePage);
setPage(Page_Hostname, new HostnamePage);
setPage(Page_PkgSimple, new PkgSimplePage);
+ setPage(Page_PkgCustom, new PkgCustomPage);
setPage(Page_PkgCustomDefault, new PkgDefaultsPage);
setPage(Page_Boot, new BootPage);
setPage(Page_Root, new RootPassphrasePage);
diff --git a/ui/qt5/pkgcustom.cc b/ui/qt5/pkgcustom.cc
new file mode 100644
index 0000000..33a56b3
--- /dev/null
+++ b/ui/qt5/pkgcustom.cc
@@ -0,0 +1,58 @@
+/*
+ * pkgcustom.cc - Implementation of the UI.Packages.Custom page
+ * horizon-qt5, the Qt 5 user interface for
+ * Project Horizon
+ *
+ * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved.
+ * This code is licensed under the AGPL 3.0 license, as noted in the
+ * LICENSE-code file in the root directory of this repository.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+#include "pkgcustom.hh"
+
+#include <QGroupBox>
+#include <QTreeView>
+#include <QVBoxLayout>
+
+PkgCustomPage::PkgCustomPage(QWidget *parent) : HorizonWizardPage(parent) {
+ setTitle(tr("Software Selection"));
+ loadWatermark("software");
+
+ QLabel *descLabel = new QLabel(tr(
+ "Choose the software you want to install on this computer.\n\n"
+ "You may select any category or software package to read a brief description of it."));
+ descLabel->setWordWrap(true);
+
+ QTreeView *pkgTree = new QTreeView;
+ model = new PkgItemModel(nullptr, this);
+ pkgTree->setHeaderHidden(true);
+ pkgTree->setModel(model);
+ pkgTree->setUniformRowHeights(true);
+
+ QItemSelectionModel *selModel = pkgTree->selectionModel();
+ connect(selModel, &QItemSelectionModel::currentChanged, [=](const QModelIndex &current){
+ QVariant data = model->data(current, Qt::StatusTipRole);
+ if(data.isValid()) {
+ pkgDescLabel->setText(data.toString());
+ }
+ });
+
+ pkgDescLabel = new QLabel(tr("Select an item to view its description.\n\n "));
+ pkgDescLabel->setWordWrap(true);
+ QGroupBox *descBox = new QGroupBox("Description");
+ QVBoxLayout *descLayout = new QVBoxLayout;
+ descLayout->addWidget(pkgDescLabel);
+ descBox->setLayout(descLayout);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(descLabel);
+ layout->addWidget(pkgTree);
+ layout->addWidget(descBox);
+ setLayout(layout);
+}
+
+void PkgCustomPage::initializePage() {
+ model->setPackageList(&(horizonWizard()->packages));
+}
diff --git a/ui/qt5/pkgcustom.hh b/ui/qt5/pkgcustom.hh
new file mode 100644
index 0000000..27d2cd2
--- /dev/null
+++ b/ui/qt5/pkgcustom.hh
@@ -0,0 +1,29 @@
+/*
+ * pkgcustom.hh - Definition of the UI.Packages.Custom page
+ * horizon-qt5, the Qt 5 user interface for
+ * Project Horizon
+ *
+ * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved.
+ * This code is licensed under the AGPL 3.0 license, as noted in the
+ * LICENSE-code file in the root directory of this repository.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+#ifndef PKGCUSTOM_HH
+#define PKGCUSTOM_HH
+
+#include "horizonwizardpage.hh"
+#include "pkgmodel.hh"
+#include <QLabel>
+
+class PkgCustomPage : public HorizonWizardPage {
+public:
+ PkgCustomPage(QWidget *parent = nullptr);
+ void initializePage();
+private:
+ QLabel *pkgDescLabel;
+ PkgItemModel *model;
+};
+
+#endif /* !PKGCUSTOM_HH */
diff --git a/ui/qt5/pkgmodel.cc b/ui/qt5/pkgmodel.cc
new file mode 100644
index 0000000..4cd9170
--- /dev/null
+++ b/ui/qt5/pkgmodel.cc
@@ -0,0 +1,296 @@
+/*
+ * pkgmodel.cc - Implementation of the custom package selection model classes
+ * horizon-qt5, the Qt 5 user interface for
+ * Project Horizon
+ *
+ * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved.
+ * This code is licensed under the AGPL 3.0 license, as noted in the
+ * LICENSE-code file in the root directory of this repository.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+#include "pkgmodel.hh"
+#include <QFile>
+#include <QIcon>
+#include <QMessageBox>
+
+PkgItem::PkgItem(PkgItem *parent, QString friendly, QString internal,
+ QString description, QString icon) : _parent(parent),
+ _friendly(friendly),
+ _internal(internal),
+ _desc(description) {
+ if(icon.isEmpty()) {
+ _icon = internal;
+ } else {
+ _icon = icon;
+ }
+}
+
+PkgItem::~PkgItem() {
+ qDeleteAll(_children);
+}
+
+void PkgItem::addChild(PkgItem *pkg) {
+ _children.append(pkg);
+}
+
+PkgItem *PkgItem::child(int row) {
+ if(row < 0 || row > _children.size()) {
+ return nullptr;
+ }
+
+ return _children.at(row);
+}
+
+int PkgItem::childCount() const {
+ return _children.size();
+}
+
+QVariant PkgItem::data(int column, int role) {
+ if(column != 0) {
+ return QVariant();
+ }
+
+ switch(role) {
+ case Qt::DisplayRole:
+ return QVariant(_friendly);
+ case Qt::DecorationRole:
+ return QVariant(QIcon::fromTheme(_icon));
+ case Qt::StatusTipRole:
+ case Qt::WhatsThisRole:
+ return QVariant(_desc);
+ case Qt::UserRole:
+ return QVariant(_internal);
+ }
+
+ return QVariant();
+}
+
+QStringList PkgItem::internalNames() const {
+ QStringList list;
+
+ if(!_internal.isEmpty()) {
+ list.append(_internal);
+ }
+
+ for(auto &child : _children) {
+ list.append(child->internalNames());
+ }
+
+ return list;
+}
+
+PkgItem *PkgItem::parent() {
+ return _parent;
+}
+
+int PkgItem::row() const {
+ if(_parent == nullptr) {
+ return 0;
+ }
+
+ return _parent->_children.indexOf(const_cast<PkgItem *>(this));
+}
+
+
+PkgItemModel::PkgItemModel(QStringList *pkgList, QObject *parent)
+ : QAbstractItemModel(parent), _packages(pkgList) {
+ _root = new PkgItem(nullptr, "Root Item", "root", "The root of the tree. Never seen.");
+
+ loadPackages();
+}
+
+PkgItemModel::~PkgItemModel() {
+ delete _root;
+}
+
+int PkgItemModel::columnCount(const QModelIndex &) const {
+ return 1;
+}
+
+QVariant PkgItemModel::data(const QModelIndex &index, int role) const {
+ if(!index.isValid()) {
+ return QVariant();
+ }
+
+ PkgItem *item = static_cast<PkgItem *>(index.internalPointer());
+ if(role == Qt::CheckStateRole && index.column() == 0) {
+ QStringList pkgs = item->internalNames();
+ if(_packages && !pkgs.isEmpty()) {
+ bool all = true, any = false;
+ for(auto &pkg : pkgs) {
+ if(_packages->contains(pkg)) {
+ any = true;
+ } else {
+ all = false;
+ }
+ }
+
+ if(all) return Qt::Checked;
+ if(any) return Qt::PartiallyChecked;
+ }
+ return Qt::Unchecked;
+ }
+
+ return item->data(index.column(), role);
+}
+
+Qt::ItemFlags PkgItemModel::flags(const QModelIndex &index) const {
+ if(!index.isValid()) {
+ return Qt::NoItemFlags;
+ }
+
+ Qt::ItemFlags flags = Qt::ItemIsEnabled;
+ if(index.column() == 0) {
+ flags |= Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsAutoTristate;
+ }
+
+ return flags;
+}
+
+QVariant PkgItemModel::headerData(int, Qt::Orientation, int) const {
+ return QVariant();
+}
+
+QModelIndex PkgItemModel::index(int row, int column,
+ const QModelIndex &parent) const {
+ if(!hasIndex(row, column, parent)) {
+ return QModelIndex();
+ }
+
+ PkgItem *p;
+
+ if(parent.isValid()) {
+ p = static_cast<PkgItem *>(parent.internalPointer());
+ } else {
+ p = _root;
+ }
+
+ PkgItem *item = p->child(row);
+ if(item) {
+ return createIndex(row, column, item);
+ } else {
+ return QModelIndex();
+ }
+}
+
+QModelIndex PkgItemModel::parent(const QModelIndex &child) const {
+ if(!child.isValid()) {
+ return QModelIndex();
+ }
+
+ PkgItem *item = static_cast<PkgItem *>(child.internalPointer());
+ PkgItem *parent = item->parent();
+
+ if(parent == _root) {
+ return QModelIndex();
+ } else {
+ return createIndex(parent->row(), 0, parent);
+ }
+}
+
+int PkgItemModel::rowCount(const QModelIndex &parent) const {
+ if(parent.column() > 0) {
+ return 0;
+ }
+
+ if(parent.isValid()) {
+ PkgItem *item = static_cast<PkgItem *>(parent.internalPointer());
+ return item->childCount();
+ } else {
+ return _root->childCount();
+ }
+}
+
+bool PkgItemModel::setData(const QModelIndex &index, const QVariant &value,
+ int role) {
+ if(!index.isValid() || role != Qt::CheckStateRole) {
+ return false;
+ }
+
+ PkgItem *item = static_cast<PkgItem *>(index.internalPointer());
+ if(item) {
+ QStringList pkgs = item->internalNames();
+ if(value.toBool()) {
+ _packages->append(pkgs);
+ } else {
+ for(auto &pkg : pkgs) {
+ _packages->removeAll(pkg);
+ }
+ }
+ emit dataChanged(index, index, {Qt::CheckStateRole});
+ if(item->childCount() > 0) {
+ emit dataChanged(createIndex(0, 0, item),
+ createIndex(item->childCount(), 0, item),
+ {Qt::CheckStateRole});
+ }
+
+ PkgItem *parent = item;
+ while(parent->parent() != _root) {
+ parent = parent->parent();
+ QModelIndex pidx = createIndex(parent->row(), 0, parent);
+ emit dataChanged(pidx, pidx, {Qt::CheckStateRole});
+ }
+ }
+
+ return true;
+}
+
+void PkgItemModel::setPackageList(QStringList *pkgList) {
+ _packages = pkgList;
+}
+
+void PkgItemModel::loadPackages() {
+ QFile myList(":/packages.txt");
+ if(!myList.open(QFile::ReadOnly)) {
+ QMessageBox::critical(nullptr, tr("Could Not Load Software List"),
+ tr("An issue occurred loading the available software list."));
+ return;
+ }
+
+ QByteArray raw_pkgs = myList.readAll();
+ QList<QByteArray> pkgs = raw_pkgs.split('\n');
+ int indent, lastIndent = 0;
+ PkgItem *temp = new PkgItem(_root, "Placeholder", "Placeholder", "Used for loading only");
+ PkgItem *last = temp;
+
+ for(auto &pkg : pkgs) {
+ indent = 0;
+
+ if(pkg.isEmpty()) continue;
+
+ while(pkg.size() > 1 && pkg.at(0) == ' ') {
+ indent++;
+ pkg.remove(0, 1);
+ }
+
+ /* minimum valid size: A\tb\tC */
+ if(pkg.size() < 6) continue;
+
+ PkgItem *myParent;
+
+ if(indent == lastIndent) {
+ /* We're siblings of the last item. */
+ myParent = last->parent();
+ } else if(indent < lastIndent) {
+ /* Traverse up until we're equal */
+ while(lastIndent-- > indent) {
+ last = last->parent();
+ }
+ myParent = last->parent();
+ } else /*(indent > lastIndent)*/ {
+ /* We're children of the last item. */
+ myParent = last;
+ }
+
+ QList<QByteArray> fields = pkg.split('\t');
+ /* at least friendly, internal, desc required */
+ if(fields.size() < 3) continue;
+ last = new PkgItem(myParent, fields[0], fields[1], fields[2],
+ (fields.size() == 4 ? fields[3] : fields[1]));
+ myParent->addChild(last);
+ lastIndent = indent;
+ }
+ delete temp;
+}
diff --git a/ui/qt5/pkgmodel.hh b/ui/qt5/pkgmodel.hh
new file mode 100644
index 0000000..85070ee
--- /dev/null
+++ b/ui/qt5/pkgmodel.hh
@@ -0,0 +1,76 @@
+/*
+ * pkgmodel.hh - Definition of the custom package selection model classes
+ * horizon-qt5, the Qt 5 user interface for
+ * Project Horizon
+ *
+ * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved.
+ * This code is licensed under the AGPL 3.0 license, as noted in the
+ * LICENSE-code file in the root directory of this repository.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+#ifndef PKGMODEL_HH
+#define PKGMODEL_HH
+
+#include <QAbstractItemModel>
+
+class PkgItem {
+public:
+ explicit PkgItem(PkgItem *parent, QString friendly, QString internal,
+ QString description, QString icon = "");
+ ~PkgItem();
+
+ void addChild(PkgItem *pkg);
+ PkgItem *child(int row);
+ int childCount() const;
+ QVariant data(int column, int role);
+ QStringList internalNames() const;
+ int row() const;
+ PkgItem *parent();
+
+private:
+ QVector<PkgItem *> _children;
+ PkgItem *_parent;
+ /*! The "friendly" or displayed name for this item. */
+ QString _friendly;
+ /*! The internal name. Typically the APK package name. */
+ QString _internal;
+ /*! The description of the item. */
+ QString _desc;
+ /*! The icon to display for this item. Defaults to internal. */
+ QString _icon;
+};
+
+class PkgItemModel : public QAbstractItemModel {
+Q_OBJECT
+public:
+ explicit PkgItemModel(QStringList *pkgList = nullptr,
+ QObject *parent = nullptr);
+ ~PkgItemModel();
+
+ QVariant data(const QModelIndex &index,
+ int role = Qt::DisplayRole) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const override;
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &child) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ bool setData(const QModelIndex &index, const QVariant &value,
+ int role = Qt::EditRole) override;
+ void setPackageList(QStringList *pkgList);
+
+private:
+ void loadPackages();
+ /*! The list of packages that will be installed.
+ * Determines which packages are ticked. */
+ QStringList *_packages;
+ /*! The special root item, which all other items have as an eventual
+ * parent. */
+ PkgItem *_root;
+};
+
+#endif /* !PKGMODEL_HH */
diff --git a/ui/qt5/resources/packages.txt b/ui/qt5/resources/packages.txt
new file mode 100644
index 0000000..ae88ab1
--- /dev/null
+++ b/ui/qt5/resources/packages.txt
@@ -0,0 +1,62 @@
+Desktop Environments X11-based desktop environments. preferences-theme
+ KDE Plasma 5 plasma-desktop The KDE Plasma desktop environment. kde-frameworks
+ LXQt lxqt-desktop Lightweight desktop environment using the Openbox window manager and Qt widgets. qt
+ MATE mate-complete The MATE desktop environment, featuring a classic desktop experience with Gtk+ 2. mate-logo
+ XFCE xfce-desktop The XFCE desktop environment. xfce4-logo
+Documentation doc Install documentation for the software you select. application-x-fictionbook
+Games Video games for your Adélie Linux computer. applications-games
+ Mednafen mednaffe An emulator for playing games from many types of 8-bit and 16-bit home consoles.
+ OpenTTD openttd Transportation simulation game.
+ TORCS torcs The Open Racing Car Simulator, a racing simulation.
+ Trigger trigger-rally A rally racing game. applications-games
+ X-Moto xmoto A motorcross game
+Internet Software Software to explore the Internet. applications-internet
+ Firefox Web browser firefox-esr Popular, powerful Web browser. Includes JavaScript and multimedia (audio/video) playback support.
+ Netsurf Web browser netsurf Lightweight Web browser. Does not include JavaScript support.
+ Otter Browser otter-browser WebKit-based Web browser with JavaScript support.
+ Thunderbird Email thunderbird Read and compose email, and participate in newsgroups.
+KDE Applications kde A variety of cohesive applications including a word processor, media player, and many games. kde-logo
+ Default Theme adelie-kde-theme The Adélie KDE theme, including wallpapers and colour themes. kcontrol
+ Educational Software kde-education Computer-assisted learning software. applications-education-mathematics
+ Games kde-games A variety of arcade games, card games, strategy games, and more. applications-games
+ Graphics kde-graphics Photo viewing and editing software, including digital cameras and photo albums. applications-graphics
+ Multimedia kde-multimedia Audio/video playback, recording, and editing. applications-multimedia
+ System Utilities kde-system Utilities for managing and maintaining your computer. applications-system
+ User Manager user-manager The KDE user account manager, for creating and modifying user accounts. preferences-system-users
+ Utilities kde-utilities Miscellaneous accessories. applications-utilities
+Multimedia Software Software to play audio and video. applications-multimedia
+ MPV mpv Command-line based multimedia player.
+ VLC Media Player vlc Multimedia player with support for a wide variety of audio and video types.
+Office and Productivity Software Software to take care of business. applications-office
+ AbiWord abiword Lightweight word processor.
+ Calligra calligra KDE office suite featuring a word processor, spreadsheet, project planning, and presentation software. calligrawords
+ FeatherPad featherpad Lightweight text editor. kwrite
+ Gnumeric gnumeric Lightweight spreadsheet.
+ LibreOffice libreoffice Extensible office suite featuring a word processor, spreadsheet, database, and presentation software.
+Programming Environments Interpreters, language tools, and development environments. applications-interfacedesign
+ Development Tools build-tools Tools used to create, build, and test software. applications-development
+ Ada gcc-gnat The Ada programming language. applications-interfacedesign
+ COBOL gnucobol The COBOL programming language. applications-interfacedesign
+ Go gcc-go The Go programming language. text-x-go
+ Java openjdk8-jdk The Java 8 programming environment. java
+ Node.js node The Node JavaScript programming environment. javascript
+ Perl perl The Perl programming language. text-x-perl
+ PHP 7 php7 The PHP 7 programming language. application-x-php
+ Python python3 The Python programming language. (3.6) python
+ Ruby ruby The Ruby programming language. text-x-ruby
+ Rust rust The Rust programming language. text-x-rust
+Server Software Software for sharing computer resources with others over a network. network-server
+ Apache Web server apache-httpd The world's most popular Web server. yast-network_services
+ MariaDB mariadb A popular relational database server. network-server
+ NFS Server nfs-utils Unix file sharing system. yast-samba-server
+ OpenSSH openssh Remote shell and file transferring system. text-x-script
+ PostgreSQL postgresql Reliable, professional relational database server. openoffice4-base
+ Postfix postfix Server for transmitting email. internet-mail
+ Qmail netqmail Server for transmitting email. internet-mail
+Window Managers Individual window managers that are not part of a desktop environment. window_list
+ Awesome awesome The Awesome window manager. window_list
+ Fluxbox fluxbox The Fluxbox window manager. window_list
+ i3 i3wm The i3 window manager. window_list
+ iceWM icewm The iceWM window manager. ice
+ Openbox openbox The Openbox window manager. openbox
+ spectrwm spectrwm The spectrwm window manager. window_list