mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
More CreateNewCustomColumn stuff.
- Improved documentation - Check column headings for duplicates - Method to return the current column headings as a dict - Improved exception handling
This commit is contained in:
parent
fbb5208aac
commit
9a95d8b0c2
@ -676,24 +676,48 @@ class CreateNewCustomColumn(object):
|
|||||||
"""
|
"""
|
||||||
Provide an API to create new custom columns.
|
Provide an API to create new custom columns.
|
||||||
|
|
||||||
Use the create_column() method to open a dialog to create a new custom
|
Usage:
|
||||||
column with given lookup_name, column_heading, datatype, and is_multiple.
|
from calibre.gui2.preferences.create_custom_column import CreateNewCustomColumn
|
||||||
The lookup name must begin with a '#'. The datatype must be valid and
|
creator = CreateNewCustomColumn(gui)
|
||||||
is_multiple must be valid for that datatype. The user cannot change
|
if creator.must_restart():
|
||||||
the datatype.
|
...
|
||||||
|
else:
|
||||||
|
result = creator.create_column(....)
|
||||||
|
if result[0] == creator.Result.COLUMN_ADDED:
|
||||||
|
|
||||||
If generate_unused_lookup_name is False then the provided lookup_name must
|
The parameter 'gui' passed when creating a class instance is the main
|
||||||
not already exist. If generate_unused_lookup_name is True then if necessary
|
calibre gui (calibre.gui2.ui.get_gui())
|
||||||
the method will add the suffix '_n' to the provided lookup_name to allocate
|
|
||||||
an unused lookup_name, where 'n' is an integer. It could be that if a new
|
Use the create_column(...) method to open a dialog to create a new custom
|
||||||
lookup name is generated then the user will be required to change the
|
column with given lookup_name, column_heading, datatype, and is_multiple.
|
||||||
column heading to make it is unique.
|
You can create as many columns as you wish with a single instance of the
|
||||||
|
CreateNewCustomColumn class. Subsequent class instances will refuse to
|
||||||
|
create columns until calibre is restarted, as will calibre Preferences.
|
||||||
|
|
||||||
|
The lookup name must begin with a '#'. All remaining characters must be
|
||||||
|
lower case letters, digits or underscores. The character after the '#' must
|
||||||
|
be a letter. The lookup name must not end with the suffix '_index'.
|
||||||
|
|
||||||
|
The datatype must be one of calibre's custom column types: 'bool',
|
||||||
|
'comments', 'composite', 'datetime', 'enumeration', 'float', 'int',
|
||||||
|
'rating', 'series', or 'text'. The datatype can't be changed in the dialog.
|
||||||
|
|
||||||
|
is_multiple tells calibre that the column contains multiple values -- is
|
||||||
|
tags-like. The value True is allowed only for 'composite' and 'text' types.
|
||||||
|
|
||||||
|
If generate_unused_lookup_name is False then the provided lookup_name and
|
||||||
|
column_heading must not already exist. If generate_unused_lookup_name is
|
||||||
|
True then if necessary the method will add the suffix '_n' to the provided
|
||||||
|
lookup_name to allocate an unused lookup_name, where 'n' is an integer.
|
||||||
|
The same processing is applied to column_heading to make it is unique, using
|
||||||
|
the same suffix used for the lookup name if possible. In either case the
|
||||||
|
user can change the column heading in the dialog.
|
||||||
|
|
||||||
Set freeze_lookup_name to False if you want to allow the user choose a
|
Set freeze_lookup_name to False if you want to allow the user choose a
|
||||||
different lookup name. The user will not be allowed to choose the lookup
|
different lookup name. The user will not be allowed to choose the lookup
|
||||||
name of an existing column. The provided lookup_name either must not exist
|
name of an existing column. The provided lookup_name and column_heading
|
||||||
or generate_unused_lookup_name must be True, regardless of the value of
|
either must not exist or generate_unused_lookup_name must be True,
|
||||||
freeze_lookup_name.
|
regardless of the value of freeze_lookup_name.
|
||||||
|
|
||||||
The 'display' parameter is used to pass item- and type-specific information
|
The 'display' parameter is used to pass item- and type-specific information
|
||||||
for the column. It is a dict. The easiest way to see the current values for
|
for the column. It is a dict. The easiest way to see the current values for
|
||||||
@ -740,21 +764,14 @@ class CreateNewCustomColumn(object):
|
|||||||
|
|
||||||
You or the user must restart calibre for the column(s) to be actually added.
|
You or the user must restart calibre for the column(s) to be actually added.
|
||||||
|
|
||||||
|
Result.EXCEPTION_RAISED is returned if the create dialog raises an exception.
|
||||||
|
This can happen if the display contains illegal values, for example a string
|
||||||
|
where a boolean is required. The string is the exception text. Run calibre
|
||||||
|
in debug mode to see the entire traceback.
|
||||||
|
|
||||||
The method returns Result.MUST_RESTART if further calibre configuration has
|
The method returns Result.MUST_RESTART if further calibre configuration has
|
||||||
been blocked. You can check for this situation in advance by calling
|
been blocked. You can check for this situation in advance by calling
|
||||||
must_restart().
|
must_restart().
|
||||||
|
|
||||||
The parameter 'gui' passed when creating a class instance is the main
|
|
||||||
calibre gui (calibre.gui2.ui.get_gui())
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
from calibre.gui2.preferences.create_custom_column import CreateNewCustomColumn
|
|
||||||
creator = CreateNewCustomColumn(gui)
|
|
||||||
if creator.must_restart():
|
|
||||||
...
|
|
||||||
else:
|
|
||||||
result = creator.create_column(....)
|
|
||||||
if result[0] == creator.Result.COLUMN_ADDED:
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Result(Enum):
|
class Result(Enum):
|
||||||
@ -762,10 +779,12 @@ class CreateNewCustomColumn(object):
|
|||||||
CANCELED = 1
|
CANCELED = 1
|
||||||
INVALID_KEY = 2
|
INVALID_KEY = 2
|
||||||
DUPLICATE_KEY = 3
|
DUPLICATE_KEY = 3
|
||||||
INVALID_TYPE = 4
|
DUPLICATE_HEADING = 4
|
||||||
INVALID_IS_MULTIPLE = 5
|
INVALID_TYPE = 5
|
||||||
INVALID_DISPLAY = 6
|
INVALID_IS_MULTIPLE = 6
|
||||||
MUST_RESTART = 7
|
INVALID_DISPLAY = 7
|
||||||
|
EXCEPTION_RAISED = 8
|
||||||
|
MUST_RESTART = 9
|
||||||
|
|
||||||
def __init__(self, gui):
|
def __init__(self, gui):
|
||||||
self.gui = gui
|
self.gui = gui
|
||||||
@ -783,14 +802,28 @@ class CreateNewCustomColumn(object):
|
|||||||
return (self.Result.MUST_RESTART, _("You must restart calibre before making any more changes"))
|
return (self.Result.MUST_RESTART, _("You must restart calibre before making any more changes"))
|
||||||
if not lookup_name.startswith('#'):
|
if not lookup_name.startswith('#'):
|
||||||
return (self.Result.INVALID_KEY, _("The lookup name must begin with a '#'"))
|
return (self.Result.INVALID_KEY, _("The lookup name must begin with a '#'"))
|
||||||
|
suffix_number = 1
|
||||||
if lookup_name in self.custcols:
|
if lookup_name in self.custcols:
|
||||||
if not generate_unused_lookup_name:
|
if not generate_unused_lookup_name:
|
||||||
return(self.Result.DUPLICATE_KEY, _("The custom column %s already exists") % lookup_name)
|
return(self.Result.DUPLICATE_KEY, _("The custom column %s already exists") % lookup_name)
|
||||||
for i in range(1, 10000):
|
for suffix_number in range(suffix_number, 100000):
|
||||||
nk = '%s_%d'%(lookup_name, i)
|
nk = '%s_%d'%(lookup_name, suffix_number)
|
||||||
if nk not in self.custcols:
|
if nk not in self.custcols:
|
||||||
lookup_name = nk
|
lookup_name = nk
|
||||||
break
|
break
|
||||||
|
if column_heading:
|
||||||
|
headings = {v['name'] for v in self.custcols.values()}
|
||||||
|
if column_heading in headings:
|
||||||
|
if not generate_unused_lookup_name:
|
||||||
|
return(self.Result.DUPLICATE_HEADING,
|
||||||
|
_("The column heading %s already exists") % column_heading)
|
||||||
|
for i in range(suffix_number, 100000):
|
||||||
|
nh = '%s_%d'%(column_heading, i)
|
||||||
|
if nh not in headings:
|
||||||
|
column_heading = nh
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
column_heading = lookup_name
|
||||||
if datatype not in CreateCustomColumn.column_types_map:
|
if datatype not in CreateCustomColumn.column_types_map:
|
||||||
return(self.Result.INVALID_TYPE,
|
return(self.Result.INVALID_TYPE,
|
||||||
_("The custom column type %s doesn't exist") % datatype)
|
_("The custom column type %s doesn't exist") % datatype)
|
||||||
@ -800,10 +833,6 @@ class CreateNewCustomColumn(object):
|
|||||||
if not isinstance(display, dict):
|
if not isinstance(display, dict):
|
||||||
return(self.Result.INVALID_DISPLAY,
|
return(self.Result.INVALID_DISPLAY,
|
||||||
_("The display parameter must a python dict"))
|
_("The display parameter must a python dict"))
|
||||||
|
|
||||||
if not column_heading:
|
|
||||||
column_heading = lookup_name
|
|
||||||
self.key = lookup_name
|
|
||||||
self.created_count += 1
|
self.created_count += 1
|
||||||
self.custcols[lookup_name] = {
|
self.custcols[lookup_name] = {
|
||||||
'label': lookup_name,
|
'label': lookup_name,
|
||||||
@ -814,18 +843,26 @@ class CreateNewCustomColumn(object):
|
|||||||
'colnum': self.created_count,
|
'colnum': self.created_count,
|
||||||
'is_multiple': is_multiple,
|
'is_multiple': is_multiple,
|
||||||
}
|
}
|
||||||
dialog = CreateCustomColumn(self.gui, self, lookup_name, self.gui.library_view.model().orig_headers,
|
try:
|
||||||
freeze_lookup_name=freeze_lookup_name)
|
dialog = CreateCustomColumn(self.gui, self, lookup_name,
|
||||||
if dialog.result() == QDialog.DialogCode.Accepted and self.cc_column_key is not None:
|
self.gui.library_view.model().orig_headers,
|
||||||
cc = self.custcols[lookup_name]
|
freeze_lookup_name=freeze_lookup_name)
|
||||||
self.db.create_custom_column(
|
if dialog.result() == QDialog.DialogCode.Accepted and self.cc_column_key is not None:
|
||||||
label=cc['label'],
|
cc = self.custcols[lookup_name]
|
||||||
name=cc['name'],
|
self.db.create_custom_column(
|
||||||
datatype=cc['datatype'],
|
label=cc['label'],
|
||||||
is_multiple=cc['is_multiple'],
|
name=cc['name'],
|
||||||
display=cc['display'])
|
datatype=cc['datatype'],
|
||||||
self.gui.must_restart_before_config = True
|
is_multiple=cc['is_multiple'],
|
||||||
return ((self.Result.COLUMN_ADDED, self.cc_column_key))
|
display=cc['display'])
|
||||||
|
self.gui.must_restart_before_config = True
|
||||||
|
return (self.Result.COLUMN_ADDED, self.cc_column_key)
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
self.custcols.pop(lookup_name, None)
|
||||||
|
return (self.Result.EXCEPTION_RAISED, str(e))
|
||||||
|
self.custcols.pop(lookup_name, None)
|
||||||
return (self.Result.CANCELED, _('Canceled'))
|
return (self.Result.CANCELED, _('Canceled'))
|
||||||
|
|
||||||
def current_columns(self):
|
def current_columns(self):
|
||||||
@ -847,7 +884,21 @@ class CreateNewCustomColumn(object):
|
|||||||
doesn't use. See calibre.library.field_metadata.add_custom_field() for the
|
doesn't use. See calibre.library.field_metadata.add_custom_field() for the
|
||||||
complete list.
|
complete list.
|
||||||
"""
|
"""
|
||||||
return copy.deepcopy(self.custcols) #deepcopy to prevent users from changing it
|
# deepcopy to prevent users from changing it. The new MappingProxyType
|
||||||
|
# isn't enough because only the top-level dict is immutable, not the
|
||||||
|
# items in the dict.
|
||||||
|
return copy.deepcopy(self.custcols)
|
||||||
|
|
||||||
|
|
||||||
|
def current_headings(self):
|
||||||
|
"""
|
||||||
|
Return the currently defined column headings
|
||||||
|
|
||||||
|
Return the column headings including the ones that haven't yet been
|
||||||
|
created. It is a dict. The key is the heading, the value is the lookup
|
||||||
|
name having that heading.
|
||||||
|
"""
|
||||||
|
return {v['name']:('#' + v['label']) for v in self.custcols.values()}
|
||||||
|
|
||||||
def must_restart(self):
|
def must_restart(self):
|
||||||
"""Return true if calibre must be restarted before new columns can be added."""
|
"""Return true if calibre must be restarted before new columns can be added."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user