Exemple #1
0
    def index(model, row, column, parent=QtCore.QModelIndex()):
        """
        Qt Override

        Returns:
            the index of the item in the model specified by the given row,
            column and parent index.  When reimplementing this function in a
            subclass, call createIndex() to generate model indexes that other
            components can use to refer to items in your model.

        NOTE:
            Object must be specified to sort delegates.
        """
        # model.lazy_checks()
        if not parent.isValid():
            # This is a top level == 0 index
            # logger.info('[model.index] ROOT: row=%r, col=%r' % (row, column))
            if row >= model.root_node.get_num_children():
                return QtCore.QModelIndex()
                # import traceback
                # traceback.print_stack()
            node = model.root_node[row]
            if model.col_level_list[column] != node.get_level():
                return QtCore.QModelIndex()
            qtindex = model.createIndex(row, column, object=node)
            return qtindex
        else:
            # This is a child level > 0 index
            parent_node = parent.internalPointer()
            node = parent_node[row]
            if ut.USE_ASSERT:
                assert isinstance(parent_node,
                                  _atn.TreeNode), type(parent_node)
                assert isinstance(node, _atn.TreeNode), type(node)
            return model.createIndex(row, column, object=node)
Exemple #2
0
    def parent(model, qindex):
        """
        A common convention used in models that expose tree data structures is
        that only items in the first column have children. For that case, when
        reimplementing this function in a subclass the column of the returned
        QModelIndex would be 0.

        When reimplementing this function in a subclass, be careful to avoid
        calling QModelIndex member functions, such as QModelIndex.parent(),
        since indexes belonging to your model will simply call your
        implementation, leading to infinite recursion.

        FIXME:
            seems to segfault in here
            https://riverbankcomputing.com/pipermail/pyqt/2016-February/036977.html
            https://gist.github.com/estan/c051d1f798c4c46caa7d

        Returns:
            the parent of the model item with the given index. If the item has
            no parent, an invalid QModelIndex is returned.
        """
        # model.lazy_checks()
        if qindex.isValid():
            try:
                node = qindex.internalPointer()
                # <HACK>
                # A segfault happens in isinstance when updating rows?
                if not isinstance(node, _atn.TreeNode):
                    logger.info(
                        'WARNING: tried to access parent of %r type object' %
                        type(node))
                    return QtCore.QModelIndex()
                # assert node.__dict__, "node.__dict__=%r" % node.__dict__
                # </HACK>
                parent_node = node.get_parent()
                parent_id = parent_node.get_id()
                if parent_id == -1 or parent_id is None:
                    return QtCore.QModelIndex()
                row = parent_node.get_row()
                col = model.col_level_list.index(parent_node.get_level())
                return model.createIndex(row, col, parent_node)
            except Exception as ex:
                import utool

                with utool.embed_on_exception_context:
                    qindex_rc = (qindex.row(), qindex.column())  # NOQA
                    ut.printex(
                        ex,
                        'failed to do parenty things',
                        keys=['qindex_rc', 'model.name'],
                        tb=True,
                    )
                import utool

                utool.embed()
                raise
        return QtCore.QModelIndex()
Exemple #3
0
 def index(self, row, col, parent=QtCore.QModelIndex()):
     """Returns the index of the item in the model specified
     by the given row, column and parent index."""
     if parent.isValid() and parent.column() != 0:
         return QtCore.QModelIndex()
     parentPref = self.index2Pref(parent)
     childPref = parentPref.qt_get_child(row)
     if childPref:
         return self.createIndex(row, col, childPref)
     else:
         return QtCore.QModelIndex()
 def parent(self, index=None):
     """Returns the parent of the model item with the given index.
     If the item has no parent, an invalid QModelIndex is returned."""
     if index is None:  # Overload with QtCore.QObject.parent()
         return QtCore.QObject.parent(self)
     if not index.isValid():
         return QtCore.QModelIndex()
     nodePref = self.index2Pref(index)
     parentPref = nodePref.qt_get_parent()
     if parentPref == self.rootPref:
         return QtCore.QModelIndex()
     return self.createIndex(parentPref.qt_parents_index_of_me(), 0, parentPref)
 def createEditor(self, parent, option, index):
     combo = QtWidgets.QComboBox(parent)
     combo.addItems(['option1', 'option2', 'option3'])
     # FIXME: Change to newstyle signal slot
     if GUITOOL_PYQT_VERSION == 5:
         self.connect(combo.currentIndexChanged, self.currentIndexChanged)
     else:
         # I believe this particular option is broken in pyqt4
         self.connect(
             combo,
             QtCore.SIGNAL('currentIndexChanged(int)'),
             self,
             QtCore.SLOT('currentIndexChanged()'),
         )
     return combo
Exemple #6
0
 def index2Pref(self, index=QtCore.QModelIndex()):
     """ Internal helper method """
     if index.isValid():
         item = index.internalPointer()
         if item:
             return item
     return self.rootPref
Exemple #7
0
    def fetchMore(model, parent=QtCore.QModelIndex()):
        """
        Fetches any available data for the items with the parent specified by
        the parent index.

        Reimplement this if you are populating your model incrementally.
        The default implementation does nothing.
        """
        if parent is None:
            return
        if parent.isValid():
            # Check if we are at a leaf node
            node = parent.internalPointer()
            if node.get_num_children() == 0:
                return

        remainder = model.num_rows_total - model.num_rows_loaded
        if model.batch_size is None:
            num_fetching = remainder
        else:
            num_fetching = min(model.batch_size, remainder)
        if VERBOSE_MODEL:
            logger.info('Fetching %r more %s' % (num_fetching, model.name))
        idx1 = model.num_rows_total
        idx2 = model.num_rows_total + num_fetching - 1
        # model.beginInsertRows(QtCore.QModelIndex(), idx1, idx2)
        model.beginInsertRows(parent, idx1, idx2)
        model.num_rows_loaded += num_fetching
        # logger.info('model.num_rows_total = %r' % (model.num_rows_total,))
        # logger.info('model.num_rows_loaded = %r' % (model.num_rows_loaded,))
        model.endInsertRows()
        if VERBOSE_MODEL:
            logger.info('Fetched %r/%r rows' %
                        (model.num_rows_loaded, model.num_rows_total))
Exemple #8
0
    def canFetchMore(model, parent=QtCore.QModelIndex()):
        """
        Returns true if there is more data available for parent; otherwise
        returns false.  The default implementation always returns false.  If
        canFetchMore() returns true, the fetchMore() function should be called.
        This is the behavior of QAbstractItemView, for example.


        References:
            http://doc.qt.io/qt-5/qtwidgets-itemviews-fetchmore-example.html
            # Extend this to work well with QTreeViews
            http://blog.tjwakeham.com/lazy-loading-pyqt-data-models/
            http://stackoverflow.com/questions/38506808/pyqt4-force-view-to-fetchmore-from
        """
        if parent is None:
            return
        if parent.isValid():
            # Check if we are at a leaf node
            node = parent.internalPointer()
            if node.get_num_children() == 0:
                return
            # if node.get_level() == len(model.col_level_list):
            #     return
        # logger.info('model.num_rows_total = %r' % (model.num_rows_total,))
        # logger.info('model.num_rows_loaded = %r' % (model.num_rows_loaded,))
        if model.num_rows_total is not None:
            if model.num_rows_loaded < model.num_rows_total:
                if VERBOSE_MODEL:
                    logger.info('canFetchMore %s? -- Yes' % (model.name, ))
                return True
        if VERBOSE_MODEL:
            logger.info('canFetchMore %s? -- No' % (model.name, ))
        return False
 def data(self, qtindex, role=Qt.DisplayRole):
     """
     Returns the data stored under the given role
     for the item referred to by the qtindex.
     """
     if not qtindex.isValid():
         return QVariantHack()
     # Specify CheckState Role:
     flags = self.flags(qtindex)
     # if role == Qt.CheckStateRole and (flags & Qt.ItemIsUserCheckable or flags & Qt.ItemIsTristate):
     if role == Qt.CheckStateRole and flags & Qt.ItemIsUserCheckable:
         data = self.index2Pref(qtindex).qt_get_data(qtindex.column())
         data_to_state = {
             True: Qt.Checked,
             'True': Qt.Checked,
             None: Qt.PartiallyChecked,
             'None': Qt.PartiallyChecked,
             False: Qt.Unchecked,
             'False': Qt.Unchecked,
         }
         state = data_to_state[data]
         return state
     # elif role == QtCore.Qt.SizeHintRole:
     #    #return QtCore.QSize(40, 30)
     #    return QVariantHack()
     if role != Qt.DisplayRole and role != Qt.EditRole:
         return QVariantHack()
     nodePref = self.index2Pref(qtindex)
     data = nodePref.qt_get_data(qtindex.column())
     if isinstance(data, float):
         var = QtCore.QLocale().toString(float(data), format='g', precision=6)
     else:
         var = data
     return str(var)
 def data(model, index, role=Qt.DisplayRole):
     """ Returns the data to display """
     if not index.isValid():
         return None
     flags = model.flags(index)
     if role == Qt.TextAlignmentRole:
         return model.get_column_alignment(index.column())
     if role == Qt.BackgroundRole and (flags & Qt.ItemIsEditable
                                       or flags & Qt.ItemIsUserCheckable):
         return QtCore.QVariant(QtGui.QColor(250, 240, 240))
     if role == Qt.DisplayRole or role == Qt.CheckStateRole:
         data = model.get_data(index)
         var = qtype.cast_into_qt(data, role, flags)
         return var
     else:
         return QtCore.QVariant()
Exemple #11
0
 def proxy_to_source(self, row, col, parent=QtCore.QModelIndex()):
     source_model = self.sourceModel()
     source_cols = source_model.columnCount(parent=parent)
     r, c, p = row, col, parent
     r2 = int(math.floor(c / source_cols)) + (r * self._nd)
     c2 = c % source_cols
     p2 = p
     return r2, c2, p2
Exemple #12
0
 def source_to_proxy(self, row, col, parent=QtCore.QModelIndex()):
     source_model = self.sourceModel()
     source_cols = source_model.columnCount(parent=parent)
     r, c, p = row, col, parent
     r2 = int(math.floor(r / self._nd))
     c2 = ((r % self._nd) * source_cols) + c
     p2 = p
     return r2, c2, p2
class GUILoggingSender(QtCore.QObject):
    write_ = QtCore.pyqtSignal(str)

    def __init__(self, write_slot):
        QtCore.QObject.__init__(self)
        self.write_.connect(write_slot)

    def write_gui(self, msg):
        self.write_.emit(str(msg))
 def sizeHint(dgt, option, qtindex):
     view = dgt.parent()
     offset = view.verticalOffset() + option.rect.y()
     try:
         thumb_path = dgt.get_thumb_path_if_exists(view, offset, qtindex)
         if thumb_path is not None:
             # Read the precomputed thumbnail
             width, height = read_thumb_size(thumb_path)
             return QtCore.QSize(width, height)
         else:
             # print("[APIThumbDelegate] Name not found")
             return QtCore.QSize()
     except Exception as ex:
         print('Error in APIThumbDelegate')
         ut.printex(ex,
                    'Error in APIThumbDelegate',
                    tb=True,
                    iswarning=True)
         return QtCore.QSize()
Exemple #15
0
    def _init_table_behavior(view):
        """ Table behavior

        SeeAlso:
            api_item_view._init_itemview_behavior
        """
        # Allow sorting by column
        view.setCornerButtonEnabled(False)
        view.setShowGrid(True)

        view.setIconSize(QtCore.QSize(64, 64))
Exemple #16
0
 def mapFromSource(self, sourceIndex):
     """ returns index into proxy model """
     if sourceIndex is None:
         return None
     if sourceIndex.isValid():
         r2, c2, p2 = self.source_to_proxy(sourceIndex.row(),
                                           sourceIndex.column(),
                                           sourceIndex.parent())
         proxyIndex = self.index(r2, c2, p2)
     else:
         proxyIndex = QtCore.QModelIndex()
     return proxyIndex
Exemple #17
0
 def mapToSource(self, proxyIndex):
     """ returns index into original model """
     if proxyIndex is None:
         return None
     if proxyIndex.isValid():
         r2, c2, p2 = self.proxy_to_source(proxyIndex.row(), proxyIndex.column())
         sourceIndex = self.sourceModel().index(
             r2, c2, parent=p2
         )  # self.sourceModel().root_node[r2]
     else:
         sourceIndex = QtCore.QModelIndex()
     return sourceIndex
def ping_python_interpreter(frequency=420):  # 4200):
    """ Create a QTimer which lets the python catch ctrl+c """
    if not QUIET and VERBOSE:
        print('[guitool] pinging python interpreter for ctrl+c freq=%r' %
              frequency)
    timer = QtCore.QTimer()

    def ping_func():
        # print('lub dub')
        return None

    timer.ping_func = ping_func
    timer.timeout.connect(timer.ping_func)
    timer.start(frequency)
    return timer
Exemple #19
0
 def rowCount(model, parent=QtCore.QModelIndex()):
     """ Qt Override """
     # model.lazy_checks()
     if not parent.isValid():
         # Root row count
         if len(model.level_index_list) == 0:
             return 0
         return model.num_rows_loaded
         # nRows = len(model.level_index_list)
         # # logger.info('* nRows=%r' % nRows)
         # return nRows
     else:
         node = parent.internalPointer()
         nRows = node.get_num_children()
         # logger.info('+ nRows=%r' % nRows)
         return nRows
 def paint(dgt, painter, option, qtindex):
     """
     TODO: prevent recursive paint
     """
     view = dgt.parent()
     offset = view.verticalOffset() + option.rect.y()
     # Check if still in viewport
     if view_would_not_be_visible(view, offset):
         return None
     try:
         thumb_path = dgt.get_thumb_path_if_exists(view, offset, qtindex)
         if thumb_path is not None:
             # Check if still in viewport
             if view_would_not_be_visible(view, offset):
                 return None
             # Read the precomputed thumbnail
             if thumb_path in dgt.thumb_cache:
                 qimg = dgt.thumb_cache[thumb_path]
             else:
                 qimg = read_thumb_as_qimg(thumb_path)
                 dgt.thumb_cache[thumb_path] = qimg
             width, height = qimg.width(), qimg.height()
             # Adjust the cell size to fit the image
             dgt.adjust_thumb_cell_size(qtindex, width, height)
             # Check if still in viewport
             if view_would_not_be_visible(view, offset):
                 return None
             # Paint image on an item in some view
             painter.save()
             painter.setClipRect(option.rect)
             painter.translate(option.rect.x(), option.rect.y())
             painter.drawImage(QtCore.QRectF(0, 0, width, height), qimg)
             painter.restore()
     except Exception as ex:
         print('Error in APIThumbDelegate')
         ut.printex(ex, 'Error in APIThumbDelegate', tb=True)
         painter.save()
         painter.restore()
Exemple #21
0
 def _get_adjacent_qtindex(model, qtindex=QtCore.QModelIndex(), offset=1):
     # check qtindex
     if qtindex is None or not qtindex.isValid():
         return None
     node = qtindex.internalPointer()
     # check node
     try:
         if ut.USE_ASSERT:
             assert isinstance(node, _atn.TreeNode), type(node)
     except AssertionError as ex:
         ut.printex(ex, key_list=['node'], pad_stdout=True)
         raise
     # get node parent
     try:
         node_parent = node.get_parent()
     except Exception as ex:
         ut.printex(ex, key_list=['node'], reraise=False, pad_stdout=True)
         raise
     # parent_node check
     if node_parent is None:
         logger.info('[model._get_adjacent_qtindex] node_parent is None!')
         return None
     # Offset to find the next qtindex
     next_index = node_parent.child_index(node) + offset
     nChildren = node_parent.get_num_children()
     # check next index validitiy
     if next_index >= 0 and next_index < nChildren:
         next_node = node_parent.get_child(next_index)
         next_level = next_node.get_level()
         col = model.col_level_list.index(next_level)
         row = next_node.get_row()
         # Create qtindex for the adjacent note
         parent_qtindex = model.parent(qtindex)
         next_qtindex = model.index(row, col, parent_qtindex)
         return next_qtindex
     else:
         # There is no adjacent node
         return None
 def _get_row_id(model, qtindex=QtCore.QModelIndex()):
     """
     returns the id (specified by iders i.e. an wbia rowid) from qtindex
     """
     if qtindex is not None and qtindex.isValid():
         node = qtindex.internalPointer()
         if ut.USE_ASSERT:
             try:
                 assert isinstance(node, _atn.TreeNode), 'type(node)=%r, node=%r' % (
                     type(node),
                     node,
                 )
             except AssertionError as ex:
                 ut.printex(
                     ex, 'error in _get_row_id', keys=['model', 'qtindex', 'node']
                 )
                 raise
         try:
             id_ = node.get_id()
         except AttributeError as ex:
             ut.printex(ex, key_list=['node', 'model', 'qtindex'])
             raise
         return id_
 def sizeHint(qres_wgt):
     # should eventually improve this to use the widths of the header columns
     return QtCore.QSize(1100, 500)
 def index(model, row, column, parent=QtCore.QModelIndex()):
     """ Qt Override """
     return model.createIndex(row, column)
Exemple #25
0
 def source_to_proxy(self, row, col, parent=QtCore.QModelIndex()):
     r2, c2, p2 = row, col, parent
     return r2, c2, p2
Exemple #26
0
 def index(self, row, col, parent=QtCore.QModelIndex()):
     if (row, col) != (-1, -1):
         proxyIndex = self.createIndex(row, col, parent)
     else:
         proxyIndex = QtCore.QModelIndex()
     return proxyIndex
Exemple #27
0
 def rowCount(self, parent=QtCore.QModelIndex()):
     sourceParent = self.mapToSource(parent)
     source_rows = self.sourceModel().rowCount(parent=sourceParent)
     rows = math.ceil(source_rows / self._nd)
     # print('StripeProxyModel.rowCount(): %r %r' % (source_rows, rows))
     return int(rows)
Exemple #28
0
 def columnCount(self, parent=QtCore.QModelIndex()):
     source_cols = self.sourceModel().columnCount(parent=parent)
     cols = self._nd * source_cols
     # print('StripeProxyModel.columnCount(): %r %r' % (source_cols, cols))
     return int(cols)
class APIButtonDelegate(DELEGATE_BASE):
    button_clicked = QtCore.pyqtSignal(QtCore.QModelIndex)

    def __init__(dgt, parent=None):
        assert parent is not None, 'parent must be a view'
        DELEGATE_BASE.__init__(dgt, parent)
        # FIXME: I don't like this state in the delegate, as it renders all
        # buttons
        dgt._pressed = None
        dgt.button_clicked.connect(dgt.on_button_click)

    def get_index_butkw(dgt, qtindex):
        """
        The model data for a button should be a (text, callback) tuple.  OR
        it could be a function which accepts an qtindex and returns a button
        """
        data = qtindex.model().data(qtindex, QtCore.Qt.DisplayRole)
        # Get info
        if isinstance(data, tuple):
            buttontup = data
        elif utool.is_funclike(data):
            func = data
            buttontup = func(qtindex)
        else:
            raise AssertionError('bad type')
        text, callback = buttontup[0:2]
        butkw = {
            # 'parent': dgt.parent(),
            'text': text,
            'clicked': callback,
        }
        if len(buttontup) > 2:
            butkw['bgcolor'] = buttontup[2]
            butkw['fgcolor'] = (0, 0, 0)
        return butkw

    def paint(dgt, painter, option, qtindex):
        painter.save()
        butkw = dgt.get_index_butkw(qtindex)
        # FIXME: I don't want to create a widget each time just
        # so I can access the button's style
        button = guitool_components.newButton(**butkw)
        pressed = dgt.is_qtindex_pressed(qtindex)
        view = dgt.parent()
        paint_button(painter,
                     option,
                     button=button,
                     pressed=pressed,
                     view=view,
                     **butkw)
        painter.restore()

    def is_qtindex_pressed(dgt, qtindex):
        return dgt._pressed is not None and dgt._pressed == (
            qtindex.row(),
            qtindex.column(),
        )

    @QtCore.pyqtSlot(QtCore.QModelIndex)
    def on_button_click(dgt, qtindex):
        if utool.VERBOSE:
            print('pressed button')
        butkw = dgt.get_index_butkw(qtindex)
        callback = butkw['clicked']
        callback()

    def editorEvent(dgt, event, model, option, qtindex):
        # http://stackoverflow.com/questions/14585575/button-delegate-issue
        # print('editor event')
        event_type = event.type()
        if event_type == QtCore.QEvent.MouseButtonPress:
            # store the position that is clicked
            dgt._pressed = (qtindex.row(), qtindex.column())
            if utool.VERBOSE:
                print('store')
            return True
        elif event_type == QtCore.QEvent.MouseButtonRelease:
            if dgt.is_qtindex_pressed(qtindex):
                print('emit')
                dgt.button_clicked.emit(qtindex)
                pass
            elif dgt._pressed is not None:
                # different place.
                # force a repaint on the pressed cell by emitting a dataChanged
                # Note: This is probably not the best idea
                # but I've yet to find a better solution.
                print('repaint')
                oldIndex = qtindex.model().index(*dgt._pressed)
                dgt._pressed = None
                qtindex.model().dataChanged.emit(oldIndex, oldIndex)
                pass
            dgt._pressed = None
            # print('mouse release')
            return True
        elif event_type == QtCore.QEvent.Leave:
            print('leave')
        elif event_type == QtCore.QEvent.MouseButtonDblClick:
            print('doubleclick')
        else:
            print('event_type = %r' % event_type)
            return DELEGATE_BASE.editorEvent(dgt, event, model, option,
                                             qtindex)
 def headerData(model, section, orientation, role=Qt.DisplayRole):
     """ Qt Override """
     if role == Qt.DisplayRole and orientation == Qt.Horizontal:
         return model.get_niceheader(section)
     else:
         return QtCore.QVariant()