Data view design
From Emergent
This document describes the DataView GUI system.
Contents |
Overview
The DataView system is a framework for describing and rendering the display of heterogenous data items. There is generally the following relationship of classes in the overall resulting system:
Data Class <--> DataView Class <--> Graphical Class(es)
Sometimes the DataView class will have no direct corresponding Data class, and is merely used to stand for some element of a complex gui entity, such as a browser window.
Classes
DataView (taBase) classes
This section presents the major classes first, then detailed hierarchies for the major classes. Anything starting with "I" is a mix-in interface class.
IDataLinkClient -- can receive data change/destroy notifications
taOBase
taDataView -- defines the basic behaviors of a data viewing client
T3DataView -- for rendering 3D displays of the data; manages a T3Node So object
DataViewer -- parts in the window viewing hiearchy; manages a IDataViewWidget Qt QWidget-based object
DataViewer (A) -- anything common to all viewer types
can only assume its gui class is a QWidget
handles: can create a gui obj, either top level or in another window
has some virt methods for when its subclass is a top-level window
ToolBar -- for toolbars
TopLevelViewer -- for anything that can have its own window
MainWindowViewer -- for the main window; has stuff only applicable to the main win;
can contain subordinate viewers, toolbars, and dock wins; widget is iMainDataViewer
is a top-level window
DockViewer -- for windows that are dockable
can be docked in a MainWindowViewer, or standalone (when undocked)
if standalone, then it can be a top-level window
when standalone, is in .viewers, else is in the .dockies of a MWV
FrameViewer (A) -- for principal contained views in main, such as browser, edit,
and T3 (in taMisc) -- these go in central area, in a splitter or other gui container
BrowseViewer -- for the tree browser -- contains most of the logic
tabBrowseViewer -- light subclass specialized for taBase root Browsers
ClassViewer -- light subclass specialized for Type item roots
PanelViewer -- for the edit panels (supports recursive splitting)
T3DataViewer -- for T3 guys -- multiple are put in a tabbed gui control
T3DataView (A)
T3DataViewPar -- for items that contain other items
T3DataViewRoot -- special guy that is a visual root
A generic list class is defined for all taDataView objects -- it provides convenience methods for forwarding rendering commands to all the children. All other more strongly-typed list classes are made by subclassing this list and adding the TA_DATAVIEWLISTFUNS macro which provides strongly typed FastEl and SafeEl (typically the only accessors needed.)
taList<taDataView>
DataView_List
DataViewer_List
ToolBar_List
FrameViewer_List
TopLevelWindow_List
T3DataView_List
Gui Interfaces
There are two key gui Interfaces that provide abstraction for the concept of contained gui items that can partipate in the following:
- parent/child hiearchies
- selection, including multi-select
- clipboard operations, such as Copy/Cut/Paste
- Drag and Drop (DND) operations
- receive updates, such as name changes
ISelectableHost -- for containers IDataLinkClient ISelectable -- for items
These two interfaces are currently expressed by two different subsystems: the Qt-based TreeView/TreeViewItem system, and the Inventor iT3ViewspaceWidget (a Qt class, actually)/T3Node.
The design of these systems enables seamless interaction between them, enabling, for example, a Copy from a 3D view, and then a Paste into a Tree browser.
Qt Gui classes
IDataViewWidget -- this provides generic shared behavior, regardless of the type of widget being used,
and is a secondary base class of the root classes below:
QWidget
iFrameViewer -- gui class for FrameViewer;
QDockWidget
iDockViewer -- gui class for DockViewer; very light subclass; can often be used directly,
just by adding your own content (see Console)
QToolBar
iToolBar -- gui class for Toolbars;
QMainWindow
iMainWindowViewer -- the gui class for MainWindowViewer; has tons of stuff for menus, toolbars, frames, etc.
Main Inventor ("So") classes
ISelectableHost QWidget iT3ViewSpaceWidget -- a widget used to display Inventor nodes
ISelectableItem
SoSeparator
T3Node -- a visual node in a 3d view
T3NodePar -- a visual node that can have visually nested subnodes
Construction and Usage Flows
DataView objects support a set of generic methods to control construction of gui widgets and display and update of gui information. The following public methods are used to invoke these actions.
- Clear -- clears (usually deletes) the gui components; usually prior to re-rendering them, or when making the gui go away while keeping the dataview classes
- Constr (DataViewer) -- constructs the Qt gui classes
- BuildAll (T3DataView) -- constructs the subclasses that are part of the hierarchy
- Render -- (re)build and show everything -- only defined on some top-level classes
- Reset -- deletes all DataView elements under this one; usually on data destroy, or rebuild of data
The actions above are top-level dispatchers that can be called publicly. A corresponding set of implementation methods is provided that are suitably overridden or derived in subclasses. These methods perform the actual work for the given stage. Some of these methods are invoked in more than one context, for example, Clear_impl is used in both Clear and Reset.
- Clear_impl (T3DataView) -- deletes the So components
- CloseWindow_impl (DataViewer) -- deletes the Qt Widget component
- Constr_impl (DataViewer) -- makes the subcomponents and gui components
- Render_pre -- called for all objects as a first stage in rendering; usually creates the gui components
- Render_impl -- called for all objects as the principle stage of rendering
- Render_post -- called for all objects as a final stage of rendering; may apply saved state information
- Reset_impl -- called for all objects to reset them (remove their children)
This table shows what impl actions comprise each high level action construct:
- Clear (T3DataView) -- Clear_impl
- Clear (DataViewer) -- CloseWindow_impl
- Constr --Constr_impl
- Render_pre (TopLevelViewer) -- Render_pre, Constr_impl
- Render -- Clear_impl,Render_pre, Render_impl, Render_post
- Reset -- Clear_impl, Reset_impl
The high level actions have guard checks to insure that the impl should actually be performed in the context, for example, insuring that the gui components exist before invoking clears or renders, or skipping the action under some overarching conditions such as loading. Impl methods should never be called directly, but are sometimes the correct method to invoke in a context, such as a Data Changed notification -- in these cases, call the DoAction method with the enum(s) for the methods to dispatch (they are dispatched in the correct order, in the above table.)
Here is a summary of the main activities performed during each stage for the major classes; subclasses that manage children perform the actions descendantly -- constructive actions (Render_xxx) done Inherited-Self-Children, destructive actions (Reset/Clear) done Children-Self-Inherited. The base class had a mechanism for efficiently distributing actions to children (see !DoActionChildren_impl). But Constr_impl is never implicitly sent to children, since typically the parent item needs to do fine-grain construction of its child components in the context of its own Constr_impl routine, and will then typically explicitly invoke these child Constr when it is ready.
| Class | Clear_impl | Constr_impl | BuildAll | Render_pre | Render_impl | Render_post | Reset_impl |
|---|---|---|---|---|---|---|---|
| DataViewer | delete QWidget | create QWidget | n/a | (typ. not used) | (typ. not used) | apply view state | delete child DataView objs |
| T3DataView | delete So node | n/a | creates child T3DataViews | create So node | dataparams -> So nodeparams | (typ. not used) | (typ nothing) |
| T3DataViewPar | (inh) | create child T3DVs | (inh) | dataparams -> So nodeparams | (typ. not used) | (typ. not used) | delete child T3DVs |
The DataChanged system is not relevant to DataViewers because they don't have data objects. For T3DataViews the following actions are invoked on dataviews of objects:
- ITEM_UPDATED -- Render_impl
- STRUCT_UPDATE_BEGIN (first one) -- Reset
- STRUCT_UPDATE_END (last one) -- Reset, BuildAll, Render
Note that DataViewer and descendants are typically not connected directly to a data item, therefore, they do not directly recieve any notifications; most of their content items though (in the various subwindows) are connected to the notify system.
Project MainWindowView Layout
Here's what a std 3-panel project view looks like in terms of classes.
(ixxx classes are usually in ta_qtviewer and other guys are in ta_viewer)
tabBrowseViewer | PanelViewer | T3DataViewer
w:iBrowseViewer | w:iTabViewer | w:iT3DataViewer
| iTabView... | i/T3DataViewFrame
| iDataPanelSet.. | T3DataViewRoot.children
| iDataPanel.. | T3DataViewPar...
| | T3DataView..
| | T3Node/Leaf/Parent
Here's the key code sequence that creates it all:
- Main constr: ta_viewer.cpp:905 -- MainWindowViewer* MainWindowViewer::NewProjectBrowser(taProject* proj)
- ta_viewer.cpp:1113 -- MainWindowViewer::ConstrFrames_impl() -- just calls Constr_impl on frames and then AddFrameViewer on the resulting widget
Note: Q/iTabBar is the item that gets focus events etc! not the widget.. this should be key for linking tabs..
iDataPanel and Subclasses
The iDataPanel is a QFrame derivative that defines an interface for things that live as one item in a tabbed viewing environment, so they live under a iTabViewer which in turn controls a set of iTabView's which in turn contain iDataPanel derivatives.
- iDataPanel -- base class (ta_qtviewer.h)
- iDataPanelFrame -- for data-like items that are viewed under user control
- iListDataPanel -- for list/group like items that need a tree view (?)
- iTextDataPanel -- for text display (scripts, etc)
- iDocDataPanel -- for taDoc items
- EditDataPanel -- base class for any edit dialog-like data panel -- linked to a taiEditDataHost (see below)
- iDataTablePanel -- for DataTable (ta_datatable_qtso.h)
- iMatrixPanel -- for Matrix (ta_matrix_qt.h)
- iProgramPanelBase -- for Program/Group (ta_program_qt.h)
- iProgramPanel -- for Program
- iProgramGroupPanel -- for Program_Group
- iViewPanelFrame -- for a gui control panel which has more automatic view control
- iDataTableView_Panel -- for datatable view control panel (ta_datatable_qtso.h)
- iGridTableView_Panel
- iGraphTableView_Panel
- VEWorldViewPanel -- VEWorld (ta_virtenv_qtso.h)
- NetViewPanel -- Network view (netstru_qtso.h)
- iDataTableView_Panel -- for datatable view control panel (ta_datatable_qtso.h)
- iDataPanelSetBase -- grouping of data panels -- one further level of org between tabs and actual panels -- this is what is actually under the main middle panel tab
- iDataPanelSet -- holds iDataPanelFrame guys
- iViewPanelSet -- holds iViewPanelFrame guys
- iDataPanelFrame -- for data-like items that are viewed under user control
The creation process goes roughly like this:
- an iDataPanelSet is created for a given object
- the taiViewType and derivatives creates subpanel(s) within the iDataPanelSet -- basic case is just an EditDataPanel, but others create specialized sets of panels per the program..
Edit Dialog Types
These are bases for actually generating/managing a "Properties" edit dialog, mostly defined in ta_qtdialog.h
- taiDataHostBase -- base class for managing the contents of an edit dialog -- inherits QObject and IDataLinkClient -- is NOT the widget -- has a widget() call
- taiDataHost_impl -- adds the IDataHost interface, seems to manage select edit and some other general purpose stuff
- taiDataHost -- specific instantiation of the gui appearance of the edit, using a QGridLayout or iFormLayout (expensive and slow -- to be replaced)
- taiEditDataHost -- final guy for class object -- iterates over members, builds views etc
- taiSelectEditDataHostBase -- for select edit -- in ta_seledit_qt.h (has further derivatives below that!!)
- cssiEditDialog -- for css items -- in css/css_qtdialog.h
- iProgramCtrlDataHost -- for program ctrl panel -- in ta_program_qt.h
- gpiMultiEditDataHost -- in ta_qtgroup.h
- gpiArrayEditDataHost -- "
- DocEditDataHost -- for taDoc items, in ta_qtgroup.h
- taiEditDataHost -- final guy for class object -- iterates over members, builds views etc
- taiDataHost -- specific instantiation of the gui appearance of the edit, using a QGridLayout or iFormLayout (expensive and slow -- to be replaced)
- taiStringDataHost -- for an edit dialog of a string field member
- taiDataHost_impl -- adds the IDataHost interface, seems to manage select edit and some other general purpose stuff
Keyboard Navigation Issues
- main docs: http://doc.trolltech.com/4.3/focus.html http://doc.trolltech.com/4.3/qt.html#Key-enum
- don't use setTabOrder -- you have to set it for the entire chain -- can't just fix one link of it.
- all the above frame/edit classes (iDataPanel derivatives, taiEditDataHost & derivatives) have a firstTabFocusWidget() function that returns the widget to focus on, and then they redefine the focusNextPrevChild function to select the appropriate widget -- this is really the way more appropriate function to use -- works like a charm!
