Add context menu entries to clear metadata edit spinboxes for date and number fields

This commit is contained in:
Kovid Goyal 2014-10-23 22:00:09 +05:30
parent ecce202556
commit 270b6f403f
3 changed files with 77 additions and 35 deletions

View File

@ -8,12 +8,13 @@ __docformat__ = 'restructuredtext en'
import sys import sys
from PyQt5.Qt import (Qt, QApplication, QStyle, QIcon, QDoubleSpinBox, QStyleOptionViewItem, from PyQt5.Qt import (Qt, QApplication, QStyle, QIcon, QDoubleSpinBox, QStyleOptionViewItem,
QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, QSize, QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, QSize, QMenu, QKeySequence,
QAbstractTextDocumentLayout, QFont, QFontInfo, QDate, QDateTimeEdit, QDateTime) QAbstractTextDocumentLayout, QFont, QFontInfo, QDate, QDateTimeEdit, QDateTime)
from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog, rating_font from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog, rating_font
from calibre.constants import iswindows from calibre.constants import iswindows
from calibre.gui2.widgets import EnLineEdit from calibre.gui2.widgets import EnLineEdit
from calibre.gui2.widgets2 import populate_standard_spinbox_context_menu
from calibre.gui2.complete2 import EditWithComplete from calibre.gui2.complete2 import EditWithComplete
from calibre.utils.date import now, format_date, qt_to_dt, is_date_undefined from calibre.utils.date import now, format_date, qt_to_dt, is_date_undefined
from calibre.utils.config import tweaks from calibre.utils.config import tweaks
@ -33,10 +34,21 @@ class DateTimeEdit(QDateTimeEdit): # {{{
self.setCalendarPopup(True) self.setCalendarPopup(True)
self.setDisplayFormat(format) self.setDisplayFormat(format)
def contextMenuEvent(self, ev):
m = QMenu(self)
m.addAction(_('Set date to undefined') + '\t' + QKeySequence(Qt.Key_Minus).toString(QKeySequence.NativeText),
self.clear_date)
m.addSeparator()
populate_standard_spinbox_context_menu(self, m)
m.popup(ev.globalPos())
def clear_date(self):
self.setDateTime(UNDEFINED_QDATETIME)
def keyPressEvent(self, ev): def keyPressEvent(self, ev):
if ev.key() == Qt.Key_Minus: if ev.key() == Qt.Key_Minus:
ev.accept() ev.accept()
self.setDateTime(UNDEFINED_QDATETIME) self.clear_date()
elif ev.key() == Qt.Key_Equal: elif ev.key() == Qt.Key_Equal:
ev.accept() ev.accept()
self.setDateTime(QDateTime.currentDateTime()) self.setDateTime(QDateTime.currentDateTime())
@ -44,20 +56,33 @@ class DateTimeEdit(QDateTimeEdit): # {{{
return QDateTimeEdit.keyPressEvent(self, ev) return QDateTimeEdit.keyPressEvent(self, ev)
# }}} # }}}
class ClearingSpinBox(QSpinBox): # {{{ # Number Editor {{{
def keyPressEvent(self, ev):
if ev.key() == Qt.Key_Space: def make_clearing_spinbox(spinbox):
self.setValue(-1000000)
else: class SpinBox(spinbox):
return QSpinBox.keyPressEvent(self, ev)
# }}} def contextMenuEvent(self, ev):
m = QMenu(self)
m.addAction(_('Set to undefined') + '\t' + QKeySequence(Qt.Key_Space).toString(QKeySequence.NativeText),
self.clear_to_undefined)
m.addSeparator()
populate_standard_spinbox_context_menu(self, m)
m.popup(ev.globalPos())
def clear_to_undefined(self):
self.setValue(self.minimum())
def keyPressEvent(self, ev):
if ev.key() == Qt.Key_Space:
self.clear_to_undefined()
else:
return spinbox.keyPressEvent(self, ev)
return SpinBox
ClearingSpinBox = make_clearing_spinbox(QSpinBox)
ClearingDoubleSpinBox = make_clearing_spinbox(QDoubleSpinBox)
class ClearingDoubleSpinBox(QDoubleSpinBox): # {{{
def keyPressEvent(self, ev):
if ev.key() == Qt.Key_Space:
self.setValue(-1000000.0)
else:
return QDoubleSpinBox.keyPressEvent(self, ev)
# }}} # }}}
class RatingDelegate(QStyledItemDelegate): # {{{ class RatingDelegate(QStyledItemDelegate): # {{{
@ -145,6 +170,7 @@ class PubDateDelegate(QStyledItemDelegate): # {{{
# }}} # }}}
class TextDelegate(QStyledItemDelegate): # {{{ class TextDelegate(QStyledItemDelegate): # {{{
def __init__(self, parent): def __init__(self, parent):
''' '''
Delegate for text data. If auto_complete_function needs to return a list Delegate for text data. If auto_complete_function needs to return a list
@ -179,9 +205,10 @@ class TextDelegate(QStyledItemDelegate): # {{{
else: else:
QStyledItemDelegate.setModelData(self, editor, model, index) QStyledItemDelegate.setModelData(self, editor, model, index)
#}}} # }}}
class CompleteDelegate(QStyledItemDelegate): # {{{ class CompleteDelegate(QStyledItemDelegate): # {{{
def __init__(self, parent, sep, items_func_name, space_before_sep=False): def __init__(self, parent, sep, items_func_name, space_before_sep=False):
QStyledItemDelegate.__init__(self, parent) QStyledItemDelegate.__init__(self, parent)
self.sep = sep self.sep = sep
@ -239,6 +266,7 @@ class LanguagesDelegate(QStyledItemDelegate): # {{{
# }}} # }}}
class CcDateDelegate(QStyledItemDelegate): # {{{ class CcDateDelegate(QStyledItemDelegate): # {{{
''' '''
Delegate for custom columns dates. Because this delegate stores the Delegate for custom columns dates. Because this delegate stores the
format as an instance variable, a new instance must be created for each format as an instance variable, a new instance must be created for each
@ -278,6 +306,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{
# }}} # }}}
class CcTextDelegate(QStyledItemDelegate): # {{{ class CcTextDelegate(QStyledItemDelegate): # {{{
''' '''
Delegate for text data. Delegate for text data.
''' '''
@ -303,6 +332,7 @@ class CcTextDelegate(QStyledItemDelegate): # {{{
# }}} # }}}
class CcNumberDelegate(QStyledItemDelegate): # {{{ class CcNumberDelegate(QStyledItemDelegate): # {{{
''' '''
Delegate for text/int/float data. Delegate for text/int/float data.
''' '''
@ -338,6 +368,7 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{
# }}} # }}}
class CcEnumDelegate(QStyledItemDelegate): # {{{ class CcEnumDelegate(QStyledItemDelegate): # {{{
''' '''
Delegate for text/int/float data. Delegate for text/int/float data.
''' '''
@ -370,6 +401,7 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
# }}} # }}}
class CcCommentsDelegate(QStyledItemDelegate): # {{{ class CcCommentsDelegate(QStyledItemDelegate): # {{{
''' '''
Delegate for comments data. Delegate for comments data.
''' '''
@ -422,6 +454,7 @@ class DelegateCB(QComboBox): # {{{
# }}} # }}}
class CcBoolDelegate(QStyledItemDelegate): # {{{ class CcBoolDelegate(QStyledItemDelegate): # {{{
def __init__(self, parent): def __init__(self, parent):
''' '''
Delegate for custom_column bool data. Delegate for custom_column bool data.
@ -470,6 +503,7 @@ class CcBoolDelegate(QStyledItemDelegate): # {{{
# }}} # }}}
class CcTemplateDelegate(QStyledItemDelegate): # {{{ class CcTemplateDelegate(QStyledItemDelegate): # {{{
def __init__(self, parent): def __init__(self, parent):
''' '''
Delegate for custom_column bool data. Delegate for custom_column bool data.
@ -506,5 +540,3 @@ class CcTemplateDelegate(QStyledItemDelegate): # {{{
# }}} # }}}

View File

@ -17,6 +17,7 @@ from PyQt5.Qt import (
QUndoStack) QUndoStack)
from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView
from calibre.gui2.widgets2 import access_key, populate_standard_spinbox_context_menu
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
from calibre.utils.config import tweaks, prefs from calibre.utils.config import tweaks, prefs
from calibre.ebooks.metadata import ( from calibre.ebooks.metadata import (
@ -109,11 +110,6 @@ class ToMetadataMixin(object):
def make_undoable(spinbox): def make_undoable(spinbox):
'Add a proper undo/redo capability to spinbox which must be a sub-class of QAbstractSpinBox' 'Add a proper undo/redo capability to spinbox which must be a sub-class of QAbstractSpinBox'
def access_key(k):
if QKeySequence.keyBindings(k):
return '\t' + QKeySequence(k).toString(QKeySequence.NativeText)
return ''
class UndoCommand(QUndoCommand): class UndoCommand(QUndoCommand):
def __init__(self, widget, val): def __init__(self, widget, val):
@ -157,20 +153,13 @@ def make_undoable(spinbox):
def contextMenuEvent(self, ev): def contextMenuEvent(self, ev):
m = QMenu(self) m = QMenu(self)
if hasattr(self, 'setDateTime'):
m.addAction(_('Set date to undefined') + '\t' + QKeySequence(Qt.Key_Minus).toString(QKeySequence.NativeText),
lambda : self.setDateTime(self.minimumDateTime()))
m.addAction(_('&Undo') + access_key(QKeySequence.Undo), self.undo).setEnabled(self.undo_stack.canUndo()) m.addAction(_('&Undo') + access_key(QKeySequence.Undo), self.undo).setEnabled(self.undo_stack.canUndo())
m.addAction(_('&Redo') + access_key(QKeySequence.Redo), self.redo).setEnabled(self.undo_stack.canRedo()) m.addAction(_('&Redo') + access_key(QKeySequence.Redo), self.redo).setEnabled(self.undo_stack.canRedo())
m.addSeparator() m.addSeparator()
le = self.lineEdit() populate_standard_spinbox_context_menu(self, m)
m.addAction(_('Cu&t') + access_key(QKeySequence.Cut), le.cut).setEnabled(not le.isReadOnly() and le.hasSelectedText())
m.addAction(_('&Copy') + access_key(QKeySequence.Copy), le.copy).setEnabled(le.hasSelectedText())
m.addAction(_('&Paste') + access_key(QKeySequence.Paste), le.paste).setEnabled(not le.isReadOnly())
m.addAction(_('Delete') + access_key(QKeySequence.Delete), le.del_).setEnabled(not le.isReadOnly() and le.hasSelectedText())
m.addSeparator()
m.addAction(_('Select &All') + access_key(QKeySequence.SelectAll), self.selectAll)
m.addSeparator()
m.addAction(_('&Step up'), self.stepUp)
m.addAction(_('Step &down'), self.stepDown)
m.setAttribute(Qt.WA_DeleteOnClose)
m.popup(ev.globalPos()) m.popup(ev.globalPos())
def set_spinbox_value(self, val): def set_spinbox_value(self, val):

View File

@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
from PyQt5.Qt import QPushButton, QPixmap, QIcon, QColor, Qt, QColorDialog, pyqtSignal from PyQt5.Qt import QPushButton, QPixmap, QIcon, QColor, Qt, QColorDialog, pyqtSignal, QKeySequence
from calibre.gui2.complete2 import LineEdit, EditWithComplete from calibre.gui2.complete2 import LineEdit, EditWithComplete
from calibre.gui2.widgets import history from calibre.gui2.widgets import history
@ -99,3 +99,24 @@ class ColorButton(QPushButton):
if col.isValid(): if col.isValid():
self.color = unicode(col.name()) self.color = unicode(col.name())
def access_key(k):
'Return shortcut text suitable for adding to a menu item'
if QKeySequence.keyBindings(k):
return '\t' + QKeySequence(k).toString(QKeySequence.NativeText)
return ''
def populate_standard_spinbox_context_menu(spinbox, menu, add_clear=False):
m = menu
le = spinbox.lineEdit()
m.addAction(_('Cu&t') + access_key(QKeySequence.Cut), le.cut).setEnabled(not le.isReadOnly() and le.hasSelectedText())
m.addAction(_('&Copy') + access_key(QKeySequence.Copy), le.copy).setEnabled(le.hasSelectedText())
m.addAction(_('&Paste') + access_key(QKeySequence.Paste), le.paste).setEnabled(not le.isReadOnly())
m.addAction(_('Delete') + access_key(QKeySequence.Delete), le.del_).setEnabled(not le.isReadOnly() and le.hasSelectedText())
m.addSeparator()
m.addAction(_('Select &All') + access_key(QKeySequence.SelectAll), spinbox.selectAll)
m.addSeparator()
m.addAction(_('&Step up'), spinbox.stepUp)
m.addAction(_('Step &down'), spinbox.stepDown)
m.setAttribute(Qt.WA_DeleteOnClose)