From b3ab68b0f5e3a51fd729d60b3202b6f731f357c9 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 31 Aug 2013 09:52:44 +0100 Subject: [PATCH] Validation in progress --- openlp/core/ui/formattingtagcontroller.py | 98 +++++++++++++++++++++ openlp/core/ui/formattingtagdialog.py | 66 -------------- openlp/core/ui/formattingtagform.py | 100 +++++++++------------- 3 files changed, 139 insertions(+), 125 deletions(-) create mode 100644 openlp/core/ui/formattingtagcontroller.py diff --git a/openlp/core/ui/formattingtagcontroller.py b/openlp/core/ui/formattingtagcontroller.py new file mode 100644 index 000000000..7e1131507 --- /dev/null +++ b/openlp/core/ui/formattingtagcontroller.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2013 Raoul Snyman # +# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are protected and included each time loaded. +Custom tags can be defined and saved. The Custom Tag arrays are saved in a pickle so QSettings works on them. Base Tags +cannot be changed. +""" + +import re +import cgi + +from openlp.core.lib import translate + + +class FormattingTagController(object): + """ + The :class:`FormattingTagController` manages the non UI functions . + """ + def __init__(self): + """ + Initiator + """ + self.html_tag_regex = re.compile(r'<(?:(?P/(?=[^\s/>]+>))?' + r'(?P[^\s/!\?>]+)(?:\s+[^\s=]+="[^"]*")*\s*(?P/)?' + r'|(?P!\[CDATA\[(?:(?!\]\]>).)*\]\])' + r'|(?P\?(?:(?!\?>).)*\?)' + r'|(?P!--(?:(?!-->).)*--))>', re.UNICODE) + self.html_regex = re.compile(r'^(?:[^<>]*%s)*[^<>]*$' % self.html_tag_regex.pattern) + + def pre_save(self): + self.custom_tags = [] + + def validate_for_save(self, desc, tag, start_html, end_html): + if not desc: + pass + print desc + print self.start_html_to_end_html(start_html) + + def html_start_validate(self, start, end): + pass + + def _strip(self, tag): + """ + Remove tag wrappers for editing. + """ + tag = tag.replace(u'{', u'') + tag = tag.replace(u'}', u'') + return tag + + def start_html_to_end_html(self, start_html): + """ + Return the end HTML for a given start HTML or None if invalid. + """ + end_tags = [] + match = self.html_regex.match(start_html) + if match: + match = self.html_tag_regex.search(start_html) + while match: + if match.group(u'tag'): + tag = match.group(u'tag').lower() + if match.group(u'close'): + if match.group(u'empty') or not end_tags or end_tags.pop() != tag: + return + elif not match.group(u'empty'): + end_tags.append(tag) + match = self.html_tag_regex.search(start_html, match.end()) + return u''.join(map(lambda tag: u'' % tag, reversed(end_tags))) + + def start_tag_changed(self, start_html, end_html): + end = self.start_html_to_end_html(start_html) + if not end_html: + return None, end \ No newline at end of file diff --git a/openlp/core/ui/formattingtagdialog.py b/openlp/core/ui/formattingtagdialog.py index cdd1d6edc..20762895f 100644 --- a/openlp/core/ui/formattingtagdialog.py +++ b/openlp/core/ui/formattingtagdialog.py @@ -90,59 +90,6 @@ class Ui_FormattingTagDialog(object): item = QtGui.QTableWidgetItem() self.tag_table_widget.setHorizontalHeaderItem(3, item) self.list_data_grid_layout.addWidget(self.tag_table_widget) - - - #self.horizontal_layout = QtGui.QHBoxLayout() - #self.horizontal_layout.setObjectName(u'horizontal_layout') - #spacer_item = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - #self.horizontal_layout.addItem(spacer_item) - #self.delete_push_button = QtGui.QPushButton(formatting_tag_dialog) - #self.delete_push_button.setObjectName(u'delete_push_button') - #self.horizontal_layout.addWidget(self.delete_push_button) - #self.list_data_grid_layout.addLayout(self.horizontal_layout, 1, 0, 1, 1) - #self.edit_group_box = QtGui.QGroupBox(formatting_tag_dialog) - #self.edit_group_box.setObjectName(u'edit_group_box') - #self.data_grid_layout = QtGui.QGridLayout(self.edit_group_box) - #self.data_grid_layout.setObjectName(u'data_grid_layout') - #self.description_label = QtGui.QLabel(self.edit_group_box) - #self.description_label.setAlignment(QtCore.Qt.AlignCenter) - #self.description_label.setObjectName(u'description_label') - #self.data_grid_layout.addWidget(self.description_label, 0, 0, 1, 1) - #self.description_line_edit = QtGui.QLineEdit(self.edit_group_box) - #self.description_line_edit.setObjectName(u'description_line_edit') - #self.data_grid_layout.addWidget(self.description_line_edit, 0, 1, 2, 1) - #self.new_push_button = QtGui.QPushButton(self.edit_group_box) - #self.new_push_button.setObjectName(u'new_push_button') - #self.data_grid_layout.addWidget(self.new_push_button, 0, 2, 2, 1) - #self.tag_label = QtGui.QLabel(self.edit_group_box) - #self.tag_label.setAlignment(QtCore.Qt.AlignCenter) - #self.tag_label.setObjectName(u'tag_label') - #self.data_grid_layout.addWidget(self.tag_label, 2, 0, 1, 1) - #self.tag_line_edit = QtGui.QLineEdit(self.edit_group_box) - #self.tag_line_edit.setMaximumSize(QtCore.QSize(50, 16777215)) - #self.tag_line_edit.setMaxLength(5) - #self.tag_line_edit.setObjectName(u'tag_line_edit') - #self.data_grid_layout.addWidget(self.tag_line_edit, 2, 1, 1, 1) - #self.start_tag_label = QtGui.QLabel(self.edit_group_box) - #self.start_tag_label.setAlignment(QtCore.Qt.AlignCenter) - #self.start_tag_label.setObjectName(u'start_tag_label') - #self.data_grid_layout.addWidget(self.start_tag_label, 3, 0, 1, 1) - #self.start_tag_line_edit = QtGui.QLineEdit(self.edit_group_box) - #self.start_tag_line_edit.setObjectName(u'start_tag_line_edit') - #self.data_grid_layout.addWidget(self.start_tag_line_edit, 3, 1, 1, 1) - #self.end_tag_label = QtGui.QLabel(self.edit_group_box) - #self.end_tag_label.setAlignment(QtCore.Qt.AlignCenter) - #self.end_tag_label.setObjectName(u'end_tag_label') - #self.data_grid_layout.addWidget(self.end_tag_label, 4, 0, 1, 1) - #self.end_tag_line_edit = QtGui.QLineEdit(self.edit_group_box) - #self.end_tag_line_edit.setObjectName(u'end_tag_line_edit') - #self.data_grid_layout.addWidget(self.end_tag_line_edit, 4, 1, 1, 1) - #self.save_push_button = QtGui.QPushButton(self.edit_group_box) - #self.save_push_button.setObjectName(u'save_push_button') - #self.data_grid_layout.addWidget(self.save_push_button, 4, 2, 1, 1) - #self.list_data_grid_layout.addWidget(self.edit_group_box, 2, 0, 1, 1) - - self.edit_button_layout = QtGui.QHBoxLayout() self.new_button = QtGui.QPushButton(formatting_tag_dialog) self.new_button.setIcon(build_icon(u':/general/general_new.png')) @@ -162,13 +109,6 @@ class Ui_FormattingTagDialog(object): self.restore_button.setIcon(build_icon(u':/general/general_revert.png')) self.restore_button.setObjectName(u'restore_button') self.list_data_grid_layout.addWidget(self.button_box) - - #self.button_box = create_button_box(formatting_tag_dialog, u'button_box', [u'close']) - #self.list_data_grid_layout.addWidget(self.button_box, 5, 0, 1, 1) - #self.delete_push_button = QtGui.QPushButton(formatting_tag_dialog) - #self.delete_push_button.setObjectName(u'delete_push_button') - #self.list_data_grid_layout.addWidget(self.delete_push_button, 5, 0, 1, 1) - self.retranslateUi(formatting_tag_dialog) def retranslateUi(self, formatting_tag_dialog): @@ -176,12 +116,6 @@ class Ui_FormattingTagDialog(object): Translate the UI on the fly """ formatting_tag_dialog.setWindowTitle(translate('OpenLP.FormattingTagDialog', 'Configure Formatting Tags')) - #self.edit_group_box.setTitle(translate('OpenLP.FormattingTagDialog', 'Edit Selection')) - #self.save_push_button.setText(translate('OpenLP.FormattingTagDialog', 'Save')) - #self.description_label.setText(translate('OpenLP.FormattingTagDialog', 'Description')) - #self.tag_label.setText(translate('OpenLP.FormattingTagDialog', 'Tag')) - #self.start_tag_label.setText(translate('OpenLP.FormattingTagDialog', 'Start HTML')) - #self.end_tag_label.setText(translate('OpenLP.FormattingTagDialog', 'End HTML')) self.delete_button.setText(UiStrings().Delete) self.new_button.setText(UiStrings().New) self.tag_table_widget_read_label.setText(translate('OpenLP.FormattingTagDialog', 'Static Formatting')) diff --git a/openlp/core/ui/formattingtagform.py b/openlp/core/ui/formattingtagform.py index a9828d228..5b65b48d4 100644 --- a/openlp/core/ui/formattingtagform.py +++ b/openlp/core/ui/formattingtagform.py @@ -32,7 +32,6 @@ Custom tags can be defined and saved. The Custom Tag arrays are saved in a pickl cannot be changed. """ -import re import cgi from PyQt4 import QtGui, QtCore @@ -40,6 +39,7 @@ from PyQt4 import QtGui, QtCore from openlp.core.lib import FormattingTags, translate from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.formattingtagdialog import Ui_FormattingTagDialog +from openlp.core.ui.formattingtagcontroller import FormattingTagController class EDITCOLUMN(object): @@ -52,7 +52,7 @@ class EDITCOLUMN(object): EndHtml = 3 -class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): +class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog, FormattingTagController): """ The :class:`FormattingTagForm` manages the settings tab . """ @@ -60,17 +60,12 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): """ Constructor """ - QtGui.QDialog.__init__(self, parent) + super(FormattingTagForm, self).__init__(parent) self.setupUi(self) - self.html_tag_regex = re.compile(r'<(?:(?P/(?=[^\s/>]+>))?' - r'(?P[^\s/!\?>]+)(?:\s+[^\s=]+="[^"]*")*\s*(?P/)?' - r'|(?P!\[CDATA\[(?:(?!\]\]>).)*\]\])' - r'|(?P\?(?:(?!\?>).)*\?)' - r'|(?P!--(?:(?!-->).)*--))>', re.UNICODE) - self.html_regex = re.compile(r'^(?:[^<>]*%s)*[^<>]*$' % self.html_tag_regex.pattern) + self.services = FormattingTagController() self.tag_table_widget.itemSelectionChanged.connect(self.on_row_selected) self.new_button.clicked.connect(self.on_new_clicked) - #self.save_push_button.clicked.connect(self.on_saved_clicked) + self.save_button.clicked.connect(self.on_saved_clicked) self.delete_button.clicked.connect(self.on_delete_clicked) self.tag_table_widget.currentCellChanged.connect(self.on_current_cell_changed) self.button_box.rejected.connect(self.close) @@ -103,8 +98,7 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): QtGui.QTableWidgetItem('n%s' % unicode(new_row))) self.tag_table_widget.setItem(new_row, 2, QtGui.QTableWidgetItem(translate('OpenLP.FormattingTagForm', ''))) - self.tag_table_widget.setItem(new_row, 3, - QtGui.QTableWidgetItem(translate('OpenLP.FormattingTagForm', ''))) + self.tag_table_widget.setItem(new_row, 3, QtGui.QTableWidgetItem(u"")) self.tag_table_widget.resizeRowsToContents() self.tag_table_widget.scrollToBottom() self.tag_table_widget.selectRow(new_row) @@ -121,26 +115,34 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): """ Update Custom Tag details if not duplicate and save the data. """ + count = 0 + self.services.pre_save() + while count < self.tag_table_widget.rowCount(): + result = self.services.validate_for_save(self.tag_table_widget.item(count, 0).text(), + self.tag_table_widget.item(count, 1).text(), self.tag_table_widget.item(count, 2).text(), + self.tag_table_widget.item(count, 3).text()) + count += 1 + html_expands = FormattingTags.get_html_tags() - if self.selected != -1: - html = html_expands[self.selected] - tag = self.tag_line_edit.text() - for linenumber, html1 in enumerate(html_expands): - if self._strip(html1[u'start tag']) == tag and linenumber != self.selected: - critical_error_message_box( - translate('OpenLP.FormattingTagForm', 'Update Error'), - translate('OpenLP.FormattingTagForm', 'Tag %s already defined.') % tag) - return - html[u'desc'] = self.description_line_edit.text() - html[u'start html'] = self.start_tag_line_edit.text() - html[u'end html'] = self.end_tag_line_edit.text() - html[u'start tag'] = u'{%s}' % tag - html[u'end tag'] = u'{/%s}' % tag - # Keep temporary tags when the user changes one. - html[u'temporary'] = False - self.selected = -1 - FormattingTags.save_html_tags() - self._reloadTable() + #if self.selected != -1: + # html = html_expands[self.selected] + # tag = self.tag_line_edit.text() + # for linenumber, html1 in enumerate(html_expands): + # if self._strip(html1[u'start tag']) == tag and linenumber != self.selected: + # critical_error_message_box( + # translate('OpenLP.FormattingTagForm', 'Update Error'), + # translate('OpenLP.FormattingTagForm', 'Tag %s already defined.') % tag) + # return + # html[u'desc'] = self.description_line_edit.text() + # html[u'start html'] = self.start_tag_line_edit.text() + # html[u'end html'] = self.end_tag_line_edit.text() + # html[u'start tag'] = u'{%s}' % tag + # html[u'end tag'] = u'{/%s}' % tag + # # Keep temporary tags when the user changes one. + # html[u'temporary'] = False + # self.selected = -1 + #FormattingTags.save_html_tags() + #self._reloadTable() def _reloadTable(self): """ @@ -166,7 +168,6 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): print self.tag_table_widget.rowCount(), html line = self.tag_table_widget.rowCount() self.tag_table_widget.setRowCount(line + 1) - self.tag_table_widget.setRowCount(self.tag_table_widget.rowCount() + 1) self.tag_table_widget.setItem(line, 0, QtGui.QTableWidgetItem(html[u'desc'])) self.tag_table_widget.setItem(line, 1, QtGui.QTableWidgetItem(self._strip(html[u'start tag']))) self.tag_table_widget.setItem(line, 2, QtGui.QTableWidgetItem(html[u'start html'])) @@ -182,8 +183,7 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): print cur_row, cur_col, pre_col, pre_col # only process for editable rows pre_row_item = self.tag_table_widget.item(pre_row, 0) - edit_item = None - if pre_row_item and (pre_row_item.flags() & QtCore.Qt.ItemIsEditable): + if pre_row_item: item = self.tag_table_widget.item(pre_row, pre_col) text = unicode(item.text()) if pre_col is EDITCOLUMN.Tag: @@ -209,25 +209,14 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): translate('OpenLP.FormattingTagForm', 'No tag name defined. Do you want to delete the whole tag?'), QtGui.QMessageBox.Yes|QtGui.QMessageBox.Discard|QtGui.QMessageBox.Cancel) - #if answer == QtGui.QMessageBox.Discard: - # item.setText(data.get(u'tag')) - #if answer == QtGui.QMessageBox.Cancel: - # edit_item = item - elif pre_row < self.tag_table_widget.rowCount() - 1: - self.tag_table_widget.removeRow(pre_row) - #elif pre_col is EDITCOLUMN.StartHtml: + elif pre_col is EDITCOLUMN.StartHtml: # HTML edited - #end_html = self.start_html_to_end_html(text) - #if end_html is not None: - # item.setToolTip(cgi.escape(text)) - ## if self.tag_table_widget.item(pre_row, 3) is None: - # self.tag_table_widget.setItem(pre_row, 3, QtGui.QTableWidgetItem(end_html)) - # else: - # self.tag_table_widget.item(pre_row, 3).setText(end_html) - # self.tag_table_widget.item(pre_row, 3).setToolTip(cgi.escape(end_html)) - # #data[u'html'] = text - # #pre_row_item.setData(QtCore.Qt.UserRole, data) - # # self.tag_table_widget.resizeRowsToContents() + item = self.tag_table_widget.item(pre_row, 3) + end_html = unicode(item.text()) + errors, tag = self.services.start_tag_changed(text, end_html) + if tag: + self.tag_table_widget.setItem(pre_row, 3, QtGui.QTableWidgetItem(tag)) + self.tag_table_widget.resizeRowsToContents() #if not edit_item: # # select the tag cell in a empty row # cur_row_item = self.tag_table_widget.item(cur_row, 0) @@ -242,10 +231,3 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): delete_enabled &= cur_row < self.tag_table_widget.rowCount() - 1 self.delete_button.setEnabled(delete_enabled) - def _strip(self, tag): - """ - Remove tag wrappers for editing. - """ - tag = tag.replace(u'{', u'') - tag = tag.replace(u'}', u'') - return tag