SageTV Community

SageTV Community (http://forums.sagetv.com/forums/index.php)
-   SageTV Studio (http://forums.sagetv.com/forums/forumdisplay.php?f=34)
-   -   Plugin: STVI Configurator (http://forums.sagetv.com/forums/showthread.php?t=49727)

GKusnick 07-17-2010 07:18 PM

Plugin: STVI Configurator
 
Per this discussion, I have created an STVI (with some Java support code) that allows STVI plugins to use the V7 plugin configuration UI instead of rolling their own config UI. Detailed instructions are in the Javadocs for Tools Library V1.2, but the gist of it is that you implement a few lines of widget code in your STVI for each of the get/setConfig* methods, insert them into a standard place in the STVI Configurator code skeleton, and declare STVI Configurator as an STVI dependency in your manifest. Once this is done, a Configure button will appear on the options dialog for your plugin, and your widget-code methods will be called by the plugin manager in lieu of Java-based config methods.

To make things even easier, Tools Library V1.2 also includes an XmlConfig class that lets you define your config settings in an XML file, so that your config methods can be one-line calls into XmlConfig. You're not obliged to use XmlConfig with the STVI Configurator, but it does simplify things.

PLUCKYHD 07-18-2010 08:10 AM

Very nice work Greg and much needed for per STVi developers who don't want to code their own stvi options.

stuckless 07-18-2010 08:39 AM

Greg, I just want to clarify... Will the PluginAPI calls, such as, GetPluginConfigSettings, work on these plugins as well? (I think it will, but I just want to make sure)

GKusnick 07-18-2010 11:17 AM

Quote:

Originally Posted by stuckless (Post 437082)
Greg, I just want to clarify... Will the PluginAPI calls, such as, GetPluginConfigSettings, work on these plugins as well? (I think it will, but I just want to make sure)

You mean if you call them yourself from Java or from another STVI? Unfortunately no, they won't. To get this to work I had to replace PluginAPI calls in the stock STV with calls to my STVI-aware wrapper methods. I would rather not have done this, so if you know of a way for me to intercept calls to the native PluginAPI methods, that would be a cleaner and more robust approach.

stuckless 07-18-2010 01:02 PM

Quote:

Originally Posted by GKusnick (Post 437116)
You mean if you call them yourself from Java or from another STVI? Unfortunately no, they won't. To get this to work I had to replace PluginAPI calls in the stock STV with calls to my STVI-aware wrapper methods. I would rather not have done this, so if you know of a way for me to intercept calls to the native PluginAPI methods, that would be a cleaner and more robust approach.

Ok.. thx. I don't know of a better way, and I'm sure the way you've done it, is one of few nice ways to do what you've done.

I was asking, because at some point, I wanted to make the plugin configuration available via the Phoenix configuration metadata (which would also make it available via the web ui) . I won't be doing this for some time, but when I do it, I'll simply create phoenix configuration nodes by iterating the plugin list and calling GetPluginConfigSettings for each plugin (as well as the other plugin apis to fully populate the metadata)

Fuzzy 07-18-2010 02:14 PM

well, the plugin configurations are still just stored in the .properties files, so you shouldn't NEED to go through the plugin config system to use them from Phoenix/BMT Web.

stuckless 07-18-2010 02:29 PM

Quote:

Originally Posted by Fuzzy (Post 437152)
well, the plugin configurations are still just stored in the .properties files, so you shouldn't NEED to go through the plugin config system to use them from Phoenix/BMT Web.

A little OT, but... I'm just looking at the simplest way to adapt sage plugin configurations to the phoenix configuration metadata, and I was curious if Greg's changes would automatically fit in this model. phoenux uses a configuration metadata that describes each configuration element, such as type, editor, scope, label, help, and even how to store it. Because of this, the phoenix/bmt web ui configuration panels are dynamic generated from the metadata. This is actually very similar to how sage does it as well (except they don't store metadata, the plugins do), which is why, it's fairly trivial to adapt the sage7 configurations to phoenix (and vice versa). In phoenix-core plugin, I actually do the opposite, and I expose its configuration metadata to the native sagetv plugin configuration. (ie, in phoenix core, when you are configuring settings, while you are doing it via the stv, it simply proxies the requests directly to the phoenix configuration system.)

I could read properties, but properties don't actually contain any metadata, such as label, description, help, data type, etc. They only contain a key and value.

Fuzzy 07-18-2010 02:39 PM

Quote:

Originally Posted by stuckless (Post 437153)
A little OT, but... I'm just looking at the simplest way to adapt sage plugin configurations to the phoenix configuration metadata, and I was curious if Greg's changes would automatically fit in this model. phoenux uses a configuration metadata that describes each configuration element, such as type, editor, scope, label, help, and even how to store it. Because of this, the phoenix/bmt web ui configuration panels are dynamic generated from the metadata. This is actually very similar to how sage does it as well (except they don't store metadata, the plugins do), which is why, it's fairly trivial to adapt the sage7 configurations to phoenix (and vice versa). In phoenix-core plugin, I actually do the opposite, and I expose its configuration metadata to the native sagetv plugin configuration. (ie, in phoenix core, when you are configuring settings, while you are doing it via the stv, it simply proxies the requests directly to the phoenix configuration system.)

I could read properties, but properties don't actually contain any metadata, such as label, description, help, data type, etc. They only contain a key and value.

So where are you tracking the configuration metadata? is it in a separate file? you'd probably just have to access it from there. Another option would be to make a java config wrapper that contained 'config' objects. The config object would include the property name, description, default, help, etc, but the actual config data would be set/looked up from SetProperty/GetProperty API calls. Give your imports that dependency, and you'd gain the ability to access all your configs in the same manner.

As you mentioned, though, this would not work through the sage plugin system... in the end, the only way to do this cleanly is for sage to add STVI's to the basic plugin config system. I would think this would be trivial, and should really be taken care of next version.... Jeff?

GKusnick 07-18-2010 03:05 PM

Quote:

Originally Posted by Fuzzy (Post 437152)
well, the plugin configurations are still just stored in the .properties files, so you shouldn't NEED to go through the plugin config system to use them from Phoenix/BMT Web.

Actually STVIs using my Configurator are free to store their config settings wherever and however they please, using arbitrary widget code to access them. Even if they're stored in the properties file, there's no guarantee they'll comprehensible to any code other than the code that put them there, since there's no explicit relation between the plugin ID and the property keys.

Quote:

Originally Posted by Fuzzy (Post 437154)
...in the end, the only way to do this cleanly is for sage to add STVI's to the basic plugin config system. I would think this would be trivial, and should really be taken care of next version.... Jeff?

Jeff has already explained why it's not trivial for STVI plugins to use Java config methods (because the rules for enabling/loading STVIs are different than those for enabling/starting Java plugins, so there can be cases where an STVI is loaded without its config methods, or vice versa). Do you have an implementation in mind that gets around this limitation?

My solution was to code an STVI's config methods in widget code as an inseparable part of the STVI, so they're always enabled/loaded together. But this requires a somewhat klugey callback mechanism from Java into widget code via ExecuteWidgetChain, with parameters passed via AddStaticContext. It works for my purposes, but I'm not sure it's something they'd want to formalize as a standard part of the PluginAPI.

skiingwiz 08-01-2010 08:46 PM

I am in the process of updating one of my STVi plugins to use this. It is excellent. Thanks for all of your work on this!

chrishallowell 08-13-2010 08:30 PM

STVi Configurator questions
 
I have a few questions as I work through the STVi Configurator process. I plan on storing the config values in an XML.

What folder do you store the config.xml (example.config.xml in the example)?

Where do you put the SettingMethod conditional in Studio? Does that go in the Application Started hook as well; right after the action that instantiates the XMLConfig via AddGlobalContext?

How do you test this? How do you test the Application Started hook? I tried F5 on the hook and a black screen showed up. Do you have to shut down SageTV and open it back up or is there a trick?

* merged *

GKusnick 08-13-2010 09:09 PM

Quote:

Originally Posted by chrishallowell (Post 442271)
I plan on storing the config values in an XML.

You can of course store config values anywhere you want, but the expected place for them is in the .properties file, and that's where my XmlConfig class will put them.

Or are you just saying you want to use XmlConfig to get the config definitions from an XML file?

Quote:

Originally Posted by chrishallowell (Post 442271)
What folder do you store the config.xml (example.config.xml in the example)?

Again, you can put it anywhere you want, so long as your plugin can find at startup time. One option is to have your plugin installer extract it to a custom folder, and set the ResourcePath in your manifest to the (relative) path of that folder. Then you can call GetPluginResourcePath() at startup time to locate it.

What I prefer to do is to package the config.xml as a resource in the JAR file, and use XmlConfig.FromResource() to load it at startup time. That way it's one less file cluttering up the user's disk.

Quote:

Originally Posted by chrishallowell (Post 442271)
Where do you put the SettingMethod conditional in Studio?

You don't. If you have STVI Configurator installed and enabled, the SettingMethod conditional should already exist in the STVI Configurator menu. You must add your methods to this existing conditional in order for STVI Configurator to find them.

(However there seems to be a new bug in 7.0.15 that prevents menus created by STVIs from showing up in Studio. I'll file a bug report on that.)

Quote:

Originally Posted by chrishallowell (Post 442271)
How do you test this? How do you test the Application Started hook? I tried F5 on the hook and a black screen showed up. Do you have to shut down SageTV and open it back up or is there a trick?

ApplicationStarted fires whenever an STV is loaded. So if you change the enable state of your STVI, the STV will be reloaded and ApplicationStarted will fire.

You can also test any arbitrary widget chain using the Execute Widget Chain command on the right-click context menu. But if the chain depends on variables that aren't globally defined, it may not do what you expect when invoked this way. (F5 is strictly for launching Menu widgets.)

As a final note, if you post questions like this to the existing STVI Configurator thread, I'll probably see them sooner because I'm subscribed to that thread. That goes for pretty much any plugin question: the plugin authors subscribe to their own support threads in order to get notifications about questions from users. Starting a new thread bypasses that notification system and may delay the response. (Plus it tends to clutter the forum unnecessarily and push useful threads off the front page.)

chrishallowell 08-14-2010 09:11 PM

More noob questions....
 
Yes, I will be using the gkusnick.sagetv.XmlConfig class to get my config definitions from an XML document.

I'm still confused what the job of the SettingMethod condition is? Is it to get any of the elements defined in the config definitions XML doc and to save values to the sageTV.properties file?

Say I have this XML config definitions file:
Code:

<config>
  <setting name="CallName" type="Text">
      <label>Call name:</label>
      <helptext>This will be the call name used.</helptext>
      <property>mypluginsCallName</property>
  </setting>
  <setting name="AgeOfUser" type="Integer">
      <label>Age:</label>
      <helptext>Enter your age.</helptext>
      <property>mypluginsAgeOfUser</property>
  </setting>
  <setting name="BkColor" type="Choice">
      <label>Background Color</label>
      <helptext>This will be the color of the table.</helptext>
      <option>red</option>
      <option>blue</option>
      <property>mypluginsBkColor</property>
      <default>red</default>
  </setting>
</config>

Where do I get the cls and the szResource for the FromResource method?
Say my jar has:
package HelloTable
class HelloTableClass1
class HelloTableClass2
Resource folder called: Resources
XML in the folder called: ConfigDefinitions.XML
Code:

In ApplicationStarted hook:
AddGlobalContext("ExampleConfig", new_gkusnick_sagetv_XmlConfig(XmlConfig.FromResource(cls, szResource)))

Is this what I need in the SettingMethod condition?
Code:

"example.getConfigSettings"
        gkusnick_sagetv_XmlConfig_getConfigSettings(ExampleConfig)
"example.getConfigType"
        gkusnick_sagetv_XmlConfig_getConfigType(ExampleConfig, SettingName)
"example.getConfigLabel"
        gkusnick_sagetv_XmlConfig_getConfigLabel(ExampleConfig, SettingName)
"example.getConfigHelpText"
        gkusnick_sagetv_XmlConfig_getConfigHelpText(ExampleConfig, SettingName)
"example.getConfigValue"
        gkusnick_sagetv_XmlConfig_getConfigValue(ExampleConfig, SettingName)
"example.setConfigValue"
        gkusnick_sagetv_XmlConfig_setConfigValue(ExampleConfig, SettingName, SettingStrValue)
"example.getConfigValueAsInt"
        gkusnick_sagetv_XmlConfig_getConfigValueAsInt(ExampleConfig, SettingName)
"example.????"
        gkusnick_sagetv_XmlConfig_setConfigValue(ExampleConfig, SettingName, SettingIntValue)

Since I already have a example.setConfigValue, I'm not sure what the ???? should be.

GKusnick 08-14-2010 10:22 PM

The SettingMethod conditional is how STVIConfig finds the right method to execute. When the UI wants to call method M of plugin P, the STVIConfig runtime sets the global variable SettingMethod to "P.M" and calls ExecuteWidgetChain on the conditional. The result is that the branch labeled "P.M" gets executed. But that's all internal to the STVIConfig implementation. Your responsibility is just to make sure that the appropriate branches exist for the methods you want to implement.

Also, as indicated in the STVIConfig docs, you're not obliged to use XmlConfig with STVIConfig. You can put any widget code you like in those method branches. Using XmlConfig is a convenient way to keep that code concise, but XmlConfig itself has no knowledge of that conditional widget structure, and STVIConfig has no special knowledge about XmlConfig, so it's not really accurate to say that the job of the conditional is to interact with XmlConfig. Its job is simply to invoke whatever code you choose to put in those branches, which can be calls to XmlConfig if that suits your needs.

The branch names you use should be specific to your plugin, e.g. "hellotable.getConfigSettings" rather than "example.getConfigSettings" (assuming "hellotable" is the unique plugin ID specified in your manifest). Your job is not to replace the contents of the existing "example" branches, but to add new, uniquely named branches below the "else" branch. Similarly, you ought not to call your XmlConfig instantiation ExampleConfig; you should call it HelloTableConfig or something else specific to your plugin. Don't step on the example code if you want your plugin to coexist peacefully with other plugins using the same machinery.

You don't need a branch for getConfigValueAsInt; that's not one of the standard methods defined by the SageTVPlugin interface (which is what you're trying to satisfy here). It's just a convenience method I thought might be useful to Java coders using XmlConfig and is not really relevant to STVI code.

I'm not following your question about setConfigValue; if you already have a branch for that, you don't need another one. Again, don't get confused by the overloads in XmlConfig.java; your guide on what to implement should be the methods defined by SageTVPlugin.

The class you pass in to XmlConfig.FromResource in some sense doesn't really matter; its only use is to determine which ClassLoader to use for loading the resource. If that doesn't mean anything to you, don't worry about it. The simplest rule of thumb is to pass in any class defined by the same JAR as the resource you're trying to load. In your case either of your HelloTable classes will work. To get a class object from STVI code, call java_lang_Object_getClass on an instance of the class.

The szResource you pass in is the string name of the resource file in the JAR. That's the filename that the resource loader will search for. As such it should be unique within the set of JARs on the search path (i.e. in the SageTV\JARs folder), to avoid collisions with other plugins and their resources. So "ConfigDefinitions.XML" is not a good choice from that perspective; something along the lines of "HelloTable.config.xml" would be better.

Your XML looks reasonable, but as a matter of convention I'd suggest putting your plugin's properties under some common key, e.g. Hallowell/HelloTable/CallName, Hallowell/HelloTable/AgeOfUser, etc. This makes it clear they belong together and lets you manipulate them as a group if you need to. Prefixing it with your name is a good idea so that if you write more than one plugin, their properties all group together in the .properties file.

The same goes for Java package names, by the way: call it Hallowell.HelloTable or something along those lines both to make it clear who it belongs to and to minimize the chance of collision with other package names. (The Java convention is to use some domain name that you own as the prefix, with the components reversed, e.g. org.apache.whatever.)

chrishallowell 08-16-2010 12:10 PM

Quote:

Originally Posted by GKusnick (Post 442435)
You don't need a branch for getConfigValueAsInt; that's not one of the standard methods defined by the SageTVPlugin interface (which is what you're trying to satisfy here).

Ok this clears things up a lot.

What does the getting/setting of the property values in the sage.properties file? STVi config, XmlConfig, SageTV internal, or something I need to do?

Do I have this right (not using the STVi config)?
1. User installs a plugin
2. SageTV internal process uses the manifest xml to ensure all dependencies are in place and then it installs the files.
3. User selects the config button of the plugin
4. SageTV internal process calls the get sage.api.PluginAPI methods to get the config options in the HelloTableConfigDefinitions.XML file and property values from the sage.properties file and then displays them in SageTV.
5. User changes a property value.
6. SageTV internal process calls a set sage.api.PluginAPI method to save the changed property to the sage.properties file.

But now since we are using the STVi config, SettingMethod conditional methods process the calls instead of the sage.api.PluginAPI. Am I right?

Assuming the above statements are true, how do I know what methods are called by the SageTV internal process?

(I know, it's like your trying to teach a baby to walk here... :eek2:)

GKusnick 08-16-2010 03:40 PM

Quote:

Originally Posted by chrishallowell (Post 442704)
What does the getting/setting of the property values in the sage.properties file? STVi config, XmlConfig, SageTV internal, or something I need to do?

The SageTV core makes no assumptions about where plugin settings are stored. By convention they're stored in the .properties file, but it's up to the plugin to put them there.

In your case you've chosen to delegate that task to XmlConfig. That's the point of specifying property names in your config.xml: so that XmlConfig knows how to store and retrieve the property values.

STVIConfig has nothing directly to do with that. Again, the sole purpose of STVIConfig is to allow the plugin manager UI to call config methods written in widget code rather than Java code. You have chosen to write widget code methods that use XmlConfig to do the bulk of the work. That's fine; that's a smart choice. But it doesn't directly relate to STVIConfig, which doesn't care about how your widget code methods do their job; all it cares about is how to invoke them when needed.

By the way, you have the Java source code for both XmlConfig and STVIConfig if you want to find out exactly what they do.

Quote:

Originally Posted by chrishallowell (Post 442704)
Do I have this right (not using the STVi config)?
1. User installs a plugin
2. SageTV internal process uses the manifest xml to ensure all dependencies are in place and then it installs the files.
3. User selects the config button of the plugin
4. SageTV internal process calls the get sage.api.PluginAPI methods to get the config options in the HelloTableConfigDefinitions.XML file and property values from the sage.properties file and then displays them in SageTV.
5. User changes a property value.
6. SageTV internal process calls a set sage.api.PluginAPI method to save the changed property to the sage.properties file.

That's correct in its broad outlines. However steps 4 and 6 are not quite accurate in their details.

It's not a a "SageTV internal process" that calls the PluginAPI methods. It's the plugin manager in the stock UI, which is a separate (and replaceable) component from the SageTV core. The core manages plugin installation and dependency resolution (step 2). The UI handles plugin configuration (steps 3-6).

Also, it's misleading to say that the plugin manager calls PluginAPI methods to get config settings from the XML file and config values from the .properties file. In fact the plugin manager doesn't care where that information comes from or how it's stored; that's completely up to the plugin. It is true that if the plugin delegates those tasks to XmlConfig, then the effect of those calls will be to retrieve said information from the XML and .properties files. But that's not the purpose of those calls; the purpose is to allow the plugin to do whatever it does to provide that information. So the division of labor is thus: the plugin manager UI handles the display and editing of config settings; the plugin (perhaps delegating to XmlConfig) handles the definition and storage of config settings.

Quote:

Originally Posted by chrishallowell (Post 442704)
But now since we are using the STVi config, SettingMethod conditional methods process the calls instead of the sage.api.PluginAPI. Am I right?

Correct.

Quote:

Originally Posted by chrishallowell (Post 442704)
Assuming the above statements are true, how do I know what methods are called by the SageTV internal process?

You mean by the plugin manager. In some sense it's up to the discretion of the plugin manager which methods it calls when in order to do its job. Your job is to implement the methods required for the particular types of settings your plugin defines.

You must implement getConfigSettings, since that's where everything starts.

You must implement getConfigType, getConfigLabel, and getConfigHelpText, since those are common to all setting types.

If you have any Choice or Multichoice settings, you must implement getConfigOptions.

If you have any Multichoice settings, you must implement get/setConfigValues.

If you have settings of any type other than Multichoice, you must implement get/setConfigValue. (However it also appears that getConfigValue can be called even on Multichoice settings, but it's not clear if that's a bug or by design.)

And of course you have access to the plugin manager's widget code in the stock UI if you want to study that to see exactly what it does.

chrishallowell 08-16-2010 09:51 PM

Ok, thanks Greg. Your explanations have really cleared things up for me and I really do appreciate you spending the time to explain these basic principles. I think I have enough understanding to give it a go.

chrishallowell 08-18-2010 10:53 PM

Is there a way to test the STVI Configurator plugin config before installing it as a plugin?

I tried:
Execute widget chain on this: AddGlobalContext("HelloTableConfig", new_gkusnick_sagetv_XmlConfig("plugins/Hallowell/HelloTable/ConfigDefinitions.xml"))

and then I tried F5 on Menu: Plugin Configure but that produced a blank Config screen. So then I noticed that the Plugin needs to be set before running that menu. So I searched for "Plugin Configure" but there wasn't a reference to that menu.

GKusnick 08-18-2010 11:11 PM

Quote:

Originally Posted by chrishallowell (Post 443278)
Is there a way to test the STVI Configurator plugin config before installing it as a plugin?

Not the whole thing. The plugin configuration machinery works on installed plugins. But you can unit-test individual methods.

Quote:

Originally Posted by chrishallowell (Post 443278)
I tried:
Execute widget chain on this: AddGlobalContext("HelloTableConfig", new_gkusnick_sagetv_XmlConfig("plugins/Hallowell/HelloTable/ConfigDefinitions.xml"))

You could then use Expression Evaluator to verify that the HelloTableConfig variable contains a valid instance of XmlConfig and try calling some of its methods manually.

Quote:

Originally Posted by chrishallowell (Post 443278)
So I searched for "Plugin Configure" but there wasn't a reference to that menu.

Yes, there is a reference; that's why the menu name appears in bold. But you won't find it with a string search, because there's only one widget with that name (the menu itself). Widget references aren't textual; they're pointers to the actual widget. You find them with the Highlight References command (or if you have my Studio Tools installed, the List Widget References command).

chrishallowell 08-19-2010 08:33 PM

1 Attachment(s)
My STVI Configurator menu is not in bold or in italics.
And the action items all have a yellow square. (Screen shot attached)

I tried uninstalling and reinstalling STVI Configurator and the same thing happens.

I'm on SageTV 7.0.15
Windows XP SP3
Using a server and starting SageTV on the server.


All times are GMT -6. The time now is 11:48 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Copyright 2003-2005 SageTV, LLC. All rights reserved.