예제 #1
0
    def __init__(self, text, name, me=False, parent=None):
        '''Initialise widget with *text* and *name*.'''
        super(Message, self).__init__(parent)

        self.setLayout(QtWidgets.QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().setSpacing(0)

        if me:
            name = 'You'

        self.sender = QtWidgets.QLabel(name)
        self.layout().addWidget(self.sender, stretch=0)

        self.text = QtWidgets.QLabel(text)
        self.text.setWordWrap(True)
        self.text.setObjectName('message-text')

        self.layout().addWidget(self.text, stretch=1)

        if me:
            self.sender.setStyleSheet('''
                    QLabel {
                        color: #1CBC90;
                    }
                ''')
            self.sender.setAlignment(QtCore.Qt.AlignRight)
            self.text.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignRight)
        else:
            self.sender.setStyleSheet('''
                    QLabel {
                        color: rgba(52, 152, 219, 255);
                    }
                ''')
예제 #2
0
    def __init__(
        self, parent, message='Processing',
        icon=':ftrack/image/default/ftrackLogoColor'
    ):
        '''Initialise with *parent*.

         *message* is the message to display on the overlay.

         '''
        super(BlockingOverlay, self).__init__(parent)
        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.content = QtWidgets.QFrame()
        self.content.setObjectName('content')
        layout.addWidget(
            self.content, alignment=QtCore.Qt.AlignCenter
        )

        self.contentLayout = QtWidgets.QVBoxLayout()
        self.contentLayout.setContentsMargins(0, 0, 0, 0)
        self.content.setLayout(self.contentLayout)

        self.icon = QtWidgets.QLabel()
        pixmap = QtGui.QPixmap(icon)
        self.icon.setPixmap(
            pixmap.scaledToHeight(36, mode=QtCore.Qt.SmoothTransformation)
        )
        self.icon.setAlignment(QtCore.Qt.AlignCenter)
        self.contentLayout.addWidget(self.icon)

        self.messageLabel = QtWidgets.QLabel()
        self.messageLabel.setWordWrap(True)
        self.messageLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.contentLayout.addWidget(self.messageLabel)

        self.setStyleSheet('''
            BlockingOverlay {
                background-color: rgba(250, 250, 250, 200);
                border: none;
            }

            BlockingOverlay QFrame#content {
                padding: 0px;
                border: 80px solid transparent;
                background-color: transparent;
                border-image: url(:ftrack/image/default/boxShadow) 140 stretch;
            }

            BlockingOverlay QLabel {
                background: transparent;
            }
        ''')

        self.setMessage(message)
예제 #3
0
파일: actions.py 프로젝트: hanbinren/wudi
    def __init__(self,
                 session,
                 all_section_text=None,
                 overlay=None,
                 parent=None):
        '''Initiate a actions view.'''
        super(Actions, self).__init__(parent)

        self.logger = logging.getLogger(__name__ + '.' +
                                        self.__class__.__name__)
        self._session = session

        self._action_label_text = all_section_text

        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)
        self.layout().setContentsMargins(0, 0, 0, 0)

        self._currentUserId = None
        self._recentActions = []
        self._actions = []

        self._recentLabel = QtWidgets.QLabel('Recent')
        layout.addWidget(self._recentLabel)
        self._recentSection = ActionSection(self)
        # self._recentSection.setFixedHeight(100)
        self._recentSection.beforeActionLaunch.connect(
            self._onBeforeActionLaunched)
        self._recentSection.actionLaunched.connect(self._onActionLaunched)
        # layout.addWidget(self._recentSection)

        self._allLabel = QtWidgets.QLabel()
        self._allLabel.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(self._allLabel)
        self._allSection = ActionSection(self)
        self._allSection.beforeActionLaunch.connect(
            self._onBeforeActionLaunched)
        self._allSection.actionLaunched.connect(self._onActionLaunched)
        layout.addWidget(self._allSection)

        if overlay is None:
            self._overlay = overlay_.BusyOverlay(self, message='Launching...')
        else:
            self._overlay = overlay

        self._overlay.setStyleSheet(OVERLAY_DARK_STYLE)
        self._overlay.setVisible(False)

        self.recentActionsChanged.connect(self._updateRecentSection)

        self._loadActionsForContext([])
        self._updateRecentActions()
    def __init__(self, *args, **kwargs):
        '''Initialise DataDropZone widget.'''
        super(DataDropZone, self).__init__(*args, **kwargs)

        self.log = logging.getLogger(__name__ + '.' + self.__class__.__name__)
        self.setAcceptDrops(True)
        self.setObjectName('ftrack-connect-publisher-browse-button')
        self.setProperty('ftrackDropZone', True)

        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)

        bottomCenterAlignment = QtCore.Qt.AlignBottom | QtCore.Qt.AlignHCenter
        topCenterAlignment = QtCore.Qt.AlignTop | QtCore.Qt.AlignHCenter

        self._label = QtWidgets.QLabel('Drop files here or')
        layout.addWidget(self._label, alignment=bottomCenterAlignment)

        self._browseButton = QtWidgets.QPushButton('Browse')
        self._browseButton.setToolTip('Browse for file(s).')
        layout.addWidget(self._browseButton, alignment=topCenterAlignment)

        self._setupConnections()

        homeFolder = os.path.expanduser('~')
        if os.path.isdir(homeFolder):
            self._currentLocation = homeFolder
예제 #5
0
    def __init__(self, username, session, parent=None):
        '''Instantiate user name and logo widget using *username*.'''

        super(User, self).__init__(parent=parent)
        self.setObjectName('ftrack-userid-widget')
        self.main_layout = QtWidgets.QHBoxLayout()
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setAlignment(QtCore.Qt.AlignRight)
        self.setLayout(self.main_layout)

        self.session = session

        self.label = QtWidgets.QLabel(self)
        self.image = thumbnail.User(self)
        self.image.setFixedSize(30, 30)

        self.main_layout.addWidget(self.label)
        self.main_layout.addWidget(self.image)

        self.username = username
        self.image.load(username)

        if username in NAME_CACHE:
            self.set_user_fullname()
        else:
            self.load_user_fullname()
예제 #6
0
    def parseRow(self, rowElement, connectorName, mainLayout, assetTypeName):
        '''Parse xml *rowElement*.'''
        accepts = rowElement.attribute('accepts')
        acceptsSplit = accepts.split(',')
        if accepts == '' or connectorName in acceptsSplit:
            rowLayout = QtWidgets.QHBoxLayout()
            rowName = rowElement.attribute('name')
            rowEnabled = rowElement.attribute('enabled')

            optionLabel = QtWidgets.QLabel(rowName)
            optionLabel.setFixedWidth(160)
            rowLayout.addWidget(optionLabel)

            if rowEnabled == 'False':
                enabled = False
                optionLabel.setEnabled(False)
            else:
                enabled = True

            optionElements = rowElement.elementsByTagName('option')
            optionsCount = self.parseOptions(rowLayout, optionElements,
                                             assetTypeName, enabled)

            return rowLayout, optionsCount
        else:
            return None, 0
    def __init__(self, parent=None, title=None, headerWidgets=None):
        '''Instantiate widget with optional *parent* and *title*.

        *headerWidgets* is an optional list of widgets to append to the header
        of the time log widget.

        '''
        super(TimeLogList,
              self).__init__(widgetFactory=self._createWidget,
                             widgetItem=lambda widget: widget.value(),
                             parent=parent)
        self.setObjectName('time-log-list')
        self.list.setShowGrid(False)

        # Disable selection on internal list.
        self.list.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)

        headerLayout = QtWidgets.QHBoxLayout()
        self.titleLabel = QtWidgets.QLabel(title)
        self.titleLabel.setProperty('title', True)

        headerLayout.addWidget(self.titleLabel, stretch=1)

        # TODO: Refacor and make use of QToolBar and QAction.
        # Also consider adding 'addAction'/'removeAction'.
        if headerWidgets:
            for widget in headerWidgets:
                headerLayout.addWidget(widget, stretch=0)

        self.layout().insertLayout(0, headerLayout)
    def __init__(self, *args, **kwargs):
        '''Initialise widget.'''
        super(ThumbnailDropZone, self).__init__(*args, **kwargs)

        self.setObjectName('ftrack-connect-thumbnail-drop-zone')

        layout = QtWidgets.QHBoxLayout()
        layout.addSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.setAcceptDrops(True)
        self.setProperty('ftrackDropZone', True)

        self._filePath = None
        self._imageWidth = 200
        self._imageHeight = 50

        self.imageLabel = QtWidgets.QLabel()
        self.setDropZoneText()
        layout.addWidget(self.imageLabel, alignment=QtCore.Qt.AlignLeft)

        # TODO: Add theme support.
        removeIcon = QtGui.QIcon(QtGui.QPixmap(':/ftrack/image/light/trash'))
        self.removeButton = QtWidgets.QPushButton()
        self.removeButton.setVisible(False)
        self.removeButton.setFlat(True)
        self.removeButton.setIcon(removeIcon)
        self.removeButton.clicked.connect(self.removeThumbnail)
        layout.addWidget(self.removeButton, alignment=QtCore.Qt.AlignRight)
예제 #9
0
    def create_overlay_widgets(self, congrat_text, success_text):
        '''Create overlay widgets to report publish result.'''

        self.activeWidget = QtWidgets.QWidget()
        self.activeWidget.setLayout(QtWidgets.QVBoxLayout())
        self.layout().addWidget(self.activeWidget)
        main_layout = self.activeWidget.layout()

        icon = QtGui.QPixmap(':ftrack/image/default/ftrackLogoLabelNew')
        icon = icon.scaled(QtCore.QSize(85, 85), QtCore.Qt.KeepAspectRatio,
                           QtCore.Qt.SmoothTransformation)

        self.ftrack_icon = QtWidgets.QLabel()
        self.ftrack_icon.setPixmap(icon)

        main_layout.addStretch(1)
        main_layout.insertWidget(1,
                                 self.ftrack_icon,
                                 alignment=QtCore.Qt.AlignCenter)

        congrat_label = QtWidgets.QLabel(congrat_text)
        congrat_label.setAlignment(QtCore.Qt.AlignCenter)

        success_label = QtWidgets.QLabel(success_text)
        success_label.setAlignment(QtCore.Qt.AlignCenter)

        main_layout.addWidget(congrat_label)
        main_layout.addWidget(success_label)
        main_layout.addStretch(1)

        buttons_layout = QtWidgets.QHBoxLayout()

        main_layout.addLayout(buttons_layout)

        self.details_button = QtWidgets.QPushButton('Details')
        buttons_layout.addWidget(self.details_button)
        self.details_button.clicked.connect(self.on_show_details)

        if self.details_window_callback is None:
            self.details_button.setDisabled(True)

        self.open_in_ftrack = QtWidgets.QPushButton('Open in ftrack')
        buttons_layout.addWidget(self.open_in_ftrack)
        self.open_in_ftrack.clicked.connect(self.on_open_in_ftrack)

        if self.asset_version is None:
            self.open_in_ftrack.setDisabled(True)
예제 #10
0
    def __init__(self, parent=None):
        '''Initiate a actions view.'''
        super(Actions, self).__init__(parent)

        self.logger = logging.getLogger(__name__ + '.' +
                                        self.__class__.__name__)
        self._session = ftrack_connect.session.get_session()

        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)

        self._currentUserId = None
        self._recentActions = []
        self._actions = []

        self._entitySelector = entity_selector.EntitySelector()
        self._entitySelector.setFixedHeight(50)
        self._entitySelector.entityChanged.connect(self._onEntityChanged)
        layout.addWidget(QtWidgets.QLabel('Select action context'))
        layout.addWidget(self._entitySelector)

        self._recentLabel = QtWidgets.QLabel('Recent')
        layout.addWidget(self._recentLabel)
        self._recentSection = ActionSection(self)
        self._recentSection.setFixedHeight(100)
        self._recentSection.beforeActionLaunch.connect(
            self._onBeforeActionLaunched)
        self._recentSection.actionLaunched.connect(self._onActionLaunched)
        layout.addWidget(self._recentSection)

        self._allLabel = QtWidgets.QLabel('Discovering actions..')
        self._allLabel.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(self._allLabel)
        self._allSection = ActionSection(self)
        self._allSection.beforeActionLaunch.connect(
            self._onBeforeActionLaunched)
        self._allSection.actionLaunched.connect(self._onActionLaunched)
        layout.addWidget(self._allSection)

        self._overlay = overlay.BusyOverlay(self, message='Launching...')
        self._overlay.setVisible(False)

        self.recentActionsChanged.connect(self._updateRecentSection)

        self._loadActionsForContext([])
        self._updateRecentActions()
    def __init__(self, event=None, date=None, parent=None):
        '''Initialise widget with initial component *event* and *parent*.'''
        super(Notification, self).__init__(parent=parent)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        verticalLayout = QtWidgets.QVBoxLayout()

        self.setLayout(self.horizontalLayout)

        self.horizontalLayout.addLayout(verticalLayout, stretch=1)

        self.textLabel = QtWidgets.QLabel()
        verticalLayout.addWidget(self.textLabel)

        self.dateLabel = QtWidgets.QLabel()
        verticalLayout.addWidget(self.dateLabel)

        self.setDate(event['created_at'])

        self.setEvent(event)
    def __init__(self, parent=None):
        '''Initialise widget with *parent*.'''
        super(ComponentsList,
              self).__init__(widgetFactory=self._createComponentWidget,
                             widgetItem=lambda widget: widget.value(),
                             parent=parent)
        self.list.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
        self.list.setShowGrid(False)

        self.label = QtWidgets.QLabel('Components')
        self.layout().insertWidget(0, self.label)
예제 #13
0
    def __init__(
        self, parent,
        icon=':ftrack/image/default/ftrackLogoColor'
    ):
        super(AboutDialog, self).__init__(parent)

        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
        self.setLayout(layout)

        self.icon = QtWidgets.QLabel()
        pixmap = QtGui.QPixmap(icon)
        self.icon.setPixmap(
            pixmap.scaledToHeight(36, mode=QtCore.Qt.SmoothTransformation)
        )
        self.icon.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(self.icon)

        self.messageLabel = QtWidgets.QLabel()
        self.messageLabel.setWordWrap(True)
        self.messageLabel.setAlignment(QtCore.Qt.AlignLeft)
        layout.addWidget(self.messageLabel)

        layout.addSpacing(25)

        self.debugButton = QtWidgets.QPushButton('More info')
        self.debugButton.clicked.connect(self._onDebugButtonClicked)

        layout.addWidget(self.debugButton)

        self.loggingButton = QtWidgets.QPushButton('Open log directory')
        self.loggingButton.clicked.connect(self._onLoggingButtonClicked)

        layout.addWidget(self.loggingButton)

        self.debugTextEdit = QtWidgets.QTextEdit()
        self.debugTextEdit.setReadOnly(True)
        self.debugTextEdit.setFontPointSize(10)
        self.debugTextEdit.hide()
        layout.addWidget(self.debugTextEdit)
예제 #14
0
    def __init__(
        self, name, userId, group=None, applications=None, parent=None
    ):
        '''Initialise widget with initial component *value* and *parent*.'''
        super(User, self).__init__(parent)
        if applications is None:
            applications = {}

        self._userId = userId
        self._applications = applications
        self._group = group

        self.setObjectName('user')

        self.setLayout(QtWidgets.QHBoxLayout())

        self.thumbnail = ftrack_connect.ui.widget.thumbnail.User()
        self.thumbnail.setFixedWidth(30)
        self.thumbnail.setFixedHeight(30)
        self.thumbnail.load(userId)
        self.layout().addWidget(self.thumbnail)

        self.layout().setContentsMargins(0, 0, 0, 0)

        nameAndActivity = QtWidgets.QWidget()
        nameAndActivity.setLayout(QtWidgets.QVBoxLayout())
        nameAndActivity.layout().setContentsMargins(0, 0, 0, 0)

        self.countLabel = QtWidgets.QLabel()
        self.countLabel.setObjectName('user-conversation-count')
        self.countLabel.hide()

        self.nameLabel = ftrack_connect.ui.widget.label.Label()
        self.nameLabel.setText(name)
        self.nameLabel.setObjectName('name')
        nameAndActivity.layout().addWidget(self.nameLabel)

        self.activityLabel = ftrack_connect.ui.widget.label.Label()
        self.activityLabel.setObjectName('user-activity')

        self.nameAndCountLayout = QtWidgets.QHBoxLayout()
        self.nameAndCountLayout.addWidget(self.nameLabel, stretch=1)
        self.nameAndCountLayout.addWidget(self.countLabel, stretch=0)
        self.nameAndCountLayout.addSpacing(5)

        nameAndActivity.layout().addLayout(self.nameAndCountLayout)
        nameAndActivity.layout().addWidget(self.activityLabel)

        self.layout().addWidget(nameAndActivity)

        self._refreshStyles()
        self._updateActivity()
예제 #15
0
    def __init__(self, parent):
        '''Initialise.'''
        super(TimerOverlay, self).__init__(parent)
        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)

        message = QtWidgets.QLabel('Select a task to activate timer.')
        message.setWordWrap(True)
        message.setAlignment(QtCore.Qt.AlignVCenter)
        layout.addWidget(message)

        # TODO: See if there is a way to stop Sass converting the rgba string
        # to the wrong value.
        self.setStyleSheet('''
            #ftrack-connect-window TimerOverlay {
                background-color: rgba(255, 255, 255, 200);
            }
        ''')
예제 #16
0
    def __init__(
        self, name, userId, applications, group=None, parent=None
    ):
        '''Initialise widget with initial component *value* and *parent*.'''
        super(UserExtended, self).__init__(parent=parent)

        self.applicationInfoWidget = QtWidgets.QLabel()

        self._userId = userId
        self._applications = applications

        self.setLayout(QtWidgets.QVBoxLayout())

        self.user = User(name, userId, group=None, applications=applications)
        self.layout().addWidget(self.user)

        self.layout().addWidget(self.applicationInfoWidget, stretch=0)

        self.updateInformation(name, userId, applications)
예제 #17
0
    def __init__(self, *args, **kwargs):
        '''Instantiate the time tracker.'''
        super(TimeTracker, self).__init__(*args, **kwargs)
        self.setObjectName('timeTracker')

        self._activeEntity = None

        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)

        self.activeLabel = QtWidgets.QLabel('Currently running')
        self.activeLabel.setProperty('title', True)
        layout.addWidget(self.activeLabel)

        self._timerEnabled = False
        self.timer = ftrack_connect.ui.widget.timer.Timer()
        layout.addWidget(self.timer)

        self.timerPlaceholder = TimerOverlay(self.timer)

        # TODO: Add theme support.
        reloadIcon = QtGui.QIcon(QtGui.QPixmap(':/ftrack/image/light/reload'))

        assignedTimeLogUpdateButton = QtWidgets.QPushButton(reloadIcon, '')
        assignedTimeLogUpdateButton.setFlat(True)
        assignedTimeLogUpdateButton.setToolTip('Refresh list')
        assignedTimeLogUpdateButton.clicked.connect(self._updateAssignedList)

        self.assignedTimeLogList = _TimeLogList(
            title='Assigned', headerWidgets=[assignedTimeLogUpdateButton])
        layout.addWidget(self.assignedTimeLogList, stretch=1)

        # Connect events.
        self.timer.stopped.connect(self._onCommitTime)
        self.timer.timeEdited.connect(self._onCommitTime)

        self.assignedTimeLogList.itemSelected.connect(self._onSelectTimeLog)

        self.blockingOverlay = TimeTrackerBlockingOverlay(
            self, 'Time tracker is currently disabled during beta.')
        self.blockingOverlay.show()

        self._updateAssignedList()
예제 #18
0
    def __init__(self, parent=None):
        '''Instantiate message widget.'''

        super(MessageBox, self).__init__(parent=parent)
        self.setObjectName('ftrack-message-box')
        self.main_layout = QtWidgets.QHBoxLayout()
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setSpacing(0)
        self.main_layout.setAlignment(QtCore.Qt.AlignTop)
        self.setLayout(self.main_layout)

        self.label = QtWidgets.QLabel(parent=self)
        self.label.resize(QtCore.QSize(900, 80))

        self.label.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                 QtWidgets.QSizePolicy.Fixed)
        self.label.hide()
        self.label.setObjectName('ftrack-header-message-info')

        self.main_layout.addWidget(self.label)
예제 #19
0
    def __init__(self, start_frame, end_frame):
        '''Instantiate start and end frame field.'''
        super(StartEndFrameField, self).__init__()
        self.setLayout(QtWidgets.QHBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.start_frame = QtWidgets.QDoubleSpinBox()
        self.start_frame.setValue(start_frame)
        self.start_frame.setMaximum(sys.maxint)
        self.start_frame.setDecimals(0)
        self.start_frame.valueChanged.connect(self.notify_changed)

        self.end_frame = QtWidgets.QDoubleSpinBox()
        self.end_frame.setValue(end_frame)
        self.end_frame.setMaximum(sys.maxint)
        self.end_frame.setDecimals(0)
        self.end_frame.valueChanged.connect(self.notify_changed)

        self.layout().addWidget(QtWidgets.QLabel('Frame Range'))
        self.layout().addWidget(self.start_frame)
        self.layout().addWidget(self.end_frame)
예제 #20
0
    def __init__(self, results):
        '''Instantiate and show results.'''
        super(Dialog, self).__init__()
        self.setObjectName('ftrack-result-dialog')
        self.setMinimumSize(1080, 720)
        main_layout = QtWidgets.QVBoxLayout(self)
        self.setLayout(main_layout)

        filter_layout = QtWidgets.QHBoxLayout()
        filter_label = QtWidgets.QLabel('Filter log')
        self.filter_field = QtWidgets.QLineEdit()
        self.filter_field.setObjectName('ftrack-log-filter-field')
        self.filter_field.textChanged.connect(self.on_search)

        filter_layout.addWidget(filter_label)
        filter_layout.addWidget(self.filter_field)
        main_layout.addLayout(filter_layout)

        log_list = QtWidgets.QTableView()
        log_list.verticalHeader().hide()

        log_list.setObjectName('ftrack-log-view')
        log_list.setAlternatingRowColors(True)
        log_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        log_list.horizontalHeader().setStretchLastSection(True)
        log_items = self._parse_results(results)

        log_model = ftrack_connect_pipeline.ui.model.log_table.LogTableModel(
            self, log_items)
        self.log_sort_model = ftrack_connect_pipeline.ui.model.log_table.FilterProxyModel(
        )
        self.log_sort_model.setDynamicSortFilter(True)
        self.log_sort_model.setSourceModel(log_model)
        log_list.setModel(self.log_sort_model)

        main_layout.addWidget(log_list)

        open_log_folder_button = QtWidgets.QPushButton('Open log directory')
        open_log_folder_button.clicked.connect(self._on_logging_button_clicked)
        main_layout.addWidget(open_log_folder_button)
    def build(self):
        '''Build widgets and layout.'''
        self.setLayout(QtWidgets.QHBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.thumbnailWidget = QtWidgets.QLabel()
        self.thumbnailWidget.setFrameStyle(QtWidgets.QFrame.StyledPanel)
        self.thumbnailWidget.setAlignment(QtCore.Qt.AlignCenter)
        self.thumbnailWidget.setFixedWidth(240)

        self.layout().addWidget(self.thumbnailWidget)

        self.propertyTableWidget = QtWidgets.QTableWidget()
        self.propertyTableWidget.setEditTriggers(
            QtWidgets.QAbstractItemView.NoEditTriggers)
        self.propertyTableWidget.setSelectionMode(
            QtWidgets.QAbstractItemView.NoSelection)

        self.propertyTableWidget.setRowCount(len(self.headers))
        self.propertyTableWidget.setVerticalHeaderLabels(self.headers)

        self.propertyTableWidget.setColumnCount(1)
        horizontalHeader = self.propertyTableWidget.horizontalHeader()
        horizontalHeader.hide()
        horizontalHeader.setResizeMode(QtWidgets.QHeaderView.Stretch)

        verticalHeader = self.propertyTableWidget.verticalHeader()
        verticalHeader.setResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        # Fix missing horizontal scrollbar when only single column
        self.propertyTableWidget.setHorizontalScrollMode(
            QtWidgets.QAbstractItemView.ScrollPerPixel)

        for index in range(len(self.headers)):
            self.propertyTableWidget.setItem(index, 0,
                                             QtWidgets.QTableWidgetItem(''))

        self.layout().addWidget(self.propertyTableWidget)
예제 #22
0
    def __init__(self, username, parent=None):
        '''Instantiate user name and logo widget using *username*.'''

        super(User, self).__init__(parent=parent)
        self.setObjectName('ftrack-userid-widget')
        self.main_layout = QtWidgets.QHBoxLayout()
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setAlignment(QtCore.Qt.AlignRight)
        self.setLayout(self.main_layout)

        self.label = QtWidgets.QLabel(self)
        self.image = thumbnail.User(self)
        self.image.setFixedSize(35, 35)

        self.main_layout.addWidget(self.label)
        self.main_layout.addWidget(self.image)

        self.image.load(username)

        if username not in NAME_CACHE:
            NAME_CACHE[username] = ftrack.User(username).getName().title()

        self.label.setText(NAME_CACHE[username])
예제 #23
0
    def setupUi(self, ExportOptions):
        ExportOptions.setObjectName("ExportOptions")
        ExportOptions.resize(339, 266)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                           QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            ExportOptions.sizePolicy().hasHeightForWidth())
        ExportOptions.setSizePolicy(sizePolicy)
        self.verticalLayout = QtWidgets.QVBoxLayout(ExportOptions)
        self.verticalLayout.setSpacing(3)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.optionsPlaceHolderLayout = QtWidgets.QHBoxLayout()
        self.optionsPlaceHolderLayout.setObjectName("optionsPlaceHolderLayout")
        self.verticalLayout.addLayout(self.optionsPlaceHolderLayout)
        self.label_4 = QtWidgets.QLabel(ExportOptions)
        self.label_4.setObjectName("label_4")
        self.verticalLayout.addWidget(self.label_4)
        self.gridLayout_4 = QtWidgets.QGridLayout()
        self.gridLayout_4.setObjectName("gridLayout_4")
        self.thumbnailLineEdit = QtWidgets.QLineEdit(ExportOptions)
        self.thumbnailLineEdit.setObjectName("thumbnailLineEdit")
        self.gridLayout_4.addWidget(self.thumbnailLineEdit, 2, 0, 1, 1)
        self.pushButton = QtWidgets.QPushButton(ExportOptions)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout_4.addWidget(self.pushButton, 2, 1, 1, 1)
        self.screenshotButton = QtWidgets.QPushButton(ExportOptions)
        self.screenshotButton.setObjectName("screenshotButton")
        self.gridLayout_4.addWidget(self.screenshotButton, 2, 2, 1, 1)
        self.verticalLayout.addLayout(self.gridLayout_4)
        self.label_5 = QtWidgets.QLabel(ExportOptions)
        self.label_5.setObjectName("label_5")
        self.verticalLayout.addWidget(self.label_5)
        self.commentTextEdit = QtWidgets.QPlainTextEdit(ExportOptions)
        self.commentTextEdit.setMaximumSize(QtCore.QSize(16777215, 80))
        self.commentTextEdit.setObjectName("commentTextEdit")
        self.verticalLayout.addWidget(self.commentTextEdit)
        self.publishButton = QtWidgets.QPushButton(ExportOptions)
        self.publishButton.setObjectName("publishButton")
        self.verticalLayout.addWidget(self.publishButton)
        self.progressBar = QtWidgets.QProgressBar(ExportOptions)
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.verticalLayout.addWidget(self.progressBar)
        self.publishMessageLabel = QtWidgets.QLabel(ExportOptions)
        self.publishMessageLabel.setText("")
        self.publishMessageLabel.setObjectName("publishMessageLabel")
        self.verticalLayout.addWidget(self.publishMessageLabel)
        spacerItem = QtWidgets.QSpacerItem(20, 40,
                                           QtWidgets.QSizePolicy.Minimum,
                                           QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)

        self.retranslateUi(ExportOptions)

        QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"),
                               ExportOptions.setThumbnailFilename)
        QtCore.QObject.connect(self.screenshotButton,
                               QtCore.SIGNAL("clicked()"),
                               ExportOptions.takeScreenshot)
        QtCore.QMetaObject.connectSlotsByName(ExportOptions)
예제 #24
0
    def __init__(self, session):
        '''Instantiate the configure scenario widget.'''
        super(ConfigureScenario, self).__init__()

        # Check if user has permissions to configure scenario.
        # TODO: Update this with an actual permission check once available in
        # the API.
        try:
            session.query('Setting where name is "storage_scenario" and '
                          'group is "STORAGE"').one()
            can_configure_scenario = True
        except ftrack_api.exception.NoResultFoundError:
            can_configure_scenario = False

        layout = QtWidgets.QVBoxLayout()
        layout.addSpacing(0)
        layout.setContentsMargins(50, 0, 50, 0)
        self.setLayout(layout)

        layout.addSpacing(100)

        svg_renderer = QtSvg.QSvgRenderer(':ftrack/image/default/cloud-done')
        image = QtWidgets.QImage(50, 50, QtWidgets.QImage.Format_ARGB32)

        # Set the ARGB to 0 to prevent rendering artifacts.
        image.fill(0x00000000)

        svg_renderer.render(QtGui.QPainter(image))

        icon = QtWidgets.QLabel()
        icon.setPixmap(QtGui.QPixmap.fromImage(image))
        icon.setAlignment(QtCore.Qt.AlignCenter)
        icon.setObjectName('icon-label')
        layout.addWidget(icon)

        layout.addSpacing(50)

        label = QtWidgets.QLabel()
        label.setObjectName('regular-label')
        text = ('Hi there, Connect needs to be configured so that ftrack can '
                'store and track your files for you.')

        if can_configure_scenario is False:
            text += (
                '<br><br> You do not have the required permission, please ask '
                'someone with access to system settings in ftrack to '
                'configure it before you proceed.')

        label.setText(text)
        label.setContentsMargins(0, 0, 0, 0)
        label.setAlignment(QtCore.Qt.AlignCenter)
        label.setWordWrap(True)

        # Min height is required due to issue when word wrap is True and window
        # being resized which cases text to dissapear.
        label.setMinimumHeight(120)

        label.setMinimumWidth(300)
        layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)

        layout.addSpacing(20)

        configure_button = QtWidgets.QPushButton(text='Configure now')
        configure_button.setObjectName('primary')
        configure_button.clicked.connect(self._configure_storage_scenario)
        configure_button.setMinimumHeight(40)
        configure_button.setMaximumWidth(125)

        dismiss_button = QtWidgets.QPushButton(text='Do it later')
        dismiss_button.clicked.connect(self._complete_configuration)
        dismiss_button.setMinimumHeight(40)
        dismiss_button.setMaximumWidth(125)

        hbox = QtWidgets.QHBoxLayout()
        hbox.addWidget(dismiss_button)
        if can_configure_scenario:
            hbox.addSpacing(10)
            hbox.addWidget(configure_button)
        layout.addLayout(hbox)

        layout.addSpacing(20)

        label = QtWidgets.QLabel()
        label.setObjectName('lead-label')
        label.setText(
            'If you decide to do this later, some of the functionality in '
            'ftrack connect and applications started from connect may not '
            'work as expected until configured.')
        label.setAlignment(QtCore.Qt.AlignCenter)
        label.setWordWrap(True)

        # Min height is required due to issue when word wrap is True and window
        # being resized which cases text to dissapear.
        label.setMinimumHeight(100)

        label.setMinimumWidth(300)
        layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)

        layout.addStretch(1)

        label = QtWidgets.QLabel()
        label.setObjectName('green-link')
        label.setText(
            '<a style="color: #1CBC90;" '
            'href="{0}/doc/using/managing_versions/storage_scenario.html"> '
            'Learn more about storage scenarios.'.format(session.server_url))
        label.setAlignment(QtCore.Qt.AlignCenter)
        label.setOpenExternalLinks(True)
        layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)
        layout.addSpacing(20)

        self._subscriber_identifier = session.event_hub.subscribe(
            'topic=ftrack.storage-scenario.configure-done',
            self._complete_configuration)
        self._session = session
예제 #25
0
    def __init__(self, actions, parent=None):
        '''Initialize action item with *actions*

        *actions* should be a list of action dictionaries with the same label.
        Each action may contain a the following:

        label
            To be displayed as text
        icon
            An URL to an image or one of the provided icons.
        variant
            A variant of the action. Will be shown in the menu shown for 
            multiple actions, or as part of the label for a single action.
        description
            A optional description of the action to be shown on hover.

        Label, icon and description will be retrieved from the first action if
        multiple actions are specified.
        '''
        super(ActionItem, self).__init__(parent=parent)
        self.logger = logging.getLogger(__name__ + '.' +
                                        self.__class__.__name__)

        self.setMouseTracking(True)
        self.setFixedSize(QtCore.QSize(80, 80))
        layout = QtWidgets.QVBoxLayout()
        layout.setAlignment(QtCore.Qt.AlignCenter)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        if not actions:
            raise ValueError('No actions specified')

        self._actions = actions
        self._label = actions[0].get('label', 'Untitled action')
        self._icon = actions[0].get('icon', None)
        self._description = actions[0].get('description', None)
        self._variants = [
            u'{0} {1}'.format(action.get('label', 'Untitled action'),
                              action.get('variant', '')).strip()
            for action in actions
        ]

        if len(actions) == 1:
            if actions[0].get('variant'):
                self._label = u'{0} {1}'.format(self._label,
                                                actions[0].get('variant'))

            self._hoverIcon = 'play'
            self._multiple = False
        else:
            self._hoverIcon = 'menu'
            self._multiple = True

        self._iconLabel = ActionIcon(self)
        self._iconLabel.setAlignment(QtCore.Qt.AlignCenter)
        self._iconLabel.setFixedSize(QtCore.QSize(80, 45))
        layout.addWidget(self._iconLabel)

        self._textLabel = QtWidgets.QLabel(self)
        self._textLabel.setAlignment(QtCore.Qt.AlignHCenter
                                     | QtCore.Qt.AlignTop)
        self._textLabel.setWordWrap(True)
        self._textLabel.setFixedSize(QtCore.QSize(80, 35))
        layout.addWidget(self._textLabel)

        self.setText(self._label)
        self.setIcon(self._icon)
        if self._description:
            self.setToolTip(self._description)
예제 #26
0
    def __init__(self,
                 label,
                 description,
                 publish_asset,
                 session,
                 settings_provider=None,
                 parent=None):
        '''Display instances that can be published.'''
        super(Workflow, self).__init__()
        self.setObjectName('ftrack-workflow-widget')
        self.session = session
        self._label_text = label
        self.publish_asset = publish_asset

        plugin = ftrack_connect_pipeline.get_plugin()
        plugin_information = plugin.get_plugin_information()
        event_metadata = {
            'workflow_label': self._label_text,
        }
        if isinstance(plugin_information, dict):
            event_metadata.update(plugin_information)

        send_usage('USED-FTRACK-CONNECT-PIPELINE-PUBLISH', event_metadata)

        self.publish_asset.prepare_publish()

        self.item_options_store = {}
        self.general_options_store = {}

        self.settings_provider = settings_provider
        if self.settings_provider is None:
            self.settings_provider = BaseSettingsProvider()

        self.settings_map = {}
        list_instances_widget = QtWidgets.QFrame()
        list_instances_widget.setObjectName('ftrack-instances-widget')

        self._list_instances_layout = QtWidgets.QVBoxLayout()

        list_instances_widget.setLayout(self._list_instances_layout)
        self._list_instances_layout.setContentsMargins(5, 5, 5, 5)

        list_instance_settings_widget = QtWidgets.QFrame()
        list_instance_settings_widget.setObjectName(
            'ftrack-instances-settings-widget')

        self._list_items_settings_layout = QtWidgets.QVBoxLayout()
        self._list_items_settings_layout.addStretch(1)
        list_instance_settings_widget.setLayout(
            self._list_items_settings_layout)
        self._list_items_settings_layout.setContentsMargins(5, 5, 5, 5)

        configuration_layout = QtWidgets.QHBoxLayout()
        configuration_layout.addWidget(list_instances_widget, stretch=1)
        configuration_layout.addWidget(list_instance_settings_widget,
                                       stretch=1)
        configuration = QtWidgets.QFrame()
        configuration.setObjectName('ftrack-configuration-widget')
        configuration.setLayout(configuration_layout)
        configuration_layout.setContentsMargins(0, 0, 0, 0)

        information_layout = QtWidgets.QHBoxLayout()
        information_layout.addWidget(
            QtWidgets.QLabel('<h3>{0}</h3>'.format(self._label_text)))
        information_layout.addWidget(QtWidgets.QLabel(
            '<i>{0}</i>'.format(description)),
                                     stretch=1)
        information = QtWidgets.QFrame()
        information.setObjectName('ftrack-information-widget')
        information.setLayout(information_layout)
        information_layout.setContentsMargins(0, 0, 0, 0)

        publish_button = QtWidgets.QPushButton('Publish')
        publish_button.clicked.connect(self.on_publish_clicked)

        main_layout = QtWidgets.QVBoxLayout(self)
        self.setLayout(main_layout)
        self.layout().setContentsMargins(0, 0, 0, 0)

        scroll = QtWidgets.QScrollArea(self)

        scroll.setWidgetResizable(True)
        scroll.setLineWidth(0)
        scroll.setFrameShape(QtWidgets.QFrame.NoFrame)
        scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

        scroll.setWidget(configuration)

        self._list_instances_layout.addWidget(information)

        main_layout.addWidget(scroll, stretch=1)
        self._list_items_settings_layout.addWidget(publish_button)

        self._publish_overlay = BusyOverlay(self,
                                            message='Publishing Assets...')
        self._publish_overlay.setStyleSheet(OVERLAY_DARK_STYLE)
        self._publish_overlay.setVisible(False)

        self.result_win = PublishResult(self.session, self)
        self.result_win.setStyleSheet(OVERLAY_DARK_STYLE)
        self.result_win.setVisible(False)

        self.refresh()
예제 #27
0
    def __init__(self, data_dict, options):
        '''Instanstiate settings from *options*.'''
        super(ActionSettingsWidget, self).__init__()

        self.setLayout(QtWidgets.QFormLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        for option in options:
            type_ = option['type']
            label = option.get('label', '')
            name = option['name']
            value = option.get('value')
            empty_text = option.get('empty_text')
            if name in data_dict.get('options', {}):
                value = data_dict['options'][name]

            if value is not None and name not in data_dict:
                # Set default value from options.
                data_dict[name] = value

            field = None

            if type_ == 'group':
                nested_dict = data_dict[name] = dict()
                settings_widget = QtWidgets.QGroupBox(label)
                settings_widget.setLayout(QtWidgets.QVBoxLayout())
                settings_widget.layout().addWidget(
                    ActionSettingsWidget(nested_dict,
                                         option.get('options', [])))
                self.layout().addRow(settings_widget)

            if type_ == 'boolean':
                field = QtWidgets.QCheckBox()
                if value is True:
                    field.setCheckState(QtCore.Qt.Checked)

                field.stateChanged.connect(
                    functools.partial(
                        self.update_on_change, data_dict, field, name,
                        lambda check_box: (check_box.checkState() == QtCore.Qt.
                                           CheckState.Checked)))

            if type_ == 'textarea':
                field = textarea.TextAreaField(empty_text or '')
                if value is not None:
                    field.setPlainText(unicode(value))

                field.value_changed.connect(
                    functools.partial(
                        self.update_on_change, data_dict, field, name,
                        lambda textarea_widget: textarea_widget.value()))

            if type_ == 'text':
                field = QtWidgets.QLineEdit()
                if value is not None:
                    field.insert(unicode(value))

                field.textChanged.connect(
                    functools.partial(self.update_on_change, data_dict, field,
                                      name,
                                      lambda line_edit: line_edit.text()))

            if type_ == 'number':
                field = QtWidgets.QDoubleSpinBox()
                if value is not None:
                    field.setValue(float(value))

                field.setMaximum(sys.maxint)
                field.setMinimum(-sys.maxint)

                field.valueChanged.connect(
                    functools.partial(self.update_on_change, data_dict, field,
                                      name, lambda spin_box: spin_box.value()))

            if type_ == 'enumerator':
                field = QtWidgets.QComboBox()
                for item in option['data']:
                    field.addItem(item['label'])

                field.currentIndexChanged.connect(
                    functools.partial(
                        self.update_on_change, data_dict, field, name,
                        lambda box:
                        (option['data'][box.currentIndex()]['value'])))

            if type_ == 'qt_widget':
                field = option['widget']
                field.value_changed.connect(
                    functools.partial(
                        self.update_on_change, data_dict, field, name,
                        lambda custom_field: (custom_field.value())))

            if field is not None:
                if label:
                    label_widget = QtWidgets.QLabel(label)
                    self.layout().addRow(label_widget, field)
                else:
                    self.layout().addRow(field)
예제 #28
0
    def __init__(self, session, parent):
        '''Instantiate with *session*.'''
        super(CreateAssetTypeOverlay, self).__init__(parent=parent)
        self.session = session

        self.main_layout = QtWidgets.QVBoxLayout()
        self.setLayout(self.main_layout)

        icon = QtGui.QPixmap(':ftrack/image/default/ftrackLogoColor')
        icon = icon.scaled(QtCore.QSize(85, 85), QtCore.Qt.KeepAspectRatio,
                           QtCore.Qt.SmoothTransformation)
        self.ftrack_icon = QtWidgets.QLabel()
        self.ftrack_icon.setPixmap(icon)

        self.main_layout.addStretch(1)
        self.main_layout.insertWidget(1,
                                      self.ftrack_icon,
                                      alignment=QtCore.Qt.AlignCenter)
        self.main_layout.addStretch(1)
        self.main_layout.setContentsMargins(20, 20, 20, 20)

        # create asset type widget
        self.create_asset_widget = QtWidgets.QFrame()
        self.create_asset_widget.setVisible(False)

        create_asset_layout = QtWidgets.QVBoxLayout()
        create_asset_layout.setContentsMargins(20, 20, 20, 20)
        create_asset_layout.addStretch(1)
        buttons_layout = QtWidgets.QHBoxLayout()
        self.create_asset_widget.setLayout(create_asset_layout)

        self.create_asset_label_top = QtWidgets.QLabel()

        self.create_asset_label_bottom = QtWidgets.QLabel(
            '<h4>Do you want to create one ?</h4>')

        create_asset_layout.insertWidget(1,
                                         self.create_asset_label_top,
                                         alignment=QtCore.Qt.AlignCenter)
        create_asset_layout.insertWidget(2,
                                         self.create_asset_label_bottom,
                                         alignment=QtCore.Qt.AlignCenter)
        self.create_asset_button = QtWidgets.QPushButton('Create')
        self.cancel_asset_button = QtWidgets.QPushButton('Cancel')
        create_asset_layout.addLayout(buttons_layout)
        buttons_layout.addWidget(self.create_asset_button)
        buttons_layout.addWidget(self.cancel_asset_button)

        # result create asset type
        self.create_asset_widget_result = QtWidgets.QFrame()
        self.create_asset_widget_result.setVisible(False)

        create_asset_layout_result = QtWidgets.QVBoxLayout()
        create_asset_layout_result.setContentsMargins(20, 20, 20, 20)
        create_asset_layout_result.addStretch(1)

        self.create_asset_widget_result.setLayout(create_asset_layout_result)
        self.create_asset_label_result = QtWidgets.QLabel()
        self.continue_button = QtWidgets.QPushButton('Continue')

        create_asset_layout_result.insertWidget(
            1, self.create_asset_label_result, alignment=QtCore.Qt.AlignCenter)

        create_asset_layout_result.insertWidget(
            2, self.continue_button, alignment=QtCore.Qt.AlignCenter)

        # error on create asset
        self.create_asset_widget_error = QtWidgets.QFrame()
        self.create_asset_widget_error.setVisible(False)

        create_asset_layout_error = QtWidgets.QVBoxLayout()
        create_asset_layout_error.setContentsMargins(20, 20, 20, 20)
        create_asset_layout_error.addStretch(1)

        self.create_asset_widget_error.setLayout(create_asset_layout_error)
        self.create_asset_label_error = QtWidgets.QLabel()
        self.close_button = QtWidgets.QPushButton('Close')

        create_asset_layout_error.insertWidget(1,
                                               self.create_asset_label_error,
                                               alignment=QtCore.Qt.AlignCenter)

        create_asset_layout_error.insertWidget(2,
                                               self.close_button,
                                               alignment=QtCore.Qt.AlignCenter)

        # parent all.
        self.main_layout.addWidget(self.create_asset_widget)
        self.main_layout.addWidget(self.create_asset_widget_result)
        self.main_layout.addWidget(self.create_asset_widget_error)

        self.main_layout.addStretch(1)

        # signals
        self.create_asset_button.clicked.connect(self.on_create_asset)
        self.continue_button.clicked.connect(self.on_continue)
        self.close_button.clicked.connect(self.on_fail)
        self.cancel_asset_button.clicked.connect(self.on_fail)
예제 #29
0
    def create_validate_failed_overlay_widgets(self, label, failed_validators):
        '''Create overlay widgets to report validation failures.'''
        congrat_text = '<h2>Validation Failed!</h2>'
        success_text = 'Your <b>{0}</b> failed to validate.'.format(label)

        self.activeWidget = QtWidgets.QWidget()
        self.activeWidget.setLayout(QtWidgets.QVBoxLayout())
        self.layout().addWidget(self.activeWidget)
        main_layout = self.activeWidget.layout()

        main_layout.addStretch(1)

        congrat_label = QtWidgets.QLabel(congrat_text)
        congrat_label.setAlignment(QtCore.Qt.AlignCenter)

        success_label = QtWidgets.QLabel(success_text)
        success_label.setAlignment(QtCore.Qt.AlignCenter)

        main_layout.addWidget(congrat_label)
        main_layout.addWidget(success_label)

        validators_table_container = QtWidgets.QWidget()
        table_layout = QtWidgets.QVBoxLayout()
        table_layout.setContentsMargins(15, 10, 15, 10)
        validators_table_container.setLayout(table_layout)

        validators_table = QtWidgets.QTableWidget()
        validators_table.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
        validators_table.setSelectionMode(QtWidgets.QTableWidget.NoSelection)

        validators_table.setColumnCount(2)
        validators_table.setHorizontalHeaderLabels(['Validation', 'Error'])
        validators_table.horizontalHeader().setResizeMode(
            0, QtWidgets.QHeaderView.ResizeToContents)
        validators_table.horizontalHeader().setSectionResizeMode(
            QtWidgets.QHeaderView.Stretch)
        validators_table.horizontalHeader().setVisible(True)

        validators_table.setRowCount(len(failed_validators))
        validators_table.verticalHeader().setVisible(False)

        icon = QtGui.QIcon(':ftrack/image/dark/remove')
        font = QtGui.QFont()
        font.setBold(True)

        for row, validator in enumerate(failed_validators):
            item = QtWidgets.QTableWidgetItem(icon, validator[0])
            item.setFont(font)
            validators_table.setItem(row, 0, item)

            error_msg = validator[1]

            # Remove quotes from error message, if present.
            if ((error_msg[0] == error_msg[-1]) and error_msg.startswith(
                ("'", '"'))):
                error_msg = error_msg[1:-1]

            item = QtWidgets.QTableWidgetItem(error_msg)
            validators_table.setItem(row, 1, item)

        table_layout.addWidget(validators_table)
        main_layout.addWidget(validators_table_container)

        main_layout.addStretch(1)
        label = QtWidgets.QLabel('See details for more information.')
        label.setAlignment(QtCore.Qt.AlignCenter)
        main_layout.addWidget(label)

        buttons_layout = QtWidgets.QHBoxLayout()
        main_layout.addLayout(buttons_layout)

        self.details_button = QtWidgets.QPushButton('Details')
        buttons_layout.addWidget(self.details_button)
        self.details_button.clicked.connect(self.on_show_details)

        self.close_button = QtWidgets.QPushButton('Close')
        buttons_layout.addWidget(self.close_button)
        self.close_button.clicked.connect(self.close_window_callback)

        if self.details_window_callback is None:
            self.details_button.setDisabled(True)
  def __init__(self, parent=None, session=None, context=None):
    super(BuildAssetTrackDialog, self).__init__(parent)

    self.setWindowTitle("Build Track")

    if not session:
      session = FnAssetAPI.SessionManager.currentSession()
    self.__session = session

    if not context:
      context = session.createContext()
    self.__context = context

    self.__selection = []
    self.__entities = []
    self.__ignoreClips = False

    self.__lastIgnoreClips = None
    self.__lastParentRef = None

    layout = QtWidgets.QVBoxLayout()
    self.setLayout(layout)

     # Asset Manager Widget

    self.__relationshipWidget = session.getManagerWidget(
        kWorkflowRelationshipWidgetId, args=[context,])
    layout.addWidget(self.__relationshipWidget)

    # Stretch
    layout.addStretch()

    # Options

    optionsBox = QtWidgets.QGroupBox("Options")
    optionsLayout = QtWidgets.QVBoxLayout()
    optionsBox.setLayout(optionsLayout)
    layout.addWidget(optionsBox)

    self.__trackName = QtWidgets.QLineEdit()
    trackNameLayout = QtWidgets.QHBoxLayout()
    trackNameLayout.addWidget(QtWidgets.QLabel("Track Name"))
    trackNameLayout.addWidget(self.__trackName)
    optionsLayout.addLayout(trackNameLayout)

    self.__useClipsRadio = QtWidgets.QRadioButton("Match by Clip")
    self.__useShotsRadio = QtWidgets.QRadioButton("Match by Shot")
    optionsLayout.addWidget(self.__useClipsRadio)
    optionsLayout.addWidget(self.__useShotsRadio)

   ## @todo Use the project entityReferences Parent if we have one?

    context.access = context.kReadMultiple
    context.retention = context.kTransient
    specification = specifications.ShotSpecification()

    self.__shotParentPicker = self.__session.getManagerWidget(
        FnAssetAPI.ui.constants.kInlinePickerWidgetId, args=[specification, context])
    optionsLayout.addWidget(self.__shotParentPicker)

    # Buttons

    ## @todo disable the ok button if using shots and no valid entity ref

    self.__buttons = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok
        | QtWidgets.QDialogButtonBox.Cancel)
    self.__buttons.button(QtWidgets.QDialogButtonBox.Ok).setText('Build')
    layout.addWidget(self.__buttons)

    # Connections

    self.__buttons.accepted.connect(self.accept)
    self.__buttons.rejected.connect(self.reject)

    self.__useShotsRadio.toggled.connect(self.__modeChanged)
    self.__useClipsRadio.toggled.connect(self.__modeChanged)

    self.__relationshipWidget.criteriaChanged.connect(self.__syncUI)
    # This might be better on editingFinished, but there is only one text field
    # some of the time so loosing focus might not happen as required
    self.__trackName.textChanged.connect(self.__syncUI)

    self.__shotParentPicker.selectionChanged.connect(self.__parentChanged)

    self.__syncUI()

    # Make sure the name field is ready for editing as we can't create without
    self.__trackName.setFocus()