Wiki Navigation
- Loading...
Configuration vs Settings
Settings are not the same as configuration.
A setting is a data storage for a single data item in an application part. It can be read and written by the application itself, and does not have a user interface.
In contrast, a configuration is a "layer" around a setting. It contains metadata for a setting (like a display name for the setting, a help text, icons, a position in a configuration tree, and code to read and write the setting's values) to present the setting to the user via a standard control in some configuration application. It's like a gateway to the setting. A configuration is used by configuration applications like the MediaPortal Manager, the MediaPortal GUI and other configuration applications for MediaPortal.
Configurations are handled by the IConfigurationManager, while settings are handled by the ISettingsManager.
Configuration.Framework
The goal of this framework is to provide an interface which is able to configure settings, while any kind of UI can use the framework to configure settings.
Applications using the configuration will focus on the mapping of predefined configuration classes to configuration UI elements.
IConfigurationManager
This interface provides access to a tree of configuration nodes, which is organized in a structure consisting of "folders" and leaves. The folders are named Sections and Groups, while the leaves are Settings. So every path in the tree consists of one or more sections, maybe a group and a setting. Note that setting in this context doesn't mean a setting to be configured over the ISettingManager, a setting in this context simply is the metadata of an underlaying application setting object. Although messy, we'll maintain this term here.
Basically, the configuration manager exposes access to a tree of IConfigurationNode elements and the functionality to search nodes by a search string.
The default implementation of IConfigurationManager is ConfigurationManager.
IConfigurationNode
A configuration node is one member in the configuration tree, which holds the structure of sections, groups and settings. It exposes methods to navigate the tree and to query the associated configuration objects (sections, groups and settings).
Configurable Settings
Introduction
Plugins can specify their configurable settings by registering the configuration objects as plugin items at the /Configuration/Settings location. The configuration manager will access those items via the plugin manager.
Settings are part of Groups, and Groups are part of Sections. A Section can be a member of another Section.
- A Section which doesn't have a parent is called a Level 1 Section.
- A Section which is a child of a Level 1 Section, is called a Level 2 Section.
- There are as many levels of sections as the plugin developer needs, but we suggest not to have more than three levels of sections.
The General idea is to have a system that can be used by an arbitrary UI (winform, inside MediaPortal, webpage, ...). So the configuration objects don't expose any concrete UI objects, they only expose general information which will be needed by the UI to render the configuration object.
Exposing configurable settings
Configuration settings can be exposed by deriving a class from ConfigSetting.
ConfigSetting already has some derived classes which can be used:
- Entry
- LimitedNumberSelect
- MultipleEntryList
- MultipleSelectionList
- NumberSelect
- PathEntry
- PreferenceList
- SingleSelectionList
- YesNo
To cover a (potentially very large) setting class, every single setting in that class needs its own configuration object. So if a setting class has 50 different settings, where 45 should be exposed to the user, there need to be 50 configuration objects (derived from ConfigSetting).
Example 1
Say we have a setting bool ShowTipOfTheDay inside a setting class MySettings, which should be made configurable. We'll then create a configuration class for that setting:
using MediaPortal.Configuration.Settings; public class MyTipOfTheDaySetting : YesNo { #region Public properties // Tell the configuration manager the type of settings we can manage in this class public override Type SettingsObjectType { get { return typeof(MySettings); } } #endregion #region Public Methods public override void Load(object settingsObject) { // The given object is castable to an instance of "MySettings", // because the configuration manager called this method with an instance of the // type provided by property "SettingsObjectType". // => Extract the setting from the given object. _yes = ((MySettings) settingsObject).TipOfTheDay; } public override void Save(object settingsObject) { // Same as in method Load: Cast to our setting type ((MySettings) settingsObject).TipOfTheDay = _yes; Commit(); } #endregion private void Commit() { // Provide code here to apply the setting to the system } }
Example 2
In some cases we have to take a different approach.
This is a code fragment from the MainLanguage setting:
public class MainLanguage : SingleSelectionList { private CultureInfo[] _cultures; // There's no object used for this setting, so nothing to register. public override Type SettingsObjectType { get { return null; } } public override void Load() { _cultures = ServiceScope.Get<ILocalisation>().AvailableLanguages(); CultureInfo current = ServiceScope.Get<ILocalisation>().CurrentCulture; // Fill items List<IResourceString> items = new List<IResourceString>(_cultures.Length); for (int i = 0; i < _cultures.Length; i++) items.Add(LocalizationHelper.CreateLabelProperty(_cultures[i].DisplayName)); items.Sort(); _items = items; // Find index to select after sorting for (int i = 0; i < _cultures.Length; i++) { if (_cultures[i].Name == current.Name) { Selected = i; break; } } } public override void Save() { ServiceScope.Get<ILocalisation>().ChangeLanguage(_cultures[_selected].Name); } }
How To: plugin.xml
- The plugin.xml file is loaded by the plugin manager, which registers all registered items (such as ConfigSetting, Resource, ...).
- All <ConfigSetting>s must be registered at the /Configuration/Settings item location (or any sub location) in order to be available via the configuration manager.
- <Setting>s cannot be registered at another item location.
- Each plugin must register all exposed configuration objects. So also sections and groups have to be registered.
Available sections (by default)
These sections are garantueed to be available by the configuration framework.
This is not a final list, just some first thoughts.
- General
- Regional
- Language
- Plugins
- Appearance
- Menu
- Skin
- More Skins
- Subtitles
- Zoom modes
- Accoustic
- Sound
- Volume settings
- Shares
- Configure shares
- Database
- Music
- Pictures
- Video
- Sort
- Music
- Pictures
- Video
- Control
- Remote control
- Remote mapping
- Keyboard/Mouse
- Keyboard mapping
- Filters
- Codecs/Players
- DirectShow Filter Control
- Post processing
- Utilities
- Watchdog
- Installer
- Backup
Available attributes for the ConfigSetting item type
Id
String
Defines the Id of the item; this is used exactly as for other plugin items.
Text
Localized string
Text to show with this setting (localized, add this to the language files)
HelpText
Localized string
Text to show with as description (localized, add this to the language files)
ClassName
string
Name of the class which is derived from ConfigSetting for this setting
ListenTo
List of items, relative or absolute
Specifies all items to register to, so a notification is received if their setting changed
Available base classes for configuration objects
YesNo
Specifies a checkbox
SingleSelectionList
Specifies a ComboBox (>3 items) or RadioButtons (<=3 items)
MultipleSelectionList
Specifies a CheckedListBox
Entry
Specifies a TextBox
MultipleEntryList
Specifies a multiline TextBox
PreferenceList
Specifies a sortable ListBox
Path
Specifies an Entry which is used to configure a path
NumberSelect
Specifies a control which only accepts numbers (Integer or FloatingPoint)
LimitedNumberSelect
Specifies a NumberSelect with a limited range.
Tutorial
In this tutorial we want a Setting to be shown as a member of a Group, which is a member of a Level 2 Section.
Let's call our plugin "HelloWorld"
Hierarchy:
- Level 1 Section [sectionid]
- Level 2 Section [subsectionid]
- Group [groupid]
- Setting [sayhello -> should "HelloWorld" say hello?]
- Group [groupid]
- Level 2 Section [subsectionid]
Register a section
<Register location = "/Configuration/Settings"> <ConfigSection Id = "sectionid" Redundant = "true" Text = "[configuration.settings.sectiontext]" IconSmallPath ="images\someImage-22.png" IconLargePath ="images\someImage-48.png"/> </Register>
When registering sections (and groups), there might be another plugin or program part which already registered the same section or group. To avoid collisions, for registering sections an groups, the attribute "Redundant" has to be set to true. This will make the plugin manager only use the first available plugin item for the same id.
So in the example, if another plugin already registered "/Configuration/Settings/sectionid", this already existing registration will be preserved.
Attributes
Id
Define an ID which will become part of the location path for child entries
Text
Text to show for this section (localised, add this to the language files)
IconSmallPath
Path of a small icon for this section (22*22px)
IconLargePath
Path of a large icon for this section (48*48px)
Register a sub section
<Register location="/Configuration/Settings/sectionid"> <ConfigSection Id = "subsectionid" Redundant = "true" Text = "[configuration.settings.subsectiontext]" IconSmallPath ="images\someImage-22.png" IconLargePath ="images\someImage-48.png"/> </Register>
Register a group
<Register location="/Configuration/Settings/sectionid/subsectionid"> <ConfigGroup Id = "groupid" Redundant = "true" Text = "[configuration.myplugin.settings.mygrouptext]"/> </Register>
- Like in the section example, note to use the "Redundant" attribute.
Attributes
Id
Define an ID which will become part of the location path for child entries
Text
Text to show with this group (localised, add this to the language files)
Register a Setting
<Register location="/Configuration/Settings/Sectionid"> <ConfigSetting Id="sayhello" Text="[configuration.helloworld.sayhello]" HelpText="[configuration.helloworld.sayhello.help]" ClassName="NameSpace.HelloWorld.SayHello"/> </Register>
Attributes
Id
Define an ID which can be used by other settings
Text
Text to show with this setting (localised, add this to the language files)
HelpText
Text to show as help for this setting (localised, add this to the language files)
ClassName
Name of the class responsible for handling the setting (define the full qualified name of the class)
Listen to other configuration items
Use the ListenTo attribute to listen for changes of other configuration items.
Next is a full example on how to exactly use the ListenTo attribute.
In this example we'll use our previously registered "SayHello" item to register a listener for /sectionid/OtherItem and /Regional/Language.main. These strings are the registration locations of those items in the plugin tree. To show both relative and absolute path usage, the first target item will be given relative (?OtherItem) and the second will be given absolute (/Regional/Language.main).
<Register location="/Configuration/Settings/sectionid"> <ConfigSetting Id="sayhello" Text="[configuration.helloworld.sayhello]" HelpText="[configuration.helloworld.sayhello.help]" ClassName="NameSpace.HelloWorld.SayHello" ListenTo="[OtherItem] [/Regional/Language.main]"/> </Register>
So in other words:
- surround items (registration locations) with the square brackets '[' and ']'
- put double quotes around the whole list
Guidelines
If you have suggestions or want to discuss any of the content, use IRC or the forums.
Nesting Sections and Groups
Try to limit the level of Sections to 2, this will keep the UI clean and simple.
Extra levels should only be used for rare/extreme situations.
Also, try to limit the number of nested Groups -> clean and simple UI.
New Sections
Avoid to create new level 1 sections.
Settings, Groups, Sections
Make sure your settings and groups are member of a section, this is the only way to expose them in the UI. Top-level settings or groups aren't supported by the configuration framework.
Settings which belong together should always be part of the same group. This is to only way to be 100% sure that your settings will stay together, and that they will be shown in a specific order.
Think MediaPortal 2
Think "MediaPortal 2", not "MediaPortal 1"!!
Suppose your plugin needs 3 sections for settings:
- Folders
- Database
- Language
How this would be handled with MediaPortal 1
- MyPlugin
- Folders
- Database
- Language
How this should be handled with MediaPortal 2
- Folders
- SomePlugin
- MyPlugin
- SomeOtherPlugin
- Database
- SomePlugin
- MyPlugin
- SomeOtherPlugin
- Language
- SomePlugin
- MyPlugin
- SomeOtherPlugin
Case Sensitivity
All xml-files are case sensitive.
"<configsetting>" != "<ConfigSetting>"
"<string>" != "<String>" (for localised strings)
This page has no comments.