MythTV master
mythtv-setup.cpp
Go to the documentation of this file.
1// C/C++
2#include <fcntl.h>
3#include <iostream>
4#include <memory>
5#include <unistd.h>
6
7// Qt
8#include <QApplication>
9#include <QDir>
10#include <QFileInfo>
11#include <QMap>
12#include <QString>
13#include <QtGlobal>
14
15// MythTV
17#include "libmyth/mythcontext.h"
19#include "libmythbase/dbutil.h"
22#include "libmythbase/mythconfig.h"
29#include "libmythbase/mythversion.h"
30#include "libmythtv/cardutil.h"
35#include "libmythtv/dbcheck.h"
43#include "libmythupnp/ssdp.h"
44
45// MythTV Setup
46#include "backendsettings.h"
47#include "channeleditor.h"
48#include "checksetup.h"
49#include "exitprompt.h"
52#include "startprompt.h"
53
56
58
59static void SetupMenuCallback(void* /* data */, QString& selection)
60{
61 QString sel = selection.toLower();
62
63 if (sel == "general")
64 {
66 auto *ssd = new StandardSettingDialog(mainStack, "generalsettings",
67 new BackendSettings());
68
69 if (ssd->Create())
70 mainStack->AddScreen(ssd);
71 else
72 delete ssd;
73 }
74 else if (sel == "capture cards")
75 {
77 auto *ssd = new StandardSettingDialog(mainStack, "capturecardeditor",
78 new CaptureCardEditor());
79
80 if (ssd->Create())
81 mainStack->AddScreen(ssd);
82 else
83 delete ssd;
84 }
85 else if (sel == "video sources")
86 {
88 auto *ssd = new StandardSettingDialog(mainStack, "videosourceeditor",
89 new VideoSourceEditor());
90 if (ssd->Create())
91 mainStack->AddScreen(ssd);
92 else
93 delete ssd;
94 }
95 else if (sel == "card inputs")
96 {
98 auto *ssd = new StandardSettingDialog(mainStack, "cardinputeditor",
99 new CardInputEditor());
100
101 if (ssd->Create())
102 mainStack->AddScreen(ssd);
103 else
104 delete ssd;
105 }
106 else if (sel == "recording profile")
107 {
109 auto *ssd = new StandardSettingDialog(mainStack, "recordingprofileeditor",
110 new ProfileGroupEditor());
111
112 if (ssd->Create())
113 mainStack->AddScreen(ssd);
114 else
115 delete ssd;
116 }
117 else if (sel == "channel editor")
118 {
120
121 auto *chanedit = new ChannelEditor(mainStack);
122
123 if (chanedit->Create())
124 mainStack->AddScreen(chanedit);
125 else
126 delete chanedit;
127 }
128 else if (sel == "storage groups")
129 {
131 auto *ssd = new StandardSettingDialog(mainStack, "storagegroupeditor",
133
134 if (ssd->Create())
135 mainStack->AddScreen(ssd);
136 else
137 delete ssd;
138 }
139 else if (sel == "systemeventeditor")
140 {
142
143 auto *msee = new MythSystemEventEditor(mainStack, "System Event Editor");
144
145 if (msee->Create())
146 mainStack->AddScreen(msee);
147 else
148 delete msee;
149 }
150 else if (sel.startsWith("exiting_app") || (sel == "standby_mode"))
151 {
152 if (!exitPrompt)
153 exitPrompt = new ExitPrompter();
155 }
156 else
157 {
158 LOG(VB_GENERAL, LOG_ERR, "Unknown menu action: " + selection);
159 }
160}
161
162static bool RunMenu(const QString& themedir, const QString& themename)
163{
164 QByteArray tmp = themedir.toLocal8Bit();
165 menu = new MythThemedMenu(
166 QString(tmp.constData()), "setup.xml",
167 GetMythMainWindow()->GetMainStack(), "mainmenu", false);
168
169 if (menu->foundTheme())
170 {
173 return true;
174 }
175
176 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't use theme '%1'").arg(themename));
177 delete menu;
178 menu = nullptr;
179
180 return false;
181}
182
183// If the theme specified in the DB is somehow broken, try a standard one:
184//
185static bool resetTheme(QString themedir, const QString &badtheme)
186{
187 QString themename = DEFAULT_UI_THEME;
188
189 if (badtheme == DEFAULT_UI_THEME)
190 themename = FALLBACK_UI_THEME;
191
192 LOG(VB_GENERAL, LOG_ERR,
193 QString("Overriding broken theme '%1' with '%2'")
194 .arg(badtheme, themename));
195
196 gCoreContext->OverrideSettingForSession("Theme", themename);
197 themedir = GetMythUI()->FindThemeDir(themename);
198
201
202 return RunMenu(themedir, themename);
203}
204
205static int reloadTheme(void)
206{
208 QString themename = gCoreContext->GetSetting("Theme", DEFAULT_UI_THEME);
209 QString themedir = GetMythUI()->FindThemeDir(themename);
210 if (themedir.isEmpty())
211 {
212 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find theme '%1'")
213 .arg(themename));
215 }
216
218
220 if (menu)
221 menu->Close();
224
225 if (!RunMenu(themedir, themename) && !resetTheme(themedir, themename))
227
228 return 0;
229}
230
231int main(int argc, char *argv[])
232{
233 QString geometry;
234 bool doScan = false;
235 bool doScanList = false;
236 bool doScanSaveOnly = false;
237 bool scanInteractive = true;
238 bool expertMode = false;
239 uint scanImport = 0;
240 bool scanFTAOnly = false;
241 bool scanLCNOnly = false;
242 bool scanCompleteOnly = false;
243 bool scanFullChannelSearch = false;
244 bool scanRemoveDuplicates = false;
245 bool addFullTS = false;
246 ServiceRequirements scanServiceRequirements = kRequireAV;
247 uint scanCardId = 0;
248 QString frequencyStandard = "atsc";
249 QString modulation = "vsb8";
250 QString region = "us";
251 QString scanInputName = "";
252
254 if (!cmdline.Parse(argc, argv))
255 {
258 }
259
260 if (cmdline.toBool("showhelp"))
261 {
263 return GENERIC_EXIT_OK;
264 }
265
266 if (cmdline.toBool("showversion"))
267 {
269 return GENERIC_EXIT_OK;
270 }
271
272 bool quiet = false;
273 bool use_display = true;
274 if (cmdline.toBool("scan"))
275 {
276 quiet = true;
277 use_display = false;
278 }
279
280 std::unique_ptr<QCoreApplication> app {nullptr};
281
282 if (use_display)
283 {
285 app = std::make_unique<QApplication>(argc, argv);
286 }
287 else
288 {
289 app = std::make_unique<QCoreApplication>(argc, argv);
290 }
291 QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHTV_SETUP);
292
293 if (cmdline.toBool("geometry"))
294 geometry = cmdline.toString("geometry");
295
296 QString mask("general");
297 int retval = cmdline.ConfigureLogging(mask, quiet);
298 if (retval != GENERIC_EXIT_OK)
299 return retval;
300
301 if (cmdline.toBool("expert"))
302 expertMode = true;
303 if (cmdline.toBool("scanlist"))
304 doScanList = true;
305 if (cmdline.toBool("savescan"))
306 doScanSaveOnly = true;
307 if (cmdline.toBool("scannoninteractive"))
308 scanInteractive = false;
309
310 if (cmdline.toBool("importscan"))
311 scanImport = cmdline.toUInt("importscan");
312 if (cmdline.toBool("ftaonly"))
313 scanFTAOnly = true;
314 if (cmdline.toBool("lcnonly"))
315 scanLCNOnly = true;
316 if (cmdline.toBool("completeonly"))
317 scanCompleteOnly = true;
318 if (cmdline.toBool("fullsearch"))
319 scanFullChannelSearch = true;
320 if (cmdline.toBool("removeduplicates"))
321 scanRemoveDuplicates = true;
322 if (cmdline.toBool("addfullts"))
323 addFullTS = true;
324 if (cmdline.toBool("servicetype"))
325 {
326 scanServiceRequirements = kRequireNothing;
327 if (cmdline.toString("servicetype").contains("radio"))
328 scanServiceRequirements = kRequireAudio;
329 if (cmdline.toString("servicetype").contains("tv"))
330 scanServiceRequirements = kRequireAV;
331 if (cmdline.toString("servicetype").contains("tv+radio") ||
332 cmdline.toString("servicetype").contains("radio+tv"))
333 scanServiceRequirements = kRequireAudio;
334 if (cmdline.toString("servicetype").contains("all"))
335 scanServiceRequirements = kRequireNothing;
336 }
337
338 if (!cmdline.toBool("noupnp"))
339 {
340 // start looking for any uPnP devices we can use like VBoxes
341 SSDP::Instance()->PerformSearch("ssdp:all");
342 }
343 if (cmdline.toBool("scan"))
344 {
345 scanCardId = cmdline.toUInt("scan");
346 doScan = true;
347 }
348 if (cmdline.toBool("freqstd"))
349 frequencyStandard = cmdline.toString("freqstd").toLower();
350 if (cmdline.toBool("modulation"))
351 modulation = cmdline.toString("modulation").toLower();
352 if (cmdline.toBool("region"))
353 region = cmdline.toString("region").toLower();
354 if (cmdline.toBool("inputname"))
355 scanInputName = cmdline.toString("inputname");
356
357 if (!geometry.isEmpty())
359
360 MythContext context {MYTH_BINARY_VERSION};
361
363 if (!context.Init(use_display,false,true)) // No Upnp, Prompt for db
364 {
365 LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
367 }
368
370
371 if (!GetMythDB()->HaveSchema())
372 {
375 }
376
377 setHttpProxy();
378
379 if (use_display)
380 {
381 QString fileprefix = GetConfDir();
382 QDir dir(fileprefix);
383 if (!dir.exists())
384 dir.mkdir(fileprefix);
385 }
386
387 if (doScan)
388 {
389 bool okCardID = scanCardId != 0U;
390
391 if (scanInputName.isEmpty())
392 scanInputName = CardUtil::GetInputName(scanCardId);
393
394 bool okInputName = (scanInputName == CardUtil::GetInputName(scanCardId)
395 && scanInputName != "None");
396
397 doScan = (okCardID && okInputName);
398
399 if (!okCardID)
400 {
401 std::cerr << "You must enter a valid cardid to scan." << std::endl;
402 std::vector<unsigned int> cardids = CardUtil::GetInputIDs();
403 if (cardids.empty())
404 {
405 std::cerr << "But no cards have been defined on this host"
406 << std::endl;
408 }
409 std::cerr << "Valid cards: " << std::endl;
410 for (uint id : cardids)
411 {
412 fprintf(stderr, "%5u: %s %s\n", id,
413 CardUtil::GetRawInputType(id).toLatin1().constData(),
414 CardUtil::GetVideoDevice(id).toLatin1().constData());
415 }
417 }
418
419 if (!okInputName)
420 {
421 std::cerr << "You must enter a valid input to scan this card."
422 << std::endl;
423 std::cerr << "Valid input: "
424 << CardUtil::GetInputName(scanCardId).toLatin1().constData()
425 << std::endl;
427 }
428 }
429
430 if (doScan)
431 {
432 int ret = 0;
433 uint inputid = scanCardId;
434 uint sourceid = CardUtil::GetSourceID(inputid);
435 QMap<QString,QString> startChan;
436 {
437 ChannelScannerCLI scanner(doScanSaveOnly, scanInteractive);
438
439 int scantype { ScanTypeSetting::FullScan_ATSC };
440 if (frequencyStandard == "atsc")
441 scantype = ScanTypeSetting::FullScan_ATSC; // NOLINT(bugprone-branch-clone)
442 else if (frequencyStandard == "dvbt")
444 else if (frequencyStandard == "mpeg")
446 else if (frequencyStandard == "iptv")
447 {
449 scanner.ImportM3U(scanCardId, scanInputName, sourceid, true);
450 }
451 else if (frequencyStandard == "extern")
452 {
454 }
455 else
456 {
458 }
459
460 scanner.Scan(scantype,
461 /* cardid */ scanCardId,
462 /* inputname */ scanInputName,
463 /* sourceid */ sourceid,
464 /* ignore signal timeout */ false,
465 /* follow_nit */ true,
466 /* test decryption */ true,
467 scanFTAOnly,
468 scanLCNOnly,
469 scanCompleteOnly,
470 scanFullChannelSearch,
471 scanRemoveDuplicates,
472 addFullTS,
473 scanServiceRequirements,
474 // stuff needed for particular scans
475 /* mplexid */ 0,
476 startChan, frequencyStandard, modulation, region);
477 ret = QCoreApplication::exec();
478 }
479 return (ret) ? GENERIC_EXIT_NOT_OK : GENERIC_EXIT_OK;
480 }
481
482 if (doScanList)
483 {
484 std::vector<ScanInfo> scans = LoadScanList();
485
486 std::cout<<" scanid cardid sourceid processed date"<<std::endl;
487 for (auto & scan : scans)
488 {
489 printf("%5i %6i %8i %8s %20s\n",
490 scan.m_scanid, scan.m_cardid,
491 scan.m_sourceid, (scan.m_processed) ? "yes" : "no",
492 scan.m_scandate.toString(Qt::ISODate)
493 .toLatin1().constData());
494 }
495 std::cout<<std::endl;
496
497 return GENERIC_EXIT_OK;
498 }
499
500 if (scanImport)
501 {
502 std::cout<<"*** SCAN IMPORT START ***"<<std::endl;
503 {
504 ScanDTVTransportList list = LoadScan(scanImport);
505 ChannelImporter ci(false, true, true, true, false,
506 scanFTAOnly, scanLCNOnly,
507 scanCompleteOnly,
508 scanFullChannelSearch,
509 scanRemoveDuplicates,
510 scanServiceRequirements);
511 ci.Process(list);
512 }
513 std::cout<<"*** SCAN IMPORT END ***"<<std::endl;
514 return GENERIC_EXIT_OK;
515 }
516
517 MythTranslation::load("mythfrontend");
518
519 QString themename = gCoreContext->GetSetting("Theme", DEFAULT_UI_THEME);
520 QString themedir = GetMythUI()->FindThemeDir(themename);
521 if (themedir.isEmpty())
522 {
523 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find theme '%1'")
524 .arg(themename));
526 }
527
528 MythMainWindow *mainWindow = GetMythMainWindow();
529 mainWindow->Init();
530 mainWindow->setWindowTitle(QObject::tr("MythTV Setup"));
531
532 // We must reload the translation after a language change and this
533 // also means clearing the cached/loaded theme strings, so reload the
534 // theme which also triggers a translation reload
536 {
537 if (!reloadTheme())
539 }
540
542 {
543 LOG(VB_GENERAL, LOG_ERR,
544 "MySQL time zone support is missing. "
545 "Please install it and try again. "
546 "See 'mysql_tzinfo_to_sql' for assistance.");
548 }
549
550 if (!UpgradeTVDatabaseSchema(true))
551 {
552 LOG(VB_GENERAL, LOG_ERR, "Couldn't upgrade database to new schema.");
554 }
555
556 // Refresh Global/Main Menu keys after DB update in case there was no DB
557 // when they were written originally
558 mainWindow->ReloadKeys();
559
560 if (!startPrompt)
563
564 // Let the user select buttons, type values, scan for channels, etc.
565 if (!RunMenu(themedir, themename) && !resetTheme(themedir, themename))
567
568 ExpertSettingsEditor *expertEditor = nullptr;
569 if (expertMode)
570 {
572 expertEditor =
573 new ExpertSettingsEditor(mainStack, "Expert Settings Editor");
574 if (expertEditor->Create())
575 mainStack->AddScreen(expertEditor);
576 else
577 {
578 delete expertEditor;
579 expertEditor = nullptr;
580 LOG(VB_GENERAL, LOG_ERR,
581 "Unable to create expert settings editor window");
582 return GENERIC_EXIT_OK;
583 }
584 }
585
586 QCoreApplication::exec();
587
589}
590
591/* vim: set expandtab tabstop=4 shiftwidth=4: */
ServiceRequirements
@ kRequireAudio
@ kRequireNothing
@ kRequireAV
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:292
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1773
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:294
static std::vector< uint > GetInputIDs(const QString &videodevice=QString(), const QString &rawtype=QString(), const QString &inputname=QString(), QString hostname=QString())
Returns all inputids of inputs that uses the specified videodevice if specified, and optionally rawty...
Definition: cardutil.cpp:1305
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1948
static void UpdateChannelGroups(void)
void Process(const ScanDTVTransportList &_transports, int sourceid=-1)
virtual bool ImportM3U(uint cardid, const QString &inputname, uint sourceid, bool is_mpts)
void Scan(int scantype, uint cardid, const QString &inputname, uint sourceid, bool do_ignore_signal_timeout, bool do_follow_nit, bool do_test_decryption, bool do_fta_only, bool do_lcn_only, bool do_complete_only, bool do_full_channel_search, bool do_remove_duplicates, bool do_add_full_ts, ServiceRequirements service_requirements, uint mplexid, const QMap< QString, QString > &startChan, const QString &freq_std, const QString &mod, const QString &tbl, const QString &tbl_start=QString(), const QString &tbl_end=QString())
static bool CheckTimeZoneSupport(void)
Check if MySQL has working timz zone support.
Definition: dbutil.cpp:865
void handleExit(void)
Definition: exitprompt.cpp:65
static bool prompt(bool force=false)
Ask the user for the language to use.
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
void ApplySettingsOverride(void)
Apply all overrides to the global context.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void PrintVersion(void)
Print application version information.
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
void PrintHelp(void) const
Print command line option help.
Startup context for MythTV.
Definition: mythcontext.h:20
QString GetSetting(const QString &key, const QString &defaultval="")
void OverrideSettingForSession(const QString &key, const QString &value)
static void ConfigureQtGUI(int SwapInterval, const MythCommandLineParser &CmdLine)
Shared static initialisation code for all MythTV GUI applications.
MythScreenStack * GetMainStack()
void SetEffectsEnabled(bool Enable)
void Init(bool MayReInit=true)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
virtual void Close()
An editor for MythSystemEvent handler commands.
Themed menu class, used for main menus in MythTV frontend.
void setCallback(void(*lcallback)(void *, QString &), void *data)
Set the themed menus callback function and data for that function.
bool foundTheme(void) const
Returns true iff a theme has been found by a previous call to SetMenuTheme().
static void reload()
Reload all active translators based on the current language setting.
static void load(const QString &module_name)
Load a QTranslator for the user's preferred language.
static void ParseGeometryOverride(const QString &Geometry)
Parse an X11 style command line geometry string.
QString FindThemeDir(const QString &ThemeName, bool Fallback=true)
Returns the full path to the theme denoted by themename.
bool Create(void) override
Creates the UI screen.
static SSDP * Instance()
Definition: ssdp.cpp:57
void PerformSearch(const QString &sST, std::chrono::seconds timeout=2s)
Send a SSDP discover multicast datagram.
Definition: ssdp.cpp:154
@ CurrentTransportScan
Scans the transport when there is no tuner (for ASI)
void handleStart()
Definition: startprompt.cpp:37
unsigned int uint
Definition: compat.h:68
bool InitializeMythSchema(void)
command to get the the initial database layout from an empty database:
Definition: dbcheck.cpp:1272
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
Definition: dbcheck.cpp:362
std::vector< ScanDTVTransport > ScanDTVTransportList
Definition: dtvmultiplex.h:143
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
Definition: exitcodes.h:16
@ GENERIC_EXIT_DB_NOTIMEZONE
Missing DB time zone support.
Definition: exitcodes.h:39
@ GENERIC_EXIT_DB_OUTOFDATE
Database needs upgrade.
Definition: exitcodes.h:19
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
@ GENERIC_EXIT_NO_THEME
No Theme available.
Definition: exitcodes.h:17
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:18
@ GENERIC_EXIT_DB_ERROR
Database error.
Definition: exitcodes.h:20
@ GENERIC_EXIT_NOT_OK
Exited with error.
Definition: exitcodes.h:14
static guint32 * tmp
Definition: goom_core.cpp:26
static constexpr const char * MYTH_APPNAME_MYTHTV_SETUP
Definition: mythappname.h:7
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDB * GetMythDB(void)
Definition: mythdb.cpp:51
static QString themedir
Definition: mythdirs.cpp:23
QString GetConfDir(void)
Definition: mythdirs.cpp:263
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
int main(int argc, char *argv[])
static bool RunMenu(const QString &themedir, const QString &themename)
StartPrompter * startPrompt
static void SetupMenuCallback(void *, QString &selection)
ExitPrompter * exitPrompt
static int reloadTheme(void)
static MythThemedMenu * menu
static bool resetTheme(QString themedir, const QString &badtheme)
MythUIHelper * GetMythUI()
static constexpr const char * FALLBACK_UI_THEME
static constexpr const char * DEFAULT_UI_THEME
@ ISODate
Default UTC.
Definition: mythdate.h:17
MythCommFlagCommandLineParser cmdline
def scan(profile, smoonURL, gate)
Definition: scan.py:54
std::vector< ScanInfo > LoadScanList(void)
Definition: scaninfo.cpp:268
ScanDTVTransportList LoadScan(uint scanid)
Definition: scaninfo.cpp:77