Exemplo n.º 1
0
    def _create_UI(self):
        QtWidgets.QVBoxLayout(self)
        o = common.MARGIN()
        self.layout().setContentsMargins(o, o * 0.5, o, o)
        self.layout().setSpacing(0)

        row = common_ui.add_row(None, padding=None, parent=self)
        self.hide_button = common_ui.ClickableIconButton(
            u'close', (common.REMOVE, common.REMOVE),
            common.ROW_HEIGHT() * 0.6)
        label = common_ui.PaintedLabel(u'Preferences',
                                       size=common.LARGE_FONT_SIZE())
        row.layout().addWidget(label, 0)
        row.layout().addStretch(1)
        row.layout().addWidget(self.hide_button, 0)
        self.hide_button.clicked.connect(
            lambda: self.done(QtWidgets.QDialog.Rejected))

        splitter = QtWidgets.QSplitter(parent=self)
        self.layout().addWidget(splitter)

        self.sections_list_widget = SectionSwitcherWidget(parent=self)
        splitter.addWidget(self.sections_list_widget)

        scroll_area = QtWidgets.QScrollArea(parent=self)
        scroll_area.setWidgetResizable(True)
        splitter.addWidget(scroll_area)

        self.sections_stack_widget = SectionsStackWidget(parent=self)
        scroll_area.setWidget(self.sections_stack_widget)
Exemplo n.º 2
0
    def _create_UI(self):
        QtWidgets.QVBoxLayout(self)
        o = common.MARGIN()
        self.layout().setContentsMargins(o, o, o, o)
        self.layout().setSpacing(common.INDICATOR_WIDTH())

        height = common.ROW_HEIGHT() * 0.7
        row = common_ui.add_row(None, height=height, padding=None, parent=self)

        self.channel_button = common_ui.ClickableIconButton(
            u'slack',
            (common.TEXT, common.TEXT),
            height,
        )
        label = common_ui.PaintedLabel(u'Send Message',
                                       size=common.LARGE_FONT_SIZE(),
                                       parent=row)
        label.setFixedHeight(height)
        self.hide_button = common_ui.ClickableIconButton(
            u'close', (common.REMOVE, common.REMOVE), height, parent=row)

        row.layout().addWidget(label, 0)
        row.layout().addStretch(1)
        row.layout().addWidget(self.channel_button, 0)
        row.layout().addWidget(self.hide_button, 0)

        self.message_widget = MessageWidget(self.token, parent=self)
        self.layout().addSpacing(o * 0.5)
        self.layout().addWidget(self.message_widget)

        self.send_button = common_ui.PaintedButton(u'Send', parent=self)
        self.layout().addSpacing(o)
        self.layout().addWidget(self.send_button)
        self.layout().addSpacing(o * 0.5)
Exemplo n.º 3
0
        def add_section(label, description, data):
            """Utility method for creating the layout needed to edit default paths."""
            height = common.ROW_HEIGHT() * 0.8
            o = common.MARGIN()

            grp = common_ui.get_group(parent=self)
            grp.layout().setContentsMargins(o, o, o, o)
            grp.layout().setSpacing(0)

            label = common_ui.PaintedLabel(label,
                                           size=common.LARGE_FONT_SIZE(),
                                           parent=self)
            grp.layout().addWidget(label)
            grp.layout().addSpacing(o)

            if description:
                common_ui.add_description(description, label=None, parent=grp)
                grp.layout().addSpacing(o)

            scroll_area = QtWidgets.QScrollArea(parent=self)
            scroll_area.setWidgetResizable(True)
            scroll_area.setMaximumHeight(common.HEIGHT() * 0.66)
            scroll_area.setAttribute(QtCore.Qt.WA_NoBackground)
            scroll_area.setAttribute(QtCore.Qt.WA_TranslucentBackground)
            grp.layout().addWidget(scroll_area)

            _row = common_ui.add_row(None,
                                     vertical=True,
                                     padding=None,
                                     height=None,
                                     parent=grp)
            _row.layout().setContentsMargins(0, 0, 0, 0)
            _row.layout().setSpacing(0)
            scroll_area.setWidget(_row)

            for k, v in sorted(data.items()):
                label = u'<span style="color:rgba({ADD});">{k}</span> - {v}:'.format(
                    ADD=common.rgb(common.ADD),
                    k=k.upper(),
                    v=v[u'description'])
                row = common_ui.add_row(None,
                                        padding=None,
                                        height=height,
                                        parent=_row)
                common_ui.add_description(label, label=u'', parent=row)
                row = common_ui.add_row(None,
                                        padding=None,
                                        height=height,
                                        parent=_row)
                line_edit = common_ui.add_line_edit(v[u'default'], parent=row)
                line_edit.setAlignment(QtCore.Qt.AlignLeft)
                line_edit.setText(v[u'value'])
                line_edit.textChanged.connect(
                    functools.partial(text_changed, data, k))
Exemplo n.º 4
0
    def _create_UI(self):
        QtWidgets.QVBoxLayout(self)
        o = common.MARGIN() * 2
        self.layout().setContentsMargins(o, o, o, o)
        self.layout().setSpacing(0)
        self.layout().setAlignment(QtCore.Qt.AlignCenter)

        row = add_row(None, parent=self, padding=0, height=common.ROW_HEIGHT())
        icon = ClickableIconButton(
            u'filter',
            (common.REMOVE, common.REMOVE),
            common.ROW_HEIGHT()
        )
        label = u'Search filter'
        label = PaintedLabel(label, parent=self)
        self.editor_widget = LineEdit(parent=self)

        row.layout().addWidget(icon, 0)
        row.layout().addWidget(label, 0)
        row.layout().addWidget(self.editor_widget, 1)
        self.layout().addStretch(1)
Exemplo n.º 5
0
 def _add_sections(self):
     """Adds the sections defined in the ``SECTIONS`` variable."""
     for s in get_sections():
         item = QtWidgets.QListWidgetItem()
         item.setData(QtCore.Qt.DisplayRole,
                      u'  {}'.format(s[u'name'].title()))
         item.setData(common.DescriptionRole, s[u'description'])
         item.setData(QtCore.Qt.StatusTipRole, s[u'description'])
         item.setData(QtCore.Qt.ToolTipRole, s[u'description'])
         item.setData(QtCore.Qt.SizeHintRole,
                      QtCore.QSize(0,
                                   common.ROW_HEIGHT() * 0.66))
         self.sections_list_widget.addItem(item)
         self.sections_stack_widget.addWidget(s[u'cls'](parent=self))
Exemplo n.º 6
0
    def __init__(self, args):
        super(StandaloneApp, self).__init__(args)
        import bookmarks

        self.setApplicationVersion(bookmarks.__version__)
        self.setApplicationName(common.PRODUCT)
        self.set_model_id()

        common.font_db = common.FontDatabase()

        pixmap = images.ImageCache.get_rsc_pixmap(u'icon', None,
                                                  common.ROW_HEIGHT() * 7.0)
        icon = QtGui.QIcon(pixmap)
        self.setWindowIcon(icon)
Exemplo n.º 7
0
def add_label(text, parent=None):
    """Utility method for creating a label.

    Returns:
        QLabel: label widget.

    """
    label = QtWidgets.QLabel(text, parent=parent)
    label.setFixedHeight(common.ROW_HEIGHT())
    label.setSizePolicy(
        QtWidgets.QSizePolicy.Expanding,
        QtWidgets.QSizePolicy.Expanding
    )
    label.setAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignLeft)
    parent.layout().addWidget(label, 0)
Exemplo n.º 8
0
        def add_name_template():
            height = common.ROW_HEIGHT() * 0.8
            o = common.MARGIN()

            grp = common_ui.get_group(parent=self)
            grp.layout().setContentsMargins(o, o, o, o)
            grp.layout().setSpacing(0)

            label = common_ui.PaintedLabel(u'Name template',
                                           size=common.LARGE_FONT_SIZE(),
                                           parent=grp)
            grp.layout().addWidget(label)
            grp.layout().addSpacing(o)

            label = u'<span style="color:rgba({ADD});">File name pattern</span> - {v}:'.format(
                ADD=common.rgb(common.ADD),
                v=u'The template used to generate new file names')
            row = common_ui.add_row(None,
                                    padding=None,
                                    height=height,
                                    parent=grp)
            common_ui.add_description(label, label=u'', parent=row)
            row = common_ui.add_row(None,
                                    padding=None,
                                    height=height,
                                    parent=grp)
            line_edit = common_ui.add_line_edit(defaultpaths.FILE_NAME_PATTERN,
                                                parent=row)
            line_edit.textChanged.connect(
                functools.partial(text_changed, defaultpaths.FILE_NAME_PATTERN,
                                  u'defaultpaths/filenamepattern'))
            line_edit.setAlignment(QtCore.Qt.AlignLeft)
            line_edit.setText(defaultpaths.FILE_NAME_PATTERN)

            s = \
                u'Available tokens<br><br>\
<span style="color:rgba({ADD});">{{folder}}</span>  -  The destination folder<br>\
<span style="color:rgba({ADD});">{{prefix}}</span>  -  Prefix defined by the bookmark<br>\
<span style="color:rgba({ADD});">{{asset}}</span>   -  Asset name<br>\
<span style="color:rgba({ADD});">{{mode}}</span>    -  Selected mode (see below)<br>\
<span style="color:rgba({ADD});">{{user}}</span>    -  Name of the current user<br>\
<span style="color:rgba({ADD});">{{version}}</span> -  Version number<br>\
<span style="color:rgba({ADD});">{{ext}}</span>     -  File extension'                                                                      .format(
                    ADD=common.rgb(common.ADD),
                    v=u'The template used to generate new file names'
                )
            grp.layout().addSpacing(o)
            common_ui.add_description(s, label='', parent=grp)
Exemplo n.º 9
0
    def _create_UI(self):
        o = 0
        top_widget = QtWidgets.QWidget(parent=self)
        QtWidgets.QVBoxLayout(top_widget)
        top_widget.layout().setContentsMargins(o, o, o, o)
        top_widget.layout().setSpacing(0)
        self.addWidget(top_widget)

        self.message_widget = QtWidgets.QTextEdit(parent=self)
        _o = common.MARGIN()
        self.message_widget.document().setDocumentMargin(_o)
        self.message_widget.setPlaceholderText(u'Enter a message to send...')
        self.message_widget.setAcceptRichText(False)
        self.message_widget.moveCursor(QtGui.QTextCursor.End)

        top_widget.layout().addWidget(self.message_widget, 0)

        bottom_widget = QtWidgets.QWidget(parent=self)
        o = common.MARGIN() * 0.5
        height = common.ROW_HEIGHT()
        QtWidgets.QVBoxLayout(bottom_widget)
        bottom_widget.layout().setContentsMargins(o, 0, o, 0)
        bottom_widget.layout().setSpacing(0)

        row = common_ui.add_row(u'', height=height, parent=bottom_widget)
        row.layout().setAlignment(QtCore.Qt.AlignBottom)
        label = common_ui.PaintedLabel(u'Channels & Direct Messages',
                                       parent=self)
        row.layout().addWidget(label, 0)

        row = common_ui.add_row(u'', height=height, parent=bottom_widget)
        row.layout().setAlignment(QtCore.Qt.AlignBottom)

        self.user_filter = common_ui.LineEdit(parent=self)
        self.user_filter.setAlignment(QtCore.Qt.AlignVCenter
                                      | QtCore.Qt.AlignRight)
        self.user_filter.setPlaceholderText(u'Search...')
        row.layout().addWidget(self.user_filter, 1)

        self.users_widget = UsersWidget(self.token, parent=self)

        bottom_widget.layout().addWidget(self.users_widget)

        self.addWidget(bottom_widget)
        self.addWidget(top_widget)

        self.setSizes([common.WIDTH() * 0.08, common.WIDTH() * 0.2])
Exemplo n.º 10
0
    def paintEvent(self, event):
        painter = QtGui.QPainter()
        painter.begin(self)

        painter.setRenderHint(QtGui.QPainter.Antialiasing)

        pen = QtGui.QPen(common.SEPARATOR)
        pen.setWidthF(common.ROW_SEPARATOR())
        painter.setPen(pen)

        o = common.MARGIN()
        rect = self.rect().marginsRemoved(QtCore.QMargins(o, o, o, o))
        rect.setHeight(common.ROW_HEIGHT() + (common.MARGIN() * 2))
        painter.setBrush(common.SECONDARY_BACKGROUND)
        painter.setOpacity(0.9)
        painter.drawRoundedRect(
            rect, common.INDICATOR_WIDTH(), common.INDICATOR_WIDTH())
        painter.end()
Exemplo n.º 11
0
def add_row(label, parent=None, padding=common.MARGIN(), height=common.ROW_HEIGHT(), cls=None, vertical=False):
    """Utility method for creating a row widget.

    Returns:
        QWidget: row widget.

    """
    if cls:
        w = cls(parent=parent)
    else:
        w = QtWidgets.QWidget(parent=parent)

    if vertical:
        QtWidgets.QVBoxLayout(w)
    else:
        QtWidgets.QHBoxLayout(w)

    w.layout().setContentsMargins(0, 0, 0, 0)
    w.layout().setSpacing(common.INDICATOR_WIDTH())
    w.layout().setAlignment(QtCore.Qt.AlignCenter)

    w.setSizePolicy(
        QtWidgets.QSizePolicy.Expanding,
        QtWidgets.QSizePolicy.Expanding,
    )
    if height:
        w.setFixedHeight(height)

    w.setAttribute(QtCore.Qt.WA_NoBackground)
    w.setAttribute(QtCore.Qt.WA_TranslucentBackground)

    if label:
        l = PaintedLabel(label, size=common.SMALL_FONT_SIZE(),
                         color=common.SECONDARY_TEXT, parent=parent)
        l.setFixedWidth(common.MARGIN() * 6.6667)
        l.setDisabled(True)
        if padding:
            w.layout().addSpacing(padding)
        w.layout().addWidget(l, 0)

    if parent:
        parent.layout().addWidget(w, 1)

    return w
Exemplo n.º 12
0
    def _create_UI(self):
        QtWidgets.QVBoxLayout(self)
        o = common.MARGIN()
        self.layout().setContentsMargins(o, o, o, o)
        self.layout().setSpacing(0)

        height = common.ROW_HEIGHT() * 0.8
        # ********************************************
        row = common_ui.add_row(None, padding=None, parent=self)
        self.save_button = common_ui.ClickableIconButton(
            u'check', (common.ADD, common.ADD), height)

        bookmark = u'{}/{}/{}'.format(self.server, self.job, self.root)
        source = images.get_thumbnail_path(self.server, self.job, self.root,
                                           bookmark)

        pixmap = images.ImageCache.get_pixmap(source, row.height())
        if not pixmap:
            source = images.get_placeholder_path(
                bookmark, fallback=u'thumb_bookmark_gray')
            pixmap = images.ImageCache.get_pixmap(source, row.height())

        if pixmap:
            thumbnail = QtWidgets.QLabel(parent=self)
            thumbnail.setPixmap(pixmap)
            row.layout().addWidget(thumbnail, 0)
            row.layout().addSpacing(o * 0.5)

        text = u'{}  |  {}'.format(self.job.upper(), self.root.upper())
        label = common_ui.PaintedLabel(text, size=common.LARGE_FONT_SIZE())

        row.layout().addWidget(label)
        row.layout().addStretch(1)
        row.layout().addWidget(self.save_button, 0)

        self.scrollarea = ScrollArea(parent=self)
        self.layout().addSpacing(o * 0.5)
        self.layout().addWidget(self.scrollarea)

        self.save_button.clicked.connect(
            lambda: self.done(QtWidgets.QDialog.Accepted))
Exemplo n.º 13
0
    def data(self, index, role):  # pylint: disable=W0613
        """Name data."""
        if not index.isValid():
            return None

        node = index.internalPointer()
        if role == QtCore.Qt.DisplayRole:
            if u'ABC.childBnds' in node.name:
                return self._name + u'.childBnds'
            return node.name

        if role == QtCore.Qt.DecorationRole:
            if u'.childBnds' in node.name:
                return images.ImageCache.get_rsc_pixmap(u'abc', None, common.MARGIN())
            if u'.geom' in node.name:
                return images.ImageCache.get_rsc_pixmap(u'mesh', None, common.MARGIN())
            if u'.xform' in node.name:
                return images.ImageCache.get_rsc_pixmap(u'loc', None, common.MARGIN())

        if role == QtCore.Qt.SizeHintRole:
            return QtCore.QSize(0, common.ROW_HEIGHT())
        return None
Exemplo n.º 14
0
class TaskFolderModel(BaseModel):
    """This model holds all the necessary data needed to display items to
    select for selecting the asset subfolders and/or bookmarks and assets.

    The model keeps track of the selections internally and is updated
    via the signals and slots."""
    ROW_SIZE = QtCore.QSize(1, common.ROW_HEIGHT() * 0.8)

    queue_type = threads.TaskFolderInfoQueue

    def __init__(self, parent=None):
        self._parent = parent
        super(TaskFolderModel, self).__init__(parent=parent)
        self.modelDataResetRequested.connect(self.__resetdata__)

    def initialise_threads(self):
        """Starts and connects the threads."""
        @QtCore.Slot(QtCore.QThread)
        def thread_started(thread):
            """Signals the model an item has been updated."""
            cnx = QtCore.Qt.QueuedConnection
            thread.updateRow.connect(self.updateRow,
                                     QtCore.Qt.DirectConnection)

            self.startCheckQueue.connect(lambda: log.debug(
                'startCheckQueue -> worker.startCheckQueue', self))
            self.startCheckQueue.connect(thread.startCheckQueue, cnx)
            self.stopCheckQueue.connect(lambda: log.debug(
                'stopCheckQueue -> worker.stopCheckQueue', self))
            self.stopCheckQueue.connect(thread.stopCheckQueue, cnx)
            self.startCheckQueue.emit()

        info_worker = threads.TaskFolderWorker(threads.TaskFolderInfoQueue)
        info_thread = threads.BaseThread(info_worker)
        self.threads[common.InfoThread].append(info_thread)
        info_thread.started.connect(partial(thread_started, info_thread))

        info_thread.start()

    @property
    def parent_path(self):
        """We will use the currently active asset as the parent."""
        if self.view.parent():
            view = self.view.parent().parent().parent().fileswidget
            return view.model().sourceModel().parent_path
        return None

    @parent_path.setter
    def parent_path(self, val):
        pass

    def data_type(self):
        return common.FileItem

    def sort_data(self):
        """This model is always alphabetical."""
        pass

    @initdata
    def __initdata__(self):
        """Bookmarks and assets are static. But files will be any number of """
        task_folder = self.task_folder()
        self.INTERNAL_MODEL_DATA[task_folder] = common.DataDict({
            common.FileItem:
            common.DataDict(),
            common.SequenceItem:
            common.DataDict()
        })

        flags = (QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
                 | QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsEditable)
        data = self.model_data()

        if not self.parent_path:
            return

        # Thumbnail image
        default_thumbnail = images.ImageCache.get_rsc_pixmap(
            u'folder_sm', common.SECONDARY_TEXT, self.ROW_SIZE.height())
        default_thumbnail = default_thumbnail.toImage()

        parent_path = u'/'.join(self.parent_path)
        entries = sorted(([f for f in _scandir.scandir(parent_path)]),
                         key=lambda x: x.name)

        for entry in entries:
            if entry.name.startswith(u'.'):
                continue
            if not entry.is_dir():
                continue
            idx = len(data)
            data[idx] = common.DataDict({
                QtCore.Qt.DisplayRole:
                entry.name,
                QtCore.Qt.EditRole:
                entry.name,
                QtCore.Qt.StatusTipRole:
                entry.path.replace(u'\\', u'/'),
                QtCore.Qt.ToolTipRole:
                u'',
                QtCore.Qt.ToolTipRole:
                defaultpaths.get_description(entry.name),
                QtCore.Qt.SizeHintRole:
                self.ROW_SIZE,
                #
                common.FlagsRole:
                flags,
                common.ParentPathRole:
                self.parent_path,
                #
                common.FileInfoLoaded:
                False,
                common.ThumbnailLoaded:
                True,
                common.TodoCountRole:
                0,
                #
                common.IdRole:
                idx,
            })
            thread = self.threads[common.InfoThread][0]
            thread.add_to_queue(weakref.ref(data[idx]))
Exemplo n.º 15
0
    def _create_UI(self):
        def get_row(vertical=False, parent=None):
            row = QtWidgets.QWidget(parent=parent)
            if vertical:
                QtWidgets.QVBoxLayout(row)
            else:
                QtWidgets.QHBoxLayout(row)
            row.layout().setContentsMargins(0, 0, 0, 0)
            row.layout().setSpacing(0)
            row.setSizePolicy(
                QtWidgets.QSizePolicy.Expanding,
                QtWidgets.QSizePolicy.Expanding,
            )
            parent.layout().addWidget(row)
            return row

        QtWidgets.QHBoxLayout(self)
        o = 0
        self.layout().setContentsMargins(o, o, o, o)
        self.layout().setSpacing(o)

        main_row = get_row(parent=self)
        main_row.layout().setContentsMargins(0, 0, 0, 0)
        main_row.layout().setSpacing(0)

        columns = get_row(vertical=True, parent=main_row)
        columns.layout().setContentsMargins(0, 0, 0, 0)
        columns.layout().setSpacing(0)

        short_text_row = get_row(parent=columns)

        columns.layout().addWidget(short_text_row, 1)
        long_text_row = get_row(parent=columns)

        pixmap = images.ImageCache.get_rsc_pixmap(
            self.icon, self.secondary_color.lighter(150), common.ROW_HEIGHT())
        label = QtWidgets.QLabel(parent=self)
        label.setPixmap(pixmap)
        label.setSizePolicy(
            QtWidgets.QSizePolicy.Minimum,
            QtWidgets.QSizePolicy.Expanding,
        )
        label.setStyleSheet(
            u'padding: {}px; background-color: rgba({});'.format(
                common.MEDIUM_FONT_SIZE(),
                common.rgb(self.primary_color)
            )
        )

        main_row.layout().insertWidget(0, label)

        short_text_row.layout().addWidget(self.short_text_label)
        self.short_text_label.setStyleSheet(
            u'padding:{m}px {s}px {m}px {s}px; background-color: rgba({c}); font-size: {s}px;'.format(
                m=common.MARGIN(),
                c=common.rgb(self.secondary_color.lighter(125)),
                s=common.MEDIUM_FONT_SIZE()
            ))
        self.short_text_label.setAlignment(QtCore.Qt.AlignLeft)

        long_text_row.layout().addWidget(self.long_text_label)
        self.long_text_label.setStyleSheet(
            u'padding:{m}px;background-color: rgba({c}); font-size:{s}px;'.format(
                m=common.MARGIN(),
                c=common.rgb(self.secondary_color),
                s=common.SMALL_FONT_SIZE()
            ))
        self.long_text_label.setAlignment(QtCore.Qt.AlignLeft)

        buttons_row = get_row(parent=columns)
        buttons_row.setStyleSheet(
            u'background-color: rgba({});'.format(common.rgb(self.secondary_color)))
        self.ok_button = QtWidgets.QPushButton(u'Ok', parent=self)
        buttons_row.layout().addWidget(self.ok_button)

        self.ok_button.setStyleSheet(
            """
        QPushButton {{
            font-size: {px}px;
            color: rgba(255,255,255,150);
            border-radius: {i}px;
            border: {s}px solid {c};
            margin: {i}px;
            padding: {i}px;
            background-color: rgba({p});
        }}
        QPushButton:hover {{
            color: white;
            background-color: rgba({pl});
        }}
        QPushButton:pressed {{
            color: rgba(255,255,255,150);
            background-color: rgba({pd});
        }}
        """.format(
                px=common.SMALL_FONT_SIZE(),
                i=common.INDICATOR_WIDTH(),
                s=common.ROW_SEPARATOR(),
                c=common.rgb(self.secondary_color.lighter(150)),
                p=common.rgb(self.primary_color),
                pl=common.rgb(self.primary_color.lighter(120)),
                pd=common.rgb(self.primary_color.darker(120))
            )
        )
Exemplo n.º 16
0
    def _create_UI(self):
        """Creates the ui layout."""
        QtWidgets.QVBoxLayout(self)
        o = common.MARGIN()
        self.layout().setSpacing(common.INDICATOR_WIDTH())
        self.layout().setContentsMargins(o, o, o, o)

        # Top row
        height = common.ROW_HEIGHT() * 0.6666
        row = common_ui.add_row(None, height=height, parent=self)
        row.layout().addSpacing(height * 0.33)

        def paintEvent(event):
            painter = QtGui.QPainter()
            painter.begin(row)
            painter.setPen(QtCore.Qt.NoPen)
            painter.setBrush(QtGui.QColor(0, 0, 0, 255))
            rect = row.rect()
            rect.setTop(rect.bottom())
            painter.drawRect(rect)
            painter.end()

        # row.paintEvent = paintEvent
        # Thumbnail
        self.add_button = common_ui.ClickableIconButton(
            u'add', (common.ADD, common.ADD),
            height,
            description=u'Click to add a new Todo item...',
            parent=self)

        # Name label
        text = u'Notes and Tasks'
        label = common_ui.PaintedLabel(text,
                                       color=common.SEPARATOR,
                                       size=common.LARGE_FONT_SIZE(),
                                       parent=self)
        row.layout().addWidget(label, 1)
        row.layout().addStretch(1)

        self.refresh_button = common_ui.ClickableIconButton(
            u'refresh',
            (QtGui.QColor(0, 0, 0, 255), QtGui.QColor(0, 0, 0, 255)),
            height,
            description=u'Refresh...',
            parent=self)
        self.refresh_button.clicked.connect(self.refresh)
        row.layout().addWidget(self.refresh_button, 0)

        self.remove_button = common_ui.ClickableIconButton(
            u'close', (QtGui.QColor(0, 0, 0, 255), QtGui.QColor(0, 0, 0, 255)),
            height,
            description=u'Refresh...',
            parent=self)
        self.remove_button.clicked.connect(self.close)
        row.layout().addWidget(self.remove_button, 0)

        row = common_ui.add_row(None, height=height, parent=self)
        text = u'Add new note'
        label = common_ui.PaintedLabel(text,
                                       color=common.SECONDARY_TEXT,
                                       size=common.SMALL_FONT_SIZE(),
                                       parent=self)

        row.layout().addWidget(self.add_button, 0)
        row.layout().addWidget(label, 0)

        row.layout().addStretch(1)

        self.add_button.clicked.connect(lambda: self.add_item(idx=0))

        self.todoeditors_widget = TodoEditors(parent=self)
        self.setMinimumHeight(common.ROW_HEIGHT() * 3.0)

        self.scrollarea = QtWidgets.QScrollArea(parent=self)
        self.scrollarea.setWidgetResizable(True)
        self.scrollarea.setWidget(self.todoeditors_widget)

        self.scrollarea.setAttribute(QtCore.Qt.WA_NoSystemBackground)
        self.scrollarea.setAttribute(QtCore.Qt.WA_TranslucentBackground)

        self.layout().addWidget(self.scrollarea)
Exemplo n.º 17
0
 def __init__(self, text, width=None, parent=None):
     super(PaintedButton, self).__init__(text, parent=parent)
     self.setFixedHeight(common.ROW_HEIGHT() * 0.7)
     if width:
         self.setFixedWidth(width)
Exemplo n.º 18
0
class FilesModel(baselist.BaseModel):
    """The model used store individual and file sequences found in `parent_path`.

    File data is saved ``self.INTERNAL_MODEL_DATA`` using the **task folder**,
    and **data_type** keys.

    .. code-block:: python

        data = self.model_data() # the currently exposed dataset
        print data == self.INTERNAL_MODEL_DATA[self.task_folder()][self.data_type()] # True

    """
    DEFAULT_ROW_SIZE = QtCore.QSize(1, common.ROW_HEIGHT())
    val = settings.local_settings.value(u'widget/FilesModel/rowheight')
    val = val if val else DEFAULT_ROW_SIZE.height()
    val = DEFAULT_ROW_SIZE.height() if val < DEFAULT_ROW_SIZE.height() else val
    ROW_SIZE = QtCore.QSize(1, val)

    queue_type = threads.FileInfoQueue
    thumbnail_queue_type = threads.FileThumbnailQueue

    def _entry_iterator(self, path):
        for entry in _scandir.scandir(path):
            if entry.is_dir():
                for _entry in self._entry_iterator(entry.path):
                    yield _entry
            else:
                yield entry

    @baselist.initdata
    def __initdata__(self):
        """The method is responsible for getting the bare-bones file and
        sequence definitions by running a file-iterator stemming from
        ``self.parent_path``.

        Getting all additional information, like description, item flags,
        thumbnails are costly and therefore are populated by thread-workers.

        The method will iterate through all files in every subfolder and will
        automatically save individual ``FileItems`` and collapsed
        ``SequenceItems``.

        Switching between the two datasets is done via emitting the
        ``dataTypeChanged`` signal.

        Note:
            Experiencing serious performance issues with the built-in
            QDirIterator on Mac OS X samba shares and the performance isn't
            great on windows either. Querrying the filesystem using the method
            is magnitudes slower than using the same methods on windows.

            A workaround I found was to use Python 3+'s ``scandir`` module. Both
            on Windows and Mac OS X the performance seems to be good.

        Internally, the actual files are returned by `self._entry_iterator()`,
        this is where scandir is evoked.

        """
        def dflags():
            """The default flags to apply to the item."""
            return (QtCore.Qt.ItemNeverHasChildren | QtCore.Qt.ItemIsEnabled
                    | QtCore.Qt.ItemIsSelectable)

        task_folder = self.task_folder().lower()

        SEQUENCE_DATA = common.DataDict()
        MODEL_DATA = common.DataDict({
            common.FileItem: common.DataDict(),
            common.SequenceItem: common.DataDict(),
        })

        favourites = settings.local_settings.favourites()
        sfavourites = set(favourites)
        activefile = settings.local_settings.value(u'activepath/file')

        server, job, root, asset = self.parent_path
        task_folder_extensions = defaultpaths.get_task_folder_extensions(
            task_folder)
        parent_path = u'/'.join(self.parent_path).lower() + \
            u'/' + task_folder

        nth = 987
        c = 0

        if not QtCore.QFileInfo(parent_path).exists():
            return

        for entry in self._entry_iterator(parent_path):
            if self._interrupt_requested:
                break

            # skipping directories
            if entry.is_dir():
                continue
            filename = entry.name.lower()

            if filename[0] == u'.':
                continue
            if u'thumbs.db' in filename:
                continue

            filepath = entry.path.lower().replace(u'\\', u'/')
            ext = filename.split(u'.')[-1]

            if task_folder_extensions and ext not in task_folder_extensions:
                continue

            # Progress bar
            c += 1
            if not c % nth:
                self.progressMessage.emit(u'Loading files (found ' +
                                          unicode(c) + u' items)...')
                QtWidgets.QApplication.instance().processEvents()

            # Getting the fileroot
            fileroot = filepath.replace(parent_path, u'')
            fileroot = u'/'.join(fileroot.split(u'/')[:-1]).strip(u'/')
            seq = common.get_sequence(filepath)

            flags = dflags()

            if seq:
                seqpath = seq.group(1) + common.SEQPROXY + \
                    seq.group(3) + u'.' + seq.group(4)
                seqpath = seqpath.lower()
                if seqpath in sfavourites:
                    flags = flags | common.MarkedAsFavourite
            else:
                if filepath in sfavourites:
                    flags = flags | common.MarkedAsFavourite

            if activefile:
                if activefile in filepath:
                    flags = flags | common.MarkedAsActive

            parent_path_role = (server, job, root, asset, task_folder,
                                fileroot)

            # Let's limit the maximum number of items we load
            idx = len(MODEL_DATA[common.FileItem])
            if idx >= common.MAXITEMS:
                break

            MODEL_DATA[common.FileItem][idx] = common.DataDict({
                QtCore.Qt.DisplayRole:
                filename,
                QtCore.Qt.EditRole:
                filename,
                QtCore.Qt.StatusTipRole:
                filepath,
                QtCore.Qt.SizeHintRole:
                self.ROW_SIZE,
                #
                common.EntryRole: [
                    entry,
                ],
                common.FlagsRole:
                flags,
                common.ParentPathRole:
                parent_path_role,
                common.DescriptionRole:
                u'',
                common.TodoCountRole:
                0,
                common.FileDetailsRole:
                u'',
                common.SequenceRole:
                seq,
                common.FramesRole: [],
                common.FileInfoLoaded:
                False,
                common.StartpathRole:
                None,
                common.EndpathRole:
                None,
                #
                common.ThumbnailLoaded:
                False,
                #
                common.TypeRole:
                common.FileItem,
                #
                common.SortByNameRole:
                common.namekey(filepath),
                common.SortByLastModifiedRole:
                0,
                common.SortBySizeRole:
                0,
                #
                common.IdRole:
                idx  # non-mutable
            })

            # If the file in question is a sequence, we will also save a reference
            # to it in `self._model_data[location][True]` dictionary.
            if seq:
                # If the sequence has not yet been added to our dictionary
                # of seqeunces we add it here
                if seqpath not in SEQUENCE_DATA:  # ... and create it if it doesn't exist
                    seqname = seqpath.split(u'/')[-1]
                    flags = dflags()

                    if seqpath in sfavourites:
                        flags = flags | common.MarkedAsFavourite

                    SEQUENCE_DATA[seqpath] = common.DataDict({
                        QtCore.Qt.DisplayRole:
                        seqname,
                        QtCore.Qt.EditRole:
                        seqname,
                        QtCore.Qt.StatusTipRole:
                        seqpath,
                        QtCore.Qt.SizeHintRole:
                        self.ROW_SIZE,
                        common.EntryRole: [],
                        common.FlagsRole:
                        flags,
                        common.ParentPathRole:
                        parent_path_role,
                        common.DescriptionRole:
                        u'',
                        common.TodoCountRole:
                        0,
                        common.FileDetailsRole:
                        u'',
                        common.SequenceRole:
                        seq,
                        common.FramesRole: [],
                        common.FileInfoLoaded:
                        False,
                        common.StartpathRole:
                        None,
                        common.EndpathRole:
                        None,
                        #
                        common.ThumbnailLoaded:
                        False,
                        #
                        common.TypeRole:
                        common.SequenceItem,
                        common.SortByNameRole:
                        common.namekey(seqpath),
                        common.SortByLastModifiedRole:
                        0,
                        common.SortBySizeRole:
                        0,  # Initializing with null-size
                        #
                        common.IdRole:
                        0
                    })

                SEQUENCE_DATA[seqpath][common.FramesRole].append(seq.group(2))
                SEQUENCE_DATA[seqpath][common.EntryRole].append(entry)
            else:
                SEQUENCE_DATA[filepath] = MODEL_DATA[common.FileItem][idx]

        # Casting the sequence data back onto the model
        for v in SEQUENCE_DATA.itervalues():
            idx = len(MODEL_DATA[common.SequenceItem])
            if len(v[common.FramesRole]) == 1:
                # A sequence with only one element is not a sequence
                _seq = v[common.SequenceRole]
                filepath = _seq.group(1) + v[common.FramesRole][
                    0] + _seq.group(3) + u'.' + _seq.group(4)
                filename = filepath.split(u'/')[-1]
                v[QtCore.Qt.DisplayRole] = filename
                v[QtCore.Qt.EditRole] = filename
                v[QtCore.Qt.StatusTipRole] = filepath
                v[common.TypeRole] = common.FileItem
                v[common.SortByNameRole] = common.namekey(filepath)
                v[common.SortByLastModifiedRole] = 0

                flags = dflags()
                if filepath.lower() in sfavourites:
                    flags = flags | common.MarkedAsFavourite

                if activefile:
                    if activefile in filepath:
                        flags = flags | common.MarkedAsActive

                v[common.FlagsRole] = flags

            elif len(v[common.FramesRole]) == 0:
                v[common.TypeRole] = common.FileItem
            else:
                if activefile:
                    _seq = v[common.SequenceRole]
                    _firsframe = _seq.group(1) + min(
                        v[common.FramesRole]) + _seq.group(
                            3) + u'.' + _seq.group(4)
                    if activefile in _firsframe:
                        v[common.FlagsRole] = v[
                            common.FlagsRole] | common.MarkedAsActive
            MODEL_DATA[common.SequenceItem][idx] = v
            MODEL_DATA[common.SequenceItem][idx][common.IdRole] = idx

        self.INTERNAL_MODEL_DATA[task_folder] = MODEL_DATA

    def task_folder(self):
        """Current key to the data dictionary."""
        if not self._task_folder:
            val = None
            key = u'activepath/task_folder'
            savedval = settings.local_settings.value(key)
            return savedval.lower() if savedval else val
        return self._task_folder

    @QtCore.Slot(unicode)
    def set_task_folder(self, val):
        """Slot used to save task folder to the model instance and the local
        settings.

        Each subfolder inside the root folder, defined by``parent_path``,
        corresponds to a `key`. We use these keys to save model data associated
        with these folders.

        It's important to make sure the key we're about to set corresponds to an
        existing folder. We will use a reasonable default if the folder does not
        exist.

        """
        log.debug('set_task_folder({})'.format(val), self)
        try:
            k = u'activepath/task_folder'
            stored_value = settings.local_settings.value(k)
            stored_value = stored_value.lower(
            ) if stored_value else stored_value
            self._task_folder = self._task_folder.lower(
            ) if self._task_folder else self._task_folder
            val = val.lower() if val else val

            # Nothing to do for us when the parent is not set
            if not self.parent_path:
                return

            if self._task_folder is None and stored_value:
                self._task_folder = stored_value.lower()

            # We are in sync with a valid value set already
            if stored_value is not None and self._task_folder == val == stored_value:
                val = None
                return

            # We only have to update the local settings, the model is
            # already set
            if self._task_folder == val and val != stored_value:
                settings.local_settings.setValue(k, val)
                return

            if val is not None and val == self._task_folder:
                val = None
                return

            # Let's check the asset folder before setting
            # the key to make sure we're pointing at a valid folder
            path = u'/'.join(self.parent_path)
            entries = [f.name.lower() for f in _scandir.scandir(path)]
            if not entries:
                val = None
                self._task_folder = val
                return

            # The key is valid
            if val in entries:
                self._task_folder = val
                settings.local_settings.setValue(k, val)
                return

            # The new proposed task_folder does not exist but the old one is
            # valid. We'll just stick with the old value instead...
            if val not in entries and self._task_folder in entries:
                val = self._task_folder.lower()
                settings.local_settings.setValue(k, self._task_folder)
                return

            # And finally, let's try to revert to a fall-back...
            if val not in entries and u'scenes' in entries:
                val = u'scenes'
                self._task_folder = val
                settings.local_settings.setValue(k, val)
                return

            # All else... let's select the first folder
            val = entries[0].lower()
            self._task_folder = val
            settings.local_settings.setValue(k, val)
        except:
            log.error(u'Could not set task folder')
        finally:
            if not self.model_data():
                self.__initdata__()
            else:
                self.sort_data()

    def data_type(self):
        """Current key to the data dictionary."""
        task_folder = self.task_folder()
        if task_folder not in self._datatype:
            cls = self.__class__.__name__
            key = u'widget/{}/{}/datatype'.format(cls, task_folder)
            val = settings.local_settings.value(key)
            val = val if val else common.SequenceItem
            self._datatype[task_folder] = val
        return self._datatype[task_folder]

    def mimeData(self, indexes):
        """The data necessary for supporting drag and drop operations are
        constructed here.

        There is ambiguity in the absence of any good documentation I could find
        regarding what mime types have to be defined exactly for fully
        supporting drag and drop on all platforms.

        Note:
            On windows, ``application/x-qt-windows-mime;value="FileName"`` and
            ``application/x-qt-windows-mime;value="FileNameW"`` types seems to be
            necessary, but on MacOS a simple uri list seem to suffice.

        """
        def add_path_to_mime(mime, path):
            """Adds the given path to the mime data."""
            if not isinstance(path, unicode):
                s = u'Expected <type \'unicode\'>, got {}'.format(type(str))
                log.error(s)
                raise TypeError(s)

            path = QtCore.QFileInfo(path).absoluteFilePath()
            mime.setUrls(mime.urls() + [
                QtCore.QUrl.fromLocalFile(path),
            ])

            path = QtCore.QDir.toNativeSeparators(path).encode('utf-8')
            _bytes = QtCore.QByteArray(path)
            mime.setData(u'application/x-qt-windows-mime;value="FileName"',
                         _bytes)
            mime.setData(u'application/x-qt-windows-mime;value="FileNameW"',
                         _bytes)

            return mime

        mime = QtCore.QMimeData()
        modifiers = QtWidgets.QApplication.instance().keyboardModifiers()
        no_modifier = modifiers == QtCore.Qt.NoModifier
        alt_modifier = modifiers & QtCore.Qt.AltModifier
        shift_modifier = modifiers & QtCore.Qt.ShiftModifier

        for index in indexes:
            if not index.isValid():
                continue
            path = index.data(QtCore.Qt.StatusTipRole)

            if no_modifier:
                path = common.get_sequence_endpath(path)
                add_path_to_mime(mime, path)
            elif alt_modifier and shift_modifier:
                path = QtCore.QFileInfo(path).dir().path()
                add_path_to_mime(mime, path)
            elif alt_modifier:
                path = common.get_sequence_startpath(path)
                add_path_to_mime(mime, path)
            elif shift_modifier:
                paths = common.get_sequence_paths(index)
                for path in paths:
                    add_path_to_mime(mime, path)
        return mime
Exemplo n.º 19
0
        def add_extensions():
            height = common.ROW_HEIGHT() * 0.8
            o = common.MARGIN()

            grp = common_ui.get_group(parent=self)
            grp.layout().setContentsMargins(o, o, o, o)
            grp.layout().setSpacing(0)

            description = \
                u'Edit the list of valid extensions. Use \
    <span style="color:rgba({ADD});">*</span> to allow all files.'                                                                  .format(
                    p=common.PRODUCT,
                    ADD=common.rgb(common.ADD))

            label = common_ui.PaintedLabel(u'Default extension filters',
                                           size=common.LARGE_FONT_SIZE(),
                                           parent=self)
            grp.layout().addWidget(label)
            grp.layout().addSpacing(o)

            if description:
                common_ui.add_description(description, label=None, parent=grp)
                grp.layout().addSpacing(o)

            scroll_area = QtWidgets.QScrollArea(parent=self)
            scroll_area.setWidgetResizable(True)
            scroll_area.setMaximumHeight(common.HEIGHT() * 0.66)
            scroll_area.setAttribute(QtCore.Qt.WA_NoBackground)
            scroll_area.setAttribute(QtCore.Qt.WA_TranslucentBackground)
            grp.layout().addWidget(scroll_area)

            _row = common_ui.add_row(None,
                                     vertical=True,
                                     padding=None,
                                     height=None,
                                     parent=grp)
            _row.layout().setContentsMargins(0, 0, 0, 0)
            _row.layout().setSpacing(0)
            scroll_area.setWidget(_row)

            for k, v in sorted(defaultpaths.FORMAT_FILTERS.items(),
                               key=lambda x: x[0]):
                label = u'<span style="color:rgba({ADD});">{k}</span> - {v}:'.format(
                    ADD=common.rgb(common.ADD),
                    k=v[u'name'],
                    v=v[u'description'])
                row = common_ui.add_row(None,
                                        padding=None,
                                        height=height,
                                        parent=_row)
                common_ui.add_description(label, label=u'', parent=row)
                row = common_ui.add_row(None,
                                        padding=None,
                                        height=height,
                                        parent=_row)
                line_edit = common_ui.add_line_edit(v[u'default'], parent=row)
                line_edit.textChanged.connect(
                    functools.partial(text_changed,
                                      defaultpaths.FORMAT_FILTERS, k))
                line_edit.setAlignment(QtCore.Qt.AlignLeft)
                line_edit.setText(v[u'value'])
Exemplo n.º 20
0
    def __init__(self, parent=None):
        """Init method.

        Adding the `HeaderWidget` here - this is the widget responsible for
        moving the widget around and providing the close and hide buttons.

        Also, the properties necessary to resize the frameless window are also
        defines here. These properties work in conjunction with the mouse events

        """
        global _instance
        if _instance is not None:
            raise RuntimeError(
                '{} cannot be initialised more than once.'.format(
                    self.__class__.__name__))
        _instance = self

        super(StandaloneMainWidget, self).__init__(parent=None)

        k = u'preferences/frameless_window'
        self._frameless = settings.local_settings.value(k)
        if self._frameless is True:
            self.setWindowFlags(QtCore.Qt.Window
                                | QtCore.Qt.FramelessWindowHint)
            self.setAttribute(QtCore.Qt.WA_NoSystemBackground)
            self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

        common.set_custom_stylesheet(self)

        self.resize_initial_pos = QtCore.QPoint(-1, -1)
        self.resize_initial_rect = None
        self.resize_area = None
        self.resize_overlay = None
        self.resize_distance = QtWidgets.QApplication.instance(
        ).startDragDistance() * 2
        self.resize_override_icons = {
            1: QtCore.Qt.SizeFDiagCursor,
            2: QtCore.Qt.SizeBDiagCursor,
            3: QtCore.Qt.SizeBDiagCursor,
            4: QtCore.Qt.SizeFDiagCursor,
            5: QtCore.Qt.SizeVerCursor,
            6: QtCore.Qt.SizeHorCursor,
            7: QtCore.Qt.SizeVerCursor,
            8: QtCore.Qt.SizeHorCursor,
        }

        self.tray = QtWidgets.QSystemTrayIcon(parent=self)
        pixmap = images.ImageCache.get_rsc_pixmap(u'icon_bw', None,
                                                  common.ROW_HEIGHT() * 7.0)
        icon = QtGui.QIcon(pixmap)
        self.tray.setIcon(icon)
        self.tray.setContextMenu(TrayMenu(parent=self))
        self.tray.setToolTip(common.PRODUCT)
        self.tray.show()

        self.tray.activated.connect(self.trayActivated)

        self.installEventFilter(self)
        self.setMouseTracking(True)

        self.initialized.connect(self.connect_extra_signals)
        self.initialized.connect(self.showNormal)
        self.initialized.connect(self.activateWindow)

        def say_hello():
            import bookmarks.common_ui as common_ui
            if self.stackedwidget.widget(
                    0).model().sourceModel().rowCount() == 0:
                common_ui.MessageBox(
                    u'Bookmarks is not set up (yet!).',
                    u'To add a server, create new jobs and bookmark folders, right-click on the main window and select "Manage Bookmarks".',
                    parent=self.stackedwidget.widget(0)).open()

        self.initialized.connect(say_hello)
        self.shutdown.connect(self.hide)

        shortcut = QtWidgets.QShortcut(QtGui.QKeySequence(u'Ctrl+Q'), self)
        shortcut.setAutoRepeat(False)
        shortcut.setContext(QtCore.Qt.ApplicationShortcut)
        shortcut.activated.connect(self.shutdown,
                                   type=QtCore.Qt.QueuedConnection)

        self.adjustSize()
Exemplo n.º 21
0
    def _create_UI(self):
        import bookmarks

        label = common_ui.PaintedLabel(u'General Preferences',
                                       size=common.LARGE_FONT_SIZE(),
                                       parent=self)
        self.layout().addWidget(label)
        grp = common_ui.get_group(parent=self)

        row = common_ui.add_row(u'Frameless window', parent=grp)
        self.frameless_window = QtWidgets.QCheckBox(u'Use frameless window',
                                                    parent=self)
        row.layout().addStretch(1)
        row.layout().addWidget(self.frameless_window)
        label = common_ui.PaintedLabel(u'(Restart required)',
                                       size=common.SMALL_FONT_SIZE(),
                                       color=common.TEXT_DISABLED)
        row.layout().addWidget(label, 0)

        if common.STANDALONE:
            row = common_ui.add_row(u'Scale interface', parent=grp)
            self.ui_scale = QtWidgets.QComboBox(parent=self)
            self.ui_scale.setFixedHeight(common.ROW_HEIGHT() * 0.66)

            for s in (u'100%', u'125%', u'150%', u'175%', u'200%'):
                self.ui_scale.addItem(s)
                idx = self.ui_scale.count() - 1
                data = int(s.strip(u'%')) * 0.01
                self.ui_scale.setItemData(idx, data, role=QtCore.Qt.UserRole)
                data = QtCore.QSize(1, common.ROW_HEIGHT() * 0.66)
                self.ui_scale.setItemData(idx,
                                          data,
                                          role=QtCore.Qt.SizeHintRole)

            row.layout().addWidget(self.ui_scale, 1)
            label = common_ui.PaintedLabel(u'(Restart required)',
                                           size=common.SMALL_FONT_SIZE(),
                                           color=common.TEXT_DISABLED)
            row.layout().addWidget(label, 0)

        ##############################
        row = common_ui.add_row(u'Update', parent=grp)
        self.check_updates = common_ui.PaintedButton(u'Check for Updates',
                                                     parent=row)
        self.show_help = common_ui.PaintedButton(u'Help', parent=row)
        row.layout().addWidget(self.check_updates)
        row.layout().addWidget(self.show_help)
        row.layout().addStretch(1.0)
        #######################################################
        row = common_ui.add_row(None, parent=self)

        label = common_ui.PaintedLabel(u'Shotgun RV',
                                       size=common.LARGE_FONT_SIZE(),
                                       parent=row)
        row.layout().addWidget(label)
        row.layout().addStretch(1)

        grp = common_ui.get_group(parent=self)

        row = common_ui.add_row(u'Path to RV', parent=grp)
        self.rv_path = common_ui.add_line_edit(u'eg. c:/rv/bin/rv.exe',
                                               parent=row)
        row.layout().addWidget(self.rv_path, 1)

        button = common_ui.PaintedButton(u'Pick')
        button.clicked.connect(self.pick_rv)
        row.layout().addWidget(button)
        button = common_ui.PaintedButton(u'Reveal')
        button.clicked.connect(lambda: common.reveal(self.rv_path.text()))
        row.layout().addWidget(button)

        text = \
            u'You can use {} to push footage to Shotgun RV \
(<span style="color:rgba({});">CTRL+P)</span>. Select the RV executable for this to work.'                                                                                          .format(
                common.PRODUCT, common.rgb(common.ADD))
        common_ui.add_description(text, label=u'Hint', parent=grp)

        #######################################################

        label = common_ui.PaintedLabel(u'Shortcuts',
                                       size=common.LARGE_FONT_SIZE(),
                                       parent=self)
        self.layout().addWidget(label)

        grp = common_ui.get_group(parent=self)

        label = QtWidgets.QLabel(parent=self)
        s = u'<table width="100%">'

        def r():
            return unicode('<tr>\
    <td align="center" style="background-color:rgba(0,0,0,80);padding:{pad}px;">\
        <span style="color:rgba({ADD});">{shortcut}</span>\
    </td>\
    <td align="left" style="background-color:rgba(0,0,0,30);padding:{pad}px;">\
        <span style="color:rgba({TEXT});">{description}</span>\
    </td>\
</tr>')

        for shortcut, description in (
            (u'Ctrl+N', u'Open new {} instance'.format(common.PRODUCT)),
            (u'Enter', u'Activate item'),
            (u'Space', u'Preview thumbnail'),
            (u'Arrow Up/Down', u'Navigate list'),
            (u'Ctrl+R', u'Reload'),
            (u'Ctrl+F', u'Edit filter'),
            (u'Ctrl+O', u'Reveal in file manager'),
            (u'Ctrl+C', u'Copy path'),
            (u'Ctrl+Shift+C', u'Copy path (alt)'),
            (u'Ctrl+S', u'Save/remove favourite'),
            (u'Ctrl+A', u'Archive/enable'),
            (u'Ctrl+T', u'Show Notes & Todos'),
            (u'Ctrl+H', u'Hide buttons'),
            (u'Ctrl+M', u'Toggle thumbnail loading'),
            (u'Ctrl+Shift+A', u'Show/Hide archived items'),
            (u'Ctrl+Shift+F', u'Show favourites only/Show all'),
            (u'Tab', u'Edit item description'),
            (u'Shift+Tab', u'Edit item description'),
            (u'Alt+Left', u'Show previous tab'),
            (u'Alt+Right', u'Show next tab'),
            (u'Ctrl+1', u'Show bookmarks'),
            (u'Ctrl+2', u'Show assets'),
            (u'Ctrl+3', u'Show files'),
            (u'Ctrl+4', u'Show favourites'),
            (u'Ctrl+Plus', u'Increase row height'),
            (u'Ctrl+Minus', u'Decrease row height'),
            (u'Ctrl+0', u'Reset row height'),
        ):
            s += r().format(
                shortcut=shortcut,
                description=description,
                pad=int(common.INDICATOR_WIDTH() * 1.5),
                ADD=common.rgb(common.ADD),
                TEXT=common.rgb(common.SECONDARY_TEXT),
            )
        s += u'</table>'
        label.setText(s)
        label.setWordWrap(True)
        grp.layout().addWidget(label)

        label = common_ui.PaintedLabel(u'About {}'.format(common.PRODUCT),
                                       size=common.LARGE_FONT_SIZE(),
                                       parent=grp)
        self.layout().addWidget(label)
        grp = common_ui.get_group(parent=self)
        o = common.MARGIN()
        grp.layout().setContentsMargins(o, o, o, o)
        # row = common_ui.add_row(u'Version', parent=grp, height=None)
        s = u'\n'.join(bookmarks.get_info())
        common_ui.add_description(s, label=None, parent=grp)

        self.layout().addStretch(1)
Exemplo n.º 22
0
 def adjust_height(self):
     height = self.document().size().height()
     if height > (common.ROW_HEIGHT() * 2) and not self.isEnabled():
         self.setFixedHeight(common.ROW_HEIGHT() * 2)
         return
     self.setFixedHeight(height)
Exemplo n.º 23
0
    def _create_UI(self):
        o = common.INDICATOR_WIDTH()
        self.setMinimumWidth(common.WIDTH() * 0.5)
        height = common.ROW_HEIGHT() * 0.8

        widget = QtWidgets.QWidget(parent=self)
        QtWidgets.QVBoxLayout(widget)
        widget.layout().setAlignment(QtCore.Qt.AlignCenter)
        widget.layout().setContentsMargins(0, 0, 0, 0)
        widget.layout().setSpacing(o * 2)
        self.setWidget(widget)

        # Main group
        grpA = common_ui.get_group(parent=widget)

        # GROUP
        grp = common_ui.get_group(parent=grpA)

        numvalidator = QtGui.QRegExpValidator(parent=self)
        numvalidator.setRegExp(QtCore.QRegExp(ur'[0-9]+[\.]?[0-9]*'))
        textvalidator = QtGui.QRegExpValidator(parent=self)
        textvalidator.setRegExp(QtCore.QRegExp(ur'[a-zA-Z0-9]+'))

        #   ROW1
        self.rectangles_widget = RectanglesWidget(parent=self)
        grp.layout().addWidget(self.rectangles_widget, 1)

        #   ROW
        row = common_ui.add_row(u'Resolution', parent=grp, height=height)
        self.width_editor = common_ui.LineEdit(parent=self)
        self.width_editor.setPlaceholderText(u'Width...')
        self.width_editor.setValidator(numvalidator)
        row.layout().addWidget(self.width_editor, 0)
        self.height_editor = common_ui.LineEdit(parent=self)
        self.height_editor.setPlaceholderText(u'Height...')
        self.height_editor.setValidator(numvalidator)
        row.layout().addWidget(self.height_editor, 0)

        #   ROW
        row = common_ui.add_row(u'Frame rate', parent=grp, height=height)
        self.framerate_editor = common_ui.LineEdit(parent=self)
        self.framerate_editor.setPlaceholderText(u'Frame rate...')
        self.framerate_editor.setValidator(numvalidator)
        row.layout().addWidget(self.framerate_editor, 0)

        # ********************************************
        grp = common_ui.get_group(parent=grpA)
        row = common_ui.add_row(u'Bookmark Prefix', parent=grp, height=height)
        self.prefix_editor = common_ui.LineEdit(parent=self)
        self.prefix_editor.setPlaceholderText(u'Prefix (eg. \'MYJOB\')...')
        self.prefix_editor.setValidator(textvalidator)

        self.suggest_prefix_button = common_ui.PaintedButton(u'Suggest')
        self.suggest_prefix_button.setFixedHeight(height * 0.7)
        row.layout().addWidget(self.prefix_editor, 0)
        row.layout().addWidget(self.suggest_prefix_button, 0)

        # ********************************************
        grp = common_ui.get_group(parent=grpA)

        row = common_ui.add_row(u'Start Frame', parent=grp, height=height)
        self.startframe_editor = common_ui.LineEdit(parent=self)
        self.startframe_editor.setPlaceholderText(u'Start Frame...')
        self.startframe_editor.setValidator(numvalidator)
        row.layout().addWidget(self.startframe_editor, 0)

        row = common_ui.add_row(u'Duration', parent=grp, height=height)
        self.duration_editor = common_ui.LineEdit(parent=self)
        self.duration_editor.setPlaceholderText(u'Duration...')
        self.duration_editor.setValidator(numvalidator)
        row.layout().addWidget(self.duration_editor, 0)
        # ********************************************
        grp = common_ui.get_group(parent=widget)
        row = common_ui.add_row(u'Asset Identifier', parent=grp)
        self.identifier_editor = common_ui.LineEdit(parent=row)
        self.identifier_editor.setPlaceholderText(
            u'Asset identifier, eg. \'workspace.mel\'')
        row.layout().addWidget(self.identifier_editor, 0)

        text = u'Only folders containing this file will be treated as assets.<br>\
Using the default Maya Workspace the identifier normally is \
<span style="text-decoration: underline;">workspace.mel</span>, but \
any other file can be used as long it is present in the root of \
the asset.<br>If not set, all folders inside the Bookmark \
will be read as assets.'.format(common.PRODUCT)
        common_ui.add_description(text, label='Hint', parent=grp)
        # ********************************************
        grpA = common_ui.get_group(parent=widget)

        # Slack API token
        label = common_ui.PaintedLabel(u'Slack Settings',
                                       size=common.MEDIUM_FONT_SIZE() * 1.2)
        grpA.layout().addWidget(label, 0)
        grpA.layout().addSpacing(o * 2)

        grp = common_ui.get_group(parent=grpA)

        row = common_ui.add_row(u'Slack API Token', parent=grp, height=height)
        self.slacktoken_editor = common_ui.LineEdit(parent=self)
        self.slacktoken_editor.setPlaceholderText(
            u'xoxb-01234567890-0123456...')
        button = common_ui.PaintedButton(u'Test Token')
        button.setFixedHeight(height * 0.7)
        button.clicked.connect(self.test_slack_token)
        row.layout().addWidget(self.slacktoken_editor, 0)
        row.layout().addWidget(button)
        text = u'{p} can send messages to team-members using Slack.<br><br>\
To get started, create a new app and install it for your workspace. \
Paste the generated <span style="{h}">OAuth</span> token, usually starting with "xoxb-0123..." above.<br> \
See <a href="http://api.slack.com/apps">http://api.slack.com/apps</a> for more information.<br><br> \
The Slack app needs to have the <span style="{h}">users:read</span> and \
<span style="{h}">chat:write</span> scopes enabled. To send messages to channels \
the bot is not part of, add <span style="{h}">chat:write.public</span>. \
Scopes <span style="{h}">channels:read</span> and <span style="{h}">groups:read</span> are needed to list available \
Slack Channels.<br><br>'.format(p=common.PRODUCT,
                                h='color: rgba({});'.format(
                                    common.rgb(common.ADD)))
        common_ui.add_description(text, label=u'Slack API Hint', parent=grp)
        # ********************************************
        self.widget().layout().addStretch(1)
Exemplo n.º 24
0
class UsersModel(QtCore.QAbstractItemModel):
    """Model used to store the available profiles.

    """
    modelDataResetRequested = QtCore.Signal()
    row_size = QtCore.QSize(1, common.ROW_HEIGHT() * 0.8)

    def __init__(self, token, parent=None):
        super(UsersModel, self).__init__(parent=parent)
        self.client = Client(token)

        self.INTERNAL_USER_DATA = common.DataDict()
        self.modelDataResetRequested.connect(self.__initdata__)

    def __initdata__(self):
        self.beginResetModel()

        self.INTERNAL_USER_DATA = common.DataDict()
        channels = self.client.get_channels()
        profiles = self.client.get_user_profiles()

        # Channels
        try:
            for channel in sorted(channels, key=lambda x: x['name']):
                idx = len(self.INTERNAL_USER_DATA)
                self.INTERNAL_USER_DATA[idx] = common.DataDict({
                    QtCore.Qt.DisplayRole:
                    u'Channel:  ' + channel['name'],
                    QtCore.Qt.DecorationRole:
                    QtGui.QIcon(),
                    QtCore.Qt.SizeHintRole:
                    self.row_size,
                    QtCore.Qt.FontRole:
                    common.font_db.primary_font(
                        font_size=common.SMALL_FONT_SIZE())[0],
                    IdRole:
                    channel[u'id'],
                    ThumbnailHashRole:
                    None,
                    ThumbnailUrlRole:
                    None,
                })
        except Exception as e:
            log.error(u'Could not get channels.')

        try:
            for profile in sorted(profiles, key=self.get_pretty_name):
                idx = len(self.INTERNAL_USER_DATA)
                self.INTERNAL_USER_DATA[idx] = common.DataDict({
                    QtCore.Qt.DisplayRole:
                    self.get_pretty_name(profile),
                    QtCore.Qt.DecorationRole:
                    QtGui.QIcon(),
                    QtCore.Qt.SizeHintRole:
                    self.row_size,
                    QtCore.Qt.FontRole:
                    common.font_db.primary_font(
                        font_size=common.SMALL_FONT_SIZE())[0],
                    IdRole:
                    profile[u'id'],
                    ThumbnailHashRole:
                    profile[u'profile']['avatar_hash'],
                    ThumbnailUrlRole:
                    profile[u'profile']['image_32'],
                })
                index = self.index(idx, 0)
                self.get_icon(index)
        except Exception as e:
            log.error('Could not get profiles')

        self.endResetModel()

    def columnCount(self, index, parent=QtCore.QModelIndex()):
        return 2

    def rowCount(self, parent=QtCore.QModelIndex()):
        return len(self.INTERNAL_USER_DATA)

    def setData(self, index, data, role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return
        if index.row() not in self.INTERNAL_USER_DATA:
            return
        self.INTERNAL_USER_DATA[index.row()][role] = data
        self.dataChanged.emit(index, index)

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.row() not in self.INTERNAL_USER_DATA:
            return None
        if role not in self.INTERNAL_USER_DATA[index.row()]:
            return None
        return self.INTERNAL_USER_DATA[index.row()][role]

    def index(self, row, column, parent=QtCore.QModelIndex()):
        """Bog-standard index creator."""
        return self.createIndex(row, 0, parent=parent)

    def parent(self, index):
        return QtCore.QModelIndex()

    def get_pretty_name(self, member):
        """Returns a pretty name for the given member.

        """
        p = member['profile']
        d = u'display_name'
        f = u'first_name'
        l = u'last_name'
        r = u'real_name'

        if all((d in p, f in p, l in p)):
            if all((p[d], p[f], p[l])):
                name = u'{} ({} {})'.format(p[d], p[f], p[l])
            elif p[d]:
                name = p[d]
            elif all((p[f], p[l])):
                name = u'{} {}'.format(p[f], p[l])
        else:
            if d in p:
                name = p[d]
            elif f in p and not l in p:
                name = p[f]
            elif f in p and l in p:
                name = u'{} {}'.format(p[f], p[l])

        if not name and r in p:
            name = p[r]
        return name

    @QtCore.Slot(QtCore.QModelIndex)
    def get_icon(self, index):
        """Downloads and sets the icon for the given index."""
        if not index.isValid():
            return

        try:
            url = index.data(ThumbnailUrlRole)
            response = urllib2.urlopen(url)
        except Exception as e:
            log.error('Could not save thumbnail')
            return

        # Cache directory
        cache_dir_path = QtCore.QStandardPaths.writableLocation(
            QtCore.QStandardPaths.GenericDataLocation)
        cache_dir_path = u'{}/{}/slack'.format(cache_dir_path, common.PRODUCT)

        cache_file_path = u'{}/{}.png'.format(cache_dir_path,
                                              index.data(ThumbnailHashRole))

        # Let's check if the thumbnail has already been cached and if not, download it.
        if not QtCore.QFileInfo(cache_file_path).exists():
            QtCore.QDir(cache_dir_path).mkpath('.')

            with open(cache_file_path, 'wb') as f:
                f.write(response.read())

        image = images.oiio_get_qimage(cache_file_path)
        if not image:
            return
        if image.isNull():
            return

        if image.isNull():
            return

        icon = QtGui.QIcon()
        pixmap = QtGui.QPixmap.fromImage(image)
        icon.addPixmap(pixmap, QtGui.QIcon.Normal)
        icon.addPixmap(pixmap, QtGui.QIcon.Active)
        self.setData(index, icon, role=QtCore.Qt.DecorationRole)