File indexing completed on 2025-11-09 04:05:09

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2012-05-28
0007  * Description : Media Server configuration dialog to share a single list of files
0008  *
0009  * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2017      by Ahmed Fathy <ahmed dot fathi dot abdelmageed at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "dmediaserverdlg.h"
0017 
0018 // Qt includes
0019 
0020 #include <QVBoxLayout>
0021 #include <QDialogButtonBox>
0022 #include <QApplication>
0023 #include <QMessageBox>
0024 #include <QPushButton>
0025 #include <QGridLayout>
0026 #include <QLabel>
0027 #include <QStyle>
0028 #include <QIcon>
0029 #include <QCheckBox>
0030 
0031 // KDE includes
0032 
0033 #include <klocalizedstring.h>
0034 #include <ksharedconfig.h>
0035 #include <kconfiggroup.h>
0036 
0037 // Local includes
0038 
0039 #include "ditemslist.h"
0040 #include "dxmlguiwindow.h"
0041 #include "workingwidget.h"
0042 #include "dmediaservermngr.h"
0043 
0044 namespace DigikamGenericMediaServerPlugin
0045 {
0046 
0047 class Q_DECL_HIDDEN DMediaServerDlg::Private
0048 {
0049 public:
0050 
0051     explicit Private()
0052       : dirty           (false),
0053         mngr            (DMediaServerMngr::instance()),
0054         srvButton       (nullptr),
0055         srvStatus       (nullptr),
0056         progress        (nullptr),
0057         aStats          (nullptr),
0058         separator       (nullptr),
0059         iStats          (nullptr),
0060         startOnStartup  (nullptr),
0061         albumSupport    (false),
0062         albumSelector   (nullptr),
0063         listView        (nullptr),
0064         iface           (nullptr),
0065         page            (nullptr),
0066         buttons         (nullptr)
0067     {
0068     }
0069 
0070     bool                dirty;
0071     DMediaServerMngr*   mngr;
0072     QPushButton*        srvButton;
0073     QLabel*             srvStatus;
0074     WorkingWidget*      progress;
0075     QLabel*             aStats;
0076     QLabel*             separator;
0077     QLabel*             iStats;
0078     QCheckBox*          startOnStartup;
0079     bool                albumSupport;
0080     QWidget*            albumSelector;
0081     DItemsList*         listView;
0082     DInfoInterface*     iface;
0083     QWidget*            page;
0084     QDialogButtonBox*   buttons;
0085 };
0086 
0087 DMediaServerDlg::DMediaServerDlg(QObject* const /*parent*/,
0088                                  DInfoInterface* const iface)
0089     : DPluginDialog(nullptr, DMediaServerMngr::instance()->configGroupName()),
0090       d            (new Private)
0091 {
0092     setWindowTitle(i18nc("@title:window", "Share Files With DLNA Media Server"));
0093 
0094     d->iface                 = iface;
0095 
0096     // NOTE: We overwrite the default albums chooser object name for load save check items state between sessions.
0097     // The goal is not mix these settings with other export tools.
0098 
0099     d->iface->setObjectName(QLatin1String("SetupMediaServerIface"));
0100 
0101     m_buttons->addButton(QDialogButtonBox::Cancel);
0102     m_buttons->addButton(QDialogButtonBox::Ok);
0103     m_buttons->button(QDialogButtonBox::Ok)->setDefault(true);
0104     d->page                  = new QWidget(this);
0105     QVBoxLayout* const vbx   = new QVBoxLayout(this);
0106     vbx->addWidget(d->page);
0107     vbx->addWidget(m_buttons);
0108     setLayout(vbx);
0109     setModal(false);
0110 
0111     // -------------------
0112 
0113     QGridLayout* const grid = new QGridLayout(d->page);
0114     d->albumSupport         = (d->iface && d->iface->supportAlbums());
0115 
0116     if (d->albumSupport)
0117     {
0118         d->albumSelector = d->iface->albumChooser(this);
0119         grid->addWidget(d->albumSelector, 0, 0, 1, 6);
0120 
0121         connect(d->iface, SIGNAL(signalAlbumChooserSelectionChanged()),
0122                 this, SLOT(slotSelectionChanged()));
0123     }
0124     else
0125     {
0126         d->listView = new DItemsList(d->page);
0127         d->listView->setObjectName(QLatin1String("MediaServer ImagesList"));
0128         d->listView->setControlButtonsPlacement(DItemsList::ControlButtonsRight);
0129         d->listView->setIface(d->iface);
0130 
0131         // Add all items currently loaded in application.
0132 
0133         d->listView->loadImagesFromCurrentSelection();
0134 
0135         // Replug the previous shared items list.
0136 
0137         d->listView->slotAddImages(d->mngr->itemsList());
0138         grid->addWidget(d->listView, 0, 0, 1, 6);
0139 
0140         connect(d->listView, SIGNAL(signalImageListChanged()),
0141                 this, SLOT(slotSelectionChanged()));
0142     }
0143 
0144     // -------------------
0145 
0146     const int spacing         = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0147                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0148 
0149     d->startOnStartup         = new QCheckBox(i18nc("@option", "Start Server at Startup"));
0150     d->startOnStartup->setWhatsThis(i18nc("@info", "Set this option to turn-on the DLNA server at application start-up automatically"));
0151     d->startOnStartup->setChecked(true);
0152 
0153     d->srvButton              = new QPushButton(this);
0154     d->srvStatus              = new QLabel(this);
0155     d->progress               = new WorkingWidget(this);
0156     d->aStats                 = new QLabel(this);
0157     d->separator              = new QLabel(QLatin1String(" / "), this);
0158     d->iStats                 = new QLabel(this);
0159 
0160     QLabel* const explanation = new QLabel(this);
0161     explanation->setOpenExternalLinks(true);
0162     explanation->setWordWrap(true);
0163     explanation->setFrameStyle(QFrame::Box | QFrame::Plain);
0164     QString txt;
0165 
0166     explanation->setText(i18nc("@info",
0167                                "The media server allows to share items through the local network "
0168                                "using %1 standard and %2 protocol. "
0169                                "Many kind of electronic devices can support DLNA, as tablets, cellulars, TV, etc.\n\n"
0170                                "Note: depending of the network features and the configuration, "
0171                                "the delay to discover the server on client devices can take a while.",
0172                                QLatin1String("<a href='https://en.wikipedia.org/wiki/Digital_Living_Network_Alliance'>DLNA</a>"),
0173                                QLatin1String("<a href='https://en.wikipedia.org/wiki/Universal_Plug_and_Play'>UPNP</a>")));
0174 
0175     grid->addWidget(d->startOnStartup, 1, 0, 1, 6);
0176     grid->addWidget(d->srvButton,      2, 0, 1, 1);
0177     grid->addWidget(d->srvStatus,      2, 1, 1, 1);
0178     grid->addWidget(d->aStats,         2, 2, 1, 1);
0179     grid->addWidget(d->separator,      2, 3, 1, 1);
0180     grid->addWidget(d->iStats,         2, 4, 1, 1);
0181     grid->addWidget(d->progress,       2, 5, 1, 1);
0182     grid->addWidget(explanation,       3, 0, 1, 6);
0183     grid->setColumnStretch(1, 10);
0184     grid->setRowStretch(0, 10);
0185     grid->setSpacing(spacing);
0186 
0187     // --------------------------------------------------------
0188 
0189     connect(d->srvButton, SIGNAL(clicked()),
0190             this, SLOT(slotToggleMediaServer()));
0191 
0192     connect(m_buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
0193             this, &DMediaServerDlg::reject);
0194 
0195     connect(m_buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked,
0196             this, &DMediaServerDlg::accept);
0197 
0198     // -------------------
0199 
0200     readSettings();
0201 }
0202 
0203 DMediaServerDlg::~DMediaServerDlg()
0204 {
0205     delete d;
0206 }
0207 
0208 void DMediaServerDlg::accept()
0209 {
0210     if (d->dirty)
0211     {
0212         bool empty = false;
0213 
0214         if (d->albumSupport)
0215         {
0216             empty = d->iface->albumChooserItems().isEmpty();
0217         }
0218         else
0219         {
0220             empty = d->listView->imageUrls().isEmpty();
0221         }
0222 
0223         if (!empty)
0224         {
0225             int rc = QMessageBox::question(this, i18nc("@title:window", "Media Server Contents"),
0226                                            i18nc("@info", "The items list to share has changed. "
0227                                                 "Do you want to start now the media server with this contents?"));
0228             if (rc == QMessageBox::Yes)
0229             {
0230                 startMediaServer();
0231             }
0232         }
0233     }
0234 
0235     saveSettings();
0236     QDialog::accept();
0237 }
0238 
0239 void DMediaServerDlg::readSettings()
0240 {
0241     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0242     KConfigGroup group        = config->group(d->mngr->configGroupName());
0243 
0244     d->startOnStartup->setChecked(group.readEntry(d->mngr->configStartServerOnStartupEntry(), false));
0245 
0246     updateServerStatus();
0247 }
0248 
0249 void DMediaServerDlg::saveSettings()
0250 {
0251     setMediaServerContents();
0252 
0253     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0254     KConfigGroup group        = config->group(d->mngr->configGroupName());
0255     group.writeEntry(d->mngr->configStartServerOnStartupEntry(), d->startOnStartup->isChecked());
0256     config->sync();
0257 }
0258 
0259 void DMediaServerDlg::updateServerStatus()
0260 {
0261     if (d->mngr->isRunning())
0262     {
0263         d->srvStatus->setText(i18nc("@label", "Server is running"));
0264         d->aStats->setText(i18ncp("@info", "1 album shared", "%1 albums shared", d->mngr->albumsShared()));
0265         d->separator->setVisible(true);
0266         d->iStats->setText(i18ncp("@info", "1 item shared",  "%1 items shared",  d->mngr->itemsShared()));
0267         d->srvButton->setText(i18nc("@action: button", "Stop"));
0268         d->srvButton->setIcon(QIcon::fromTheme(QLatin1String("media-playback-stop")));
0269         d->progress->toggleTimer(true);
0270         d->progress->setVisible(true);
0271     }
0272     else
0273     {
0274         d->srvStatus->setText(i18nc("@label", "Server is not running"));
0275         d->aStats->clear();
0276         d->separator->setVisible(false);
0277         d->iStats->clear();
0278         d->srvButton->setText(i18nc("@action: button", "Start"));
0279         d->srvButton->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start")));
0280         d->progress->toggleTimer(false);
0281         d->progress->setVisible(false);
0282     }
0283 }
0284 
0285 bool DMediaServerDlg::setMediaServerContents()
0286 {
0287     if (d->albumSupport)
0288     {
0289         DInfoInterface::DAlbumIDs albums = d->iface->albumChooserItems();
0290         MediaServerMap map;
0291 
0292         Q_FOREACH (int id, albums)
0293         {
0294             DAlbumInfo anf(d->iface->albumInfo(id));
0295             map.insert(anf.title(), d->iface->albumItems(id));
0296         }
0297 
0298         if (map.isEmpty())
0299         {
0300             QMessageBox::information(this, i18nc("@title:window", "Media Server Contents"),
0301                                      i18nc("@info", "There is no collection to share with the current selection..."));
0302             return false;
0303         }
0304 
0305         d->mngr->setCollectionMap(map);
0306     }
0307     else
0308     {
0309         QList<QUrl> urls = d->listView->imageUrls();
0310 
0311         if (urls.isEmpty())
0312         {
0313             QMessageBox::information(this, i18nc("@title:window", "Media Server Contents"),
0314                                      i18nc("@info", "There is no item to share with the current selection..."));
0315 
0316             return false;
0317         }
0318 
0319         d->mngr->setItemsList(i18nc("@info", "Shared Items"), urls);
0320     }
0321 
0322     return true;
0323 }
0324 
0325 void DMediaServerDlg::startMediaServer()
0326 {
0327     if (d->dirty)
0328     {
0329         d->dirty = false;
0330     }
0331 
0332     if (!setMediaServerContents())
0333     {
0334         return;
0335     }
0336 
0337     if (!d->mngr->startMediaServer())
0338     {
0339         QMessageBox::warning(this, i18nc("@title:window", "Starting Media Server"),
0340                              i18nc("@info", "An error occurs while to start Media Server..."));
0341     }
0342     else
0343     {
0344         d->mngr->mediaServerNotification(true);
0345     }
0346 
0347     updateServerStatus();
0348 }
0349 
0350 void DMediaServerDlg::slotSelectionChanged()
0351 {
0352     d->dirty = true;
0353 }
0354 
0355 void DMediaServerDlg::slotToggleMediaServer()
0356 {
0357     if (!d->mngr->isRunning())
0358     {
0359         startMediaServer();
0360     }
0361     else
0362     {
0363         d->mngr->cleanUp();
0364         updateServerStatus();
0365     }
0366 }
0367 
0368 } // namespace DigikamGenericMediaServerPlugin
0369 
0370 #include "moc_dmediaserverdlg.cpp"