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"
28#include "libmythbase/mythversion.h"
29#include "libmythtv/cardutil.h"
34#include "libmythtv/dbcheck.h"
42#include "libmythupnp/ssdp.h"
43
44// MythTV Setup
45#include "backendsettings.h"
46#include "channeleditor.h"
47#include "checksetup.h"
48#include "exitprompt.h"
51#include "startprompt.h"
52
55
57
58static void SetupMenuCallback(void* /* data */, QString& selection)
59{
60 QString sel = selection.toLower();
61
62 if (sel == "general")
63 {
65 auto *ssd = new StandardSettingDialog(mainStack, "generalsettings",
66 new BackendSettings());
67
68 if (ssd->Create())
69 mainStack->AddScreen(ssd);
70 else
71 delete ssd;
72 }
73 else if (sel == "capture cards")
74 {
76 auto *ssd = new StandardSettingDialog(mainStack, "capturecardeditor",
77 new CaptureCardEditor());
78
79 if (ssd->Create())
80 mainStack->AddScreen(ssd);
81 else
82 delete ssd;
83 }
84 else if (sel == "video sources")
85 {
87 auto *ssd = new StandardSettingDialog(mainStack, "videosourceeditor",
88 new VideoSourceEditor());
89 if (ssd->Create())
90 mainStack->AddScreen(ssd);
91 else
92 delete ssd;
93 }
94 else if (sel == "card inputs")
95 {
97 auto *ssd = new StandardSettingDialog(mainStack, "cardinputeditor",
98 new CardInputEditor());
99
100 if (ssd->Create())
101 mainStack->AddScreen(ssd);
102 else
103 delete ssd;
104 }
105 else if (sel == "recording profile")
106 {
108 auto *ssd = new StandardSettingDialog(mainStack, "recordingprofileeditor",
109 new ProfileGroupEditor());
110
111 if (ssd->Create())
112 mainStack->AddScreen(ssd);
113 else
114 delete ssd;
115 }
116 else if (sel == "channel editor")
117 {
119
120 auto *chanedit = new ChannelEditor(mainStack);
121
122 if (chanedit->Create())
123 mainStack->AddScreen(chanedit);
124 else
125 delete chanedit;
126 }
127 else if (sel == "storage groups")
128 {
130 auto *ssd = new StandardSettingDialog(mainStack, "storagegroupeditor",
132
133 if (ssd->Create())
134 mainStack->AddScreen(ssd);
135 else
136 delete ssd;
137 }
138 else if (sel == "systemeventeditor")
139 {
141
142 auto *msee = new MythSystemEventEditor(mainStack, "System Event Editor");
143
144 if (msee->Create())
145 mainStack->AddScreen(msee);
146 else
147 delete msee;
148 }
149 else if (sel.startsWith("exiting_app") || (sel == "standby_mode"))
150 {
151 if (!exitPrompt)
152 exitPrompt = new ExitPrompter();
154 }
155 else
156 {
157 LOG(VB_GENERAL, LOG_ERR, "Unknown menu action: " + selection);
158 }
159}
160
161static bool RunMenu(const QString& themedir, const QString& themename)
162{
163 QByteArray tmp = themedir.toLocal8Bit();
164 menu = new MythThemedMenu(
165 QString(tmp.constData()), "setup.xml",
166 GetMythMainWindow()->GetMainStack(), "mainmenu", false);
167
168 if (menu->foundTheme())
169 {
172 return true;
173 }
174
175 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't use theme '%1'").arg(themename));
176 delete menu;
177 menu = nullptr;
178
179 return false;
180}
181
182// If the theme specified in the DB is somehow broken, try a standard one:
183//
184static bool resetTheme(QString themedir, const QString &badtheme)
185{
186 QString themename = DEFAULT_UI_THEME;
187
188 if (badtheme == DEFAULT_UI_THEME)
189 themename = FALLBACK_UI_THEME;
190
191 LOG(VB_GENERAL, LOG_ERR,
192 QString("Overriding broken theme '%1' with '%2'")
193 .arg(badtheme, themename));
194
195 gCoreContext->OverrideSettingForSession("Theme", themename);
196 themedir = GetMythUI()->FindThemeDir(themename);
197
200
201 return RunMenu(themedir, themename);
202}
203
204static int reloadTheme(void)
205{
207 QString themename = gCoreContext->GetSetting("Theme", DEFAULT_UI_THEME);
208 QString themedir = GetMythUI()->FindThemeDir(themename);
209 if (themedir.isEmpty())
210 {
211 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find theme '%1'")
212 .arg(themename));
214 }
215
217
219 if (menu)
220 menu->Close();
223
224 if (!RunMenu(themedir, themename) && !resetTheme(themedir, themename))
226
227 return 0;
228}
229
230int main(int argc, char *argv[])
231{
232 QString geometry;
233 bool doScan = false;
234 bool doScanList = false;
235 bool doScanSaveOnly = false;
236 bool scanInteractive = true;
237 bool expertMode = false;
238 uint scanImport = 0;
239 bool scanFTAOnly = false;
240 bool scanLCNOnly = false;
241 bool scanCompleteOnly = false;
242 bool scanFullChannelSearch = false;
243 bool scanRemoveDuplicates = false;
244 bool addFullTS = false;
245 ServiceRequirements scanServiceRequirements = kRequireAV;
246 uint scanCardId = 0;
247 QString frequencyStandard = "atsc";
248 QString modulation = "vsb8";
249 QString region = "us";
250 QString scanInputName = "";
251
253 if (!cmdline.Parse(argc, argv))
254 {
257 }
258
259 if (cmdline.toBool("showhelp"))
260 {
262 return GENERIC_EXIT_OK;
263 }
264
265 if (cmdline.toBool("showversion"))
266 {
268 return GENERIC_EXIT_OK;
269 }
270
271 bool quiet = false;
272 bool use_display = true;
273 if (cmdline.toBool("scan"))
274 {
275 quiet = true;
276 use_display = false;
277 }
278
279 std::unique_ptr<QCoreApplication> app {nullptr};
280
281 if (use_display)
282 {
284 app = std::make_unique<QApplication>(argc, argv);
285 }
286 else
287 {
288 app = std::make_unique<QCoreApplication>(argc, argv);
289 }
290 QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHTV_SETUP);
291
292 if (cmdline.toBool("geometry"))
293 geometry = cmdline.toString("geometry");
294
295 QString mask("general");
296 int retval = cmdline.ConfigureLogging(mask, quiet);
297 if (retval != GENERIC_EXIT_OK)
298 return retval;
299
300 if (cmdline.toBool("expert"))
301 expertMode = true;
302 if (cmdline.toBool("scanlist"))
303 doScanList = true;
304 if (cmdline.toBool("savescan"))
305 doScanSaveOnly = true;
306 if (cmdline.toBool("scannoninteractive"))
307 scanInteractive = false;
308
309 if (cmdline.toBool("importscan"))
310 scanImport = cmdline.toUInt("importscan");
311 if (cmdline.toBool("ftaonly"))
312 scanFTAOnly = true;
313 if (cmdline.toBool("lcnonly"))
314 scanLCNOnly = true;
315 if (cmdline.toBool("completeonly"))
316 scanCompleteOnly = true;
317 if (cmdline.toBool("fullsearch"))
318 scanFullChannelSearch = true;
319 if (cmdline.toBool("removeduplicates"))
320 scanRemoveDuplicates = true;
321 if (cmdline.toBool("addfullts"))
322 addFullTS = true;
323 if (cmdline.toBool("servicetype"))
324 {
325 scanServiceRequirements = kRequireNothing;
326 if (cmdline.toString("servicetype").contains("radio"))
327 scanServiceRequirements = kRequireAudio;
328 if (cmdline.toString("servicetype").contains("tv"))
329 scanServiceRequirements = kRequireAV;
330 if (cmdline.toString("servicetype").contains("tv+radio") ||
331 cmdline.toString("servicetype").contains("radio+tv"))
332 scanServiceRequirements = kRequireAudio;
333 if (cmdline.toString("servicetype").contains("all"))
334 scanServiceRequirements = kRequireNothing;
335 }
336
337 if (!cmdline.toBool("noupnp"))
338 {
339 // start looking for any uPnP devices we can use like VBoxes
340 SSDP::Instance()->PerformSearch("ssdp:all");
341 }
342 if (cmdline.toBool("scan"))
343 {
344 scanCardId = cmdline.toUInt("scan");
345 doScan = true;
346 }
347 if (cmdline.toBool("freqstd"))
348 frequencyStandard = cmdline.toString("freqstd").toLower();
349 if (cmdline.toBool("modulation"))
350 modulation = cmdline.toString("modulation").toLower();
351 if (cmdline.toBool("region"))
352 region = cmdline.toString("region").toLower();
353 if (cmdline.toBool("inputname"))
354 scanInputName = cmdline.toString("inputname");
355
356 if (!geometry.isEmpty())
358
359 MythContext context {MYTH_BINARY_VERSION};
360
362 if (!context.Init(use_display,false,true)) // No Upnp, Prompt for db
363 {
364 LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
366 }
367
369
370 if (!GetMythDB()->HaveSchema())
371 {
374 }
375
376 setHttpProxy();
377
378 if (use_display)
379 {
380 QString fileprefix = GetConfDir();
381 QDir dir(fileprefix);
382 if (!dir.exists())
383 dir.mkdir(fileprefix);
384 }
385
386 if (doScan)
387 {
388 bool okCardID = scanCardId != 0U;
389
390 if (scanInputName.isEmpty())
391 scanInputName = CardUtil::GetInputName(scanCardId);
392
393 bool okInputName = (scanInputName == CardUtil::GetInputName(scanCardId)
394 && scanInputName != "None");
395
396 doScan = (okCardID && okInputName);
397
398 if (!okCardID)
399 {
400 std::cerr << "You must enter a valid cardid to scan.\n";
401 std::vector<unsigned int> cardids = CardUtil::GetInputIDs();
402 if (cardids.empty())
403 {
404 std::cerr << "But no cards have been defined on this host\n";
406 }
407 std::cerr << "Valid cards:\n";
408 for (uint id : cardids)
409 {
410 fprintf(stderr, "%5u: %s %s\n", id,
411 CardUtil::GetRawInputType(id).toLatin1().constData(),
412 CardUtil::GetVideoDevice(id).toLatin1().constData());
413 }
415 }
416
417 if (!okInputName)
418 {
419 std::cerr << "You must enter a valid input to scan this card.\n";
420 std::cerr << "Valid input: "
421 << CardUtil::GetInputName(scanCardId).toLatin1().constData()
422 << '\n';
424 }
425 }
426
427 if (doScan)
428 {
429 int ret = 0;
430 uint inputid = scanCardId;
431 uint sourceid = CardUtil::GetSourceID(inputid);
432 QMap<QString,QString> startChan;
433 {
434 ChannelScannerCLI scanner(doScanSaveOnly, scanInteractive);
435
436 int scantype { ScanTypeSetting::FullScan_ATSC };
437 if (frequencyStandard == "atsc")
438 scantype = ScanTypeSetting::FullScan_ATSC; // NOLINT(bugprone-branch-clone)
439 else if (frequencyStandard == "dvbt")
441 else if (frequencyStandard == "mpeg")
443 else if (frequencyStandard == "iptv")
444 {
446 scanner.ImportM3U(scanCardId, scanInputName, sourceid, true);
447 }
448 else if (frequencyStandard == "extern")
449 {
451 }
452 else
453 {
455 }
456
457 scanner.Scan(scantype,
458 /* cardid */ scanCardId,
459 /* inputname */ scanInputName,
460 /* sourceid */ sourceid,
461 /* ignore signal timeout */ false,
462 /* follow_nit */ true,
463 /* test decryption */ true,
464 scanFTAOnly,
465 scanLCNOnly,
466 scanCompleteOnly,
467 scanFullChannelSearch,
468 scanRemoveDuplicates,
469 addFullTS,
470 scanServiceRequirements,
471 // stuff needed for particular scans
472 /* mplexid */ 0,
473 startChan, frequencyStandard, modulation, region);
474 ret = QCoreApplication::exec();
475 }
476 return (ret) ? GENERIC_EXIT_NOT_OK : GENERIC_EXIT_OK;
477 }
478
479 if (doScanList)
480 {
481 std::vector<ScanInfo> scans = LoadScanList();
482
483 std::cout<<" scanid cardid sourceid processed date\n";
484 for (auto & scan : scans)
485 {
486 printf("%5i %6i %8i %8s %20s\n",
487 scan.m_scanid, scan.m_cardid,
488 scan.m_sourceid, (scan.m_processed) ? "yes" : "no",
489 scan.m_scandate.toString(Qt::ISODate)
490 .toLatin1().constData());
491 }
492 std::cout<<'\n';
493
494 return GENERIC_EXIT_OK;
495 }
496
497 if (scanImport)
498 {
499 std::cout<<"*** SCAN IMPORT START ***\n";
500 {
501 ScanDTVTransportList list = LoadScan(scanImport);
502 ChannelImporter ci(false, true, true, true, false,
503 scanFTAOnly, scanLCNOnly,
504 scanCompleteOnly,
505 scanFullChannelSearch,
506 scanRemoveDuplicates,
507 scanServiceRequirements);
508 ci.Process(list);
509 }
510 std::cout<<"*** SCAN IMPORT END ***\n";
511 return GENERIC_EXIT_OK;
512 }
513
514 MythTranslation::load("mythfrontend");
515
516 QString themename = gCoreContext->GetSetting("Theme", DEFAULT_UI_THEME);
517 QString themedir = GetMythUI()->FindThemeDir(themename);
518 if (themedir.isEmpty())
519 {
520 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find theme '%1'")
521 .arg(themename));
523 }
524
525 MythMainWindow *mainWindow = GetMythMainWindow();
526 mainWindow->Init();
527 mainWindow->setWindowTitle(QObject::tr("MythTV Setup"));
528
529 // We must reload the translation after a language change and this
530 // also means clearing the cached/loaded theme strings, so reload the
531 // theme which also triggers a translation reload
533 {
534 if (!reloadTheme())
536 }
537
539 {
540 LOG(VB_GENERAL, LOG_ERR,
541 "MySQL time zone support is missing. "
542 "Please install it and try again. "
543 "See 'mysql_tzinfo_to_sql' for assistance.");
545 }
546
547 if (!UpgradeTVDatabaseSchema(true))
548 {
549 LOG(VB_GENERAL, LOG_ERR, "Couldn't upgrade database to new schema.");
551 }
552
553 // Refresh Global/Main Menu keys after DB update in case there was no DB
554 // when they were written originally
555 mainWindow->ReloadKeys();
556
557 if (!startPrompt)
560
561 // Let the user select buttons, type values, scan for channels, etc.
562 if (!RunMenu(themedir, themename) && !resetTheme(themedir, themename))
564
565 ExpertSettingsEditor *expertEditor = nullptr;
566 if (expertMode)
567 {
569 expertEditor =
570 new ExpertSettingsEditor(mainStack, "Expert Settings Editor");
571 if (expertEditor->Create())
572 mainStack->AddScreen(expertEditor);
573 else
574 {
575 delete expertEditor;
576 expertEditor = nullptr;
577 LOG(VB_GENERAL, LOG_ERR,
578 "Unable to create expert settings editor window");
579 return GENERIC_EXIT_OK;
580 }
581 }
582
583 QCoreApplication::exec();
584
586}
587
588/* vim: set expandtab tabstop=4 shiftwidth=4: */
ServiceRequirements
@ kRequireAudio
@ kRequireNothing
@ kRequireAV
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:294
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1779
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:296
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:1311
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1954
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:869
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:159
@ CurrentTransportScan
Scans the transport when there is no tuner (for ASI)
void handleStart()
Definition: startprompt.cpp:37
unsigned int uint
Definition: compat.h:60
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 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:50
static QString themedir
Definition: mythdirs.cpp:26
QString GetConfDir(void)
Definition: mythdirs.cpp:285
#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