File indexing completed on 2024-03-24 17:23:04

0001 // This license reflects the original Adept code:
0002 // -*- C++ -*- (c) 2008 Petr Rockai <me@mornfall.net>
0003 // Redistribution and use in source and binary forms, with or without
0004 // modification, are permitted provided that the following conditions are
0005 // met:
0006 //
0007 //     * Redistributions of source code must retain the above copyright
0008 //       notice, this list of conditions and the following disclaimer.
0009 //
0010 //     * Redistributions in binary form must reproduce the above
0011 //       copyright notice, this list of conditions and the following
0012 //       disclaimer in the documentation and/or other materials provided
0013 //       with the distribution.
0014 //
0015 //     * Neither the name of [original copyright holder] nor the names of
0016 //       its contributors may be used to endorse or promote products
0017 //       derived from this software without specific prior written
0018 //       permission.
0019 //
0020 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0021 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0022 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0023 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0024 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0026 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0027 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0028 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0029 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0030 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0031 /*
0032  * All the modifications below are licensed under this license
0033  * Copyright (C) 2010-2018 Daniel Nicoletti <dantti12@gmail.com>
0034  *
0035  * This library is free software; you can redistribute it and/or
0036  * modify it under the terms of the GNU Library General Public
0037  * License as published by the Free Software Foundation; either
0038  * version 2 of the License, or (at your option) any later version.
0039  *
0040  * This library is distributed in the hope that it will be useful,
0041  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0042  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0043  * Library General Public License for more details.
0044  *
0045  * You should have received a copy of the GNU Library General Public License
0046  * along with this library; see the file COPYING.LIB. If not, write to
0047  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0048  * Boston, MA 02110-1301, USA.
0049  */
0050 
0051 #include "DebconfGui.h"
0052 
0053 #include "ui_DebconfGui.h"
0054 
0055 #include "DebconfBoolean.h"
0056 #include "DebconfError.h"
0057 #include "DebconfMultiselect.h"
0058 #include "DebconfNote.h"
0059 #include "DebconfPassword.h"
0060 #include "DebconfProgress.h"
0061 #include "DebconfSelect.h"
0062 #include "DebconfString.h"
0063 #include "DebconfText.h"
0064 #include "Debug_p.h"
0065 
0066 #include <QtCore/QDebug>
0067 #include <QtCore/QProcess>
0068 #include <QtCore/QFile>
0069 #include <QtWidgets/QLabel>
0070 #include <QHostInfo>
0071 
0072 #include <KGuiItem>
0073 #include <KIconLoader>
0074 #include <KLocalizedString>
0075 #include <KStandardGuiItem>
0076 #include <KOSRelease>
0077 
0078 #include <debconf.h>
0079 
0080 using namespace DebconfKde;
0081 
0082 class DebconfKde::DebconfGuiPrivate : public Ui::DebconfGui
0083 {
0084 public:
0085     virtual ~DebconfGuiPrivate() { }
0086     DebconfFrontend *frontend;
0087     DebconfProgress *elementProgress = nullptr;
0088     QWidget *parentWidget = nullptr;
0089     QVector<DebconfElement*> elements;
0090 
0091     DebconfElement* createElement(const QString &k);
0092     void cleanup();
0093 };
0094 
0095 DebconfGui::DebconfGui(const QString &socketName, QWidget *parent)
0096  : QWidget(parent),
0097    d_ptr(new DebconfGuiPrivate)
0098 {
0099     Q_D(DebconfGui);
0100     d->frontend = new DebconfFrontendSocket(socketName, this);
0101     init();
0102 }
0103 
0104 DebconfGui::DebconfGui(int readfd, int writefd, QWidget *parent)
0105  : QWidget(parent),
0106    d_ptr(new DebconfGuiPrivate)
0107 {
0108     Q_D(DebconfGui);
0109     d->frontend = new DebconfFrontendFifo(readfd, writefd, this);
0110     init();
0111 }
0112 
0113 DebconfGui::~DebconfGui()
0114 {
0115     delete d_ptr;
0116 }
0117 
0118 void DebconfGui::init()
0119 {
0120     Q_D(DebconfGui);
0121     d->setupUi(this);
0122 
0123     // Setup buttons. They are marked non-translatable in the UI file.
0124     KGuiItem::assign(d->cancelPB, KStandardGuiItem::cancel());
0125     KGuiItem::assign(d->backPB, KStandardGuiItem::back());
0126     KGuiItem::assign(d->nextPB, KStandardGuiItem::cont());
0127 
0128     setMinimumSize(500, 400);
0129     d->cancelPB->setVisible(false);
0130 
0131     connect(d->frontend, &DebconfFrontend::go, this, &DebconfGui::cmd_go);
0132     connect(d->frontend, &DebconfFrontend::finished, this, &DebconfGui::deactivated);
0133     connect(d->frontend, &DebconfFrontend::progress, this, &DebconfGui::cmd_progress);
0134     connect(d->frontend, &DebconfFrontend::backup, d->backPB, &QPushButton::setEnabled);
0135 
0136     setWindowTitle(i18n("Debconf on %1", QHostInfo::localHostName()));
0137 
0138     // find out the distribution logo
0139     QString distroLogo(QLatin1String("/usr/share/pixmaps/debian-logo.png"));
0140     KOSRelease osInfo;
0141     if (!osInfo.logo().isEmpty())
0142         distroLogo = osInfo.logo();
0143 
0144     const QPixmap icon = KIconLoader::global()->loadIcon(distroLogo,
0145                                                          KIconLoader::NoGroup,
0146                                                          KIconLoader::SizeLarge,
0147                                                          KIconLoader::DefaultState);
0148     if (!icon.isNull()) {
0149         d->iconL->setPixmap(icon);
0150         setWindowIcon(icon);
0151     }
0152 
0153     d->scrollArea->viewport()->setAutoFillBackground(false);
0154 }
0155 
0156 DebconfElement* DebconfGuiPrivate::createElement(const QString &k)
0157 {
0158     qCDebug(DEBCONF) << "creating widget for " << k;
0159 
0160     QString extendedDescription = frontend->property(k, DebconfFrontend::ExtendedDescription);
0161     extendedDescription.replace(QLatin1String("\\n"), QLatin1String("\n"));
0162 
0163     switch (frontend->type(k)) {
0164     case DebconfFrontend::Boolean:
0165     {
0166         auto element = new DebconfBoolean(k, parentWidget);
0167         element->setBoolean(extendedDescription,
0168                             frontend->property(k, DebconfFrontend::Description),
0169                             frontend->value(k) == QLatin1String("true"));
0170         return element;
0171     }
0172     case DebconfFrontend::Error:
0173     {
0174         auto element = new DebconfError(k, parentWidget);
0175         element->setError(extendedDescription,
0176                           frontend->property(k, DebconfFrontend::Description));
0177         return element;
0178     }
0179     case DebconfFrontend::Multiselect:
0180     {
0181         auto element = new DebconfMultiselect(k, parentWidget);
0182         element->setMultiselect(extendedDescription,
0183                                 frontend->property(k, DebconfFrontend::Description),
0184                                 frontend->value(k).split(QLatin1String(", ")),
0185                                 frontend->property(k, DebconfFrontend::Choices).split(QLatin1String(", ")));
0186         return element;
0187     }
0188     case DebconfFrontend::Note:
0189     {
0190         auto element = new DebconfNote(k, parentWidget);
0191         element->setNote(extendedDescription,
0192                          frontend->property(k, DebconfFrontend::Description));
0193         return element;
0194     }
0195     case DebconfFrontend::Password:
0196     {
0197         auto element = new DebconfPassword(k, parentWidget);
0198         element->setPassword(extendedDescription,
0199                              frontend->property(k, DebconfFrontend::Description));
0200         return element;
0201     }
0202     case DebconfFrontend::Select:
0203     {
0204         auto element = new DebconfSelect(k, parentWidget);
0205         element->setSelect(extendedDescription,
0206                            frontend->property(k, DebconfFrontend::Description),
0207                            frontend->value(k),
0208                            frontend->property(k, DebconfFrontend::Choices).split(QLatin1String(", ")));
0209         return element;
0210     }
0211     case DebconfFrontend::String:
0212     {
0213         auto element = new DebconfString(k, parentWidget);
0214         element->setString(extendedDescription,
0215                            frontend->property(k, DebconfFrontend::Description),
0216                            frontend->value(k));
0217         return element;
0218     }
0219     case DebconfFrontend::Text:
0220     {
0221         auto element = new DebconfText(k, parentWidget);
0222         element->setText(frontend->property(k, DebconfFrontend::Description));
0223         return element;
0224     }
0225     default:
0226         qWarning() << "Default REACHED!!!";
0227         auto element = new DebconfElement(k, parentWidget);
0228         auto label = new QLabel(element);
0229         label->setText(i18n("<b>Not implemented</b>: The input widget for data"
0230                             " type '%1' is not implemented. Will use default of '%2'.",
0231                             frontend->property(k, DebconfFrontend::Type),
0232                             frontend->value(k)));
0233         label->setWordWrap(true);
0234         return element;
0235     }
0236 }
0237 
0238 void DebconfGui::cmd_go(const QString &title, const QStringList &input)
0239 {
0240     Q_D(DebconfGui);
0241     qCDebug(DEBCONF) << "# GO GUI";
0242     d->cleanup();
0243     auto layout = qobject_cast<QVBoxLayout*>(d->parentWidget->layout());
0244     // if we have just one element and we are showing
0245     // elements that can make use of extra space
0246     // we don't add stretches
0247     bool needStretch = true;
0248     if (input.size() == 1) {
0249         const QString key = input.first();
0250         if (d->frontend->type(key) == DebconfFrontend::Text &&
0251             d->frontend->type(key) == DebconfFrontend::Note &&
0252             d->frontend->type(key) == DebconfFrontend::Error &&
0253             d->frontend->type(key) == DebconfFrontend::Multiselect) {
0254             needStretch = false;
0255         }
0256     }
0257 
0258     if (needStretch) {
0259         layout->addStretch();
0260     }
0261 
0262     for (const QString &elementName : input) {
0263         DebconfElement *element =  d->createElement(elementName);
0264         d->elements.append(element);
0265         layout->addWidget(element);
0266     }
0267 
0268     if (needStretch) {
0269         layout->addStretch();
0270     }
0271 
0272     d->parentWidget->setAutoFillBackground(false);
0273 
0274     d->titleL->setText(title);
0275     d->nextPB->setEnabled(true);
0276     Q_EMIT activated();
0277 }
0278 
0279 void DebconfGui::cmd_progress(const QString &cmd)
0280 {
0281     Q_D(DebconfGui);
0282     if (!d->elementProgress) {
0283         d->cleanup();
0284         d->elementProgress = new DebconfProgress(QString(), d->parentWidget);
0285         auto layout = qobject_cast<QVBoxLayout*>(d->parentWidget->layout());
0286         layout->addStretch();
0287         layout->addWidget(d->elementProgress);
0288         layout->addStretch();
0289         d->parentWidget->setAutoFillBackground(false);
0290         d->nextPB->setEnabled(false);
0291         d->backPB->setEnabled(false);
0292     }
0293     DebconfProgress *element = d->elementProgress;
0294 
0295     QStringList commands = cmd.split(QLatin1Char(' '));
0296     qCDebug(DEBCONF) << "KPROGRESS" << commands;
0297     if (commands.first() == QLatin1String("START")) {
0298         d->titleL->setText(d->frontend->property(commands.at(3), DebconfFrontend::Description));
0299         int progress_min = commands.at(1).toInt();
0300         int progress_max = commands.at(2).toInt();
0301         element->startProgress(d->frontend->property(commands.at(3), DebconfFrontend::ExtendedDescription),
0302                                progress_min,
0303                                progress_max);
0304     } else if (commands.first() == QLatin1String("SET")) {
0305         element->setProgress(commands.at(1).toInt());
0306     } else if (commands.first() == QLatin1String("STEP")) {
0307         element->stepProgress(commands.at(1).toInt());
0308     } else if (commands.first() == QLatin1String("INFO")) {
0309         element->setProgressInfo(d->frontend->property(commands.at(1), DebconfFrontend::Description));
0310     } else if (commands.first() == QLatin1String("STOP")) {
0311         element->stopProgress();
0312     }
0313     Q_EMIT activated();
0314     d->frontend->say(QLatin1String("0 ok"));
0315 }
0316 
0317 void DebconfGuiPrivate::cleanup()
0318 {
0319     delete parentWidget;
0320     elementProgress = nullptr;
0321     elements.clear();
0322 
0323     parentWidget = new QWidget(scrollArea);
0324     scrollArea->setWidget(parentWidget);
0325     auto layout = new QVBoxLayout(parentWidget);
0326     parentWidget->setLayout(layout);
0327 }
0328 
0329 void DebconfGui::on_nextPB_clicked()
0330 {
0331     Q_D(DebconfGui);
0332     // extract all the elements
0333     const auto elements = d->elements;
0334     for (const DebconfElement *element : elements) {
0335         d->frontend->setValue(element->name(), element->value());
0336     }
0337 
0338     d->frontend->next();
0339 }
0340 
0341 void DebconfGui::on_backPB_clicked()
0342 {
0343     Q_D(DebconfGui);
0344     d->frontend->back();
0345 }
0346 
0347 void DebconfGui::on_cancelPB_clicked()
0348 {
0349     Q_D(DebconfGui);
0350     d->frontend->cancel();
0351 }
0352 
0353 void DebconfGui::closeEvent(QCloseEvent *event)
0354 {
0355     Q_D(DebconfGui);
0356     // It would be better to hid the close button on
0357     // on the window decoration:
0358     d->frontend->cancel();
0359     QWidget::closeEvent(event);
0360 }
0361 
0362 #include "moc_DebconfGui.cpp"