Qube ArtistView can be customized through plugins. Plugins are python scripts that live in the "plugins" dir next to the qubeArtistView binary (or within the application bundle on OS X).  Plugins define both right-click menu items and the right-hand side tabs, e.g. Job Properties and Output log.

    Plugin Paths

    • You can easily navigate to the stock plugins dir by going to File > Open Plugins Directory
    • You can add additional plugins path(s) under the Plugins tab in the preferences
    • You can add additional plugins path(s) by setting a comma-separated list of paths in an environment variable called ARTISTVIEW_ADDITIONAL_PLUGINS_PATHS
       

    Adding Custom Right Tabs

    All of the right-side tabs in ArtistView are driven by Python plugins.  Depending on the type of tab displayed, the plugin's job is to retrieve data from the selected items (jobs, instances, frames, or hosts) and present some type of data to be displayed.  While ArtistView is written in PyQt, no knowledge of PyQt is needed to create a plugin.

    Plugin Layout

    • All plugins are of class UserUIPlugin and extend QbUIPlugin.
    • In the class's __init__ function, the following are defined:
      • Required:
        • name: the display name of the plugin
        • type: the type of plugin.  Options:
          • tab: this plugin creates a new tab
          • menu: this plugin creates a right-click menu item
        • context: Where the tab will be displayed. Options:
          • job: this tab plugin will be shown when the job list is visible.
          • host: this plugin will be shown with the host/workers list is visible.
        • tab_type: the type of tab plugin.  See above "Types of Tab Plugins" for a list of options.
        • functions: a dictionary that maps UI focus to a plugin function.  As an example, a tab plugin showing logs should show the job log when the job list has focus, an instance log when the instance list has focus, and a frame log when the frame list has focus. More information on the details of the user-defined function can be found in the section below entitled "Accessing Qube Information from the Plugin"
      • Optional:
        • hidden: Setting this to true makes the function completely hidden from the UI - it will not even show up in the preferences.
        • search_field: Setting this to true displays a search field below the content.  That search field will search through displayed content.  This only has meaning for "html" plugins.
        • frame_slider: Setting this to true displays a frame slider below the content. This only has meaning for "preview" plugins.
        • aspect_mode: For the preview tab, this drives how the frame will fit into the window. Options:
          • -1: display the original image - do not resize or scale.
          • 0: ignore aspect ratio - stretch the image to fully fill the display window.
          • 1: resize to fit within the display window, but maintain aspect ratio.
          • 2: resize to fit shortest dimension into the display window, and maintain aspect ratio
        • sort_order: order in which to display this tab in the list of tabs
    • Beyond the __init__, only the functions defined in the functions member variable are required.  They should return the data specified in the "Types of Plugins" section above.

    Types of Tab Plugins (tab_type attribute)

    • html
      • Example: The stock "Job Properties" tab
      • Will display basic html but not much in the way of css or javascript.  
      • The functional goal of this plugin is to return basic html as a string.
    • webkit
      • Example: The stock "Thumbnails" tab.
      • Will display advanced html, including css and javascript - much like a typical web browser. 
      • The functional goal of this plugin is to return a complete [x]html page.
    • tree
      • Example: QubeTabTreeExample.py in the plugins directory
      • Will display a list of [nested] lists in a tree widget.
      • The functional goal of this plugin is to return a [nested list of] list[s].
    • preview
      • Example: The stock "Preview" tab.
      • Will create an image viewer with scrubber for flipping between output frames. 
      • The functional goal of this plugin is to return a list of paths to images.
    • openGL:
      • Deprecated in 6.5-0

    Accessing Qube Information from the Plugin

    In order for the plugin to do anything meaningful, it must know what entities are selected and have access to the Qube data that drives those entities. Any user function defines must take the kwarg "**selected".  Selected will be a dictionary containing lists of items that are selected in the interface.  The dictionary is keyed on the type of item.  Regardless of the function, selected will always contain the following keys:

    • jobs - a list of currently selected jobs, if any
    • subjobs - a list of currently selected subjobs/instances, if any
    • frames - a list of currently selected frames/work items/agenda items, if any
    • hosts - a list of currently selected hosts, if any
    • user_response - True or False answer from challenge given to user (the challenge would come from an "askUser" function).

    In the body of your custom function, then, you will retrieve the selected items that matter, based on your function mapping, and do with them what you choose.

    Example

    This is the QubeTabHelloWorld.py example file you will find in your plugins directory.  It unhidden, this plugin would display a tab called "Hello Wold (tab)" that you display basic HTML about the currently selected items.  The comments in this example have been changed from those you will find on your system.

    The plugin without docstrings and debug logging is quite simple:

     

    With doc strings, you get a little more information:

    QubeTabHelloWorld.py

     

    Adding Right-Click Menu Items

    All of the right-click menu items in ArtistView are driven by Python plugins.  These plugins have access to the data behind the selected entities and can do with that data what they choose.  When the plugin operation is complete, the interface will update.  While ArtistView is written in PyQt, no knowledge of PyQt is needed to create a plugin.

    Plugin Layout

    • All plugins are of class UserUIPlugin and extend QbUIPlugin.
    • All menu plugins must define __init__ and run methods.
    • In the class's __init__ function, the following are defined:
      • Required:
        • name: the display name of the plugin
        • type: the type of plugin.  Options:
          • tab: this plugin creates a new tab
          • menu: this plugin creates a right-click menu item
        • context: Where the menu will be displayed - if you need the same menu in multiple places, you will need to create multiple plugins. Options:
          • job: this menu plugin will be a part of the right-click menu list when clicking on a job.
          • subjob: this menu plugin will be a part of the right-click menu list when clicking on a subjob/instance.
          • frame: this menu plugin will be a part of the right-click menu list when clicking on a frame/agenda item/work item.
          • host: this menu plugin will be a part of the right-click menu list when clicking on a job.
      • Optional:
        • hidden: Setting this to true makes the function completely hidden from the UI - it will not even show up in the preferences.
        • permission: Permission required to use this plugin (see "Working with Permissions" section above")
        • sort_order: order in which to display this tab in the list of tabs
    • The class's run method does all the work.  
      • There is no return value. 
      • Run is passed a **selected argument that contains data from the interface.  See "Access Qube Information from the Plugin"
      • There is no limit to what the run method can do - it doesn't have to do anything Qube related.  It could run a qb API call as well as it could make a call to subprocess.Popen, interact with your production tracking system, etc.

    Working with Permissions

    Qube has a set of internal permissions viewable under the WV User Permissions in WranglerView.  Those permissions determine which users can perform which actions and are ultimately controlled by the supervisor.  ArtistView can reflect those permissions in its interface by assigning a permission member variable to the permission required to perform the actions performed by the plugin.  For example, in order to block a job, one must have the "block" permission.  In order the modify a job, one must have the "modify" permission.

    These permissions can also be used as an obfuscation layer.  For example, requiring an "admin" permission would block the plugin from being performed by anyone who is not a Qube admin.  This plugin could perform non-Qube-specific actions, but would only be available to Qube administrators.

    If a user does not have required permission to run the plugin, then the plugin will not show at all.  If the user has required permission, but is not an admin, then the plugin will be visible but disabled when the user attempts to perform the action on any entity they do not own (for example, one cannot modify someone else's job unless they are an admin).

    Accessing Qube Information from the Plugin

    In order for the plugin to do anything meaningful, it must know what entities are selected and have access to the Qube data that drives those entities. Any user function defines must take the kwarg "**selected".  Selected will be a dictionary containing lists of items that are selected in the interface.  The dictionary is keyed on the type of item.  Regardless of the function, selected will always contain the following keys:

    • jobs - a list of currently selected jobs, if any
    • subjobs - a list of currently selected subjobs/instances, if any
    • frames - a list of currently selected frames/work items/agenda items, if any
    • hosts - a list of currently selected hosts, if any

    In the body of your run method, then, you will retrieve the selected items that matter, and do with them what you choose.

    When the plugin completes, it signals the interface to update the related jobs or hosts.

    Challenging the User - "Are you sure?"

    If you would like to display a dialog that the user must agree to before the plugin is to be run, you do so by adding an askUser method to the plugin class. This function should return a dictionary that drives the interface.  That dictionary must contain the following key/value pairs:

    • "title": The window title of the challenge dialog, i.e. "Performing an action"
    • "text": The main text to be displayed, i.e. "Are you sure?"
    • "info_text": The small-print text displayed below the main text, i.e. "You're about to do something important.  Be sure you know what you're doing."
    • "detailed_text": If this exists, a "More info" button will be displayed that, when pressed, will expand the dialog, display a scroll bar & allow much more text to be displayed, i.e. "This is what you're about to do to these jobs: ...."
    • "icon": The type of icon to display.  Options are (the strings):
      • 'information' - a white speech box
      • 'question' -  a yellow question mark
      • 'warning' - a yellow exclamation point
      • 'critical' - a red stop sign
      • 'noicon' - nothing
    • "button": A list of button(s) text to be displayed.  All positive answers eventually return True, all negatives return False.  Options are (the strings):
      • 'ok'
      • 'cancel'
      • 'save'
      • 'discard'
      • 'yes'
      • 'no'
      • 'apply'
      • 'abort'
      • 'close'

    Performing a search from a Plugin

    If you would like to set a search field and perform a search, programmatically, from a plugin, you do so by adding an updateUI method to the plugin class. This function should return a dictionary of UI fields that need updating.  For 6.7, the only UI fields that can be updated are the search fields which are denoted by the keys search_jobssearch_framessearch_instances, or search_workers for the search field in the job list, frame, list, instance list, or worker list, respectively.

    For example, to perform a search for all jobs with a matching pgrp to the selected job(s), the updateUI function would look like:

    ..which would return a dictionary that looks like {"search_jobs":"pgrp:1234 OR pgrp:1235"}.  This would then fill the job list search field with pgrp:1234 OR pgrp:1235 and perform the search.

    Icon
    Searches are performed after the plugin's run method is scheduled to run, however, because the run method runs in its own thread, there is no guarantee that the run method will have completed before the search is performed.

    Example

    This is the QubeMenuJobHelloWorld.py plugin from the plugins directory that is shipped with ArtistView.  If unhidden, this plugin will challenge the user if they really wish to run the plugin.  Their choice will logged to stderr in the run method.

    The plugin without doc strings or the user challenge info is quite simple:

     

    The same plugin with doc strings is a little more descriptive:

    QubeMenuJobHelloWorld.py
    • No labels