1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2021-07-24
7 * Description : MJPEG Stream configuration dialog - Views methods
8 *
9 * Copyright (C) 2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 * Copyright (C) 2021 by Quoc Hưng Tran <quochungtran1999 at gmail dot com>
11 *
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software Foundation;
15 * either version 2, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "mjpegstreamdlg_p.h"
25
26 namespace DigikamGenericMjpegStreamPlugin
27 {
28
setupItemsView()29 QWidget* MjpegStreamDlg::setupItemsView()
30 {
31 d->albumSupport = (d->settings.iface && d->settings.iface->supportAlbums());
32 QWidget* itemsSel = nullptr;
33
34 if (d->albumSupport)
35 {
36 d->albumSelector = d->settings.iface->albumChooser(this);
37 itemsSel = d->albumSelector;
38
39 connect(d->settings.iface, SIGNAL(signalAlbumChooserSelectionChanged()),
40 this, SLOT(slotSelectionChanged()));
41 }
42 else
43 {
44 d->listView = new DItemsList(this);
45 d->listView->setObjectName(QLatin1String("MjpegStream ImagesList"));
46 d->listView->setControlButtonsPlacement(DItemsList::ControlButtonsRight);
47 d->listView->setIface(d->settings.iface);
48
49 // Add all items currently loaded in application.
50
51 d->listView->loadImagesFromCurrentSelection();
52
53 // Replug the previous shared items list.
54
55 d->listView->slotAddImages(d->mngr->itemsList());
56 itemsSel = d->listView;
57
58 connect(d->listView, SIGNAL(signalImageListChanged()),
59 this, SLOT(slotSelectionChanged()));
60 }
61
62 return itemsSel;
63 }
64
setupServerView()65 void MjpegStreamDlg::setupServerView()
66 {
67 QWidget* const serverSettings = new QWidget(d->tabView);
68
69 QLabel* const portLbl = new QLabel(i18nc("@label", "Server Port:"), serverSettings);
70 d->srvPort = new DIntNumInput(serverSettings);
71 d->srvPort->setDefaultValue(8080);
72 d->srvPort->setRange(1025, 65535, 1);
73 d->srvPort->setWhatsThis(i18nc("@info", "The MJPEG server IP port."));
74 portLbl->setBuddy(d->srvPort);
75
76 d->startOnStartup = new QCheckBox(i18nc("@option", "Start Server at Startup"));
77 d->startOnStartup->setWhatsThis(i18nc("@info", "Set this option to turn-on the MJPEG server at application start-up automatically"));
78 d->startOnStartup->setChecked(true);
79
80 // ---
81
82 QLabel* const explanation = new QLabel(serverSettings);
83 explanation->setOpenExternalLinks(true);
84 explanation->setWordWrap(true);
85 explanation->setFrameStyle(QFrame::Box | QFrame::Plain);
86
87 explanation->setText(i18nc("@info",
88 "The %1 server allows to share items through the local network using a web browser. "
89 "Motion JPEG is a video compression format in which each video frame is compressed "
90 "separately as a JPEG image. MJPEG streams is a standard which allows network clients to be "
91 "connected without additional module. Most major web browsers and players support MJPEG stream. "
92 "To access to stream from your browser, just use http://address:port as url, with address " // krazy:exclude=insecurenet
93 "the MJPEG server IP, and port the server port set in this config dialog.",
94 QLatin1String("<a href='https://en.wikipedia.org/wiki/Motion_JPEG'>Motion JPEG</a>")));
95
96 d->srvButton = new QPushButton(serverSettings);
97 d->srvStatus = new QLabel(serverSettings);
98 d->aStats = new QLabel(serverSettings);
99 d->separator = new QLabel(QLatin1String(" / "), serverSettings);
100 d->iStats = new QLabel(serverSettings);
101 d->progress = new WorkingWidget(serverSettings);
102 d->srvPreview = new QPushButton(i18nc("@action: button", "Preview..."), serverSettings);
103 d->srvPreview->setWhatsThis(i18nc("@info", "Press this button to preview the stream on your computer with your browser."));
104
105 QGridLayout* const grid3 = new QGridLayout(serverSettings);
106 grid3->addWidget(portLbl, 0, 0, 1, 1);
107 grid3->addWidget(d->srvPort, 0, 1, 1, 1);
108 grid3->addWidget(d->startOnStartup, 0, 2, 1, 5);
109 grid3->addWidget(d->srvButton, 1, 0, 1, 1);
110 grid3->addWidget(d->srvStatus, 1, 1, 1, 1);
111 grid3->addWidget(d->aStats, 1, 2, 1, 1);
112 grid3->addWidget(d->separator, 1, 3, 1, 1);
113 grid3->addWidget(d->iStats, 1, 4, 1, 1);
114 grid3->addWidget(d->progress, 1, 5, 1, 1);
115 grid3->addWidget(d->srvPreview, 1, 6, 1, 1);
116 grid3->addWidget(explanation, 2, 0, 1, 7);
117 grid3->setSpacing(d->spacing);
118
119 d->tabView->insertTab(Private::Server, serverSettings, i18nc("@title", "Server"));
120
121 connect(d->srvButton, SIGNAL(clicked()),
122 this, SLOT(slotToggleMjpegServer()));
123
124 connect(d->srvPort, SIGNAL(valueChanged(int)),
125 this, SLOT(slotSettingsChanged()));
126
127 connect(d->srvPreview, SIGNAL(clicked()),
128 this, SLOT(slotOpenPreview()));
129 }
130
setupStreamView()131 void MjpegStreamDlg::setupStreamView()
132 {
133 d->streamSettings = new QWidget(d->tabView);
134
135 QLabel* const qualityLbl = new QLabel(i18nc("@label", "JPEG Quality:"), d->streamSettings);
136 d->quality = new DIntNumInput(d->streamSettings);
137 d->quality->setDefaultValue(75);
138 d->quality->setRange(50, 100, 1);
139 d->quality->setWhatsThis(i18nc("@info", "The JPEG quality [50:lower - 100:higher]. "
140 "Warning: better quality require more network bandwidth"));
141
142 qualityLbl->setBuddy(d->quality);
143
144 // ---
145
146 QLabel* const typeLabel = new QLabel(d->streamSettings);
147 typeLabel->setWordWrap(false);
148 typeLabel->setText(i18nc("@label", "JPEG Size:"));
149 d->typeVal = new DComboBox(d->streamSettings);
150 d->typeVal->combo()->setEditable(false);
151
152 QMap<VidSlideSettings::VidType, QString> map = VidSlideSettings::videoTypeNames();
153 QMap<VidSlideSettings::VidType, QString>::const_iterator it = map.constBegin();
154
155 while (it != map.constEnd())
156 {
157 d->typeVal->addItem(it.value(), (int)it.key());
158 ++it;
159 }
160
161 d->typeVal->setDefaultIndex(VidSlideSettings::BLUERAY);
162 d->typeVal->setWhatsThis(i18nc("@info", "The JPEG image size in pixels, using standard screen resolutions. "
163 "Warning: larger size require more network bandwidth"));
164 typeLabel->setBuddy(d->typeVal);
165
166 // ---
167
168 QLabel* const delayLbl = new QLabel(i18nc("@label", "Delay in Seconds:"), d->streamSettings);
169 d->delay = new DIntNumInput(d->streamSettings);
170 d->delay->setDefaultValue(5);
171 d->delay->setRange(1, 3600, 1);
172 d->delay->setWhatsThis(i18nc("@info", "The delay in seconds between images."));
173 delayLbl->setBuddy(d->delay);
174
175 QLabel* const rateLbl = new QLabel(i18nc("@label", "Frames by Second:"), d->streamSettings);
176 d->rate = new DIntNumInput(d->streamSettings);
177 d->rate->setDefaultValue(10);
178 d->rate->setRange(5, 24, 1);
179 d->rate->setWhatsThis(i18nc("@info", "The number of frames by second to render the stream. "
180 "Warning: larger rate require more network bandwidth"));
181 rateLbl->setBuddy(d->rate);
182
183 d->streamLoop = new QCheckBox(i18nc("@option:check", "Stream in Loop"), d->streamSettings);
184 d->streamLoop->setChecked(true);
185 d->streamLoop->setWhatsThis(i18nc("@info", "The MJPEG stream will be played in loop instead once."));
186
187 QGridLayout* const grid2 = new QGridLayout(d->streamSettings);
188 grid2->addWidget(qualityLbl, 0, 0, 1, 1);
189 grid2->addWidget(d->quality, 0, 1, 1, 1);
190 grid2->addWidget(typeLabel, 1, 0, 1, 1);
191 grid2->addWidget(d->typeVal, 1, 1, 1, 1);
192 grid2->addWidget(delayLbl, 2, 0, 1, 1);
193 grid2->addWidget(d->delay, 2, 1, 1, 1);
194 grid2->addWidget(rateLbl, 3, 0, 1, 1);
195 grid2->addWidget(d->rate, 3, 1, 1, 1);
196 grid2->addWidget(d->streamLoop, 4, 0, 1, 2);
197 grid2->setSpacing(d->spacing);
198
199 d->tabView->insertTab(Private::Stream, d->streamSettings, i18nc("@title", "Stream"));
200
201 connect(d->delay, SIGNAL(valueChanged(int)),
202 this, SLOT(slotSettingsChanged()));
203
204 connect(d->rate, SIGNAL(valueChanged(int)),
205 this, SLOT(slotSettingsChanged()));
206
207 connect(d->quality, SIGNAL(valueChanged(int)),
208 this, SLOT(slotSettingsChanged()));
209
210 connect(d->streamLoop, SIGNAL(stateChanged(int)),
211 this, SLOT(slotSettingsChanged()));
212
213 connect(d->typeVal, SIGNAL(currentIndexChanged(int)),
214 this, SLOT(slotSettingsChanged()));
215 }
216
setupTransitionView()217 void MjpegStreamDlg::setupTransitionView()
218 {
219 QWidget* const transitionSettings = new QWidget(d->tabView);
220
221 QLabel* const transLabel = new QLabel(transitionSettings);
222 transLabel->setWordWrap(false);
223 transLabel->setText(i18nc("@label", "Type:"));
224 d->transVal = new DComboBox(transitionSettings);
225 d->transVal->combo()->setEditable(false);
226
227 QMap<TransitionMngr::TransType, QString> map4 = TransitionMngr::transitionNames();
228 QMap<TransitionMngr::TransType, QString>::const_iterator it4 = map4.constBegin();
229
230 while (it4 != map4.constEnd())
231 {
232 d->transVal->addItem(it4.value(), (int)it4.key());
233 ++it4;
234 }
235
236 d->transVal->setDefaultIndex(TransitionMngr::None);
237 transLabel->setBuddy(d->transVal);
238
239 QLabel* const transNote = new QLabel(transitionSettings);
240 transNote->setWordWrap(true);
241 transNote->setText(i18nc("@label", "A transition is an visual effect applied between two images. "
242 "For some effects, the duration can depend of random values and "
243 "can change while the stream."));
244
245 d->transPreview = new TransitionPreview(transitionSettings);
246 d->transPreview->setImagesList(QList<QUrl>());
247
248 QGridLayout* const transGrid = new QGridLayout(transitionSettings);
249 transGrid->setSpacing(d->spacing);
250 transGrid->addWidget(transLabel, 0, 0, 1, 1);
251 transGrid->addWidget(d->transVal, 0, 1, 1, 1);
252 transGrid->addWidget(transNote, 1, 0, 1, 2);
253 transGrid->addWidget(d->transPreview, 0, 2, 2, 1);
254 transGrid->setColumnStretch(1, 10);
255 transGrid->setRowStretch(1, 10);
256
257 d->tabView->insertTab(Private::Transition, transitionSettings, i18nc("@title", "Transition"));
258
259 connect(d->transVal, SIGNAL(currentIndexChanged(int)),
260 this, SLOT(slotSettingsChanged()));
261 }
262
setupEffectView()263 void MjpegStreamDlg::setupEffectView()
264 {
265 QWidget* const effectSettings = new QWidget(d->tabView);
266
267 QLabel* const effLabel = new QLabel(effectSettings);
268 effLabel->setWordWrap(false);
269 effLabel->setText(i18nc("@label", "Type:"));
270 d->effVal = new DComboBox(effectSettings);
271 d->effVal->combo()->setEditable(false);
272
273 QMap<EffectMngr::EffectType, QString> map6 = EffectMngr::effectNames();
274 QMap<EffectMngr::EffectType, QString>::const_iterator it6 = map6.constBegin();
275
276 while (it6 != map6.constEnd())
277 {
278 d->effVal->insertItem((int)it6.key(), it6.value(), (int)it6.key());
279 ++it6;
280 }
281
282 d->effVal->setDefaultIndex(EffectMngr::None);
283 effLabel->setBuddy(d->effVal);
284
285 QLabel* const effNote = new QLabel(effectSettings);
286 effNote->setWordWrap(true);
287 effNote->setText(i18nc("@label", "An effect is an visual panning or zooming applied while an image "
288 "is displayed in MJPEG stream."));
289
290 d->effPreview = new EffectPreview(effectSettings);
291 d->effPreview->setImagesList(QList<QUrl>());
292
293 QGridLayout* const effGrid = new QGridLayout(effectSettings);
294 effGrid->setSpacing(d->spacing);
295 effGrid->addWidget(effLabel, 0, 0, 1, 1);
296 effGrid->addWidget(d->effVal, 0, 1, 1, 1);
297 effGrid->addWidget(effNote, 1, 0, 1, 2);
298 effGrid->addWidget(d->effPreview, 0, 2, 2, 1);
299 effGrid->setColumnStretch(1, 10);
300 effGrid->setRowStretch(1, 10);
301
302 d->tabView->insertTab(Private::Effect, effectSettings, i18nc("@title", "Effect"));
303
304 connect(d->effVal, SIGNAL(currentIndexChanged(int)),
305 this, SLOT(slotSettingsChanged()));
306 }
307
setupOSDView()308 void MjpegStreamDlg::setupOSDView()
309 {
310 QWidget* const OSDSettings = new QWidget(d->tabView);
311
312 d->showName = new QCheckBox(i18nc("@option:check", "Show image file name"), OSDSettings);
313 d->showName->setWhatsThis(i18nc("@info", "Show the image file name at the bottom of the screen."));
314
315 d->showDate = new QCheckBox(i18nc("@option:check", "Show image creation date"), OSDSettings);
316 d->showDate->setWhatsThis(i18nc("@info", "Show the image creation time/date at the bottom of the screen."));
317
318 d->showApertureFocal = new QCheckBox(i18nc("@option:check", "Show camera aperture and focal length"), OSDSettings);
319 d->showApertureFocal->setWhatsThis(i18nc("@info", "Show the camera aperture and focal length at the bottom of the screen."));
320
321 d->showExpoSensitivity = new QCheckBox(i18nc("@option:check", "Show camera exposure and sensitivity"), OSDSettings);
322 d->showExpoSensitivity->setWhatsThis(i18nc("@info", "Show the camera exposure and sensitivity at the bottom of the screen."));
323
324 d->showMakeModel = new QCheckBox(i18nc("@option:check", "Show camera make and model"), OSDSettings);
325 d->showMakeModel->setWhatsThis(i18nc("@info", "Show the camera make and model at the bottom of the screen."));
326
327 d->showLensModel = new QCheckBox(i18nc("@option:check", "Show camera lens model"), OSDSettings);
328 d->showLensModel->setWhatsThis(i18nc("@info", "Show the camera lens model at the bottom of the screen."));
329
330 d->showComment = new QCheckBox(i18nc("@option:check", "Show image caption"), OSDSettings);
331 d->showComment->setWhatsThis(i18nc("@info", "Show the image caption at the bottom of the screen."));
332
333 d->showTitle = new QCheckBox(i18nc("@option:check", "Show image title"), OSDSettings);
334 d->showTitle->setWhatsThis(i18nc("@info", "Show the image title at the bottom of the screen."));
335
336 d->showCapIfNoTitle = new QCheckBox(i18nc("@option:check", "Show image caption if it has not title"), OSDSettings);
337 d->showCapIfNoTitle->setWhatsThis(i18nc("@info", "Show the image caption at the bottom of the screen if no titles existed."));
338
339 d->showRating = new QCheckBox(i18nc("@option:check", "Show image rating"), OSDSettings);
340 d->showRating->setWhatsThis(i18nc("@info", "Show the digiKam image rating at the bottom of the screen."));
341
342 d->showTags = new QCheckBox(i18nc("@option:check", "Show image tags"), OSDSettings);
343 d->showTags->setWhatsThis(i18nc("@info", "Show the digiKam image tag names at the bottom of the screen."));
344
345 d->osdFont = new DFontSelect(i18nc("@option", "On Screen Display Font:"), OSDSettings);
346 d->osdFont->setToolTip(i18nc("@info", "Select here the font used to display text in the MJPEG."));
347
348 QGridLayout* const grid = new QGridLayout(OSDSettings);
349 grid->addWidget(d->showName, 1, 0, 1, 1);
350 grid->addWidget(d->showRating, 1, 1, 1, 1);
351 grid->addWidget(d->showApertureFocal, 2, 0, 1, 1);
352 grid->addWidget(d->showDate, 2, 1, 1, 1);
353 grid->addWidget(d->showMakeModel, 3, 0, 1, 1);
354 grid->addWidget(d->showExpoSensitivity, 3, 1, 1, 1);
355 grid->addWidget(d->showLensModel, 4, 0, 1, 1);
356 grid->addWidget(d->showComment, 4, 1, 1, 1);
357 grid->addWidget(d->showTitle, 5, 0, 1, 1);
358 grid->addWidget(d->showCapIfNoTitle, 5, 1, 1, 1);
359 grid->addWidget(d->showTags, 6, 0, 1, 1);
360 grid->addWidget(d->osdFont, 7, 0, 1, 2);
361
362 d->tabView->insertTab(Private::OSD, OSDSettings, i18nc("@title: On Screen Display", "OSD"));
363
364 connect(d->showName, SIGNAL(stateChanged(int)),
365 this, SLOT(slotSettingsChanged()));
366
367 connect(d->showApertureFocal, SIGNAL(stateChanged(int)),
368 this, SLOT(slotSettingsChanged()));
369
370 connect(d->showDate, SIGNAL(stateChanged(int)),
371 this, SLOT(slotSettingsChanged()));
372
373 connect(d->showMakeModel, SIGNAL(stateChanged(int)),
374 this, SLOT(slotSettingsChanged()));
375
376 connect(d->showExpoSensitivity, SIGNAL(stateChanged(int)),
377 this, SLOT(slotSettingsChanged()));
378
379 connect(d->showLensModel, SIGNAL(stateChanged(int)),
380 this, SLOT(slotSettingsChanged()));
381
382 connect(d->showComment, SIGNAL(stateChanged(int)),
383 this, SLOT(slotSettingsChanged()));
384
385 // Disable and uncheck the "Show captions if no title" checkbox if the "Show comment" checkbox enabled
386
387 connect(d->showComment, SIGNAL(stateChanged(int)),
388 this, SLOT(slotSetUnchecked(int)));
389
390 connect(d->showComment, SIGNAL(toggled(bool)),
391 d->showCapIfNoTitle, SLOT(setDisabled(bool)));
392
393 connect(d->showTitle, SIGNAL(stateChanged(int)),
394 this, SLOT(slotSettingsChanged()));
395
396 connect(d->showCapIfNoTitle, SIGNAL(stateChanged(int)),
397 this, SLOT(slotSettingsChanged()));
398
399 connect(d->showTags, SIGNAL(stateChanged(int)),
400 this, SLOT(slotSettingsChanged()));
401
402 connect(d->showRating, SIGNAL(stateChanged(int)),
403 this, SLOT(slotSettingsChanged()));
404
405 connect(d->osdFont, SIGNAL(signalFontChanged()),
406 this, SLOT(slotSettingsChanged()));
407 }
408
slotSetUnchecked(int)409 void MjpegStreamDlg::slotSetUnchecked(int)
410 {
411 d->showCapIfNoTitle->setCheckState(Qt::Unchecked);
412 }
413
414 } // namespace DigikamGenericMjpegStreamPlugin
415