From 1ff334698fc2aa874cf0944e0b1f4072b7cdeccb Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sun, 15 Mar 2015 15:17:26 +0100 Subject: [PATCH 1/3] When editing on the spreadsheet, grow the edit box to the size of the contents if possible. --- src/calibre/gui2/library/delegates.py | 71 +++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 4ce8fff84d..1315e22c15 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -126,6 +126,7 @@ class DateDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent, tweak_name='gui_timestamp_display_format', default_format='dd MMM yyyy'): QStyledItemDelegate.__init__(self, parent) + self.parent = parent self.tweak_name = tweak_name self.format = tweaks[self.tweak_name] if self.format is None: @@ -140,6 +141,10 @@ class DateDelegate(QStyledItemDelegate): # {{{ def createEditor(self, parent, option, index): return DateTimeEdit(parent, self.format) + def setEditorData(self, editor, index): + QStyledItemDelegate.setEditorData(self, editor, index) + resize_line_edit_to_contents(self.parent, editor) + # }}} class PubDateDelegate(QStyledItemDelegate): # {{{ @@ -147,6 +152,7 @@ class PubDateDelegate(QStyledItemDelegate): # {{{ def __init__(self, *args, **kwargs): QStyledItemDelegate.__init__(self, *args, **kwargs) self.format = tweaks['gui_pubdate_display_format'] + self.parent = args[0] if self.format is None: self.format = 'MMM yyyy' @@ -166,9 +172,43 @@ class PubDateDelegate(QStyledItemDelegate): # {{{ if isinstance(val, QDateTime): val = val.date() editor.setDate(val) + resize_line_edit_to_contents(self.parent, editor) # }}} +def resize_line_edit_to_contents(parent, line_edit): + if isinstance(line_edit, DelegateCB): + text = line_edit.currentText() + else: + text = line_edit.text(); + + fm = line_edit.fontMetrics(); + style = QApplication.style() + orig_width = line_edit.width() + + # I can't figure out how to find the size of the area around where the text + # goes. A constant of 10 seems to work. + srect = style.itemTextRect(fm, line_edit.geometry(), Qt.AlignLeft, True, text) + new_width = (srect.right() - srect.left()) + 10 + + if isinstance(line_edit, (QComboBox, QDateTimeEdit, QSpinBox, QDoubleSpinBox)): + # And again, I can't find the size of the down arrow that opens the + # combo box. A constant of 20 seems to work + new_width += 20 + + style = QApplication.style() + srect = style.itemTextRect(fm, line_edit.geometry(), Qt.AlignLeft, True, text) + + # Compute the space available from the left edge of the widget to the + # right edge of the table + max_width = (parent.horizontalScrollBar().geometry().width() - + parent.verticalHeader().width() - + line_edit.pos().x()) + new_width = new_width if new_width < max_width else max_width + + if new_width > orig_width: + line_edit.resize(new_width, line_edit.height()); + class TextDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): @@ -178,6 +218,7 @@ class TextDelegate(QStyledItemDelegate): # {{{ auto-complete will be used. ''' QStyledItemDelegate.__init__(self, parent) + self.parent = parent self.auto_complete_function = None def set_auto_complete_function(self, f): @@ -197,6 +238,7 @@ class TextDelegate(QStyledItemDelegate): # {{{ ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) editor.selectAll() + resize_line_edit_to_contents(self.parent, editor) def setModelData(self, editor, model, index): if isinstance(editor, EditWithComplete): @@ -214,6 +256,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ self.sep = sep self.items_func_name = items_func_name self.space_before_sep = space_before_sep + self.parent = parent def set_database(self, db): self.db = db @@ -240,6 +283,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) editor.selectAll() + resize_line_edit_to_contents(self.parent, editor) def setModelData(self, editor, model, index): if isinstance(editor, EditWithComplete): @@ -251,6 +295,10 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ class LanguagesDelegate(QStyledItemDelegate): # {{{ + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + self.parent = parent + def createEditor(self, parent, option, index): editor = LanguagesEdit(parent=parent) editor.init_langs(index.model().db) @@ -259,6 +307,7 @@ class LanguagesDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): ct = unicode(index.data(Qt.DisplayRole) or '') editor.show_initial_value(ct) + resize_line_edit_to_contents(self.parent, editor) def setModelData(self, editor, model, index): val = ','.join(editor.lang_codes) @@ -273,6 +322,10 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ column. This differs from all the other delegates. ''' + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + self.parent = parent + def set_format(self, format): if not format: self.format = 'dd MMM yyyy' @@ -296,6 +349,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ if val is None: val = now() editor.setDateTime(val) + resize_line_edit_to_contents(self.parent, editor) def setModelData(self, editor, model, index): val = editor.dateTime() @@ -311,6 +365,10 @@ class CcTextDelegate(QStyledItemDelegate): # {{{ Delegate for text data. ''' + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + self.parent = parent + def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] @@ -324,6 +382,7 @@ class CcTextDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) + resize_line_edit_to_contents(self.parent, editor) editor.selectAll() def setModelData(self, editor, model, index): @@ -337,6 +396,10 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ Delegate for text/int/float data. ''' + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + self.parent = parent + def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] @@ -357,6 +420,7 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ if val == editor.minimum(): val = None model.setData(index, (val), Qt.EditRole) + editor.adjustSize() def setEditorData(self, editor, index): m = index.model() @@ -364,6 +428,7 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ if val is None: val = 0 editor.setValue(val) + resize_line_edit_to_contents(self.parent, editor) # }}} @@ -373,6 +438,10 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ Delegate for text/int/float data. ''' + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + self.parent = parent + def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] @@ -398,6 +467,7 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ editor.setCurrentIndex(0) else: editor.setCurrentIndex(idx) + resize_line_edit_to_contents(self.parent, editor) # }}} class CcCommentsDelegate(QStyledItemDelegate): # {{{ @@ -464,6 +534,7 @@ class CcBoolDelegate(QStyledItemDelegate): # {{{ Delegate for custom_column bool data. ''' QStyledItemDelegate.__init__(self, parent) + self.parent = parent def createEditor(self, parent, option, index): editor = DelegateCB(parent) From 5f9bb605870c6c9f25484a76712b4d2fb4941328 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Sun, 15 Mar 2015 18:11:29 +0100 Subject: [PATCH 2/3] Take two. I tried for a while to use updateEditorGeometry. It turned out to be as or more complicated as the current implementation, so I stayed with doing the calculations when setting the contents of the widget. --- src/calibre/gui2/library/delegates.py | 75 ++++++++++++++------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 1315e22c15..65ebe30241 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -9,7 +9,8 @@ import sys from PyQt5.Qt import (Qt, QApplication, QStyle, QIcon, QDoubleSpinBox, QStyleOptionViewItem, QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, QSize, QMenu, QKeySequence, - QAbstractTextDocumentLayout, QFont, QFontInfo, QDate, QDateTimeEdit, QDateTime) + QAbstractTextDocumentLayout, QFont, QFontInfo, QDate, QDateTimeEdit, QDateTime, + QStyleOptionComboBox, QStyleOptionSpinBox) from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog, rating_font from calibre.constants import iswindows @@ -126,7 +127,7 @@ class DateDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent, tweak_name='gui_timestamp_display_format', default_format='dd MMM yyyy'): QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent self.tweak_name = tweak_name self.format = tweaks[self.tweak_name] if self.format is None: @@ -143,7 +144,7 @@ class DateDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): QStyledItemDelegate.setEditorData(self, editor, index) - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) # }}} @@ -152,7 +153,7 @@ class PubDateDelegate(QStyledItemDelegate): # {{{ def __init__(self, *args, **kwargs): QStyledItemDelegate.__init__(self, *args, **kwargs) self.format = tweaks['gui_pubdate_display_format'] - self.parent = args[0] + self.table_widget = args[0] if self.format is None: self.format = 'MMM yyyy' @@ -172,37 +173,41 @@ class PubDateDelegate(QStyledItemDelegate): # {{{ if isinstance(val, QDateTime): val = val.date() editor.setDate(val) - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) # }}} -def resize_line_edit_to_contents(parent, line_edit): +def resize_line_edit_to_contents(table_widget, line_edit): if isinstance(line_edit, DelegateCB): text = line_edit.currentText() else: text = line_edit.text(); fm = line_edit.fontMetrics(); - style = QApplication.style() + orig_width = line_edit.width() - # I can't figure out how to find the size of the area around where the text - # goes. A constant of 10 seems to work. - srect = style.itemTextRect(fm, line_edit.geometry(), Qt.AlignLeft, True, text) - new_width = (srect.right() - srect.left()) + 10 - - if isinstance(line_edit, (QComboBox, QDateTimeEdit, QSpinBox, QDoubleSpinBox)): - # And again, I can't find the size of the down arrow that opens the - # combo box. A constant of 20 seems to work - new_width += 20 - + # The line edit box seems to extend by the space consumed by an 'M'. So add + # that to the text style = QApplication.style() - srect = style.itemTextRect(fm, line_edit.geometry(), Qt.AlignLeft, True, text) + srect = style.itemTextRect(fm, line_edit.geometry(), Qt.AlignLeft, False, text + 'M') + new_width = srect.right() - srect.left() + + # Now compute the size of the combo/spinner arrow + if isinstance(line_edit, (QComboBox, QDateTimeEdit)): + r = style.subControlRect(QStyle.CC_ComboBox, QStyleOptionComboBox(), + QStyle.SC_ComboBoxArrow) + new_width -= r.left() + elif isinstance(line_edit, (QSpinBox, QDoubleSpinBox)): + r = style.subControlRect(QStyle.CC_SpinBox, QStyleOptionSpinBox(), + QStyle.SC_SpinBoxUp) + new_width -= r.left() # Compute the space available from the left edge of the widget to the - # right edge of the table - max_width = (parent.horizontalScrollBar().geometry().width() - - parent.verticalHeader().width() - + # right edge of the displayed table (the viewport). We can't display any + # more than that + max_width = (table_widget.horizontalScrollBar().geometry().width() - + table_widget.verticalHeader().width() - line_edit.pos().x()) new_width = new_width if new_width < max_width else max_width @@ -218,7 +223,7 @@ class TextDelegate(QStyledItemDelegate): # {{{ auto-complete will be used. ''' QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent self.auto_complete_function = None def set_auto_complete_function(self, f): @@ -238,7 +243,7 @@ class TextDelegate(QStyledItemDelegate): # {{{ ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) editor.selectAll() - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): if isinstance(editor, EditWithComplete): @@ -256,7 +261,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ self.sep = sep self.items_func_name = items_func_name self.space_before_sep = space_before_sep - self.parent = parent + self.table_widget = parent def set_database(self, db): self.db = db @@ -283,7 +288,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) editor.selectAll() - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): if isinstance(editor, EditWithComplete): @@ -297,7 +302,7 @@ class LanguagesDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent def createEditor(self, parent, option, index): editor = LanguagesEdit(parent=parent) @@ -307,7 +312,7 @@ class LanguagesDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): ct = unicode(index.data(Qt.DisplayRole) or '') editor.show_initial_value(ct) - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): val = ','.join(editor.lang_codes) @@ -324,7 +329,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent def set_format(self, format): if not format: @@ -349,7 +354,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ if val is None: val = now() editor.setDateTime(val) - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): val = editor.dateTime() @@ -367,7 +372,7 @@ class CcTextDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent def createEditor(self, parent, option, index): m = index.model() @@ -382,7 +387,7 @@ class CcTextDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) editor.selectAll() def setModelData(self, editor, model, index): @@ -398,7 +403,7 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent def createEditor(self, parent, option, index): m = index.model() @@ -428,7 +433,7 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ if val is None: val = 0 editor.setValue(val) - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) # }}} @@ -440,7 +445,7 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent def createEditor(self, parent, option, index): m = index.model() @@ -467,7 +472,7 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ editor.setCurrentIndex(0) else: editor.setCurrentIndex(idx) - resize_line_edit_to_contents(self.parent, editor) + resize_line_edit_to_contents(self.table_widget, editor) # }}} class CcCommentsDelegate(QStyledItemDelegate): # {{{ From a4be0c76a21ebd3c6a21d913b9a379f7ccfef6b1 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Mon, 16 Mar 2015 12:03:01 +0100 Subject: [PATCH 3/3] Take 3. This one will take the entire viewport if needed. It aligns on the left edge if the language is LtR, otherwise on the right edge. I have tested it on all column types with the RtL test in both senses. I have not tested it on a machine running an RtL locale. --- src/calibre/gui2/library/delegates.py | 194 ++++++++++++++++---------- 1 file changed, 119 insertions(+), 75 deletions(-) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 65ebe30241..7083465053 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -10,7 +10,7 @@ import sys from PyQt5.Qt import (Qt, QApplication, QStyle, QIcon, QDoubleSpinBox, QStyleOptionViewItem, QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, QSize, QMenu, QKeySequence, QAbstractTextDocumentLayout, QFont, QFontInfo, QDate, QDateTimeEdit, QDateTime, - QStyleOptionComboBox, QStyleOptionSpinBox) + QStyleOptionComboBox, QStyleOptionSpinBox, QLocale) from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog, rating_font from calibre.constants import iswindows @@ -25,6 +25,75 @@ from calibre.gui2.dialogs.comments_dialog import CommentsDialog from calibre.gui2.dialogs.template_dialog import TemplateDialog from calibre.gui2.languages import LanguagesEdit +class UpdateEditorGeometry(object): + + def updateEditorGeometry(self, editor, option, index): + if editor is None: + return + fm = editor.fontMetrics(); + + # get the original size of the edit widget + opt = QStyleOptionViewItem(option) + self.initStyleOption(opt, index) + style = QApplication.style() + initial_geometry = style.subElementRect(style.SE_ItemViewItemText, opt, None) + orig_width = initial_geometry.width() + + # Compute the required width: the width that can show all of the current value + if hasattr(self, 'get_required_width'): + new_width = self.get_required_width(editor, index, style, fm) + else: + # The line edit box seems to extend by the space consumed by an 'M'. + # So add that to the text + text = self.displayText(index.data(Qt.DisplayRole), QLocale()) + u'M' + srect = style.itemTextRect(fm, editor.geometry(), Qt.AlignLeft, False, text) + new_width = srect.width() + + # Now get the size of the combo/spinner arrows and add them to the needed width + if isinstance(editor, (QComboBox, QDateTimeEdit)): + r = style.subControlRect(QStyle.CC_ComboBox, QStyleOptionComboBox(), + QStyle.SC_ComboBoxArrow) + new_width += r.width() + elif isinstance(editor, (QSpinBox, QDoubleSpinBox)): + r = style.subControlRect(QStyle.CC_SpinBox, QStyleOptionSpinBox(), + QStyle.SC_SpinBoxUp) + new_width += r.width() + + # Compute the maximum we can show if we consume the entire viewport + max_width = (self.table_widget.horizontalScrollBar().geometry().width() - + self.table_widget.verticalHeader().width()) + # What we have to display might not fit. If so, adjust down + new_width = new_width if new_width < max_width else max_width + + # See if we need to change the editor's geometry + if new_width <= orig_width: + delta_x = 0 + delta_width = 0 + else: + # Compute the space available from the left edge of the widget to + # the right edge of the displayed table (the viewport) and the left + # edge of the widget to the left edge of the viewport. These are + # used to position the edit box + space_left = initial_geometry.x() + space_right = max_width - space_left + + if editor.layoutDirection() == Qt.RightToLeft: + # If language is RtL, align to the cell's right edge if possible + cw = initial_geometry.width() + consume_on_left = min(space_left, new_width - cw) + consume_on_right = max(0, new_width - (consume_on_left + cw)) + delta_x = -consume_on_left + delta_width = consume_on_right + else: + # If language is LtR, align to the left if possible + consume_on_right = min(space_right, new_width) + consume_on_left = max(0, new_width - consume_on_right) + delta_x = -consume_on_left + delta_width = consume_on_right - initial_geometry.width() + + initial_geometry.adjust(delta_x, 0, delta_width, 0) + editor.setGeometry(initial_geometry) + class DateTimeEdit(QDateTimeEdit): # {{{ def __init__(self, parent, format): @@ -86,10 +155,11 @@ ClearingDoubleSpinBox = make_clearing_spinbox(QDoubleSpinBox) # }}} -class RatingDelegate(QStyledItemDelegate): # {{{ +class RatingDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, *args, **kwargs): QStyledItemDelegate.__init__(self, *args, **kwargs) + self.table_widget = args[0] self.rf = QFont(rating_font()) self.em = Qt.ElideMiddle delta = 0 @@ -98,12 +168,19 @@ class RatingDelegate(QStyledItemDelegate): # {{{ self.rf.setPointSize(QFontInfo(QApplication.font()).pointSize()+delta) def createEditor(self, parent, option, index): - sb = QStyledItemDelegate.createEditor(self, parent, option, index) + sb = QSpinBox(parent) sb.setMinimum(0) sb.setMaximum(5) sb.setSuffix(' ' + _('stars')) return sb + def get_required_width(self, editor, index, style, fm): + val = editor.maximum() + text = editor.textFromValue(val) + editor.suffix() + srect = style.itemTextRect(fm, editor.geometry(), Qt.AlignLeft, False, + text + u'M') + return srect.width() + def displayText(self, value, locale): r = int(value) if r < 0 or r > 5: @@ -122,7 +199,7 @@ class RatingDelegate(QStyledItemDelegate): # {{{ # }}} -class DateDelegate(QStyledItemDelegate): # {{{ +class DateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent, tweak_name='gui_timestamp_display_format', default_format='dd MMM yyyy'): @@ -144,11 +221,10 @@ class DateDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): QStyledItemDelegate.setEditorData(self, editor, index) - resize_line_edit_to_contents(self.table_widget, editor) # }}} -class PubDateDelegate(QStyledItemDelegate): # {{{ +class PubDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, *args, **kwargs): QStyledItemDelegate.__init__(self, *args, **kwargs) @@ -173,48 +249,10 @@ class PubDateDelegate(QStyledItemDelegate): # {{{ if isinstance(val, QDateTime): val = val.date() editor.setDate(val) - resize_line_edit_to_contents(self.table_widget, editor) # }}} -def resize_line_edit_to_contents(table_widget, line_edit): - if isinstance(line_edit, DelegateCB): - text = line_edit.currentText() - else: - text = line_edit.text(); - - fm = line_edit.fontMetrics(); - - orig_width = line_edit.width() - - # The line edit box seems to extend by the space consumed by an 'M'. So add - # that to the text - style = QApplication.style() - srect = style.itemTextRect(fm, line_edit.geometry(), Qt.AlignLeft, False, text + 'M') - new_width = srect.right() - srect.left() - - # Now compute the size of the combo/spinner arrow - if isinstance(line_edit, (QComboBox, QDateTimeEdit)): - r = style.subControlRect(QStyle.CC_ComboBox, QStyleOptionComboBox(), - QStyle.SC_ComboBoxArrow) - new_width -= r.left() - elif isinstance(line_edit, (QSpinBox, QDoubleSpinBox)): - r = style.subControlRect(QStyle.CC_SpinBox, QStyleOptionSpinBox(), - QStyle.SC_SpinBoxUp) - new_width -= r.left() - - # Compute the space available from the left edge of the widget to the - # right edge of the displayed table (the viewport). We can't display any - # more than that - max_width = (table_widget.horizontalScrollBar().geometry().width() - - table_widget.verticalHeader().width() - - line_edit.pos().x()) - new_width = new_width if new_width < max_width else max_width - - if new_width > orig_width: - line_edit.resize(new_width, line_edit.height()); - -class TextDelegate(QStyledItemDelegate): # {{{ +class TextDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent): ''' @@ -243,7 +281,6 @@ class TextDelegate(QStyledItemDelegate): # {{{ ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) editor.selectAll() - resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): if isinstance(editor, EditWithComplete): @@ -254,7 +291,7 @@ class TextDelegate(QStyledItemDelegate): # {{{ # }}} -class CompleteDelegate(QStyledItemDelegate): # {{{ +class CompleteDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent, sep, items_func_name, space_before_sep=False): QStyledItemDelegate.__init__(self, parent) @@ -288,7 +325,6 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) editor.selectAll() - resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): if isinstance(editor, EditWithComplete): @@ -298,7 +334,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ QStyledItemDelegate.setModelData(self, editor, model, index) # }}} -class LanguagesDelegate(QStyledItemDelegate): # {{{ +class LanguagesDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) @@ -312,14 +348,13 @@ class LanguagesDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): ct = unicode(index.data(Qt.DisplayRole) or '') editor.show_initial_value(ct) - resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): val = ','.join(editor.lang_codes) model.setData(index, (val), Qt.EditRole) # }}} -class CcDateDelegate(QStyledItemDelegate): # {{{ +class CcDateDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ ''' Delegate for custom columns dates. Because this delegate stores the @@ -354,7 +389,6 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ if val is None: val = now() editor.setDateTime(val) - resize_line_edit_to_contents(self.table_widget, editor) def setModelData(self, editor, model, index): val = editor.dateTime() @@ -364,7 +398,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ # }}} -class CcTextDelegate(QStyledItemDelegate): # {{{ +class CcTextDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ ''' Delegate for text data. @@ -387,7 +421,6 @@ class CcTextDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): ct = unicode(index.data(Qt.DisplayRole) or '') editor.setText(ct) - resize_line_edit_to_contents(self.table_widget, editor) editor.selectAll() def setModelData(self, editor, model, index): @@ -395,7 +428,7 @@ class CcTextDelegate(QStyledItemDelegate): # {{{ model.setData(index, (val), Qt.EditRole) # }}} -class CcNumberDelegate(QStyledItemDelegate): # {{{ +class CcNumberDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ ''' Delegate for text/int/float data. @@ -433,11 +466,17 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ if val is None: val = 0 editor.setValue(val) - resize_line_edit_to_contents(self.table_widget, editor) + + def get_required_width(self, editor, index, style, fm): + val = editor.maximum() + text = editor.textFromValue(val) + srect = style.itemTextRect(fm, editor.geometry(), Qt.AlignLeft, False, + text + u'M') + return srect.width() # }}} -class CcEnumDelegate(QStyledItemDelegate): # {{{ +class CcEnumDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ ''' Delegate for text/int/float data. @@ -446,14 +485,19 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent): QStyledItemDelegate.__init__(self, parent) self.table_widget = parent + self.longest_text = '' def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] editor = DelegateCB(parent) editor.addItem('') + max_len = 0 + self.longest_text = '' for v in m.custom_columns[col]['display']['enum_values']: editor.addItem(v) + if len(v) > max_len: + self.longest_text = v return editor def setModelData(self, editor, model, index): @@ -462,6 +506,14 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ val = None model.setData(index, (val), Qt.EditRole) + def get_required_width(self, editor, index, style, fm): + m = index.model() + col = m.column_map[index.column()] + use_decorations = m.custom_columns[col]['display'].get('use_decorations', False) + srect = style.itemTextRect(fm, editor.geometry(), Qt.AlignLeft, False, + self.longest_text + u'M') + return srect.width() + editor.iconSize().width() if use_decorations else 0 + def setEditorData(self, editor, index): m = index.model() val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']] @@ -472,7 +524,6 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ editor.setCurrentIndex(0) else: editor.setCurrentIndex(idx) - resize_line_edit_to_contents(self.table_widget, editor) # }}} class CcCommentsDelegate(QStyledItemDelegate): # {{{ @@ -532,14 +583,14 @@ class DelegateCB(QComboBox): # {{{ return QComboBox.event(self, e) # }}} -class CcBoolDelegate(QStyledItemDelegate): # {{{ +class CcBoolDelegate(QStyledItemDelegate, UpdateEditorGeometry): # {{{ def __init__(self, parent): ''' Delegate for custom_column bool data. ''' QStyledItemDelegate.__init__(self, parent) - self.parent = parent + self.table_widget = parent def createEditor(self, parent, option, index): editor = DelegateCB(parent) @@ -548,10 +599,18 @@ class CcBoolDelegate(QStyledItemDelegate): # {{{ if not index.model().db.prefs.get('bools_are_tristate'): items = items[:-1] icons = icons[:-1] + self.longest_text = '' for icon, text in zip(icons, items): editor.addItem(QIcon(icon), text) + if len(text) > len(self.longest_text): + self.longest_text = text return editor + def get_required_width(self, editor, index, style, fm): + srect = style.itemTextRect(fm, editor.geometry(), Qt.AlignLeft, False, + self.longest_text + u'M') + return srect.width() + editor.iconSize().width() + def setModelData(self, editor, model, index): val = {0:True, 1:False, 2:None}[editor.currentIndex()] model.setData(index, (val), Qt.EditRole) @@ -565,21 +624,6 @@ class CcBoolDelegate(QStyledItemDelegate): # {{{ val = 2 if val is None else 1 if not val else 0 editor.setCurrentIndex(val) - def updateEditorGeometry(self, editor, option, index): - if editor is None: - return - opt = QStyleOptionViewItem(option) - self.initStyleOption(opt, index) - opt.showDecorationSelected = True - opt.decorationSize = QSize(0, 0) # We want the editor to cover the decoration - style = QApplication.style() - geom = style.subElementRect(style.SE_ItemViewItemText, opt, None) - - if editor.layoutDirection() == Qt.RightToLeft: - delta = editor.sizeHint().width() - geom.width() - if delta > 0: - geom.adjust(-delta, 0, 0, 0) - editor.setGeometry(geom) # }}} class CcTemplateDelegate(QStyledItemDelegate): # {{{