}
static int
-wizard_cancel
- ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+wizard_page
+ ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp, const char *page )
{
pthread_mutex_lock(&global_lock);
free(config.wizard);
- config.wizard = strdup("");
+ config.wizard = strdup(page);
config_save();
pthread_mutex_unlock(&global_lock);
return 0;
}
+static int
+wizard_cancel
+ ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+{
+ return wizard_page(perm, opaque, op, args, resp, "");
+}
+
+static int
+wizard_start
+ ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+{
+ return wizard_page(perm, opaque, op, args, resp, "hello");
+}
+
void
api_wizard_init ( void )
{
{ "wizard/status/save", ACCESS_ADMIN, wizard_idnode_save_simple, wizard_status },
{ "wizard/mapping/load", ACCESS_ADMIN, wizard_idnode_load_simple, wizard_mapping },
{ "wizard/mapping/save", ACCESS_ADMIN, wizard_idnode_save_simple, wizard_mapping },
+ { "wizard/start", ACCESS_ADMIN, wizard_start, NULL },
{ "wizard/cancel", ACCESS_ADMIN, wizard_cancel, NULL },
{ NULL },
};
'channel_tag_exclude,channel_tag,comment';
tvheadend.idnode_grid(panel, {
+ id: 'access_entry',
url: 'api/access/entry',
titleS: _('Access Entry'),
titleP: _('Access Entries'),
};
tvheadend.idnode_grid(panel, {
+ id: 'channels',
url: 'api/channel',
all: 1,
comet: 'channel',
tvheadend.baseconf = function(panel, index) {
+ var wizardButton = {
+ name: 'wizard',
+ builder: function() {
+ return new Ext.Toolbar.Button({
+ tooltip: _('Start initial configuration wizard'),
+ iconCls: 'wizard',
+ text: _('Start wizard')
+ });
+ },
+ callback: function(conf) {
+ tvheadend.Ajax({
+ url: 'api/wizard/start',
+ success: function() {
+ window.location.reload();
+ }
+ });
+ }
+ };
+
tvheadend.idnode_simple(panel, {
url: 'api/config',
title: _('Base'),
tabIndex: index,
comet: 'config',
labelWidth: 250,
+ tbar: [wizardButton],
postsave: function(data, abuttons) {
var l = data['uilevel'];
if (l >= 0) {
background-image: url(../icons/arrow_right.png) !important;
}
+.finish {
+ background-image: url(../icons/accept.png) !important;
+}
.x-linked {
display: inline-block;
color: white;
}
+.x-wizard-icon {
+ float: right;
+}
+
+.x-wizard-description {
+ margin: 5px;
+ font: normal 12px arial, tahoma, helvetica, sans-serif;
+}
+
/* Table styles for webUI help */
.hts-doc-text table, .hts-doc-text th, .hts-doc-text td {
});
build();
+ if (conf.build)
+ conf.build(conf, panel);
return panel;
};
var width = p.fixedWidth;
var w = new Ext.ux.Window({
title: conf.winTitle,
- iconCls: 'edit',
+ iconCls: conf.iconCls || 'edit',
layout: 'fit',
autoWidth: width ? false : true,
autoHeight: true,
}
var dpanel = new Ext.Panel({
+ id: conf.id || null,
border: false,
header: false,
layout: 'fit',
}
var dpanel = new Ext.Panel({
+ id: conf.id || null,
border: false,
header: false,
layout: 'fit',
}
var dpanel = new Ext.Panel({
+ id: conf.id || null,
border: false,
header: false,
layout: 'fit',
}
tvheadend.idnode_grid(panel, {
+ id: 'mpegts_network',
url: 'api/mpegts/network',
titleS: _('Network'),
titleP: _('Networks'),
}
var dpanel = new Ext.Panel({
+ id: 'status_streams',
border: false,
header: false,
layout: 'fit',
tvheadend.tvadapters = function(panel, index) {
tvheadend.idnode_tree(panel, {
+ id: 'tvadapters',
url: 'api/hardware/tree',
title: _('TV adapters'),
iconCls: 'tvCards',
tvheadend.wizard_start = function(page) {
var w = null;
+ var tabMapping = {
+ hello: 'access_entry',
+ network: 'mpegts_network',
+ input: 'tvadapters',
+ status: 'status_streams',
+ mapping: 'channels',
+ }
function cancel(conf) {
tvheadend.Ajax({
return null;
}
+ function getvalue(data, prefix) {
+ var m = data.params;
+ var l = prefix.length;
+ for (var i = 0; i < m.length; i++) {
+ var id = m[i].id;
+ if (id === prefix)
+ return m[i].value;
+ }
+ return null;
+ }
+
function newpage(conf, prefix) {
var p = getparam(conf.fullData, prefix);
if (p)
});
buttons.splice(0, 0, prevBtn);
}
+
+ function pbuild(conf, panel) {
+ var data = conf.fullData;
+ var icon = getvalue(data, 'icon');
+ var text = getvalue(data, 'description');
+ var c = '';
+ if (icon)
+ c += '<img class="x-wizard-icon" src="' + icon + '"/>';
+ c += '<div class="x-wizard-description">' + text + '</div>';
+ var p = new Ext.Panel({
+ width: 570,
+ html: c
+ });
+ panel.insert(0, p);
+ }
function build(d) {
d = json_decode(d);
var m = d[0];
var last = getparam(m, 'page_next_') === null;
tvheadend.idnode_editor_win('basic', m, {
+ build: pbuild,
fullData: m,
url: 'api/wizard/' + page,
winTitle: m.caption,
buildbtn: buildbtn,
labelWidth: 250,
saveText: last ? _('Finish') : _('Save & Next'),
- saveIconCls: last ? 'exit' : 'next',
+ saveIconCls: last ? 'finish' : 'next',
cancel: cancel,
uilevel: 'expert',
help: function() {
}
tvheadend.wizard = page;
+
+ if (page in tabMapping) {
+ var i = Ext.getCmp(tabMapping[page]);
+ var c = i ? i.ownerCt : null;
+ while (c) {
+ if ('activeTab' in c)
+ c.setActiveTab(i);
+ i = c;
+ c = c.ownerCt;
+ }
+ }
+
tvheadend.Ajax({
url: 'api/wizard/' + page + '/load',
params: {
return &prop_sbuf_ptr;
}
-#define SPECIAL_PROP(idval) { \
+static const void *icon_get(void *o)
+{
+ strcpy(prop_sbuf, "docresources/tvheadendlogo.png");
+ return &prop_sbuf_ptr;
+}
+
+#define SPECIAL_PROP(idval, getfcn) { \
.type = PT_STR, \
.id = idval, \
.name = "", \
- .get = empty_get, \
+ .get = getfcn, \
.opts = PO_RDONLY | PO_NOUI \
}
-#define PREV_BUTTON(page) SPECIAL_PROP("page_prev_" STRINGIFY(page))
-#define NEXT_BUTTON(page) SPECIAL_PROP("page_next_" STRINGIFY(page))
-#define LAST_BUTTON() SPECIAL_PROP("page_last")
+#define PREV_BUTTON(page) SPECIAL_PROP("page_prev_" STRINGIFY(page), empty_get)
+#define NEXT_BUTTON(page) SPECIAL_PROP("page_next_" STRINGIFY(page), empty_get)
+#define LAST_BUTTON() SPECIAL_PROP("page_last", empty_get)
+#define ICON() SPECIAL_PROP("icon", icon_get)
+#define DESCRIPTION(page) SPECIAL_PROP("description", wizard_description_##page)
+
+#define DESCRIPTION_FCN(page, desc) \
+static const void *wizard_description_##page(void *o) \
+{ \
+ static const char *t = desc; \
+ return &t; \
+}
/*
*
return 0;
}
+DESCRIPTION_FCN(hello, N_("\
+Enter allowed network (like 192.168.1.0/24) and user logins for administrator and ordinary user. \
+If the username is empty, anonymous access will be allowed.\
+"))
+
wizard_page_t *wizard_hello(void)
{
+ static const property_group_t groups[] = {
+ {
+ .name = N_("Network access"),
+ .number = 1,
+ },
+ {
+ .name = N_("Administrator login"),
+ .number = 2,
+ },
+ {
+ .name = N_("User login"),
+ .number = 3,
+ },
+ {}
+ };
static const property_t props[] = {
{
.type = PT_STR,
.id = "network",
- .name = N_("Network (like 192.168.1.0/24)"),
+ .name = N_("Allowed network"),
.get = hello_get_network,
.set = hello_set_network,
+ .group = 1
+ },
+ {
+ .type = PT_STR,
+ .id = "admin_username",
+ .name = N_("Admin username"),
+ .get = hello_get_network,
+ .set = hello_set_network,
+ .group = 2
+ },
+ {
+ .type = PT_STR,
+ .id = "admin_password",
+ .name = N_("Admin password"),
+ .get = hello_get_network,
+ .set = hello_set_network,
+ .group = 2
},
{
.type = PT_STR,
.name = N_("Username"),
.get = hello_get_network,
.set = hello_set_network,
+ .group = 3
},
{
.type = PT_STR,
.name = N_("Password"),
.get = hello_get_network,
.set = hello_set_network,
+ .group = 3
},
+ ICON(),
+ DESCRIPTION(hello),
NEXT_BUTTON(network),
{}
};
- wizard_page_t *page = page_init("wizard_hello", N_("Welcome - Tvheadend - your TV streaming server and video recorder"));
+ wizard_page_t *page =
+ page_init("wizard_hello",
+ N_("Welcome - Tvheadend - your TV streaming server and video recorder"));
idclass_t *ic = (idclass_t *)page->idnode.in_class;
ic->ic_properties = props;
+ ic->ic_groups = groups;
return page;
}
* Network settings
*/
+DESCRIPTION_FCN(network, N_("\
+Create networks.\
+"))
+
+
wizard_page_t *wizard_network(void)
{
static const property_t props[] = {
.get = hello_get_network,
.set = hello_set_network,
},
+ ICON(),
+ DESCRIPTION(network),
PREV_BUTTON(hello),
NEXT_BUTTON(input),
{}
* Input settings
*/
+DESCRIPTION_FCN(input, N_("\
+Assign inputs to networks.\
+"))
+
+
wizard_page_t *wizard_input(void)
{
static const property_t props[] = {
.get = hello_get_network,
.set = hello_set_network,
},
+ ICON(),
+ DESCRIPTION(input),
PREV_BUTTON(network),
NEXT_BUTTON(status),
{}
* Status
*/
+DESCRIPTION_FCN(status, N_("\
+Show the scan status.\
+"))
+
+
wizard_page_t *wizard_status(void)
{
static const property_t props[] = {
.get = hello_get_network,
.set = hello_set_network,
},
+ ICON(),
+ DESCRIPTION(status),
PREV_BUTTON(input),
NEXT_BUTTON(mapping),
{}
* Service Mapping
*/
+DESCRIPTION_FCN(mapping, N_("\
+Do the service mapping to channels.\
+"))
+
+
wizard_page_t *wizard_mapping(void)
{
static const property_t props[] = {
.get = hello_get_network,
.set = hello_set_network,
},
+ ICON(),
+ DESCRIPTION(mapping),
PREV_BUTTON(status),
LAST_BUTTON(),
{}