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