mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Changed to GenericRulesTable model
This commit is contained in:
parent
67c98bae56
commit
3b5fd30b0a
@ -17,8 +17,9 @@ from PyQt4 import QtGui
|
|||||||
from PyQt4.Qt import (Qt, QAbstractItemView, QCheckBox, QComboBox, QDialog,
|
from PyQt4.Qt import (Qt, QAbstractItemView, QCheckBox, QComboBox, QDialog,
|
||||||
QDialogButtonBox, QDoubleSpinBox,
|
QDialogButtonBox, QDoubleSpinBox,
|
||||||
QHBoxLayout, QIcon, QLabel, QLineEdit,
|
QHBoxLayout, QIcon, QLabel, QLineEdit,
|
||||||
QPlainTextEdit, QRadioButton, QSize, QTableWidget, QTableWidgetItem,
|
QPlainTextEdit, QRadioButton, QSize, QSizePolicy,
|
||||||
QVBoxLayout, QWidget)
|
QTableWidget, QTableWidgetItem,
|
||||||
|
QToolButton, QVBoxLayout, QWidget)
|
||||||
|
|
||||||
class PluginWidget(QWidget,Ui_Form):
|
class PluginWidget(QWidget,Ui_Form):
|
||||||
|
|
||||||
@ -190,7 +191,9 @@ class PluginWidget(QWidget,Ui_Form):
|
|||||||
self.generate_descriptions.stateChanged.connect(self.generate_descriptions_changed)
|
self.generate_descriptions.stateChanged.connect(self.generate_descriptions_changed)
|
||||||
|
|
||||||
# Initialize prefix rules
|
# Initialize prefix rules
|
||||||
self.prefix_rules_initialize(prefix_rules)
|
self.prefix_rules_table = PrefixRules(self.prefix_rules_gb_hl, "prefix_rules_tw",
|
||||||
|
prefix_rules, self.eligible_custom_fields,
|
||||||
|
self.db)
|
||||||
|
|
||||||
def options(self):
|
def options(self):
|
||||||
# Save/return the current options
|
# Save/return the current options
|
||||||
@ -212,7 +215,7 @@ class PluginWidget(QWidget,Ui_Form):
|
|||||||
elif c_type in ['spin_box']:
|
elif c_type in ['spin_box']:
|
||||||
opt_value = unicode(getattr(self, c_name).value())
|
opt_value = unicode(getattr(self, c_name).value())
|
||||||
elif c_type in ['table_widget']:
|
elif c_type in ['table_widget']:
|
||||||
opt_value = self.prefix_rules_get_data()
|
opt_value = self.prefix_rules_table.get_data()
|
||||||
|
|
||||||
gprefs.set(self.name + '_' + c_name, opt_value)
|
gprefs.set(self.name + '_' + c_name, opt_value)
|
||||||
|
|
||||||
@ -346,393 +349,6 @@ class PluginWidget(QWidget,Ui_Form):
|
|||||||
self.merge_after.setEnabled(False)
|
self.merge_after.setEnabled(False)
|
||||||
self.include_hr.setEnabled(False)
|
self.include_hr.setEnabled(False)
|
||||||
|
|
||||||
|
|
||||||
def prefix_rules_add_row(self):
|
|
||||||
# Called when '+' clicked
|
|
||||||
self.prefix_rules_tw.setFocus()
|
|
||||||
row = self.prefix_rules_tw.currentRow() + 1
|
|
||||||
self.prefix_rules_tw.insertRow(row)
|
|
||||||
self.prefix_rules_populate_table_row(row, self.prefix_rules_create_blank_row_data())
|
|
||||||
self.prefix_rules_select_and_scroll_to_row(row)
|
|
||||||
self.prefix_rules_tw.resizeColumnsToContents()
|
|
||||||
# Just in case table was empty
|
|
||||||
self.prefix_rules_tw.horizontalHeader().setStretchLastSection(True)
|
|
||||||
|
|
||||||
def prefix_rules_convert_row_to_data(self, row):
|
|
||||||
data = self.prefix_rules_create_blank_row_data()
|
|
||||||
data['ordinal'] = row
|
|
||||||
data['enabled'] = self.prefix_rules_tw.item(row,0).checkState() == Qt.Checked
|
|
||||||
data['name'] = unicode(self.prefix_rules_tw.cellWidget(row,1).text()).strip()
|
|
||||||
data['prefix'] = unicode(self.prefix_rules_tw.cellWidget(row,2).currentText()).strip()
|
|
||||||
data['field'] = unicode(self.prefix_rules_tw.cellWidget(row,3).currentText()).strip()
|
|
||||||
data['pattern'] = unicode(self.prefix_rules_tw.cellWidget(row,4).currentText()).strip()
|
|
||||||
return data
|
|
||||||
|
|
||||||
def prefix_rules_create_blank_row_data(self):
|
|
||||||
data = {}
|
|
||||||
data['ordinal'] = -1
|
|
||||||
data['enabled'] = False
|
|
||||||
data['name'] = 'New rule'
|
|
||||||
data['field'] = ''
|
|
||||||
data['pattern'] = ''
|
|
||||||
data['prefix'] = ''
|
|
||||||
return data
|
|
||||||
|
|
||||||
def prefix_rules_delete_row(self):
|
|
||||||
self.prefix_rules_tw.setFocus()
|
|
||||||
rows = self.prefix_rules_tw.selectionModel().selectedRows()
|
|
||||||
if len(rows) == 0:
|
|
||||||
return
|
|
||||||
message = '<p>Are you sure you want to delete this rule?'
|
|
||||||
if len(rows) > 1:
|
|
||||||
message = '<p>Are you sure you want to delete the %d selected rules?'%len(rows)
|
|
||||||
if not question_dialog(self, _('Are you sure?'), message, show_copy_button=False):
|
|
||||||
return
|
|
||||||
first_sel_row = self.prefix_rules_tw.currentRow()
|
|
||||||
for selrow in reversed(rows):
|
|
||||||
self.prefix_rules_tw.removeRow(selrow.row())
|
|
||||||
if first_sel_row < self.prefix_rules_tw.rowCount():
|
|
||||||
self.prefix_rules_select_and_scroll_to_row(first_sel_row)
|
|
||||||
elif self.prefix_rules_tw.rowCount() > 0:
|
|
||||||
self.prefix_rules_select_and_scroll_to_row(first_sel_row - 1)
|
|
||||||
|
|
||||||
def prefix_rules_generate_prefix_list(self):
|
|
||||||
def prefix_sorter(item):
|
|
||||||
key = item
|
|
||||||
if item[0] == "_":
|
|
||||||
key = 'zzz' + item
|
|
||||||
return key
|
|
||||||
|
|
||||||
|
|
||||||
# Create a list of prefixes for user selection
|
|
||||||
raw_prefix_list = [
|
|
||||||
('Ampersand',u'&'),
|
|
||||||
('Angle left double',u'\u00ab'),
|
|
||||||
('Angle left',u'\u2039'),
|
|
||||||
('Angle right double',u'\u00bb'),
|
|
||||||
('Angle right',u'\u203a'),
|
|
||||||
('Arrow carriage return',u'\u21b5'),
|
|
||||||
('Arrow double',u'\u2194'),
|
|
||||||
('Arrow down',u'\u2193'),
|
|
||||||
('Arrow left',u'\u2190'),
|
|
||||||
('Arrow right',u'\u2192'),
|
|
||||||
('Arrow up',u'\u2191'),
|
|
||||||
('Asterisk',u'*'),
|
|
||||||
('At sign',u'@'),
|
|
||||||
('Bullet smallest',u'\u22c5'),
|
|
||||||
('Bullet small',u'\u00b7'),
|
|
||||||
('Bullet',u'\u2022'),
|
|
||||||
('Cards clubs',u'\u2663'),
|
|
||||||
('Cards diamonds',u'\u2666'),
|
|
||||||
('Cards hearts',u'\u2665'),
|
|
||||||
('Cards spades',u'\u2660'),
|
|
||||||
('Caret',u'^'),
|
|
||||||
('Checkmark',u'\u2713'),
|
|
||||||
('Copyright circle c',u'\u00a9'),
|
|
||||||
('Copyright circle r',u'\u00ae'),
|
|
||||||
('Copyright trademark',u'\u2122'),
|
|
||||||
('Currency cent',u'\u00a2'),
|
|
||||||
('Currency dollar',u'$'),
|
|
||||||
('Currency euro',u'\u20ac'),
|
|
||||||
('Currency pound',u'\u00a3'),
|
|
||||||
('Currency yen',u'\u00a5'),
|
|
||||||
('Dagger double',u'\u2021'),
|
|
||||||
('Dagger',u'\u2020'),
|
|
||||||
('Degree',u'\u00b0'),
|
|
||||||
('Dots3',u'\u2234'),
|
|
||||||
('Hash',u'#'),
|
|
||||||
('Infinity',u'\u221e'),
|
|
||||||
('Lozenge',u'\u25ca'),
|
|
||||||
('Math divide',u'\u00f7'),
|
|
||||||
('Math empty',u'\u2205'),
|
|
||||||
('Math equals',u'='),
|
|
||||||
('Math minus',u'\u2212'),
|
|
||||||
('Math plus circled',u'\u2295'),
|
|
||||||
('Math times circled',u'\u2297'),
|
|
||||||
('Math times',u'\u00d7'),
|
|
||||||
('O slash',u'\u00d8'),
|
|
||||||
('Paragraph',u'\u00b6'),
|
|
||||||
('Percent',u'%'),
|
|
||||||
('Plus-or-minus',u'\u00b1'),
|
|
||||||
('Plus',u'+'),
|
|
||||||
('Punctuation colon',u':'),
|
|
||||||
('Punctuation colon-semi',u';'),
|
|
||||||
('Punctuation exclamation',u'!'),
|
|
||||||
('Punctuation question',u'?'),
|
|
||||||
('Punctuation period',u'.'),
|
|
||||||
('Punctuation slash back',u'\\'),
|
|
||||||
('Punctuation slash forward',u'/'),
|
|
||||||
('Section',u'\u00a7'),
|
|
||||||
('Tilde',u'~'),
|
|
||||||
('Vertical bar',u'|'),
|
|
||||||
('Vertical bar broken',u'\u00a6'),
|
|
||||||
('_0',u'0'),
|
|
||||||
('_1',u'1'),
|
|
||||||
('_2',u'2'),
|
|
||||||
('_3',u'3'),
|
|
||||||
('_4',u'4'),
|
|
||||||
('_5',u'5'),
|
|
||||||
('_6',u'6'),
|
|
||||||
('_7',u'7'),
|
|
||||||
('_8',u'8'),
|
|
||||||
('_9',u'9'),
|
|
||||||
('_A',u'A'),
|
|
||||||
('_B',u'B'),
|
|
||||||
('_C',u'C'),
|
|
||||||
('_D',u'D'),
|
|
||||||
('_E',u'E'),
|
|
||||||
('_F',u'F'),
|
|
||||||
('_G',u'G'),
|
|
||||||
('_H',u'H'),
|
|
||||||
('_I',u'I'),
|
|
||||||
('_J',u'J'),
|
|
||||||
('_K',u'K'),
|
|
||||||
('_L',u'L'),
|
|
||||||
('_M',u'M'),
|
|
||||||
('_N',u'N'),
|
|
||||||
('_O',u'O'),
|
|
||||||
('_P',u'P'),
|
|
||||||
('_Q',u'Q'),
|
|
||||||
('_R',u'R'),
|
|
||||||
('_S',u'S'),
|
|
||||||
('_T',u'T'),
|
|
||||||
('_U',u'U'),
|
|
||||||
('_V',u'V'),
|
|
||||||
('_W',u'W'),
|
|
||||||
('_X',u'X'),
|
|
||||||
('_Y',u'Y'),
|
|
||||||
('_Z',u'Z'),
|
|
||||||
('_a',u'a'),
|
|
||||||
('_b',u'b'),
|
|
||||||
('_c',u'c'),
|
|
||||||
('_d',u'd'),
|
|
||||||
('_e',u'e'),
|
|
||||||
('_f',u'f'),
|
|
||||||
('_g',u'g'),
|
|
||||||
('_h',u'h'),
|
|
||||||
('_i',u'i'),
|
|
||||||
('_j',u'j'),
|
|
||||||
('_k',u'k'),
|
|
||||||
('_l',u'l'),
|
|
||||||
('_m',u'm'),
|
|
||||||
('_n',u'n'),
|
|
||||||
('_o',u'o'),
|
|
||||||
('_p',u'p'),
|
|
||||||
('_q',u'q'),
|
|
||||||
('_r',u'r'),
|
|
||||||
('_s',u's'),
|
|
||||||
('_t',u't'),
|
|
||||||
('_u',u'u'),
|
|
||||||
('_v',u'v'),
|
|
||||||
('_w',u'w'),
|
|
||||||
('_x',u'x'),
|
|
||||||
('_y',u'y'),
|
|
||||||
('_z',u'z'),
|
|
||||||
]
|
|
||||||
raw_prefix_list = sorted(raw_prefix_list, key=prefix_sorter)
|
|
||||||
self.prefixes = [x[1] for x in raw_prefix_list]
|
|
||||||
|
|
||||||
def prefix_rules_get_data(self):
|
|
||||||
data_items = []
|
|
||||||
for row in range(self.prefix_rules_tw.rowCount()):
|
|
||||||
data = self.prefix_rules_convert_row_to_data(row)
|
|
||||||
data_items.append(
|
|
||||||
{'ordinal':data['ordinal'],
|
|
||||||
'enabled':data['enabled'],
|
|
||||||
'name':data['name'],
|
|
||||||
'field':data['field'],
|
|
||||||
'pattern':data['pattern'],
|
|
||||||
'prefix':data['prefix']})
|
|
||||||
return data_items
|
|
||||||
|
|
||||||
def prefix_rules_initialize(self, prefix_rules):
|
|
||||||
# Assign icons to buttons, hook clicks
|
|
||||||
self.move_rule_up_tb.setToolTip('Move rule up')
|
|
||||||
self.move_rule_up_tb.setIcon(QIcon(I('arrow-up.png')))
|
|
||||||
self.move_rule_up_tb.clicked.connect(self.prefix_rules_move_row_up)
|
|
||||||
|
|
||||||
self.add_rule_tb.setToolTip('Add a new rule')
|
|
||||||
self.add_rule_tb.setIcon(QIcon(I('plus.png')))
|
|
||||||
self.add_rule_tb.clicked.connect(self.prefix_rules_add_row)
|
|
||||||
|
|
||||||
self.delete_rule_tb.setToolTip('Delete selected rule')
|
|
||||||
self.delete_rule_tb.setIcon(QIcon(I('list_remove.png')))
|
|
||||||
self.delete_rule_tb.clicked.connect(self.prefix_rules_delete_row)
|
|
||||||
|
|
||||||
self.move_rule_down_tb.setToolTip('Move rule down')
|
|
||||||
self.move_rule_down_tb.setIcon(QIcon(I('arrow-down.png')))
|
|
||||||
self.move_rule_down_tb.clicked.connect(self.prefix_rules_move_row_down)
|
|
||||||
|
|
||||||
# Configure the QTableWidget
|
|
||||||
# enabled/prefix/rule name/source field/pattern
|
|
||||||
self.prefix_rules_tw.clear()
|
|
||||||
header_labels = ['','Name','Prefix','Source','Pattern']
|
|
||||||
self.prefix_rules_tw.setColumnCount(len(header_labels))
|
|
||||||
self.prefix_rules_tw.setHorizontalHeaderLabels(header_labels)
|
|
||||||
self.prefix_rules_tw.setSortingEnabled(False)
|
|
||||||
self.prefix_rules_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
||||||
|
|
||||||
# Generate the prefix list
|
|
||||||
self.prefix_rules_generate_prefix_list()
|
|
||||||
|
|
||||||
# Populate the table
|
|
||||||
self.prefix_rules_populate(prefix_rules)
|
|
||||||
self.prefix_rules_tw.resizeColumnsToContents()
|
|
||||||
self.prefix_rules_resize_name(1.5)
|
|
||||||
self.prefix_rules_tw.horizontalHeader().setStretchLastSection(True)
|
|
||||||
|
|
||||||
def prefix_rules_move_row_down(self):
|
|
||||||
self.prefix_rules_tw.setFocus()
|
|
||||||
rows = self.prefix_rules_tw.selectionModel().selectedRows()
|
|
||||||
if len(rows) == 0:
|
|
||||||
return
|
|
||||||
last_sel_row = rows[-1].row()
|
|
||||||
if last_sel_row == self.prefix_rules_tw.rowCount() - 1:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.prefix_rules_tw.blockSignals(True)
|
|
||||||
for selrow in reversed(rows):
|
|
||||||
dest_row = selrow.row() + 1
|
|
||||||
src_row = selrow.row()
|
|
||||||
|
|
||||||
# Save the contents of the destination row
|
|
||||||
saved_data = self.prefix_rules_convert_row_to_data(dest_row)
|
|
||||||
|
|
||||||
# Remove the destination row
|
|
||||||
self.prefix_rules_tw.removeRow(dest_row)
|
|
||||||
|
|
||||||
# Insert a new row at the original location
|
|
||||||
self.prefix_rules_tw.insertRow(src_row)
|
|
||||||
|
|
||||||
# Populate it with the saved data
|
|
||||||
self.prefix_rules_populate_table_row(src_row, saved_data)
|
|
||||||
self.blockSignals(False)
|
|
||||||
scroll_to_row = last_sel_row + 1
|
|
||||||
if scroll_to_row < self.prefix_rules_tw.rowCount() - 1:
|
|
||||||
scroll_to_row = scroll_to_row + 1
|
|
||||||
self.prefix_rules_tw.scrollToItem(self.prefix_rules_tw.item(scroll_to_row, 0))
|
|
||||||
|
|
||||||
def prefix_rules_move_row_up(self):
|
|
||||||
self.prefix_rules_tw.setFocus()
|
|
||||||
rows = self.prefix_rules_tw.selectionModel().selectedRows()
|
|
||||||
if len(rows) == 0:
|
|
||||||
return
|
|
||||||
first_sel_row = rows[0].row()
|
|
||||||
if first_sel_row <= 0:
|
|
||||||
return
|
|
||||||
self.prefix_rules_tw.blockSignals(True)
|
|
||||||
for selrow in rows:
|
|
||||||
# Save the row above
|
|
||||||
saved_data = self.prefix_rules_convert_row_to_data(selrow.row() - 1)
|
|
||||||
|
|
||||||
# Add a row below us with the source data
|
|
||||||
self.prefix_rules_tw.insertRow(selrow.row() + 1)
|
|
||||||
self.prefix_rules_populate_table_row(selrow.row() + 1, saved_data)
|
|
||||||
|
|
||||||
# Delete the row above
|
|
||||||
self.prefix_rules_tw.removeRow(selrow.row() - 1)
|
|
||||||
self.blockSignals(False)
|
|
||||||
|
|
||||||
scroll_to_row = first_sel_row - 1
|
|
||||||
if scroll_to_row > 0:
|
|
||||||
scroll_to_row = scroll_to_row - 1
|
|
||||||
self.prefix_rules_tw.scrollToItem(self.prefix_rules_tw.item(scroll_to_row, 0))
|
|
||||||
|
|
||||||
def prefix_rules_populate(self,rules):
|
|
||||||
# Format of rules list is different if default values vs retrieved JSON
|
|
||||||
# Hack to normalize list style
|
|
||||||
if type(rules[0]) is list:
|
|
||||||
rules = rules[0]
|
|
||||||
self.prefix_rules_tw.setFocus()
|
|
||||||
rules = sorted(rules, key=lambda k: k['ordinal'])
|
|
||||||
for row, rule in enumerate(rules):
|
|
||||||
self.prefix_rules_tw.insertRow(row)
|
|
||||||
self.prefix_rules_select_and_scroll_to_row(row)
|
|
||||||
self.prefix_rules_populate_table_row(row, rule)
|
|
||||||
self.prefix_rules_tw.selectRow(0)
|
|
||||||
|
|
||||||
def prefix_rules_populate_table_row(self, row, data):
|
|
||||||
|
|
||||||
def set_prefix_field_in_row(row, col, field=''):
|
|
||||||
prefix_combo = PrefixRulesComboBox(self, self.prefixes, field)
|
|
||||||
self.prefix_rules_tw.setCellWidget(row, col, prefix_combo)
|
|
||||||
|
|
||||||
def set_rule_name_in_row(row, col, name=''):
|
|
||||||
rule_name = QLineEdit(name)
|
|
||||||
rule_name.home(False)
|
|
||||||
rule_name.editingFinished.connect(self.prefix_rules_rule_name_edited)
|
|
||||||
self.prefix_rules_tw.setCellWidget(row, col, rule_name)
|
|
||||||
|
|
||||||
def set_source_field_in_row(row, col, field=''):
|
|
||||||
source_combo = PrefixRulesComboBox(self, sorted(self.eligible_custom_fields.keys(), key=sort_key), field)
|
|
||||||
source_combo.currentIndexChanged.connect(partial(self.prefix_rules_source_index_changed, source_combo, row))
|
|
||||||
#source_combo.currentIndexChanged.connect(self.prefix_rules_source_index_changed, source_combo, row)
|
|
||||||
self.prefix_rules_tw.setCellWidget(row, col, source_combo)
|
|
||||||
return source_combo
|
|
||||||
|
|
||||||
|
|
||||||
# Entry point
|
|
||||||
self.prefix_rules_tw.blockSignals(True)
|
|
||||||
#print("prefix_rules_populate_table_row processing rule:\n%s\n" % data)
|
|
||||||
|
|
||||||
# Column 0: Enabled
|
|
||||||
self.prefix_rules_tw.setItem(row, 0, CheckableTableWidgetItem(data['enabled']))
|
|
||||||
|
|
||||||
# Column 1: Rule name
|
|
||||||
#rule_name = QTableWidgetItem(data['name'])
|
|
||||||
#self.prefix_rules_tw.setItem(row, 1, rule_name)
|
|
||||||
set_rule_name_in_row(row, 1, name=data['name'])
|
|
||||||
|
|
||||||
# Column 2: Prefix
|
|
||||||
set_prefix_field_in_row(row, 2, field=data['prefix'])
|
|
||||||
|
|
||||||
# Column 3: Source field
|
|
||||||
source_combo = set_source_field_in_row(row, 3, field=data['field'])
|
|
||||||
|
|
||||||
# Column 4: Pattern
|
|
||||||
# The contents of the Pattern field is driven by the Source field
|
|
||||||
self.prefix_rules_source_index_changed(source_combo, row, 4, pattern=data['pattern'])
|
|
||||||
|
|
||||||
self.prefix_rules_tw.blockSignals(False)
|
|
||||||
|
|
||||||
def prefix_rules_resize_name(self, scale):
|
|
||||||
current_width = self.prefix_rules_tw.columnWidth(1)
|
|
||||||
self.prefix_rules_tw.setColumnWidth(1, min(225,int(current_width * scale)))
|
|
||||||
|
|
||||||
def prefix_rules_rule_name_edited(self):
|
|
||||||
current_row = self.prefix_rules_tw.currentRow()
|
|
||||||
self.prefix_rules_tw.cellWidget(current_row,1).home(False)
|
|
||||||
self.prefix_rules_tw.setFocus()
|
|
||||||
self.prefix_rules_select_and_scroll_to_row(current_row)
|
|
||||||
|
|
||||||
def prefix_rules_select_and_scroll_to_row(self, row):
|
|
||||||
self.prefix_rules_tw.selectRow(row)
|
|
||||||
self.prefix_rules_tw.scrollToItem(self.prefix_rules_tw.currentItem())
|
|
||||||
|
|
||||||
def prefix_rules_source_index_changed(self, combo, row, col, pattern=''):
|
|
||||||
# Populate the Pattern field based upon the Source field
|
|
||||||
|
|
||||||
source_field = str(combo.currentText())
|
|
||||||
if source_field == '':
|
|
||||||
values = []
|
|
||||||
elif source_field == 'Tags':
|
|
||||||
values = sorted(self.db.all_tags(), key=sort_key)
|
|
||||||
else:
|
|
||||||
if self.eligible_custom_fields[source_field]['datatype'] in ['enumeration', 'text']:
|
|
||||||
values = self.db.all_custom(self.db.field_metadata.key_to_label(
|
|
||||||
self.eligible_custom_fields[source_field]['field']))
|
|
||||||
values = sorted(values, key=sort_key)
|
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['bool']:
|
|
||||||
values = ['True','False','unspecified']
|
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['datetime']:
|
|
||||||
values = ['any date','unspecified']
|
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['composite']:
|
|
||||||
values = ['any value','unspecified']
|
|
||||||
|
|
||||||
values_combo = PrefixRulesComboBox(self, values, pattern)
|
|
||||||
self.prefix_rules_tw.setCellWidget(row, 4, values_combo)
|
|
||||||
|
|
||||||
|
|
||||||
def read_source_field_changed(self,new_index):
|
def read_source_field_changed(self,new_index):
|
||||||
'''
|
'''
|
||||||
Process changes in the read_source_field combo box
|
Process changes in the read_source_field combo box
|
||||||
@ -887,3 +503,463 @@ class PrefixRulesComboBox(NoWheelComboBox):
|
|||||||
self.setCurrentIndex(idx)
|
self.setCurrentIndex(idx)
|
||||||
else:
|
else:
|
||||||
self.setCurrentIndex(0)
|
self.setCurrentIndex(0)
|
||||||
|
|
||||||
|
class GenericRulesTable(QTableWidget):
|
||||||
|
'''
|
||||||
|
Generic methods for managing rows
|
||||||
|
Add QTableWidget, controls to parent QGroupBox
|
||||||
|
placeholders for basic methods to be overriden
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, parent_gb_hl, object_name, prefix_rules, eligible_custom_fields, db):
|
||||||
|
self.prefix_rules = prefix_rules
|
||||||
|
self.eligible_custom_fields = eligible_custom_fields
|
||||||
|
self.db = db
|
||||||
|
QTableWidget.__init__(self)
|
||||||
|
self.setObjectName(object_name)
|
||||||
|
self.layout = parent_gb_hl
|
||||||
|
|
||||||
|
# Add ourselves to the layout
|
||||||
|
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
|
||||||
|
self.setSizePolicy(sizePolicy)
|
||||||
|
self.setMaximumSize(QSize(16777215, 118))
|
||||||
|
self.setColumnCount(0)
|
||||||
|
self.setRowCount(0)
|
||||||
|
self.layout.addWidget(self)
|
||||||
|
|
||||||
|
|
||||||
|
self._init_table_widget()
|
||||||
|
self._init_controls()
|
||||||
|
self._initialize()
|
||||||
|
|
||||||
|
def _init_controls(self):
|
||||||
|
# Add the control set
|
||||||
|
vbl = QVBoxLayout()
|
||||||
|
self.move_rule_up_tb = QToolButton()
|
||||||
|
self.move_rule_up_tb.setObjectName("move_rule_up_tb")
|
||||||
|
self.move_rule_up_tb.setToolTip('Move rule up')
|
||||||
|
self.move_rule_up_tb.setIcon(QIcon(I('arrow-up.png')))
|
||||||
|
self.move_rule_up_tb.clicked.connect(self.move_row_up)
|
||||||
|
vbl.addWidget(self.move_rule_up_tb)
|
||||||
|
|
||||||
|
self.add_rule_tb = QToolButton()
|
||||||
|
self.add_rule_tb.setObjectName("add_rule_tb")
|
||||||
|
self.add_rule_tb.setToolTip('Add a new rule')
|
||||||
|
self.add_rule_tb.setIcon(QIcon(I('plus.png')))
|
||||||
|
self.add_rule_tb.clicked.connect(self.add_row)
|
||||||
|
vbl.addWidget(self.add_rule_tb)
|
||||||
|
|
||||||
|
self.delete_rule_tb = QToolButton()
|
||||||
|
self.delete_rule_tb.setObjectName("delete_rule_tb")
|
||||||
|
self.delete_rule_tb.setToolTip('Delete selected rule')
|
||||||
|
self.delete_rule_tb.setIcon(QIcon(I('list_remove.png')))
|
||||||
|
self.delete_rule_tb.clicked.connect(self.delete_row)
|
||||||
|
vbl.addWidget(self.delete_rule_tb)
|
||||||
|
|
||||||
|
self.move_rule_down_tb = QToolButton()
|
||||||
|
self.move_rule_down_tb.setObjectName("move_rule_down_tb")
|
||||||
|
self.move_rule_down_tb.setToolTip('Move rule down')
|
||||||
|
self.move_rule_down_tb.setIcon(QIcon(I('arrow-down.png')))
|
||||||
|
self.move_rule_down_tb.clicked.connect(self.move_row_down)
|
||||||
|
vbl.addWidget(self.move_rule_down_tb)
|
||||||
|
|
||||||
|
self.layout.addLayout(vbl)
|
||||||
|
|
||||||
|
def _init_table_widget(self):
|
||||||
|
'''
|
||||||
|
Override this in the specific instance
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
'''
|
||||||
|
Override this in the specific instance
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_row(self):
|
||||||
|
self.setFocus()
|
||||||
|
row = self.currentRow() + 1
|
||||||
|
self.insertRow(row)
|
||||||
|
self.populate_table_row(row, self.create_blank_row_data())
|
||||||
|
self.select_and_scroll_to_row(row)
|
||||||
|
self.resizeColumnsToContents()
|
||||||
|
# Just in case table was empty
|
||||||
|
self.horizontalHeader().setStretchLastSection(True)
|
||||||
|
|
||||||
|
def convert_row_to_data(self):
|
||||||
|
'''
|
||||||
|
override
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_blank_row_data(self):
|
||||||
|
'''
|
||||||
|
ovverride
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def delete_row(self):
|
||||||
|
self.setFocus()
|
||||||
|
rows = self.selectionModel().selectedRows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
message = '<p>Are you sure you want to delete this rule?'
|
||||||
|
if len(rows) > 1:
|
||||||
|
message = '<p>Are you sure you want to delete the %d selected rules?'%len(rows)
|
||||||
|
if not question_dialog(self, _('Are you sure?'), message, show_copy_button=False):
|
||||||
|
return
|
||||||
|
first_sel_row = self.currentRow()
|
||||||
|
for selrow in reversed(rows):
|
||||||
|
self.removeRow(selrow.row())
|
||||||
|
if first_sel_row < self.rowCount():
|
||||||
|
self.select_and_scroll_to_row(first_sel_row)
|
||||||
|
elif self.rowCount() > 0:
|
||||||
|
self.select_and_scroll_to_row(first_sel_row - 1)
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def move_row_down(self):
|
||||||
|
self.setFocus()
|
||||||
|
rows = self.selectionModel().selectedRows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
last_sel_row = rows[-1].row()
|
||||||
|
if last_sel_row == self.rowCount() - 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.blockSignals(True)
|
||||||
|
for selrow in reversed(rows):
|
||||||
|
dest_row = selrow.row() + 1
|
||||||
|
src_row = selrow.row()
|
||||||
|
|
||||||
|
# Save the contents of the destination row
|
||||||
|
saved_data = self.convert_row_to_data(dest_row)
|
||||||
|
|
||||||
|
# Remove the destination row
|
||||||
|
self.removeRow(dest_row)
|
||||||
|
|
||||||
|
# Insert a new row at the original location
|
||||||
|
self.insertRow(src_row)
|
||||||
|
|
||||||
|
# Populate it with the saved data
|
||||||
|
self.populate_table_row(src_row, saved_data)
|
||||||
|
self.blockSignals(False)
|
||||||
|
scroll_to_row = last_sel_row + 1
|
||||||
|
if scroll_to_row < self.rowCount() - 1:
|
||||||
|
scroll_to_row = scroll_to_row + 1
|
||||||
|
self.scrollToItem(self.item(scroll_to_row, 0))
|
||||||
|
|
||||||
|
def move_row_up(self):
|
||||||
|
self.setFocus()
|
||||||
|
rows = self.selectionModel().selectedRows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
first_sel_row = rows[0].row()
|
||||||
|
if first_sel_row <= 0:
|
||||||
|
return
|
||||||
|
self.blockSignals(True)
|
||||||
|
for selrow in rows:
|
||||||
|
# Save the row above
|
||||||
|
saved_data = self.convert_row_to_data(selrow.row() - 1)
|
||||||
|
|
||||||
|
# Add a row below us with the source data
|
||||||
|
self.insertRow(selrow.row() + 1)
|
||||||
|
self.populate_table_row(selrow.row() + 1, saved_data)
|
||||||
|
|
||||||
|
# Delete the row above
|
||||||
|
self.removeRow(selrow.row() - 1)
|
||||||
|
self.blockSignals(False)
|
||||||
|
|
||||||
|
scroll_to_row = first_sel_row - 1
|
||||||
|
if scroll_to_row > 0:
|
||||||
|
scroll_to_row = scroll_to_row - 1
|
||||||
|
self.scrollToItem(self.item(scroll_to_row, 0))
|
||||||
|
|
||||||
|
def populate_table_row(self):
|
||||||
|
'''
|
||||||
|
override
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
class PrefixRules(GenericRulesTable):
|
||||||
|
|
||||||
|
def _init_table_widget(self):
|
||||||
|
header_labels = ['','Name','Prefix','Source','Pattern']
|
||||||
|
self.setColumnCount(len(header_labels))
|
||||||
|
self.setHorizontalHeaderLabels(header_labels)
|
||||||
|
self.setSortingEnabled(False)
|
||||||
|
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
|
||||||
|
def _initialize(self):
|
||||||
|
self.generate_prefix_list()
|
||||||
|
self.populate()
|
||||||
|
self.resizeColumnsToContents()
|
||||||
|
self.resize_name(1.5)
|
||||||
|
self.horizontalHeader().setStretchLastSection(True)
|
||||||
|
|
||||||
|
def convert_row_to_data(self, row):
|
||||||
|
data = self.create_blank_row_data()
|
||||||
|
data['ordinal'] = row
|
||||||
|
data['enabled'] = self.item(row,0).checkState() == Qt.Checked
|
||||||
|
data['name'] = unicode(self.cellWidget(row,1).text()).strip()
|
||||||
|
data['prefix'] = unicode(self.cellWidget(row,2).currentText()).strip()
|
||||||
|
data['field'] = unicode(self.cellWidget(row,3).currentText()).strip()
|
||||||
|
data['pattern'] = unicode(self.cellWidget(row,4).currentText()).strip()
|
||||||
|
return data
|
||||||
|
|
||||||
|
def create_blank_row_data(self):
|
||||||
|
data = {}
|
||||||
|
data['ordinal'] = -1
|
||||||
|
data['enabled'] = False
|
||||||
|
data['name'] = 'New rule'
|
||||||
|
data['field'] = ''
|
||||||
|
data['pattern'] = ''
|
||||||
|
data['prefix'] = ''
|
||||||
|
return data
|
||||||
|
|
||||||
|
def generate_prefix_list(self):
|
||||||
|
def prefix_sorter(item):
|
||||||
|
key = item
|
||||||
|
if item[0] == "_":
|
||||||
|
key = 'zzz' + item
|
||||||
|
return key
|
||||||
|
|
||||||
|
# Create a list of prefixes for user selection
|
||||||
|
raw_prefix_list = [
|
||||||
|
('Ampersand',u'&'),
|
||||||
|
('Angle left double',u'\u00ab'),
|
||||||
|
('Angle left',u'\u2039'),
|
||||||
|
('Angle right double',u'\u00bb'),
|
||||||
|
('Angle right',u'\u203a'),
|
||||||
|
('Arrow carriage return',u'\u21b5'),
|
||||||
|
('Arrow double',u'\u2194'),
|
||||||
|
('Arrow down',u'\u2193'),
|
||||||
|
('Arrow left',u'\u2190'),
|
||||||
|
('Arrow right',u'\u2192'),
|
||||||
|
('Arrow up',u'\u2191'),
|
||||||
|
('Asterisk',u'*'),
|
||||||
|
('At sign',u'@'),
|
||||||
|
('Bullet smallest',u'\u22c5'),
|
||||||
|
('Bullet small',u'\u00b7'),
|
||||||
|
('Bullet',u'\u2022'),
|
||||||
|
('Cards clubs',u'\u2663'),
|
||||||
|
('Cards diamonds',u'\u2666'),
|
||||||
|
('Cards hearts',u'\u2665'),
|
||||||
|
('Cards spades',u'\u2660'),
|
||||||
|
('Caret',u'^'),
|
||||||
|
('Checkmark',u'\u2713'),
|
||||||
|
('Copyright circle c',u'\u00a9'),
|
||||||
|
('Copyright circle r',u'\u00ae'),
|
||||||
|
('Copyright trademark',u'\u2122'),
|
||||||
|
('Currency cent',u'\u00a2'),
|
||||||
|
('Currency dollar',u'$'),
|
||||||
|
('Currency euro',u'\u20ac'),
|
||||||
|
('Currency pound',u'\u00a3'),
|
||||||
|
('Currency yen',u'\u00a5'),
|
||||||
|
('Dagger double',u'\u2021'),
|
||||||
|
('Dagger',u'\u2020'),
|
||||||
|
('Degree',u'\u00b0'),
|
||||||
|
('Dots3',u'\u2234'),
|
||||||
|
('Hash',u'#'),
|
||||||
|
('Infinity',u'\u221e'),
|
||||||
|
('Lozenge',u'\u25ca'),
|
||||||
|
('Math divide',u'\u00f7'),
|
||||||
|
('Math empty',u'\u2205'),
|
||||||
|
('Math equals',u'='),
|
||||||
|
('Math minus',u'\u2212'),
|
||||||
|
('Math plus circled',u'\u2295'),
|
||||||
|
('Math times circled',u'\u2297'),
|
||||||
|
('Math times',u'\u00d7'),
|
||||||
|
('O slash',u'\u00d8'),
|
||||||
|
('Paragraph',u'\u00b6'),
|
||||||
|
('Percent',u'%'),
|
||||||
|
('Plus-or-minus',u'\u00b1'),
|
||||||
|
('Plus',u'+'),
|
||||||
|
('Punctuation colon',u':'),
|
||||||
|
('Punctuation colon-semi',u';'),
|
||||||
|
('Punctuation exclamation',u'!'),
|
||||||
|
('Punctuation question',u'?'),
|
||||||
|
('Punctuation period',u'.'),
|
||||||
|
('Punctuation slash back',u'\\'),
|
||||||
|
('Punctuation slash forward',u'/'),
|
||||||
|
('Section',u'\u00a7'),
|
||||||
|
('Tilde',u'~'),
|
||||||
|
('Vertical bar',u'|'),
|
||||||
|
('Vertical bar broken',u'\u00a6'),
|
||||||
|
('_0',u'0'),
|
||||||
|
('_1',u'1'),
|
||||||
|
('_2',u'2'),
|
||||||
|
('_3',u'3'),
|
||||||
|
('_4',u'4'),
|
||||||
|
('_5',u'5'),
|
||||||
|
('_6',u'6'),
|
||||||
|
('_7',u'7'),
|
||||||
|
('_8',u'8'),
|
||||||
|
('_9',u'9'),
|
||||||
|
('_A',u'A'),
|
||||||
|
('_B',u'B'),
|
||||||
|
('_C',u'C'),
|
||||||
|
('_D',u'D'),
|
||||||
|
('_E',u'E'),
|
||||||
|
('_F',u'F'),
|
||||||
|
('_G',u'G'),
|
||||||
|
('_H',u'H'),
|
||||||
|
('_I',u'I'),
|
||||||
|
('_J',u'J'),
|
||||||
|
('_K',u'K'),
|
||||||
|
('_L',u'L'),
|
||||||
|
('_M',u'M'),
|
||||||
|
('_N',u'N'),
|
||||||
|
('_O',u'O'),
|
||||||
|
('_P',u'P'),
|
||||||
|
('_Q',u'Q'),
|
||||||
|
('_R',u'R'),
|
||||||
|
('_S',u'S'),
|
||||||
|
('_T',u'T'),
|
||||||
|
('_U',u'U'),
|
||||||
|
('_V',u'V'),
|
||||||
|
('_W',u'W'),
|
||||||
|
('_X',u'X'),
|
||||||
|
('_Y',u'Y'),
|
||||||
|
('_Z',u'Z'),
|
||||||
|
('_a',u'a'),
|
||||||
|
('_b',u'b'),
|
||||||
|
('_c',u'c'),
|
||||||
|
('_d',u'd'),
|
||||||
|
('_e',u'e'),
|
||||||
|
('_f',u'f'),
|
||||||
|
('_g',u'g'),
|
||||||
|
('_h',u'h'),
|
||||||
|
('_i',u'i'),
|
||||||
|
('_j',u'j'),
|
||||||
|
('_k',u'k'),
|
||||||
|
('_l',u'l'),
|
||||||
|
('_m',u'm'),
|
||||||
|
('_n',u'n'),
|
||||||
|
('_o',u'o'),
|
||||||
|
('_p',u'p'),
|
||||||
|
('_q',u'q'),
|
||||||
|
('_r',u'r'),
|
||||||
|
('_s',u's'),
|
||||||
|
('_t',u't'),
|
||||||
|
('_u',u'u'),
|
||||||
|
('_v',u'v'),
|
||||||
|
('_w',u'w'),
|
||||||
|
('_x',u'x'),
|
||||||
|
('_y',u'y'),
|
||||||
|
('_z',u'z'),
|
||||||
|
]
|
||||||
|
raw_prefix_list = sorted(raw_prefix_list, key=prefix_sorter)
|
||||||
|
self.prefix_list = [x[1] for x in raw_prefix_list]
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
data_items = []
|
||||||
|
for row in range(self.rowCount()):
|
||||||
|
data = self.convert_row_to_data(row)
|
||||||
|
data_items.append(
|
||||||
|
{'ordinal':data['ordinal'],
|
||||||
|
'enabled':data['enabled'],
|
||||||
|
'name':data['name'],
|
||||||
|
'field':data['field'],
|
||||||
|
'pattern':data['pattern'],
|
||||||
|
'prefix':data['prefix']})
|
||||||
|
return data_items
|
||||||
|
|
||||||
|
def populate(self):
|
||||||
|
# Format of rules list is different if default values vs retrieved JSON
|
||||||
|
# Hack to normalize list style
|
||||||
|
rules = self.prefix_rules
|
||||||
|
if type(rules[0]) is list:
|
||||||
|
rules = rules[0]
|
||||||
|
self.setFocus()
|
||||||
|
rules = sorted(rules, key=lambda k: k['ordinal'])
|
||||||
|
for row, rule in enumerate(rules):
|
||||||
|
self.insertRow(row)
|
||||||
|
self.select_and_scroll_to_row(row)
|
||||||
|
self.populate_table_row(row, rule)
|
||||||
|
self.selectRow(0)
|
||||||
|
|
||||||
|
def populate_table_row(self, row, data):
|
||||||
|
|
||||||
|
def set_prefix_field_in_row(row, col, field=''):
|
||||||
|
prefix_combo = PrefixRulesComboBox(self, self.prefix_list, field)
|
||||||
|
self.setCellWidget(row, col, prefix_combo)
|
||||||
|
|
||||||
|
def set_rule_name_in_row(row, col, name=''):
|
||||||
|
rule_name = QLineEdit(name)
|
||||||
|
rule_name.home(False)
|
||||||
|
rule_name.editingFinished.connect(self.rule_name_edited)
|
||||||
|
self.setCellWidget(row, col, rule_name)
|
||||||
|
|
||||||
|
def set_source_field_in_row(row, col, field=''):
|
||||||
|
source_combo = PrefixRulesComboBox(self, sorted(self.eligible_custom_fields.keys(), key=sort_key), field)
|
||||||
|
source_combo.currentIndexChanged.connect(partial(self.source_index_changed, source_combo, row))
|
||||||
|
self.setCellWidget(row, col, source_combo)
|
||||||
|
return source_combo
|
||||||
|
|
||||||
|
|
||||||
|
# Entry point
|
||||||
|
self.blockSignals(True)
|
||||||
|
#print("prefix_rules_populate_table_row processing rule:\n%s\n" % data)
|
||||||
|
|
||||||
|
# Column 0: Enabled
|
||||||
|
self.setItem(row, 0, CheckableTableWidgetItem(data['enabled']))
|
||||||
|
|
||||||
|
# Column 1: Rule name
|
||||||
|
#rule_name = QTableWidgetItem(data['name'])
|
||||||
|
set_rule_name_in_row(row, 1, name=data['name'])
|
||||||
|
|
||||||
|
# Column 2: Prefix
|
||||||
|
set_prefix_field_in_row(row, 2, field=data['prefix'])
|
||||||
|
|
||||||
|
# Column 3: Source field
|
||||||
|
source_combo = set_source_field_in_row(row, 3, field=data['field'])
|
||||||
|
|
||||||
|
# Column 4: Pattern
|
||||||
|
# The contents of the Pattern field is driven by the Source field
|
||||||
|
self.source_index_changed(source_combo, row, 4, pattern=data['pattern'])
|
||||||
|
|
||||||
|
self.blockSignals(False)
|
||||||
|
|
||||||
|
def resize_name(self, scale):
|
||||||
|
current_width = self.columnWidth(1)
|
||||||
|
self.setColumnWidth(1, min(225,int(current_width * scale)))
|
||||||
|
|
||||||
|
def rule_name_edited(self):
|
||||||
|
current_row = self.currentRow()
|
||||||
|
self.cellWidget(current_row,1).home(False)
|
||||||
|
self.setFocus()
|
||||||
|
self.select_and_scroll_to_row(current_row)
|
||||||
|
|
||||||
|
def select_and_scroll_to_row(self, row):
|
||||||
|
self.selectRow(row)
|
||||||
|
self.scrollToItem(self.currentItem())
|
||||||
|
|
||||||
|
def source_index_changed(self, combo, row, col, pattern=''):
|
||||||
|
# Populate the Pattern field based upon the Source field
|
||||||
|
|
||||||
|
source_field = str(combo.currentText())
|
||||||
|
if source_field == '':
|
||||||
|
values = []
|
||||||
|
elif source_field == 'Tags':
|
||||||
|
values = sorted(self.db.all_tags(), key=sort_key)
|
||||||
|
else:
|
||||||
|
if self.eligible_custom_fields[source_field]['datatype'] in ['enumeration', 'text']:
|
||||||
|
values = self.db.all_custom(self.db.field_metadata.key_to_label(
|
||||||
|
self.eligible_custom_fields[source_field]['field']))
|
||||||
|
values = sorted(values, key=sort_key)
|
||||||
|
elif self.eligible_custom_fields[source_field]['datatype'] in ['bool']:
|
||||||
|
values = ['True','False','unspecified']
|
||||||
|
elif self.eligible_custom_fields[source_field]['datatype'] in ['datetime']:
|
||||||
|
values = ['any date','unspecified']
|
||||||
|
elif self.eligible_custom_fields[source_field]['datatype'] in ['composite']:
|
||||||
|
values = ['any value','unspecified']
|
||||||
|
|
||||||
|
values_combo = PrefixRulesComboBox(self, values, pattern)
|
||||||
|
self.setCellWidget(row, 4, values_combo)
|
||||||
|
|
||||||
|
@ -327,7 +327,7 @@ Default: ~,Catalog</string>
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="prefixRules">
|
<widget class="QGroupBox" name="prefix_rules_gb">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@ -342,56 +342,7 @@ Default: ~,Catalog</string>
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="prefix_rules_gb_hl"/>
|
||||||
<item>
|
|
||||||
<widget class="QTableWidget" name="prefix_rules_tw">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>16777215</width>
|
|
||||||
<height>118</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="move_rule_up_tb">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="add_rule_tb">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="delete_rule_tb">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="move_rule_down_tb">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -47,28 +47,44 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
"of the conversion process a bug is occurring.\n"
|
"of the conversion process a bug is occurring.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--exclude-book-marker',
|
|
||||||
default=':',
|
|
||||||
dest='exclude_book_marker',
|
|
||||||
action = None,
|
|
||||||
help=_("#<custom field>:pattern specifying custom field/contents indicating book should be excluded.\n"
|
|
||||||
"For example: '#status:Archived' will exclude a book with a value of 'Archived' in the custom column 'status'.\n"
|
|
||||||
"Default: '%default'\n"
|
|
||||||
"Applies to ePub, MOBI output formats")),
|
|
||||||
Option('--exclude-genre',
|
Option('--exclude-genre',
|
||||||
default='\[.+\]',
|
default='\[.+\]',
|
||||||
dest='exclude_genre',
|
dest='exclude_genre',
|
||||||
action = None,
|
action = None,
|
||||||
help=_("Regex describing tags to exclude as genres.\n" "Default: '%default' excludes bracketed tags, e.g. '[<tag>]'\n"
|
help=_("Regex describing tags to exclude as genres.\n" "Default: '%default' excludes bracketed tags, e.g. '[<tag>]'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--exclude-tags',
|
|
||||||
default=('~,'+_('Catalog')),
|
# Option('--exclude-book-marker',
|
||||||
dest='exclude_tags',
|
# default=':',
|
||||||
|
# dest='exclude_book_marker',
|
||||||
|
# action = None,
|
||||||
|
# help=_("#<custom field>:pattern specifying custom field/contents indicating book should be excluded.\n"
|
||||||
|
# "For example: '#status:Archived' will exclude a book with a value of 'Archived' in the custom column 'status'.\n"
|
||||||
|
# "Default: '%default'\n"
|
||||||
|
# "Applies to ePub, MOBI output formats")),
|
||||||
|
# Option('--exclude-tags',
|
||||||
|
# default=('~,Catalog'),
|
||||||
|
# dest='exclude_tags',
|
||||||
|
# action = None,
|
||||||
|
# help=_("Comma-separated list of tag words indicating book should be excluded from output. "
|
||||||
|
# "For example: 'skip' will match 'skip this book' and 'Skip will like this'. "
|
||||||
|
# "Default:'%default'\n"
|
||||||
|
# "Applies to: ePub, MOBI output formats")),
|
||||||
|
|
||||||
|
Option('--exclusion-rules',
|
||||||
|
default="(('Excluded tags','Tags','~,Catalog'),)",
|
||||||
|
dest='exclusion_rules',
|
||||||
action=None,
|
action=None,
|
||||||
help=_("Comma-separated list of tag words indicating book should be excluded from output. "
|
help=_("Specifies the rules used to exclude books from the generated catalog.\n"
|
||||||
"For example: 'skip' will match 'skip this book' and 'Skip will like this'. "
|
"The model for an exclusion rule is either\n('<rule name>','Tags','<comma-separated list of tags>') or\n"
|
||||||
"Default: '%default'\n"
|
"('<rule name>','<custom column>','<pattern>').\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"For example:\n"
|
||||||
|
"(('Archived books','#status','Archived'),)\n"
|
||||||
|
"will exclude a book with a value of 'Archived' in the custom column 'status'.\n"
|
||||||
|
"When multiple rules are defined, all rules will be applied.\n"
|
||||||
|
"Default: \n" + '"' + '%default' + '"' + "\n"
|
||||||
|
"Applies to ePub, MOBI output formats")),
|
||||||
|
|
||||||
Option('--generate-authors',
|
Option('--generate-authors',
|
||||||
default=False,
|
default=False,
|
||||||
dest='generate_authors',
|
dest='generate_authors',
|
||||||
@ -142,7 +158,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
help=_("Specifies the rules used to include prefixes indicating read books, wishlist items and other user-specifed prefixes.\n"
|
help=_("Specifies the rules used to include prefixes indicating read books, wishlist items and other user-specifed prefixes.\n"
|
||||||
"The model for a prefix rule is ('<rule name>','<source field>','<pattern>','<prefix>').\n"
|
"The model for a prefix rule is ('<rule name>','<source field>','<pattern>','<prefix>').\n"
|
||||||
"When multiple rules are defined, the first matching rule will be used.\n"
|
"When multiple rules are defined, the first matching rule will be used.\n"
|
||||||
"Default: '%default'\n"
|
"Default:\n" + '"' + '%default' + '"' + "\n"
|
||||||
"Applies to ePub, MOBI output formats")),
|
"Applies to ePub, MOBI output formats")),
|
||||||
Option('--thumb-width',
|
Option('--thumb-width',
|
||||||
default='1.0',
|
default='1.0',
|
||||||
@ -285,6 +301,17 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
if len(rule) != 4:
|
if len(rule) != 4:
|
||||||
log.error("incorrect number of args for --prefix-rules: %s" % repr(rule))
|
log.error("incorrect number of args for --prefix-rules: %s" % repr(rule))
|
||||||
|
|
||||||
|
# eval exclusion_rules if passed from command line
|
||||||
|
if type(opts.exclusion_rules) is not tuple:
|
||||||
|
try:
|
||||||
|
opts.exclusion_rules = eval(opts.exclusion_rules)
|
||||||
|
except:
|
||||||
|
log.error("malformed --exclusion-rules: %s" % opts.exclusion_rules)
|
||||||
|
raise
|
||||||
|
for rule in opts.exclusion_rules:
|
||||||
|
if len(rule) != 3:
|
||||||
|
log.error("incorrect number of args for --exclusion-rules: %s" % repr(rule))
|
||||||
|
|
||||||
# Display opts
|
# Display opts
|
||||||
keys = opts_dict.keys()
|
keys = opts_dict.keys()
|
||||||
keys.sort()
|
keys.sort()
|
||||||
@ -292,6 +319,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
for key in keys:
|
for key in keys:
|
||||||
if key in ['catalog_title','authorClip','connected_kindle','descriptionClip',
|
if key in ['catalog_title','authorClip','connected_kindle','descriptionClip',
|
||||||
'exclude_book_marker','exclude_genre','exclude_tags',
|
'exclude_book_marker','exclude_genre','exclude_tags',
|
||||||
|
'exclusion_rules',
|
||||||
'header_note_source_field','merge_comments',
|
'header_note_source_field','merge_comments',
|
||||||
'output_profile','prefix_rules','read_book_marker',
|
'output_profile','prefix_rules','read_book_marker',
|
||||||
'search_text','sort_by','sort_descriptions_by_author','sync',
|
'search_text','sort_by','sort_descriptions_by_author','sync',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user