Combining SettingsModels

Hi,

I'm currently working on an enhanced version of the Number to String node with formating options. For that, I want to present the possible settings in a radio group with sub elements. Those sub elements would then be activated when the corresponding radio button is active. This seems to be a recurring pattern, yet there's nothing suitable in the DialogComponents yet. No problem, I thought, let's just create it then.

One of the components of that would be to create a SettingsModel that more or less just contains the current selection and a mapping from choices to sets of child-SettingsModels. This way I could free the user from dealing with many of the details while reusing as much as possible.

The thing is: I can't seem to create a combining SettingsModel, because all the loadSettings- and saveSettings- methods of the children are invisible to the parent. I could use reflection, but normally that's a red flag that I'm thinking in the wrong direction... Are SettingModels not meant to be combined, is that an option that just hasn't occured to anyone yet, am I using the elements wrong, or am I just missing something?

I did something similiar with the SettingsModelDisactableLong. Maybe helps taking a look at.

Iris

Thanks for the hint, Iris, but I think we're talking about slightly different things here. Your SettingsModelDisactableLong is "just" an extension of the existing SettingsModelLong, and as such has access to the methods and the configName of its base class.

What I'm after is more of a composite pattern, a SettingsModel that can contain other SettingsModels that are only specified later on. If the loadSettings- and saveSettings-methods where not protected, they might look something like this in my class:

protected void loadSettingsForDialog(final NodeSettingsRO settings, final PortObjectSpec[] specs) throws NotConfigurableException {
    try {
        setSelection(settings.getString(m_configName, m_selection));
    } catch (IllegalArgumentException e) {
        // if the value is not accepted, keep the old value.
    }
    for (SettingsModel childModel : m_childModels.values()) {
        childModel.loadSettingsForDialog(settings,specs); // doesn't work :(
    }
}

It is very easy to implement an own SettingsModel. Making a collection of old SettingsModels sounds quite inefficient.

Marlin, I think you miss the fact that many KNIME dialogs do not extend the DefaultNodeSettingsPane. In those cases they usually use custum settings objects instead of the predefined SettingsModels.

In case you stay on the path of DefaultNodeSettingsPane (and want to disable enable certain options based on other properties), I would suggest adding a custom DialogComponent after all other DialogComponents to set initial state. Here is an example.

Cheers, gabor

PS.: Using custom NodeDialogs are not too hard either, but a bit repetitive.

Gabor, of course I can implement my own dialog, of course I can create a complex settings object or use a workaround that is not especially user friendly or in compliance with the noding guidelines. But that's not what this question is about. This question is about composeability of SettingsModels. They are a good idea, because they simplify the layouting and because they encourage reuse, that's why I want to use them. I thought that maybe I could create something with more than a single use case. (And without reinventing the wheel.) But if the system can't handle anything beyond the simplest tasks (which is supported by the facts in your first two sentences), that sounds like they're simply not good enough yet... Which is an answer to my initial questions, too.

Well, the default dialog components were never intended for complex dialogs, they were explicitly designed for simple tasks only. All our dialogs that are a bit more complex actually don't use the default dialog components.

Mh... I suppose one of the reasons for introducing the default components was that you saw a possibility to reduce repetitions and human errors. The focus should be on other parts, after all.

So, what tools do you recommend for this end instead, when you go beyond their capabilities? Are there any other tricks in the system, or are you using something like generator scripts yourself? Of course there's no magic solution for every use case, but after developing a lot of dialogs you probably weren't satisfied with having to write everything by hand yourself.

Sure, this is what we do. This gives you the most flexibility. Usually finding an easy to use solution that is generic enough for almost all use cases is impossible.

We are thinking about using annotation to simplify dialog creation and settings handling, but then again this won't be flexible enough to solve all problems.

Sure, nothing is applicable to everything. If the problem were simple, we would all be using java beans or something now. I was just wondering about that (perceived) large jump from the defaults to completly manual, without anything in between. Giving "us" something to start off of is a good idea, it's just that a big enough step can feel like a wall if you're running. Also, I'm still learning how not to run. ;)

Annotations do sound like a good way to go to smooth that step, though. I'm still not entirely unconvinced of my idea, but I'll just chalk it up as a suggestion for an alternative/additional possibility.

On a side note: Some of the walls I'm running into while trying to find my way around the code are created by restrictive access rules, including this one. Many of these might be necessary or required, but certainly not all of them. Just food for thought.

The more API you make public the harder it is to change it lateron without breaking 3rd party code. Therefore being as restrictive as possible isn't a bad approach. If it's of general use and has already matured, then we may make it public API.

Another reason for having a restrictive API is to prevent developers from making accidental errors or abusing methods. This quite often leads to problems that are hard to debug. Especially if you are working in a highly extensible framework such as Eclipse.

For the first problem it might be a solution to expose the API through x-internal. That way the usage will not be forbidden (by default error and does not work at runtime), just discouraged (by default warning, works at runtime).

Though this would work against the second concern, so that might be not so useful afterall.

Yeah, I get that, that's why I said it's just food for thought. You don't have an easy job there.

Just consider that walls can not only channel water away from your shed, but also towards your house. If I want to reuse something and can't do it directly, I'm more prone to abuse something else to get there. Like using a foreign NodeFactory to get access to a constructor or manually copying configNames, hoping they wont get changed too often. Or worse, I could give up, leaving even more work for you to do. ;)

On the other hand, water in your cellar can keep your boiler from blowing up in your face, so that's that...

I wish you all warm, un-blown-up holidays.