Plans for RGG and descriptive phrases

Hi all, but esp @Haocheng_Liu and @aron.helser,

Here are some broad plans on how to customize descriptive phrases for RGG. The basic idea is to make the resource panel inherit qtBaseView and use its XML configuration to control what the panel displays. Then a ParaView-aware and RGG-aware selection observer can change what is rendered and selectable.

Resource panel

The qtResourceBrowser (inherited by pqSMTKResourceBrowser) should itself inherit qtBaseView and accept configuration via the smtk::view::View class. The specific things that should be configurable:

  • which smtk::view::PhraseModel subclass to use for its QAbstractItemModel;
  • whether to use an intermediate QSortFilterProxyModel and add GUI controls (a search text entry and sort control buttons) to the panel;
  • which smtk::view::SubphraseGenerator subclass to use (and any configuration controls that are required);

Custom RGG PhraseModel subclass

PhraseModel subclasses determine what phrases make up the top-level items of a QAbstractItemModel in a QTreeView. RGG wants this to be a fixed set corresponding to functional groups (pins, ducts, assemblies, cores). For the purpose of this discussion, let’s say the new class is named smtk::session::rgg::PhraseModel.

Customizable subphrase generator

Rather than hardcode a subphrase generator to list pins under the smtk::session::rgg::PhraseModel's top-level “pins” item, we should create a new class (say smtk::view::QueryPhraseModel for this discussion). That class could hold a map<std::string, std::string> that uses top-level phrase title() strings as keys and returns query-strings to pass to smtk::resource::Resource::find().

Note that the subphrase generator is responsible for implementing both the subphrases() and subphrasesForCreatedObjects() methods. The former is called when the view is first created or a tree item expanded ‒ it must provide an ordered list of subphrases on demand; the latter is invoked when SMTK operations report newly-created objects (components) in their results ‒ it must provide new phrases and their locations corresponding to each new object, but only where the parent phrase already exists.

RGG selection behavior

To provide RGG users with control over what is visualized, a selection observer can identify when a pin/duct/assembly/core is selected and update component visibility in ParaView (as well as change the camera as needed).

Thanks for the Tips.

Do yo mean that QueryPhraseModel should be a generic class that can be reused by other sessions? As a result RGGSubphraseGenerator is just a subclass user who uses the API defined in this class?

Yes.

You should not need to write an RGGSubphraseGenerator class. Instead the rgg session will provide <View>...</View> configuration XML that tells the QueryPhraseModel what to do. For example, we might have

<View Type="DescriptivePhrase" TopLevel="true" AllowSortFilter="true">
  <PhraseModel Type="RGGPhraseModel"/>
  <SubphraseGenerator Type="QueryPhraseModel">
    <MapPhrase ParentTitle="pins">
      <Resource Type="smtk::session::rgg::Resource" 
        Filter="aux_geom[string{'rgg_type'='pin'}]"/>
   </MapPhrase>
    <MapPhrase ParentTitle="ducts">
      <Resource Type="smtk::session::rgg::Resource" 
        Filter="aux_geom[string{'rgg_type'='duct'}]"/>
   </MapPhrase>
    <MapPhrase ParentTitle="assemblies">
      <Resource Type="smtk::session::rgg::Resource" 
        Filter="group[string{'rgg_type'='assembly'}]"/>
   </MapPhrase>
    <MapPhrase ParentTitle="cores">
      <Resource Type="smtk::session::rgg::Resource" 
        Filter="group[string{'rgg_type'='core'}]"/>
   </MapPhrase>
  </SubphraseGenerator>
</View>

(The filter strings are discussed here: Query filter strings for model resources .)

It looks like @aron.helser’s changes are in SMTK MR 1753 and @Haocheng_Liu’s changes are in SMTK MR 1741. I just want to make sure the train tracks meet in Promontory, UT… have you two looked at each other’s work?

  1. @Haocheng_Liu
    a. Do you see how to register your new PhraseModel and SubphraseGenerator subclasses?
    b. And how to call pqSMTKResourcePanel::setView() inside your plugin’s autostart?

  2. @aron.helser Are there things missing from the view configuration information that Haocheng’s work will need?

Not yet. But I’m aware of Aron’s work and try to keep my interaction with ResourceBrowser and ResourcePanel as little as possible to mitigate the transition cost as you’ve adviced.

I think we are all set to allow a custom PhraseModel and SubphraseGenerator. I see RGG will be compiled in, so this should work:

  • Add new subclasses to the lists in smtk::view::Registrar
  • Copy ResourcePanelConfiguration.json from extension/paraview/appcomponents and modify it with the new class names. Add the new .json to CMakeLists.txt so it gets converted to a header
  • When RGG is activated, pass the string representing the json to the json parser, which creates a smtk::view::View to pass to pqSMTKResourcePanel::setView()

Of course, I’ve only tried it with ResourcePhraseModel, and default or TwoLevel SubphraseGenerator, so we’ll probably run into some issues, but hopefully my MR can get merged today(?) so you can try it out.

My testing so far has been hacking the default json - I think you are the test case :grinning:
Please bug me when you want to get started!

OK, quick talk with David, and my three bullets aren’t sufficient when RGG is a plugin. Instead, you need to take some additional steps:

  • The plugin needs to create its own Registrar.[h,cxx], patterned after the one in smtk::view, which lists the PhraseModel and SubphraseGenerator subclasses it wants to register.
  • in CmakeLists.txt, add (or augment) two properties inside add_smtk_plugin() (with the right namespace for Registrar, look at smtk::view for an example):
    REGISTRAR rgg::Registrar
    MANAGERS smtk::view::Manager
  • Copy ResourcePanelConfiguration.json from extension/paraview/appcomponents and modify it with the new class names in the Type attributes. Add the new .json to CMakeLists.txt so it gets converted to a header. The current one looks like:
# put contents of this file in a string in a header. It's not xml, but it still works.
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/ResourcePanelConfiguration.json" smtkResourcePanelJSON)
  • Inside the plugin’s AutoStart file, get the json string:
// cmake puts the .json file contents into a static string, named _xml
#include "..../ResourcePanelConfiguration_xml.h"
  • In the setup() method, parse the json and create the view, something like this:
  nlohmann::json j = nlohmann::json::parse(ResourcePanelConfiguration_xml);
  resourcePanel->setView(j[0]);

I don’t actually know how you get ahold of the resourcePanel from the plugin?

You would do something like this (rough sketch):

for (QWidget* w : QApplication::topLevelWidgets())
{
  auto mainWindow = dynamic_cast<QMainWindow>(w);
  if (mainWindow)
  {
    auto dock = mainWindow->findChild<pqSMTKResourcePanel*>();
    if (dock)
    {
      dock->setView(viewInfo);
    }
  }
}

:flushed: Thanks guys. I will be the daredevil to try it out once the view stuff lands in master and bug you later!

Hi David and Aron,

With the current smtk master + ParaView master, I can no longer find the pqSMTKResourcePanel. Any idea what’s going on here?

Edit: Now the construction of pqSMTKResourcePanel(aka smtkPQComponentsExt) is after the rgg autostart(aka loading smtkRGGSessionPlugin). Humm, let me see what I can do here.

IDK why that would have changed…

It turns out that we are hitting the indeterministic ordering of static initialization. In my case, the smtkRGGSessionPlugin is loaded before smtkPQComponentPlugin so the pqSMTKResourcePanel has not been constructed yet. I got a not so beautiful solution to solve the problem here. Ideas?

@T.J. Corona Didn’t we have a method for forcing static initialization order?

I think QTimer::singleshot is the solution we are using right now.

Maybe we can do something with the ParaView registration logic? It is populated during a plugins startup.