예제 #1
0
    def __init__(self, parent=None):
        """
        Initialize the demo widget.
        """

        # call the base class init
        super(NavigationDemo, self).__init__(parent)

        # get a handle on the current toolkit bundle (the demo app).
        self._app = sgtk.platform.current_bundle()

        # create a background task manager for the widget to use
        self._bg_task_manager = task_manager.BackgroundTaskManager(self)

        # keep track of when we're navigating
        self._navigating = False

        # setup the designer UI
        self.ui = Ui_NavigationWidgetDemoUI()
        self.ui.setupUi(self)

        project = self._app.get_demo_entity("Project")
        if not project:
            raise Exception("Could not find suitable project for this demo!")

        # create a hierarchy model to display data an attach it to the view
        self._hierarchy_model = shotgun_model.SimpleShotgunHierarchyModel(
            self,
            bg_task_manager=self._bg_task_manager
        )

        # create a proxy model to sort the hierarchy
        self._hierarchy_proxy_model = QtGui.QSortFilterProxyModel(self)
        self._hierarchy_proxy_model.setDynamicSortFilter(True)

        # set the proxy model's source to the hierarchy model
        self._hierarchy_proxy_model.setSourceModel(self._hierarchy_model)

        # set the proxy model as the data source for the view
        self.ui.tree_view.setModel(self._hierarchy_proxy_model)
        self.ui.tree_view.header().hide()
        self.ui.tree_view.setSortingEnabled(True)
        self.ui.tree_view.sortByColumn(0, QtCore.Qt.AscendingOrder)

        # build a hierarchy for the current project targeting entities linked
        # to the "entity" field on "Version" entities
        self._hierarchy_model.load_data("Version.entity")

        # ---- connect some signals

        # handle navigation widget clicks
        self.ui.nav_widget.home_clicked.connect(self._on_home_clicked)
        self.ui.nav_widget.navigate.connect(self._on_navigate)

        # now handle hierarchy selection
        selection_model = self.ui.tree_view.selectionModel()
        selection_model.selectionChanged.connect(
            self._on_hierarchy_selection_changed
        )
예제 #2
0
    def __init__(self, parent=None):
        """
        Return the ``QtGui.QWidget`` instance for this demo.
        """

        super(ShotgunEntityModelDemo, self).__init__(parent)

        # see if we can determine the current project. if we can, only show the
        # assets for this project.
        self._app = sgtk.platform.current_bundle()
        if self._app.context.project:
            filters = ["project", "is", self._app.context.project]
        else:
            filters = []

        # construct the view and set the model
        self._entity_view = QtGui.QTreeView()
        self._entity_view.setIndentation(16)
        self._entity_view.setUniformRowHeights(True)
        self._entity_view.setSortingEnabled(True)
        self._entity_view.sortByColumn(0, QtCore.Qt.AscendingOrder)

        # construct an entity model then load some data.
        self._entity_model = shotgun_model.ShotgunEntityModel(
            "Asset",  # entity type
            [filters],  # filters
            ["project.Project.name", "sg_asset_type", "code"],  # hierarchy
            ["description", "id", "project", "sg_asset_type"],  # fields
            self,
        )

        # refresh the data to ensure it is up-to-date
        self._entity_model.async_refresh()

        # create a proxy model to sort the model
        self._entity_proxy_model = QtGui.QSortFilterProxyModel(self)
        self._entity_proxy_model.setDynamicSortFilter(True)

        # set the proxy model's source to the entity model
        self._entity_proxy_model.setSourceModel(self._entity_model)

        # set the proxy model as the data source for the view
        self._entity_view.setModel(self._entity_proxy_model)

        info_lbl = QtGui.QLabel(
            "This demo shows how to use the <tt>ShotgunEntityModel</tt> to "
            "display a hierarchy of <b>Asset</b> entities."
        )

        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(info_lbl)
        layout.addWidget(self._entity_view)
예제 #3
0
    def _populate_ui(self):
        """
        Populate the UI with the data.
        """

        # construct a hierarchy model then load some data.
        # "Version.entity" seed means build a hierarchy that leads to
        # entities that are linked via the Version.entity field.
        # by default the model will be built for the current project.
        # if no project can be determined from the current context,
        # the model will be built with top-level items for each project.
        self._hierarchy_model = shotgun_model.SimpleShotgunHierarchyModel(
            self, bg_task_manager=self._bg_task_manager)
        self._hierarchy_model.load_data("Version.entity")

        # create a proxy model to sort the hierarchy
        self._hierarchy_proxy_model = QtGui.QSortFilterProxyModel(self)
        self._hierarchy_proxy_model.setDynamicSortFilter(True)

        # set the proxy model's source to the hierarchy model
        self._hierarchy_proxy_model.setSourceModel(self._hierarchy_model)

        # set the proxy model as the data source for the view
        self._hierarchy_view.setModel(self._hierarchy_proxy_model)

        # create a simple shotgun model for querying the versions
        self._version_model = shotgun_model.SimpleShotgunModel(
            self, bg_task_manager=self._bg_task_manager)

        # --- connect some signals

        # as hierarchy view selection changes, query versions
        selection_model = self._hierarchy_view.selectionModel()
        selection_model.selectionChanged.connect(
            self._on_hierarchy_selection_changed)

        # show the overlay on the versions as they're being queried
        self._version_model.data_refreshing.connect(
            lambda: self._overlay_widget.start_spin())
        self._version_model.data_refreshed.connect(self._on_data_refreshed)
예제 #4
0
    def __init__(self, parent=None):
        """
        Constructor
        """
        # first, call the base class and let it do its thing.
        QtGui.QWidget.__init__(self, parent)

        # most of the useful accessors are available through the Application class instance
        # it is often handy to keep a reference to this. You can get it via the following method:
        self._app = sgtk.platform.current_bundle()

        self._action_manager = ActionManager(self)
        self._action_manager.refresh_request.connect(self.setup_ui)

        # create a background task manager
        self._task_manager = task_manager.BackgroundTaskManager(
            self, start_processing=True, max_threads=2)

        # register the data fetcher with the global schema manager
        shotgun_globals.register_bg_task_manager(self._task_manager)

        # now load in the UI that was created in the UI designer
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        # create a note updater to run operations on notes in the db
        self._note_updater = NoteUpdater(self._task_manager, self)

        # flag to keep track of when we are navigating
        self._navigating = False

        # hook up a data retriever with all objects needing to talk to sg
        self.ui.search_input.set_bg_task_manager(self._task_manager)
        self.ui.note_reply_widget.set_bg_task_manager(self._task_manager)
        self.ui.entity_activity_stream.set_bg_task_manager(self._task_manager)
        self.ui.version_activity_stream.set_bg_task_manager(self._task_manager)

        # set up action menu. parent it to the action button to prevent cases
        # where it shows up elsewhere on screen (as in Houdini)
        self._menu = shotgun_menus.ShotgunMenu(self.ui.action_button)
        self.ui.action_button.setMenu(self._menu)

        # this forces the menu to be right aligned with the button. This is
        # preferable since many DCCs show the embed panel on the far right. In
        # houdini at least, before forcing this layout direction, the menu was
        # showing up partially offscreen.
        self.ui.action_button.setLayoutDirection(QtCore.Qt.RightToLeft)

        # our current object we are currently displaying
        self._current_location = None

        # track the history
        self._history_items = []
        self._history_index = 0

        # overlay to show messages
        self._overlay = overlay_module.ShotgunOverlayWidget(self)

        # figure out which type of publish this toolkit project is using
        self._publish_entity_type = sgtk.util.get_published_file_entity_type(
            self._app.sgtk)

        # create a settings manager where we can pull and push prefs later
        # prefs in this manager are shared
        self._settings_manager = settings.UserSettings(self._app)

        # set previously stored value for "show latest"
        latest_pubs_only = self._settings_manager.retrieve(
            "latest_publishes_only", True)
        self.ui.latest_publishes_only.setChecked(latest_pubs_only)

        # set previously stored value for "show pending"
        pending_versions_only = self._settings_manager.retrieve(
            "pending_versions_only", False)
        self.ui.pending_versions_only.setChecked(pending_versions_only)

        # navigation
        self.ui.navigation_home.clicked.connect(self._on_home_clicked)
        self.ui.navigation_next.clicked.connect(self._on_next_clicked)
        self.ui.navigation_prev.clicked.connect(self._on_prev_clicked)

        # search
        self.ui.search.clicked.connect(self._on_search_clicked)
        self.ui.cancel_search.clicked.connect(self._cancel_search)
        self.ui.search_input.entity_selected.connect(
            self._on_search_item_selected)

        # latest publishes only
        self.ui.latest_publishes_only.toggled.connect(
            self._on_latest_publishes_toggled)
        self.ui.pending_versions_only.toggled.connect(
            self._on_pending_versions_toggled)

        # tabs
        self.ui.entity_tab_widget.currentChanged.connect(
            self._load_entity_tab_data)
        self.ui.version_tab_widget.currentChanged.connect(
            self._load_version_tab_data)
        self.ui.publish_tab_widget.currentChanged.connect(
            self._load_publish_tab_data)

        # model to get the current user's details
        self._current_user_model = SgCurrentUserModel(self, self._task_manager)
        self._current_user_model.thumbnail_updated.connect(
            self._update_current_user)
        self._current_user_model.data_updated.connect(
            self._update_current_user)
        self._current_user_model.load()
        self.ui.current_user.clicked.connect(self._on_user_home_clicked)

        # top detail section
        self._details_model = SgEntityDetailsModel(self, self._task_manager)
        self._details_overlay = ShotgunModelOverlayWidget(
            self._details_model, self.ui.top_group)

        self._details_model.data_updated.connect(self._refresh_details)
        self._details_model.thumbnail_updated.connect(
            self._refresh_details_thumbnail)

        # hyperlink clicking
        self.ui.details_text_header.linkActivated.connect(
            self._on_link_clicked)
        self.ui.details_text_middle.linkActivated.connect(
            self._on_link_clicked)
        self.ui.details_thumb.playback_clicked.connect(self._playback_version)

        self.ui.note_reply_widget.entity_requested.connect(
            self.navigate_to_entity)
        self.ui.entity_activity_stream.entity_requested.connect(
            self.navigate_to_entity)
        self.ui.version_activity_stream.entity_requested.connect(
            self.navigate_to_entity)

        self.ui.entity_activity_stream.playback_requested.connect(
            self._playback_version)
        self.ui.version_activity_stream.playback_requested.connect(
            self._playback_version)

        # set up the UI tabs. Each tab has a model, a delegate, a view and
        # an associated enity type

        self._detail_tabs = {}

        # tabs on entity view
        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_NOTES)
        self._detail_tabs[idx] = {
            "model_class": SgEntityListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_note_view,
            "entity_type": "Note",
        }

        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_VERSIONS)
        self._detail_tabs[idx] = {
            "model_class": SgVersionModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_version_view,
            "entity_type": "Version",
        }

        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_PUBLISHES)
        self._detail_tabs[idx] = {
            "model_class": SgLatestPublishListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_publish_view,
            "entity_type": self._publish_entity_type,
        }

        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_TASKS)
        self._detail_tabs[idx] = {
            "model_class": SgTaskListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_task_view,
            "entity_type": "Task",
        }

        # tabs on publish view
        idx = (self.PUBLISH_PAGE_IDX, self.PUBLISH_TAB_HISTORY)
        self._detail_tabs[idx] = {
            "model_class": SgPublishHistoryListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.publish_history_view,
            "entity_type": self._publish_entity_type,
        }

        idx = (self.PUBLISH_PAGE_IDX, self.PUBLISH_TAB_CONTAINS)
        self._detail_tabs[idx] = {
            "model_class": SgPublishDependencyDownstreamListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.publish_upstream_view,
            "entity_type": self._publish_entity_type,
        }

        idx = (self.PUBLISH_PAGE_IDX, self.PUBLISH_TAB_USED_IN)
        self._detail_tabs[idx] = {
            "model_class": SgPublishDependencyUpstreamListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.publish_downstream_view,
            "entity_type": self._publish_entity_type,
        }

        # tabs on version view
        idx = (self.VERSION_PAGE_IDX, self.VERSION_TAB_NOTES)
        self._detail_tabs[idx] = {
            "model_class": SgEntityListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.version_note_view,
            "entity_type": "Note",
        }

        idx = (self.VERSION_PAGE_IDX, self.VERSION_TAB_PUBLISHES)
        self._detail_tabs[idx] = {
            "model_class": SgLatestPublishListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.version_publish_view,
            "entity_type": self._publish_entity_type,
        }

        # now initialize all tabs. This will add two model and delegate keys
        # to all the dicts

        for tab_dict in self._detail_tabs.values():

            ModelClass = tab_dict["model_class"]
            DelegateClass = tab_dict["delegate_class"]

            self._app.log_debug("Creating %r..." % ModelClass)

            # create model
            tab_dict["model"] = ModelClass(tab_dict["entity_type"],
                                           tab_dict["view"],
                                           self._task_manager)

            # create proxy for sorting
            tab_dict["sort_proxy"] = QtGui.QSortFilterProxyModel(self)
            tab_dict["sort_proxy"].setSourceModel(tab_dict["model"])

            # now use the proxy model to sort the data to ensure
            # higher version numbers appear earlier in the list
            # the history model is set up so that the default display
            # role contains the version number field in shotgun.
            # This field is what the proxy model sorts by default
            # We set the dynamic filter to true, meaning QT will keep
            # continously sorting. And then tell it to use column 0
            # (we only have one column in our models) and descending order.
            tab_dict["sort_proxy"].setDynamicSortFilter(True)
            tab_dict["sort_proxy"].sort(0, QtCore.Qt.DescendingOrder)

            # set up model
            tab_dict["view"].setModel(tab_dict["sort_proxy"])
            # set up a global on-click handler for
            tab_dict["view"].doubleClicked.connect(
                self._on_entity_doubleclicked)
            # create delegate
            tab_dict["delegate"] = DelegateClass(tab_dict["view"],
                                                 self._action_manager)
            tab_dict["delegate"].change_work_area.connect(
                self._change_work_area)
            # hook up delegate renderer with view
            tab_dict["view"].setItemDelegate(tab_dict["delegate"])
            # and set up a spinner overlay
            tab_dict["overlay"] = NotFoundModelOverlay(tab_dict["model"],
                                                       tab_dict["view"])

            if ModelClass == SgPublishHistoryListingModel:
                # this class needs special access to the overlay
                tab_dict["model"].set_overlay(tab_dict["overlay"])

        # set up the all fields tabs
        self._entity_details_model = SgAllFieldsModel(self, self._task_manager)
        self._entity_details_overlay = ShotgunModelOverlayWidget(
            self._entity_details_model, self.ui.entity_info_widget)

        self._entity_details_model.data_updated.connect(
            self.ui.entity_info_widget.set_data)
        self.ui.entity_info_widget.link_activated.connect(
            self._on_link_clicked)

        self._version_details_model = SgAllFieldsModel(
            self.ui.version_info_widget, self._task_manager)
        self._version_details_model.data_updated.connect(
            self.ui.version_info_widget.set_data)
        self.ui.version_info_widget.link_activated.connect(
            self._on_link_clicked)

        self._publish_details_model = SgAllFieldsModel(
            self.ui.publish_info_widget, self._task_manager)
        self._publish_details_model.data_updated.connect(
            self.ui.publish_info_widget.set_data)
        self.ui.publish_info_widget.link_activated.connect(
            self._on_link_clicked)

        # the set work area overlay
        self.ui.set_context.change_work_area.connect(self._change_work_area)

        # kick off
        self._on_home_clicked()

        # register a startup splash screen
        splash_pix = QtGui.QPixmap(":/tk_multi_infopanel/splash.png")
        self._overlay.show_message_pixmap(splash_pix)
        QtCore.QCoreApplication.processEvents()
        QtCore.QTimer.singleShot(SPLASH_UI_TIME_MILLISECONDS,
                                 self._overlay.hide)
    def setup_entity_model_view(self, entity_data):
        """
        Given the entiy tab data, set up a model and view for the tab. This method
        will modify the `entity_data` dict passed in with the created model and view.

        :param entity_data:
        :type entity_data: dict
        :return: None
        """

        # Check for the required entity data to set up the model and view.
        if not (entity_data.get("model_class", None)
                and entity_data.get("delegate_class", None)
                and entity_data.get("entity_type", None)
                and entity_data.get("view", None)):
            return

        ModelClass = entity_data["model_class"]
        DelegateClass = entity_data["delegate_class"]

        self._app.log_debug("Creating %r..." % ModelClass)

        # create model
        entity_data["model"] = ModelClass(entity_data["entity_type"],
                                          entity_data["view"],
                                          self._task_manager)

        # create proxy for sorting
        entity_data["sort_proxy"] = QtGui.QSortFilterProxyModel(self)
        entity_data["sort_proxy"].setSourceModel(entity_data["model"])

        # now use the proxy model to sort the data to ensure
        # higher version numbers appear earlier in the list
        # the history model is set up so that the default display
        # role contains the version number field in shotgun.
        # This field is what the proxy model sorts by default
        # We set the dynamic filter to true, meaning QT will keep
        # continously sorting. And then tell it to use column 0
        # (we only have one column in our models) and descending order.
        entity_data["sort_proxy"].setDynamicSortFilter(True)
        entity_data["sort_proxy"].sort(0, QtCore.Qt.DescendingOrder)

        # set up model
        entity_data["view"].setModel(entity_data["sort_proxy"])
        # set up a global on-click handler for
        entity_data["view"].doubleClicked.connect(
            self._on_entity_doubleclicked)
        # create delegate
        entity_data["delegate"] = DelegateClass(entity_data["view"],
                                                self._action_manager)
        entity_data["delegate"].change_work_area.connect(
            self._change_work_area)
        # hook up delegate renderer with view
        entity_data["view"].setItemDelegate(entity_data["delegate"])
        # and set up a spinner overlay
        entity_data["overlay"] = NotFoundModelOverlay(entity_data["model"],
                                                      entity_data["view"])

        if ModelClass == SgPublishHistoryListingModel:
            # this class needs special access to the overlay
            entity_data["model"].set_overlay(entity_data["overlay"])
예제 #6
0
    def __init__(self, parent=None):
        """
        Constructor
        """
        # first, call the base class and let it do its thing.
        QtGui.QWidget.__init__(self, parent)

        # most of the useful accessors are available through the Application class instance
        # it is often handy to keep a reference to this. You can get it via the following method:
        self._app = sgtk.platform.current_bundle()

        self._action_manager = ActionManager(self)

        # set up an asynchronous shotgun retriever to pull down data
        self._sg_data_retriever = shotgun_data.ShotgunDataRetriever(self)
        self._sg_data_retriever.start()

        # register the data fetcher with the global schema manager
        CachedShotgunSchema.register_data_retriever(self._sg_data_retriever)

        # now load in the UI that was created in the UI designer
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        # create a note updater to run operations on notes in the db
        self._note_updater = NoteUpdater(self._sg_data_retriever, self)

        # hook up a data retriever with all objects needing to talk to sg
        self.ui.search_input.set_data_retriever(self._sg_data_retriever)
        self.ui.note_reply_widget.set_data_retriever(self._sg_data_retriever)
        self.ui.entity_activity_stream.set_data_retriever(
            self._sg_data_retriever)
        self.ui.version_activity_stream.set_data_retriever(
            self._sg_data_retriever)

        # set up action menu
        self._menu = QtGui.QMenu()
        self._actions = []
        self.ui.action_button.setMenu(self._menu)

        # our current object we are currently displaying
        self._current_location = None

        # track the history
        self._history_items = []
        self._history_index = 0

        # overlay to show messages
        self._overlay = overlay_module.ShotgunOverlayWidget(self)

        # figure out which type of publish this toolkit project is using
        self._publish_entity_type = sgtk.util.get_published_file_entity_type(
            self._app.sgtk)

        # create a settings manager where we can pull and push prefs later
        # prefs in this manager are shared
        self._settings_manager = settings.UserSettings(self._app)

        # set previously stored value for "show latest"
        latest_pubs_only = self._settings_manager.retrieve(
            "latest_publishes_only", True)
        self.ui.latest_publishes_only.setChecked(latest_pubs_only)

        # set previously stored value for "show pending"
        pending_versions_only = self._settings_manager.retrieve(
            "pending_versions_only", False)
        self.ui.pending_versions_only.setChecked(pending_versions_only)

        # navigation
        self.ui.navigation_home.clicked.connect(self._on_home_clicked)
        self.ui.navigation_next.clicked.connect(self._on_next_clicked)
        self.ui.navigation_prev.clicked.connect(self._on_prev_clicked)

        # search
        self.ui.search.clicked.connect(self._on_search_clicked)
        self.ui.cancel_search.clicked.connect(self._cancel_search)
        self.ui.search_input.entity_selected.connect(
            self._on_search_item_selected)

        # latest publishes only
        self.ui.latest_publishes_only.toggled.connect(
            self._on_latest_publishes_toggled)
        self.ui.pending_versions_only.toggled.connect(
            self._on_pending_versions_toggled)

        # tabs
        self.ui.entity_tab_widget.currentChanged.connect(
            self._load_entity_tab_data)
        self.ui.version_tab_widget.currentChanged.connect(
            self._load_version_tab_data)
        self.ui.publish_tab_widget.currentChanged.connect(
            self._load_publish_tab_data)

        # model to get the current user's details
        self._current_user_model = SgCurrentUserModel(self)
        self._current_user_model.thumbnail_updated.connect(
            self._update_current_user)
        self._current_user_model.data_updated.connect(
            self._update_current_user)
        self._current_user_model.load()
        self.ui.current_user.clicked.connect(self._on_user_home_clicked)

        # top detail section
        self._details_model = SgEntityDetailsModel(self.ui.top_group)
        self._details_model.data_updated.connect(self._refresh_details)
        self._details_model.thumbnail_updated.connect(
            self._refresh_details_thumbnail)

        # hyperlink clicking
        self.ui.details_text_header.linkActivated.connect(
            self._on_link_clicked)
        self.ui.details_text_middle.linkActivated.connect(
            self._on_link_clicked)
        self.ui.details_thumb.playback_clicked.connect(self._playback_version)

        self.ui.note_reply_widget.entity_requested.connect(
            self._navigate_to_entity)
        self.ui.entity_activity_stream.entity_requested.connect(
            self._navigate_to_entity)
        self.ui.version_activity_stream.entity_requested.connect(
            self._navigate_to_entity)

        self.ui.entity_activity_stream.playback_requested.connect(
            self._playback_version)
        self.ui.version_activity_stream.playback_requested.connect(
            self._playback_version)

        # set up the UI tabs. Each tab has a model, a delegate, a view and
        # an associated enity type

        self._detail_tabs = {}

        # tabs on entity view
        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_NOTES)
        self._detail_tabs[idx] = {
            "model_class": SgEntityListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_note_view,
            "entity_type": "Note"
        }

        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_VERSIONS)
        self._detail_tabs[idx] = {
            "model_class": SgVersionModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_version_view,
            "entity_type": "Version"
        }

        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_PUBLISHES)
        self._detail_tabs[idx] = {
            "model_class": SgLatestPublishListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_publish_view,
            "entity_type": self._publish_entity_type
        }

        idx = (self.ENTITY_PAGE_IDX, self.ENTITY_TAB_TASKS)
        self._detail_tabs[idx] = {
            "model_class": SgTaskListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.entity_task_view,
            "entity_type": "Task"
        }

        # tabs on publish view
        idx = (self.PUBLISH_PAGE_IDX, self.PUBLISH_TAB_HISTORY)
        self._detail_tabs[idx] = {
            "model_class": SgPublishHistoryListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.publish_history_view,
            "entity_type": self._publish_entity_type
        }

        idx = (self.PUBLISH_PAGE_IDX, self.PUBLISH_TAB_CONTAINS)
        self._detail_tabs[idx] = {
            "model_class": SgPublishDependencyDownstreamListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.publish_upstream_view,
            "entity_type": self._publish_entity_type
        }

        idx = (self.PUBLISH_PAGE_IDX, self.PUBLISH_TAB_USED_IN)
        self._detail_tabs[idx] = {
            "model_class": SgPublishDependencyUpstreamListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.publish_downstream_view,
            "entity_type": self._publish_entity_type
        }

        # tabs on version view
        idx = (self.VERSION_PAGE_IDX, self.VERSION_TAB_NOTES)
        self._detail_tabs[idx] = {
            "model_class": SgEntityListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.version_note_view,
            "entity_type": "Note"
        }

        idx = (self.VERSION_PAGE_IDX, self.VERSION_TAB_PUBLISHES)
        self._detail_tabs[idx] = {
            "model_class": SgLatestPublishListingModel,
            "delegate_class": ListItemDelegate,
            "view": self.ui.version_publish_view,
            "entity_type": self._publish_entity_type
        }

        # now initialize all tabs. This will add two model and delegate keys
        # to all the dicts

        for (idx, tab_dict) in self._detail_tabs.iteritems():

            ModelClass = tab_dict["model_class"]
            DelegateClass = tab_dict["delegate_class"]

            self._app.log_debug("Creating %r..." % ModelClass)

            # create model
            if idx == (self.PUBLISH_PAGE_IDX, self.PUBLISH_TAB_HISTORY):
                # special case for the version history model
                tab_dict["model"] = ModelClass(tab_dict["entity_type"],
                                               self._sg_data_retriever,
                                               tab_dict["view"])

            else:
                tab_dict["model"] = ModelClass(tab_dict["entity_type"],
                                               tab_dict["view"])

            # create proxy for sorting
            tab_dict["sort_proxy"] = QtGui.QSortFilterProxyModel(self)
            tab_dict["sort_proxy"].setSourceModel(tab_dict["model"])

            # now use the proxy model to sort the data to ensure
            # higher version numbers appear earlier in the list
            # the history model is set up so that the default display
            # role contains the version number field in shotgun.
            # This field is what the proxy model sorts by default
            # We set the dynamic filter to true, meaning QT will keep
            # continously sorting. And then tell it to use column 0
            # (we only have one column in our models) and descending order.
            tab_dict["sort_proxy"].setDynamicSortFilter(True)
            tab_dict["sort_proxy"].sort(0, QtCore.Qt.DescendingOrder)

            # set up model
            tab_dict["view"].setModel(tab_dict["sort_proxy"])
            # set up a global on-click handler for
            tab_dict["view"].doubleClicked.connect(self._on_entity_clicked)
            # create delegate
            tab_dict["delegate"] = DelegateClass(tab_dict["view"],
                                                 self._action_manager)
            # hook up delegate renderer with view
            tab_dict["view"].setItemDelegate(tab_dict["delegate"])

        # set up the all fields tabs
        self._entity_details_model = SgAllFieldsModel(
            self.ui.entity_info_widget)
        self._entity_details_model.data_updated.connect(
            self.ui.entity_info_widget.set_data)
        self.ui.entity_info_widget.link_activated.connect(
            self._on_link_clicked)

        self._version_details_model = SgAllFieldsModel(
            self.ui.version_info_widget)
        self._version_details_model.data_updated.connect(
            self.ui.version_info_widget.set_data)
        self.ui.version_info_widget.link_activated.connect(
            self._on_link_clicked)

        self._publish_details_model = SgAllFieldsModel(
            self.ui.publish_info_widget)
        self._publish_details_model.data_updated.connect(
            self.ui.publish_info_widget.set_data)
        self.ui.publish_info_widget.link_activated.connect(
            self._on_link_clicked)

        # kick off
        self._on_home_clicked()