Untergeordnete Seiten
  • Configuration Plugin Modules

  Wiki Navigation

    Loading...


 Recently Updated


 Latest Releases

 MediaPortal 1.32
            Releasenews | Download
 MediaPortal 2.5
            Releasenews | Download


Table of Contents

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?]

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.