mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Add context menu entries to clear metadata edit spinboxes for date and number fields
This commit is contained in:
parent
ecce202556
commit
270b6f403f
@ -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): # {{{
|
|||||||
|
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user