diff --git a/.bzrignore b/.bzrignore index 2620fea42..1d2bb8267 100644 --- a/.bzrignore +++ b/.bzrignore @@ -20,3 +20,4 @@ _eric4project openlp/core/resources.py.old *.qm resources/windows/warnOpenLP.txt +openlp.cfg diff --git a/openlp.pyw b/openlp.pyw index a39f6cf65..962109592 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -79,6 +79,8 @@ class OpenLP(QtGui.QApplication): class in order to provide the core of the application. """ + args = [] + def exec_(self): """ Override exec method to allow the shared memory to be released on exit @@ -92,7 +94,7 @@ class OpenLP(QtGui.QApplication): """ # On Windows, the args passed into the constructor are # ignored. Not very handy, so set the ones we want to use. - self.args = args + self.args.extend(args) # provide a listener for widgets to reqest a screen update. QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_process_events'), self.processEvents) @@ -125,6 +127,8 @@ class OpenLP(QtGui.QApplication): # now kill the splashscreen self.splash.finish(self.mainWindow) log.debug(u'Splashscreen closed') + # make sure Qt really display the splash screen + self.processEvents() self.mainWindow.repaint() self.processEvents() if not has_run_wizard: @@ -180,6 +184,18 @@ class OpenLP(QtGui.QApplication): """ self.restoreOverrideCursor() + def event(self, event): + """ + Enables direct file opening on OS X + """ + if event.type() == QtCore.QEvent.FileOpen: + file_name = event.file() + log.debug(u'Got open file event for %s!', file_name) + self.args.insert(0, unicode(file_name)) + return True + else: + return QtGui.QApplication.event(self, event) + def main(): """ The main function which parses command line options and then runs diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 7fbd5243c..f83e92de7 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -205,7 +205,7 @@ def clean_tags(text): text = text.replace(u'
', u'\n') text = text.replace(u'{br}', u'\n') text = text.replace(u' ', u' ') - for tag in DisplayTags.get_html_tags(): + for tag in FormattingTags.get_html_tags(): text = text.replace(tag[u'start tag'], u'') text = text.replace(tag[u'end tag'], u'') return text @@ -214,7 +214,7 @@ def expand_tags(text): """ Expand tags HTML for display """ - for tag in DisplayTags.get_html_tags(): + for tag in FormattingTags.get_html_tags(): text = text.replace(tag[u'start tag'], tag[u'start html']) text = text.replace(tag[u'end tag'], tag[u'end html']) return text @@ -233,9 +233,9 @@ def check_directory_exists(dir): except IOError: pass -from listwidgetwithdnd import ListWidgetWithDnD -from displaytags import DisplayTags from eventreceiver import Receiver +from listwidgetwithdnd import ListWidgetWithDnD +from formattingtags import FormattingTags from spelltextedit import SpellTextEdit from settingsmanager import SettingsManager from plugin import PluginStatus, StringContent, Plugin diff --git a/openlp/core/lib/displaytags.py b/openlp/core/lib/formattingtags.py similarity index 76% rename from openlp/core/lib/displaytags.py rename to openlp/core/lib/formattingtags.py index 95ce13bda..ae9d5c1cf 100644 --- a/openlp/core/lib/displaytags.py +++ b/openlp/core/lib/formattingtags.py @@ -25,12 +25,12 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -Provide Html Tag management and Display Tag access class +Provide HTML Tag management and Formatting Tag access class """ from openlp.core.lib import translate -class DisplayTags(object): +class FormattingTags(object): """ Static Class to HTML Tags to be access around the code the list is managed by the Options Tab. @@ -42,89 +42,93 @@ class DisplayTags(object): """ Provide access to the html_expands list. """ - return DisplayTags.html_expands + return FormattingTags.html_expands @staticmethod def reset_html_tags(): """ Resets the html_expands list. """ - DisplayTags.html_expands = [] + FormattingTags.html_expands = [] base_tags = [] # Append the base tags. # Hex Color tags from http://www.w3schools.com/html/html_colornames.asp - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Red'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Red'), u'start tag': u'{r}', u'start html': u'', u'end tag': u'{/r}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Black'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Black'), u'start tag': u'{b}', u'start html': u'', u'end tag': u'{/b}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Blue'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Blue'), u'start tag': u'{bl}', u'start html': u'', u'end tag': u'{/bl}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Yellow'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Yellow'), u'start tag': u'{y}', u'start html': u'', u'end tag': u'{/y}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Green'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Green'), u'start tag': u'{g}', u'start html': u'', u'end tag': u'{/g}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Pink'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Pink'), u'start tag': u'{pk}', u'start html': u'', u'end tag': u'{/pk}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Orange'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Orange'), u'start tag': u'{o}', u'start html': u'', u'end tag': u'{/o}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Purple'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Purple'), u'start tag': u'{pp}', u'start html': u'', u'end tag': u'{/pp}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'White'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'White'), u'start tag': u'{w}', u'start html': u'', u'end tag': u'{/w}', u'end html': u'', u'protected': True}) base_tags.append({ - u'desc': translate('OpenLP.DisplayTags', 'Superscript'), + u'desc': translate('OpenLP.FormattingTags', 'Superscript'), u'start tag': u'{su}', u'start html': u'', u'end tag': u'{/su}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Subscript'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Subscript'), u'start tag': u'{sb}', u'start html': u'', u'end tag': u'{/sb}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Paragraph'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Paragraph'), u'start tag': u'{p}', u'start html': u'

', u'end tag': u'{/p}', u'end html': u'

', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Bold'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Bold'), u'start tag': u'{st}', u'start html': u'', u'end tag': u'{/st}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Italics'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Italics'), u'start tag': u'{it}', u'start html': u'', u'end tag': u'{/it}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Underline'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Underline'), u'start tag': u'{u}', u'start html': u'', u'end tag': u'{/u}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Break'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Break'), u'start tag': u'{br}', u'start html': u'
', u'end tag': u'', u'end html': u'', u'protected': True}) - DisplayTags.add_html_tags(base_tags) + FormattingTags.add_html_tags(base_tags) @staticmethod def add_html_tags(tags): """ Add a list of tags to the list """ - DisplayTags.html_expands.extend(tags) + FormattingTags.html_expands.extend(tags) @staticmethod def remove_html_tag(tag_id): """ Removes an individual html_expands tag. """ - DisplayTags.html_expands.pop(tag_id) + FormattingTags.html_expands.pop(tag_id) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 1f50e0d65..6f56cf8b2 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -34,6 +34,7 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, \ log = logging.getLogger(__name__) +# FIXME: Add html5 doctype. However, do not break theme gradients. HTMLSRC = u""" @@ -56,44 +57,44 @@ body { height: %spx; } #black { - z-index:8; + z-index: 8; background-color: black; display: none; } #bgimage { - z-index:1; + z-index: 1; } #image { - z-index:2; + z-index: 2; } #video1 { - z-index:3; + z-index: 3; } #video2 { - z-index:3; + z-index: 3; } #alert { position: absolute; left: 0px; top: 0px; - z-index:10; + z-index: 10; %s } #footer { position: absolute; - z-index:6; + z-index: 6; %s } /* lyric css */ %s sup { - font-size:0.6em; - vertical-align:top; - position:relative; - top:-0.3em; + font-size: 0.6em; + vertical-align: top; + position: relative; + top: -0.3em; } - +
""" % \ (build_lyrics_format_css(self.theme_data, self.page_width, self.page_height), build_lyrics_outline_css(self.theme_data)) + self.web.setHtml(html) - def _paginate_slide(self, lines, line_break, force_page=False): + def _paginate_slide(self, lines, line_end): """ Figure out how much text can appear on a slide, using the current theme settings. + **Note:** The smallest possible "unit" of text for a slide is one line. + If the line is too long it will be cut off when displayed. ``lines`` - The words to be fitted on the slide split into lines. - - ``line_break`` - Add line endings after each line of text (used for bibles). - - ``force_page`` - Flag to tell message lines in page. + The text to be fitted on the slide split into lines. + ``line_end`` + The text added after each line. Either ``u' '`` or ``u'
``. """ log.debug(u'_paginate_slide - Start') - line_end = u'' - if line_break: - line_end = u'
' - formatted = [] - html_text = u'' - styled_text = u'' - line_count = 0 - for line in lines: - if line_count != -1: - line_count += 1 - styled_line = expand_tags(line) + line_end - styled_text += styled_line - html = self.page_shell + styled_text + HTML_END - self.web.setHtml(html) - # Text too long so go to next page. - if self.web_frame.contentsSize().height() > self.page_height: - if force_page and line_count > 0: - Receiver.send_message(u'theme_line_count', line_count - 1) - line_count = -1 - while html_text.endswith(u'
'): - html_text = html_text[:-4] - formatted.append(html_text) - html_text = u'' - styled_text = styled_line - html_text += line + line_end - while html_text.endswith(u'
'): - html_text = html_text[:-4] - formatted.append(html_text) - log.debug(u'_paginate_slide - End') - return formatted - - def _paginate_slide_words(self, text, line_break): - """ - Figure out how much text can appear on a slide, using the current - theme settings. This version is to handle text which needs to be split - into words to get it to fit. - - ``text`` - The words to be fitted on the slide split into lines. - - ``line_break`` - Add line endings after each line of text used for bibles. - - """ - log.debug(u'_paginate_slide_words - Start') - line_end = u' ' - if line_break: - line_end = u'
' formatted = [] previous_html = u'' previous_raw = u'' - lines = text.split(u'\n') + separator = u'
' + html_lines = map(expand_tags, lines) + # Text too long so go to next page. + if self._text_fits_on_slide(separator.join(html_lines)): + html_text, previous_raw = self._binary_chop(formatted, + previous_html, previous_raw, html_lines, lines, separator, u'') + else: + previous_raw = separator.join(lines) + if previous_raw: + formatted.append(previous_raw) + log.debug(u'_paginate_slide - End') + return formatted + + def _paginate_slide_words(self, lines, line_end): + """ + Figure out how much text can appear on a slide, using the current + theme settings. + **Note:** The smallest possible "unit" of text for a slide is one word. + If one line is too long it will be processed word by word. This is + sometimes need for **bible** verses. + + ``lines`` + The text to be fitted on the slide split into lines. + + ``line_end`` + The text added after each line. Either ``u' '`` or ``u'
``. + This is needed for **bibles**. + """ + log.debug(u'_paginate_slide_words - Start') + formatted = [] + previous_html = u'' + previous_raw = u'' for line in lines: line = line.strip() - styled_line = expand_tags(line) - html = self.page_shell + previous_html + styled_line + HTML_END - self.web.setHtml(html) + html_line = expand_tags(line) # Text too long so go to next page. - if self.web_frame.contentsSize().height() > self.page_height: + if self._text_fits_on_slide(previous_html + html_line): # Check if there was a verse before the current one and append # it, when it fits on the page. if previous_html: - html = self.page_shell + previous_html + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() <= \ - self.page_height: - while previous_raw.endswith(u'
'): - previous_raw = previous_raw[:-4] + if not self._text_fits_on_slide(previous_html): formatted.append(previous_raw) previous_html = u'' previous_raw = u'' - html = self.page_shell + styled_line + HTML_END - self.web.setHtml(html) # Now check if the current verse will fit, if it does # not we have to start to process the verse word by # word. - if self.web_frame.contentsSize().height() <= \ - self.page_height: - previous_html = styled_line + line_end + if not self._text_fits_on_slide(html_line): + previous_html = html_line + line_end previous_raw = line + line_end continue - # Figure out how many words of the line will fit on screen by - # using the algorithm known as "binary chop". + # Figure out how many words of the line will fit on screen as + # the line will not fit as a whole. raw_words = self._words_split(line) - html_words = [expand_tags(word) for word in raw_words] - smallest_index = 0 - highest_index = len(html_words) - 1 - index = int(highest_index / 2) - while True: - html = self.page_shell + previous_html + \ - u''.join(html_words[:index + 1]).strip() + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() > \ - self.page_height: - # We know that it does not fit, so change/calculate the - # new index and highest_index accordingly. - highest_index = index - index = int(index - (index - smallest_index) / 2) - else: - smallest_index = index - index = int(index + (highest_index - index) / 2) - # We found the number of words which will fit. - if smallest_index == index or highest_index == index: - index = smallest_index - formatted.append(previous_raw.rstrip(u'
') + - u''.join(raw_words[:index + 1])) - previous_html = u'' - previous_raw = u'' - else: - continue - # Check if the rest of the line fits on the slide. If it - # does we do not have to do the much more intensive "word by - # word" checking. - html = self.page_shell + \ - u''.join(html_words[index + 1:]).strip() + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() <= \ - self.page_height: - previous_html = \ - u''.join(html_words[index + 1:]).strip() + line_end - previous_raw = \ - u''.join(raw_words[index + 1:]).strip() + line_end - break - else: - # The other words do not fit, thus reset the indexes, - # create a new list and continue with "word by word". - raw_words = raw_words[index + 1:] - html_words = html_words[index + 1:] - smallest_index = 0 - highest_index = len(html_words) - 1 - index = int(highest_index / 2) + html_words = map(expand_tags, raw_words) + previous_html, previous_raw = self._binary_chop( + formatted, previous_html, previous_raw, html_words, + raw_words, u' ', line_end) else: - previous_html += styled_line + line_end + previous_html += html_line + line_end previous_raw += line + line_end - while previous_raw.endswith(u'
'): - previous_raw = previous_raw[:-4] formatted.append(previous_raw) log.debug(u'_paginate_slide_words - End') return formatted + def _binary_chop(self, formatted, previous_html, previous_raw, html_list, + raw_list, separator, line_end): + """ + This implements the binary chop algorithm for faster rendering. This + algorithm works line based (line by line) and word based (word by word). + It is assumed that this method is **only** called, when the lines/words + to be rendered do **not** fit as a whole. + + ``formatted`` + The list to append any slides. + + ``previous_html`` + The html text which is know to fit on a slide, but is not yet added + to the list of slides. (unicode string) + + ``previous_raw`` + The raw text (with formatting tags) which is know to fit on a slide, + but is not yet added to the list of slides. (unicode string) + + ``html_list`` + The elements which do not fit on a slide and needs to be processed + using the binary chop. The text contains html. + + ``raw_list`` + The elements which do not fit on a slide and needs to be processed + using the binary chop. The elements can contain formatting tags. + + ``separator`` + The separator for the elements. For lines this is ``u'
'`` and + for words this is ``u' '``. + + ``line_end`` + The text added after each "element line". Either ``u' '`` or + ``u'
``. This is needed for bibles. + """ + smallest_index = 0 + highest_index = len(html_list) - 1 + index = int(highest_index / 2) + while True: + if self._text_fits_on_slide( + previous_html + separator.join(html_list[:index + 1]).strip()): + # We know that it does not fit, so change/calculate the + # new index and highest_index accordingly. + highest_index = index + index = int(index - (index - smallest_index) / 2) + else: + smallest_index = index + index = int(index + (highest_index - index) / 2) + # We found the number of words which will fit. + if smallest_index == index or highest_index == index: + index = smallest_index + formatted.append(previous_raw.rstrip(u'
') + + separator.join(raw_list[:index + 1])) + previous_html = u'' + previous_raw = u'' + # Stop here as the theme line count was requested. + if self.force_page: + Receiver.send_message(u'theme_line_count', index + 1) + break + else: + continue + # Check if the remaining elements fit on the slide. + if not self._text_fits_on_slide( + separator.join(html_list[index + 1:]).strip()): + previous_html = separator.join( + html_list[index + 1:]).strip() + line_end + previous_raw = separator.join( + raw_list[index + 1:]).strip() + line_end + break + else: + # The remaining elements do not fit, thus reset the indexes, + # create a new list and continue. + raw_list = raw_list[index + 1:] + html_list = html_list[index + 1:] + smallest_index = 0 + highest_index = len(html_list) - 1 + index = int(highest_index / 2) + return previous_html, previous_raw + + def _text_fits_on_slide(self, text): + """ + Checks if the given ``text`` fits on a slide. If it does ``True`` is + returned, otherwise ``False``. + + ``text`` + The text to check. It can contain HTML tags. + """ + self.web_frame.evaluateJavaScript(u'show_text("%s")' % + text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) + return self.web_frame.contentsSize().height() > self.page_height + def _words_split(self, line): """ Split the slide up by word so can wrap better """ # this parse we are to be wordy line = line.replace(u'\n', u' ') - words = line.split(u' ') - return [word + u' ' for word in words] + return line.split(u' ') def _lines_split(self, text): """ @@ -479,5 +508,5 @@ class Renderer(object): """ # this parse we do not want to use this so remove it text = text.replace(u'\n[---]', u'') - lines = text.split(u'\n') - return [line.replace(u'[---]', u'') for line in lines] + text = text.replace(u'[---]', u'') + return text.split(u'\n') diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 2aa1efbc2..15c16c551 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -164,7 +164,6 @@ class ServiceItem(object): log.debug(u'Render called') self._display_frames = [] self.bg_image_bytes = None - line_break = not self.is_capable(ItemCapabilities.NoLineBreaks) theme = self.theme if self.theme else None self.main, self.footer = \ self.renderer.set_override_theme(theme, use_override) @@ -172,9 +171,8 @@ class ServiceItem(object): if self.service_item_type == ServiceItemType.Text: log.debug(u'Formatting slides') for slide in self._raw_frames: - formatted = self.renderer \ - .format_slide(slide[u'raw_slide'], line_break, self) - for page in formatted: + pages = self.renderer.format_slide(slide[u'raw_slide'], self) + for page in pages: page = page.replace(u'
', u'{br}') html = expand_tags(cgi.escape(page.rstrip())) self._display_frames.append({ @@ -209,7 +207,7 @@ class ServiceItem(object): """ self.service_item_type = ServiceItemType.Image self._raw_frames.append({u'title': title, u'path': path}) - self.renderer.image_manager.add_image(title, path) + self.renderer.imageManager.add_image(title, path) self._new_item() def add_from_text(self, title, raw_slide, verse_tag=None): @@ -463,7 +461,7 @@ class ServiceItem(object): elif not start and end: return end else: - return u'%s
%s' % (start, end) + return u'%s
%s' % (start, end) def update_theme(self, theme): """ diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py index 0d277b9fe..25e4e24ae 100644 --- a/openlp/core/lib/spelltextedit.py +++ b/openlp/core/lib/spelltextedit.py @@ -39,7 +39,7 @@ except ImportError: from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate, DisplayTags +from openlp.core.lib import translate, FormattingTags from openlp.core.lib.ui import checkable_action log = logging.getLogger(__name__) @@ -48,9 +48,10 @@ class SpellTextEdit(QtGui.QPlainTextEdit): """ Spell checking widget based on QPlanTextEdit. """ - def __init__(self, *args): + def __init__(self, parent=None, formattingTagsAllowed=True): global ENCHANT_AVAILABLE - QtGui.QPlainTextEdit.__init__(self, *args) + QtGui.QPlainTextEdit.__init__(self, parent) + self.formattingTagsAllowed = formattingTagsAllowed # Default dictionary based on the current locale. if ENCHANT_AVAILABLE: try: @@ -110,16 +111,17 @@ class SpellTextEdit(QtGui.QPlainTextEdit): spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. - if len(spell_menu.actions()): + if spell_menu.actions(): popupMenu.insertMenu(popupMenu.actions()[0], spell_menu) tagMenu = QtGui.QMenu(translate('OpenLP.SpellTextEdit', 'Formatting Tags')) - for html in DisplayTags.get_html_tags(): - action = SpellAction(html[u'desc'], tagMenu) - action.correct.connect(self.htmlTag) - tagMenu.addAction(action) - popupMenu.insertSeparator(popupMenu.actions()[0]) - popupMenu.insertMenu(popupMenu.actions()[0], tagMenu) + if self.formattingTagsAllowed: + for html in FormattingTags.get_html_tags(): + action = SpellAction(html[u'desc'], tagMenu) + action.correct.connect(self.htmlTag) + tagMenu.addAction(action) + popupMenu.insertSeparator(popupMenu.actions()[0]) + popupMenu.insertMenu(popupMenu.actions()[0], tagMenu) popupMenu.exec_(event.globalPos()) def setLanguage(self, action): @@ -148,7 +150,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit): """ Replaces the selected text with word. """ - for html in DisplayTags.get_html_tags(): + for html in FormattingTags.get_html_tags(): if tag == html[u'desc']: cursor = self.textCursor() if self.textCursor().hasSelection(): diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 7aebcb1df..e754480e0 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -69,7 +69,7 @@ from advancedtab import AdvancedTab from aboutform import AboutForm from pluginform import PluginForm from settingsform import SettingsForm -from displaytagform import DisplayTagForm +from formattingtagform import FormattingTagForm from shortcutlistform import ShortcutListForm from mediadockmanager import MediaDockManager from servicemanager import ServiceManager diff --git a/openlp/core/ui/aboutform.py b/openlp/core/ui/aboutform.py index 2909503f6..4e031656c 100644 --- a/openlp/core/ui/aboutform.py +++ b/openlp/core/ui/aboutform.py @@ -61,6 +61,5 @@ class AboutForm(QtGui.QDialog, Ui_AboutDialog): Launch a web browser and go to the contribute page on the site. """ import webbrowser - url = u'http://www.openlp.org/en/documentation/introduction/' \ - + u'contributing.html' + url = u'http://openlp.org/en/documentation/introduction/contributing' webbrowser.open_new(url) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 8ffd87bcf..4beebfde6 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -129,6 +129,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): os.path.join(gettempdir(), u'openlp', screenshot))) item.setCheckState(QtCore.Qt.Unchecked) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) + Receiver.send_message(u'cursor_normal') def nextId(self): """ @@ -156,10 +157,27 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): item = self.themesListWidget.item(iter) if item.checkState() == QtCore.Qt.Checked: self.themeComboBox.addItem(item.text()) + # Check if this is a re-run of the wizard. + self.has_run_wizard = QtCore.QSettings().value( + u'general/has run wizard', QtCore.QVariant(False)).toBool() + if self.has_run_wizard: + # Add any existing themes to list. + for theme in self.parent().themeManagerContents.getThemes(): + index = self.themeComboBox.findText(theme) + if index == -1: + self.themeComboBox.addItem(theme) + default_theme = unicode(QtCore.QSettings().value( + u'themes/global theme', + QtCore.QVariant(u'')).toString()) + # Pre-select the current default theme. + index = self.themeComboBox.findText(default_theme) + self.themeComboBox.setCurrentIndex(index) elif pageId == FirstTimePage.Progress: + Receiver.send_message(u'cursor_busy') self._preWizard() self._performWizard() self._postWizard() + Receiver.send_message(u'cursor_normal') def updateScreenListCombo(self): """ @@ -248,11 +266,21 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): """ if self.max_progress: self.progressBar.setValue(self.progressBar.maximum()) - self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', - 'Download complete. Click the finish button to start OpenLP.')) + if self.has_run_wizard: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Download complete.' + ' Click the finish button to return to OpenLP.')) + else: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Download complete.' + ' Click the finish button to start OpenLP.')) else: - self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', - 'Click the finish button to start OpenLP.')) + if self.has_run_wizard: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Click the finish button to return to OpenLP.')) + else: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Click the finish button to start OpenLP.')) self.finishButton.setVisible(True) self.finishButton.setEnabled(True) self.cancelButton.setVisible(False) diff --git a/openlp/core/ui/displaytagdialog.py b/openlp/core/ui/formattingtagdialog.py similarity index 82% rename from openlp/core/ui/displaytagdialog.py rename to openlp/core/ui/formattingtagdialog.py index 328fcd137..186f4739b 100644 --- a/openlp/core/ui/displaytagdialog.py +++ b/openlp/core/ui/formattingtagdialog.py @@ -30,15 +30,15 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import translate from openlp.core.lib.ui import UiStrings -class Ui_DisplayTagDialog(object): +class Ui_FormattingTagDialog(object): - def setupUi(self, displayTagDialog): - displayTagDialog.setObjectName(u'displayTagDialog') - displayTagDialog.resize(725, 548) - self.listdataGridLayout = QtGui.QGridLayout(displayTagDialog) + def setupUi(self, formattingTagDialog): + formattingTagDialog.setObjectName(u'formattingTagDialog') + formattingTagDialog.resize(725, 548) + self.listdataGridLayout = QtGui.QGridLayout(formattingTagDialog) self.listdataGridLayout.setMargin(8) self.listdataGridLayout.setObjectName(u'listdataGridLayout') - self.tagTableWidget = QtGui.QTableWidget(displayTagDialog) + self.tagTableWidget = QtGui.QTableWidget(formattingTagDialog) self.tagTableWidget.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.tagTableWidget.setEditTriggers( @@ -67,11 +67,11 @@ class Ui_DisplayTagDialog(object): spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) - self.deletePushButton = QtGui.QPushButton(displayTagDialog) + self.deletePushButton = QtGui.QPushButton(formattingTagDialog) self.deletePushButton.setObjectName(u'deletePushButton') self.horizontalLayout.addWidget(self.deletePushButton) self.listdataGridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) - self.editGroupBox = QtGui.QGroupBox(displayTagDialog) + self.editGroupBox = QtGui.QGroupBox(formattingTagDialog) self.editGroupBox.setObjectName(u'editGroupBox') self.dataGridLayout = QtGui.QGridLayout(self.editGroupBox) self.dataGridLayout.setObjectName(u'dataGridLayout') @@ -112,38 +112,38 @@ class Ui_DisplayTagDialog(object): self.savePushButton.setObjectName(u'savePushButton') self.dataGridLayout.addWidget(self.savePushButton, 4, 2, 1, 1) self.listdataGridLayout.addWidget(self.editGroupBox, 2, 0, 1, 1) - self.buttonBox = QtGui.QDialogButtonBox(displayTagDialog) - self.buttonBox.setObjectName('displayTagDialogButtonBox') + self.buttonBox = QtGui.QDialogButtonBox(formattingTagDialog) + self.buttonBox.setObjectName('formattingTagDialogButtonBox') self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close) self.listdataGridLayout.addWidget(self.buttonBox, 3, 0, 1, 1) - self.retranslateUi(displayTagDialog) - QtCore.QMetaObject.connectSlotsByName(displayTagDialog) + self.retranslateUi(formattingTagDialog) + QtCore.QMetaObject.connectSlotsByName(formattingTagDialog) - def retranslateUi(self, displayTagDialog): - displayTagDialog.setWindowTitle(translate('OpenLP.displayTagDialog', - 'Configure Display Tags')) + def retranslateUi(self, formattingTagDialog): + formattingTagDialog.setWindowTitle(translate( + 'OpenLP.FormattingTagDialog', 'Configure Formatting Tags')) self.editGroupBox.setTitle( - translate('OpenLP.DisplayTagDialog', 'Edit Selection')) + translate('OpenLP.FormattingTagDialog', 'Edit Selection')) self.savePushButton.setText( - translate('OpenLP.DisplayTagDialog', 'Save')) + translate('OpenLP.FormattingTagDialog', 'Save')) self.descriptionLabel.setText( - translate('OpenLP.DisplayTagDialog', 'Description')) - self.tagLabel.setText(translate('OpenLP.DisplayTagDialog', 'Tag')) + translate('OpenLP.FormattingTagDialog', 'Description')) + self.tagLabel.setText(translate('OpenLP.FormattingTagDialog', 'Tag')) self.startTagLabel.setText( - translate('OpenLP.DisplayTagDialog', 'Start tag')) + translate('OpenLP.FormattingTagDialog', 'Start tag')) self.endTagLabel.setText( - translate('OpenLP.DisplayTagDialog', 'End tag')) + translate('OpenLP.FormattingTagDialog', 'End tag')) self.deletePushButton.setText(UiStrings().Delete) self.newPushButton.setText(UiStrings().New) self.tagTableWidget.horizontalHeaderItem(0).setText( - translate('OpenLP.DisplayTagDialog', 'Description')) + translate('OpenLP.FormattingTagDialog', 'Description')) self.tagTableWidget.horizontalHeaderItem(1).setText( - translate('OpenLP.DisplayTagDialog', 'Tag Id')) + translate('OpenLP.FormattingTagDialog', 'Tag Id')) self.tagTableWidget.horizontalHeaderItem(2).setText( - translate('OpenLP.DisplayTagDialog', 'Start HTML')) + translate('OpenLP.FormattingTagDialog', 'Start HTML')) self.tagTableWidget.horizontalHeaderItem(3).setText( - translate('OpenLP.DisplayTagDialog', 'End HTML')) + translate('OpenLP.FormattingTagDialog', 'End HTML')) self.tagTableWidget.setColumnWidth(0, 120) self.tagTableWidget.setColumnWidth(1, 80) self.tagTableWidget.setColumnWidth(2, 330) diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/formattingtagform.py similarity index 82% rename from openlp/core/ui/displaytagform.py rename to openlp/core/ui/formattingtagform.py index 22ac38f06..2a8625b1a 100644 --- a/openlp/core/ui/displaytagform.py +++ b/openlp/core/ui/formattingtagform.py @@ -25,22 +25,22 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`DisplayTagTab` 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 +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 cPickle from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate, DisplayTags +from openlp.core.lib import translate, FormattingTags from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.displaytagdialog import Ui_DisplayTagDialog +from openlp.core.ui.formattingtagdialog import Ui_FormattingTagDialog -class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): +class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): """ - The :class:`DisplayTagTab` manages the settings tab . + The :class:`FormattingTagForm` manages the settings tab . """ def __init__(self, parent): """ @@ -48,7 +48,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): """ QtGui.QDialog.__init__(self, parent) self.setupUi(self) - self._loadDisplayTags() + self._loadFormattingTags() QtCore.QObject.connect(self.tagTableWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onRowSelected) QtCore.QObject.connect(self.newPushButton, @@ -65,19 +65,20 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): Load Display and set field state. """ # Create initial copy from master - self._loadDisplayTags() + self._loadFormattingTags() self._resetTable() self.selected = -1 return QtGui.QDialog.exec_(self) - def _loadDisplayTags(self): + def _loadFormattingTags(self): """ Load the Tags from store so can be used in the system or used to update the display. If Cancel was selected this is needed to reset the dsiplay to the correct version. """ # Initial Load of the Tags - DisplayTags.reset_html_tags() + FormattingTags.reset_html_tags() + # Formatting Tags were also known as display tags. user_expands = QtCore.QSettings().value(u'displayTags/html_tags', QtCore.QVariant(u'')).toString() # cPickle only accepts str not unicode strings @@ -85,14 +86,14 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): if user_expands_string: user_tags = cPickle.loads(user_expands_string) # If we have some user ones added them as well - DisplayTags.add_html_tags(user_tags) + FormattingTags.add_html_tags(user_tags) def onRowSelected(self): """ Table Row selected so display items and set field state. """ row = self.tagTableWidget.currentRow() - html = DisplayTags.get_html_tags()[row] + html = FormattingTags.get_html_tags()[row] self.selected = row self.descriptionLineEdit.setText(html[u'desc']) self.tagLineEdit.setText(self._strip(html[u'start tag'])) @@ -117,23 +118,23 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): """ Add a new tag to list only if it is not a duplicate. """ - for html in DisplayTags.get_html_tags(): + for html in FormattingTags.get_html_tags(): if self._strip(html[u'start tag']) == u'n': critical_error_message_box( - translate('OpenLP.DisplayTagTab', 'Update Error'), - translate('OpenLP.DisplayTagTab', + translate('OpenLP.FormattingTagForm', 'Update Error'), + translate('OpenLP.FormattingTagForm', 'Tag "n" already defined.')) return # Add new tag to list tag = { - u'desc': translate('OpenLP.DisplayTagTab', 'New Tag'), + u'desc': translate('OpenLP.FormattingTagForm', 'New Tag'), u'start tag': u'{n}', - u'start html': translate('OpenLP.DisplayTagTab', ''), + u'start html': translate('OpenLP.FormattingTagForm', ''), u'end tag': u'{/n}', - u'end html': translate('OpenLP.DisplayTagTab', ''), + u'end html': translate('OpenLP.FormattingTagForm', ''), u'protected': False } - DisplayTags.add_html_tags([tag]) + FormattingTags.add_html_tags([tag]) self._resetTable() # Highlight new row self.tagTableWidget.selectRow(self.tagTableWidget.rowCount() - 1) @@ -145,7 +146,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): Delete selected custom tag. """ if self.selected != -1: - DisplayTags.remove_html_tag(self.selected) + FormattingTags.remove_html_tag(self.selected) self.selected = -1 self._resetTable() self._saveTable() @@ -154,7 +155,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): """ Update Custom Tag details if not duplicate and save the data. """ - html_expands = DisplayTags.get_html_tags() + html_expands = FormattingTags.get_html_tags() if self.selected != -1: html = html_expands[self.selected] tag = unicode(self.tagLineEdit.text()) @@ -162,8 +163,8 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): if self._strip(html1[u'start tag']) == tag and \ linenumber != self.selected: critical_error_message_box( - translate('OpenLP.DisplayTagTab', 'Update Error'), - unicode(translate('OpenLP.DisplayTagTab', + translate('OpenLP.FormattingTagForm', 'Update Error'), + unicode(translate('OpenLP.FormattingTagForm', 'Tag %s already defined.')) % tag) return html[u'desc'] = unicode(self.descriptionLineEdit.text()) @@ -177,18 +178,15 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): def _saveTable(self): """ - Saves all display tags except protected ones. + Saves all formatting tags except protected ones. """ tags = [] - for tag in DisplayTags.get_html_tags(): + for tag in FormattingTags.get_html_tags(): if not tag[u'protected']: tags.append(tag) - if tags: - QtCore.QSettings().setValue(u'displayTags/html_tags', - QtCore.QVariant(cPickle.dumps(tags))) - else: - QtCore.QSettings().setValue(u'displayTags/html_tags', - QtCore.QVariant(u'')) + # Formatting Tags were also known as display tags. + QtCore.QSettings().setValue(u'displayTags/html_tags', + QtCore.QVariant(cPickle.dumps(tags) if tags else u'')) def _resetTable(self): """ @@ -199,7 +197,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): self.newPushButton.setEnabled(True) self.savePushButton.setEnabled(False) self.deletePushButton.setEnabled(False) - for linenumber, html in enumerate(DisplayTags.get_html_tags()): + for linenumber, html in enumerate(FormattingTags.get_html_tags()): self.tagTableWidget.setRowCount( self.tagTableWidget.rowCount() + 1) self.tagTableWidget.setItem(linenumber, 0, diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 72a998efe..9904868ce 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -48,13 +48,13 @@ class MainDisplay(QtGui.QGraphicsView): """ This is the display screen. """ - def __init__(self, parent, image_manager, live): + def __init__(self, parent, imageManager, live): if live: QtGui.QGraphicsView.__init__(self) else: QtGui.QGraphicsView.__init__(self, parent) self.isLive = live - self.image_manager = image_manager + self.imageManager = imageManager self.screens = ScreenList.get_instance() self.alertTab = None self.hideMode = None @@ -188,7 +188,7 @@ class MainDisplay(QtGui.QGraphicsView): while not self.webLoaded: Receiver.send_message(u'openlp_process_events') self.setGeometry(self.screen[u'size']) - self.frame.evaluateJavaScript(u'show_text("%s")' % \ + self.frame.evaluateJavaScript(u'show_text("%s")' % slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) return self.preview() @@ -232,7 +232,7 @@ class MainDisplay(QtGui.QGraphicsView): """ API for replacement backgrounds so Images are added directly to cache """ - self.image_manager.add_image(name, path) + self.imageManager.add_image(name, path) if hasattr(self, u'serviceItem'): self.override[u'image'] = name self.override[u'theme'] = self.serviceItem.themedata.theme_name @@ -249,7 +249,7 @@ class MainDisplay(QtGui.QGraphicsView): The name of the image to be displayed """ log.debug(u'image to display') - image = self.image_manager.get_image_bytes(name) + image = self.imageManager.get_image_bytes(name) self.resetVideo() self.displayImage(image) return self.preview() @@ -482,13 +482,13 @@ class MainDisplay(QtGui.QGraphicsView): self.override = {} else: # replace the background - background = self.image_manager. \ + background = self.imageManager. \ get_image_bytes(self.override[u'image']) if self.serviceItem.themedata.background_filename: - self.serviceItem.bg_image_bytes = self.image_manager. \ + self.serviceItem.bg_image_bytes = self.imageManager. \ get_image_bytes(self.serviceItem.themedata.theme_name) if image: - image_bytes = self.image_manager.get_image_bytes(image) + image_bytes = self.imageManager.get_image_bytes(image) else: image_bytes = None html = build_html(self.serviceItem, self.screen, self.alertTab, diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index c88508672..d9c8111bb 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -33,15 +33,17 @@ from tempfile import gettempdir from PyQt4 import QtCore, QtGui from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, \ - PluginManager, Receiver, translate, ImageManager + PluginManager, Receiver, translate, ImageManager, PluginStatus from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \ icon_action, shortcut_action from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \ ThemeManager, SlideController, PluginForm, MediaDockManager, \ - ShortcutListForm, DisplayTagForm + ShortcutListForm, FormattingTagForm from openlp.core.utils import AppLocation, add_actions, LanguageManager, \ get_application_version, delete_file from openlp.core.utils.actions import ActionList, CategoryOrder +from openlp.core.ui.firsttimeform import FirstTimeForm +from openlp.core.ui import ScreenList log = logging.getLogger(__name__) @@ -107,6 +109,8 @@ class Ui_MainWindow(object): self.menuBar.setObjectName(u'menuBar') self.fileMenu = QtGui.QMenu(self.menuBar) self.fileMenu.setObjectName(u'fileMenu') + self.recentFilesMenu = QtGui.QMenu(self.fileMenu) + self.recentFilesMenu.setObjectName(u'recentFilesMenu') self.fileImportMenu = QtGui.QMenu(self.fileMenu) self.fileImportMenu.setObjectName(u'fileImportMenu') self.fileExportMenu = QtGui.QMenu(self.fileMenu) @@ -244,6 +248,9 @@ class Ui_MainWindow(object): self.toolsOpenDataFolder = icon_action(mainWindow, u'toolsOpenDataFolder', u':/general/general_open.png', category=UiStrings().Tools) + self.toolsFirstTimeWizard = icon_action(mainWindow, + u'toolsFirstTimeWizard', u':/general/general_revert.png', + category=UiStrings().Tools) self.updateThemeImages = base_action(mainWindow, u'updateThemeImages', category=UiStrings().Tools) action_list.add_category(UiStrings().Settings, @@ -269,7 +276,8 @@ class Ui_MainWindow(object): u'settingsShortcutsItem', u':/system/system_configure_shortcuts.png', category=UiStrings().Settings) - self.displayTagItem = icon_action(mainWindow, + # Formatting Tags were also known as display tags. + self.formattingTagItem = icon_action(mainWindow, u'displayTagItem', u':/system/tag_editor.png', category=UiStrings().Settings) self.settingsConfigureItem = icon_action(mainWindow, @@ -296,10 +304,11 @@ class Ui_MainWindow(object): (self.importThemeItem, self.importLanguageItem)) add_actions(self.fileExportMenu, (self.exportThemeItem, self.exportLanguageItem)) - self.fileMenuActions = (self.fileNewItem, self.fileOpenItem, - self.fileSaveItem, self.fileSaveAsItem, None, - self.printServiceOrderItem, None, self.fileImportMenu.menuAction(), - self.fileExportMenu.menuAction(), self.fileExitItem) + add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem, + self.fileSaveItem, self.fileSaveAsItem, + self.recentFilesMenu.menuAction(), None, + self.fileImportMenu.menuAction(), self.fileExportMenu.menuAction(), + None, self.printServiceOrderItem, self.fileExitItem)) add_actions(self.viewModeMenu, (self.modeDefaultItem, self.modeSetupItem, self.modeLiveItem)) add_actions(self.viewMenu, (self.viewModeMenu.menuAction(), @@ -315,14 +324,15 @@ class Ui_MainWindow(object): add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, self.settingsConfigureItem, self.settingsShortcutsItem, - self.displayTagItem)) + self.formattingTagItem)) else: add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, - self.displayTagItem, self.settingsShortcutsItem, + self.formattingTagItem, self.settingsShortcutsItem, self.settingsConfigureItem)) add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) + add_actions(self.toolsMenu, (self.toolsFirstTimeWizard, None)) add_actions(self.toolsMenu, [self.updateThemeImages]) if os.name == u'nt': add_actions(self.helpMenu, (self.offlineHelpItem, @@ -339,7 +349,7 @@ class Ui_MainWindow(object): self.mediaToolBox.setCurrentIndex(0) # Connect up some signals and slots QtCore.QObject.connect(self.fileMenu, - QtCore.SIGNAL(u'aboutToShow()'), self.updateFileMenu) + QtCore.SIGNAL(u'aboutToShow()'), self.updateRecentFilesMenu) QtCore.QMetaObject.connectSlotsByName(mainWindow) # Hide the entry, as it does not have any functionality yet. self.toolsAddToolItem.setVisible(False) @@ -356,6 +366,8 @@ class Ui_MainWindow(object): self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File')) self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import')) self.fileExportMenu.setTitle(translate('OpenLP.MainWindow', '&Export')) + self.recentFilesMenu.setTitle( + translate('OpenLP.MainWindow', '&Recent Files')) self.viewMenu.setTitle(translate('OpenLP.MainWindow', '&View')) self.viewModeMenu.setTitle(translate('OpenLP.MainWindow', 'M&ode')) self.toolsMenu.setTitle(translate('OpenLP.MainWindow', '&Tools')) @@ -403,8 +415,8 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', '&Language')) self.settingsShortcutsItem.setText( translate('OpenLP.MainWindow', 'Configure &Shortcuts...')) - self.displayTagItem.setText( - translate('OpenLP.MainWindow', '&Configure Display Tags')) + self.formattingTagItem.setText( + translate('OpenLP.MainWindow', '&Configure Formatting Tags...')) self.settingsConfigureItem.setText( translate('OpenLP.MainWindow', '&Configure OpenLP...')) self.viewMediaManagerItem.setText( @@ -471,6 +483,10 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', 'Open &Data Folder...')) self.toolsOpenDataFolder.setStatusTip(translate('OpenLP.MainWindow', 'Open the folder where songs, bibles and other data resides.')) + self.toolsFirstTimeWizard.setText( + translate('OpenLP.MainWindow', 'Re-run First Time Wizard')) + self.toolsFirstTimeWizard.setStatusTip(translate('OpenLP.MainWindow', + 'Re-run the First Time Wizard, importing songs, Bibles and themes.')) self.updateThemeImages.setText( translate('OpenLP.MainWindow', 'Update Theme Images')) self.updateThemeImages.setStatusTip( @@ -511,7 +527,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.serviceNotSaved = False self.aboutForm = AboutForm(self) self.settingsForm = SettingsForm(self, self) - self.displayTagForm = DisplayTagForm(self) + self.formattingTagForm = FormattingTagForm(self) self.shortcutForm = ShortcutListForm(self) self.recentFiles = QtCore.QStringList() # Set up the path with plugins @@ -523,8 +539,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.setupUi(self) # Load settings after setupUi so default UI sizes are overwritten self.loadSettings() - # Once settings are loaded update FileMenu with recentFiles - self.updateFileMenu() + # Once settings are loaded update the menu with the recent files. + self.updateRecentFilesMenu() self.pluginForm = PluginForm(self) # Set up signals and slots QtCore.QObject.connect(self.importThemeItem, @@ -546,10 +562,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked) QtCore.QObject.connect(self.toolsOpenDataFolder, QtCore.SIGNAL(u'triggered()'), self.onToolsOpenDataFolderClicked) + QtCore.QObject.connect(self.toolsFirstTimeWizard, + QtCore.SIGNAL(u'triggered()'), self.onFirstTimeWizardClicked) QtCore.QObject.connect(self.updateThemeImages, QtCore.SIGNAL(u'triggered()'), self.onUpdateThemeImages) - QtCore.QObject.connect(self.displayTagItem, - QtCore.SIGNAL(u'triggered()'), self.onDisplayTagItemClicked) + QtCore.QObject.connect(self.formattingTagItem, + QtCore.SIGNAL(u'triggered()'), self.onFormattingTagItemClicked) QtCore.QObject.connect(self.settingsConfigureItem, QtCore.SIGNAL(u'triggered()'), self.onSettingsConfigureItemClicked) QtCore.QObject.connect(self.settingsShortcutsItem, @@ -714,6 +732,45 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): delete_file(os.path.join(temp_dir, filename)) os.removedirs(temp_dir) + def onFirstTimeWizardClicked(self): + """ + Re-run the first time wizard. Prompts the user for run confirmation + If wizard is run, songs, bibles and themes are imported. The default + theme is changed (if necessary). The plugins in pluginmanager are + set active/in-active to match the selection in the wizard. + """ + answer = QtGui.QMessageBox.warning(self, + translate('OpenLP.MainWindow', 'Re-run First Time Wizard?'), + translate('OpenLP.MainWindow', + 'Are you sure you want to re-run the First Time Wizard?\n\n' + 'Re-running this wizard may make changes to your current ' + 'OpenLP configuration and possibly add songs to your ' + 'existing songs list and change your default theme.'), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.No) + if answer == QtGui.QMessageBox.No: + return + Receiver.send_message(u'cursor_busy') + screens = ScreenList.get_instance() + if FirstTimeForm(screens, self).exec_() == QtGui.QDialog.Accepted: + self.firstTime() + for plugin in self.pluginManager.plugins: + self.activePlugin = plugin + oldStatus = self.activePlugin.status + self.activePlugin.setStatus() + if oldStatus != self.activePlugin.status: + if self.activePlugin.status == PluginStatus.Active: + self.activePlugin.toggleStatus(PluginStatus.Active) + self.activePlugin.appStartup() + else: + self.activePlugin.toggleStatus(PluginStatus.Inactive) + self.themeManagerContents.configUpdated() + self.themeManagerContents.loadThemes(True) + Receiver.send_message(u'theme_update_global', + self.themeManagerContents.global_theme) + def blankCheck(self): """ Check and display message if screen blank on setup. @@ -788,11 +845,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ self.themeManagerContents.updatePreviewImages() - def onDisplayTagItemClicked(self): + def onFormattingTagItemClicked(self): """ Show the Settings dialog """ - self.displayTagForm.exec_() + self.formattingTagForm.exec_() def onSettingsConfigureItemClicked(self): """ @@ -1085,30 +1142,36 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QVariant(self.controlSplitter.saveState())) settings.endGroup() - def updateFileMenu(self): + def updateRecentFilesMenu(self): """ - Updates the file menu with the latest list of service files accessed. + Updates the recent file menu with the latest list of service files + accessed. """ recentFileCount = QtCore.QSettings().value( u'advanced/recent file count', QtCore.QVariant(4)).toInt()[0] - self.fileMenu.clear() - add_actions(self.fileMenu, self.fileMenuActions[:-1]) existingRecentFiles = [recentFile for recentFile in self.recentFiles if QtCore.QFile.exists(recentFile)] recentFilesToDisplay = existingRecentFiles[0:recentFileCount] - if recentFilesToDisplay: - self.fileMenu.addSeparator() - for fileId, filename in enumerate(recentFilesToDisplay): - log.debug('Recent file name: %s', filename) - action = base_action(self, u'') - action.setText(u'&%d %s' % - (fileId + 1, QtCore.QFileInfo(filename).fileName())) - action.setData(QtCore.QVariant(filename)) - self.connect(action, QtCore.SIGNAL(u'triggered()'), - self.serviceManagerContents.onRecentServiceClicked) - self.fileMenu.addAction(action) - self.fileMenu.addSeparator() - self.fileMenu.addAction(self.fileMenuActions[-1]) + self.recentFilesMenu.clear() + for fileId, filename in enumerate(recentFilesToDisplay): + log.debug('Recent file name: %s', filename) + action = base_action(self, u'') + action.setText(u'&%d %s' % + (fileId + 1, QtCore.QFileInfo(filename).fileName())) + action.setData(QtCore.QVariant(filename)) + self.connect(action, QtCore.SIGNAL(u'triggered()'), + self.serviceManagerContents.onRecentServiceClicked) + self.recentFilesMenu.addAction(action) + clearRecentFilesAction = base_action(self, u'') + clearRecentFilesAction.setText( + translate('OpenLP.MainWindow', 'Clear List', + 'Clear List of recent files')) + clearRecentFilesAction.setStatusTip( + translate('OpenLP.MainWindow', 'Clear the list of recent files.')) + add_actions(self.recentFilesMenu, (None, clearRecentFilesAction)) + self.connect(clearRecentFilesAction, QtCore.SIGNAL(u'triggered()'), + self.recentFiles.clear) + clearRecentFilesAction.setEnabled(not self.recentFiles.isEmpty()) def addRecentFile(self, filename): """ diff --git a/openlp/core/ui/mediadockmanager.py b/openlp/core/ui/mediadockmanager.py index 3eb5a899c..cc6cc92bc 100644 --- a/openlp/core/ui/mediadockmanager.py +++ b/openlp/core/ui/mediadockmanager.py @@ -66,7 +66,7 @@ class MediaDockManager(object): match = False for dock_index in range(0, self.media_dock.count()): if self.media_dock.widget(dock_index).settingsSection == \ - media_item.plugin.name.lower(): + media_item.plugin.name: match = True break if not match: @@ -84,6 +84,6 @@ class MediaDockManager(object): for dock_index in range(0, self.media_dock.count()): if self.media_dock.widget(dock_index): if self.media_dock.widget(dock_index).settingsSection == \ - media_item.plugin.name.lower(): + media_item.plugin.name: self.media_dock.widget(dock_index).setVisible(False) self.media_dock.removeItem(dock_index) diff --git a/openlp/core/ui/printservicedialog.py b/openlp/core/ui/printservicedialog.py index b0065df99..8287ef02a 100644 --- a/openlp/core/ui/printservicedialog.py +++ b/openlp/core/ui/printservicedialog.py @@ -108,7 +108,7 @@ class Ui_PrintServiceDialog(object): self.footerLabel = QtGui.QLabel(self.optionsWidget) self.footerLabel.setObjectName(u'footerLabel') self.optionsLayout.addWidget(self.footerLabel) - self.footerTextEdit = SpellTextEdit(self.optionsWidget) + self.footerTextEdit = SpellTextEdit(self.optionsWidget, False) self.footerTextEdit.setObjectName(u'footerTextEdit') self.optionsLayout.addWidget(self.footerTextEdit) self.optionsGroupBox = QtGui.QGroupBox() diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index 2bbf2ab56..55fc6eb3c 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -24,6 +24,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import cgi import datetime import os @@ -183,7 +184,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): self._addElement(u'style', custom_css, html_data.head, attribute=(u'type', u'text/css')) self._addElement(u'body', parent=html_data) - self._addElement(u'h1', unicode(self.titleLineEdit.text()), + self._addElement(u'h1', cgi.escape(unicode(self.titleLineEdit.text())), html_data.body, classId=u'serviceTitle') for index, item in enumerate(self.serviceManager.serviceItems): self._addPreviewItem(html_data.body, item[u'service_item'], index) @@ -193,8 +194,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): classId=u'customNotes') self._addElement(u'span', translate('OpenLP.ServiceManager', 'Custom Service Notes: '), div, classId=u'customNotesTitle') - self._addElement(u'span', self.footerTextEdit.toPlainText(), div, - classId=u'customNotesText') + self._addElement(u'span', + cgi.escape(self.footerTextEdit.toPlainText()), + div, classId=u'customNotesText') self.document.setHtml(html.tostring(html_data)) self.previewWidget.updatePreview() @@ -204,8 +206,8 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): item_title = self._addElement(u'h2', parent=div, classId=u'itemTitle') self._addElement(u'img', parent=item_title, attribute=(u'src', item.icon)) - self._addElement(u'span', u' ' + item.get_display_title(), - item_title) + self._addElement(u'span', + u' ' + cgi.escape(item.get_display_title()), item_title) if self.slideTextCheckBox.isChecked(): # Add the text of the service item. if item.is_text(): @@ -230,8 +232,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): foot_text = item.foot_text foot_text = foot_text.partition(u'
')[2] if foot_text: - foot = self._addElement(u'div', foot_text, parent=div, - classId=u'itemFooter') + foot_text = cgi.escape(foot_text.replace(u'
', u'\n')) + self._addElement(u'div', foot_text.replace(u'\n', u'
'), + parent=div, classId=u'itemFooter') # Add service items' notes. if self.notesCheckBox.isChecked(): if item.notes: @@ -239,8 +242,8 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): self._addElement(u'span', translate('OpenLP.ServiceManager', 'Notes: '), p, classId=u'itemNotesTitle') - notes = self._addElement(u'span', - item.notes.replace(u'\n', u'
'), p, + self._addElement(u'span', + cgi.escape(unicode(item.notes)).replace(u'\n', u'
'), p, classId=u'itemNotesText') # Add play length of media files. if item.is_media() and self.metaDataCheckBox.isChecked(): diff --git a/openlp/core/ui/serviceitemeditform.py b/openlp/core/ui/serviceitemeditform.py index f19638e43..974133c3d 100644 --- a/openlp/core/ui/serviceitemeditform.py +++ b/openlp/core/ui/serviceitemeditform.py @@ -79,7 +79,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog): if not item: return row = self.listWidget.row(item) - self.itemList.remove(self.itemList[row]) + self.itemList.pop(row) self.loadData() if row == self.listWidget.count(): self.listWidget.setCurrentRow(row - 1) @@ -109,7 +109,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog): return row = self.listWidget.row(item) temp = self.itemList[row] - self.itemList.remove(self.itemList[row]) + self.itemList.pop(row) if direction == u'up': row -= 1 else: diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index dd7720331..3ab2e9239 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -24,6 +24,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import cgi import cPickle import logging import os @@ -408,20 +409,33 @@ class ServiceManager(QtGui.QWidget): return False self.newFile() - def onLoadServiceClicked(self): + def onLoadServiceClicked(self, loadFile=None): + """ + Loads the service file and saves the existing one it there is one + unchanged + + ``loadFile`` + The service file to the loaded. Will be None is from menu so + selection will be required. + """ if self.isModified(): result = self.saveModifiedService() if result == QtGui.QMessageBox.Cancel: return False elif result == QtGui.QMessageBox.Save: self.saveFile() - fileName = unicode(QtGui.QFileDialog.getOpenFileName(self.mainwindow, - translate('OpenLP.ServiceManager', 'Open File'), - SettingsManager.get_last_dir( - self.mainwindow.serviceSettingsSection), - translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) - if not fileName: - return False + if not loadFile: + fileName = unicode(QtGui.QFileDialog.getOpenFileName( + self.mainwindow, + translate('OpenLP.ServiceManager', 'Open File'), + SettingsManager.get_last_dir( + self.mainwindow.serviceSettingsSection), + translate('OpenLP.ServiceManager', + 'OpenLP Service Files (*.osz)'))) + if not fileName: + return False + else: + fileName = loadFile SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, split_filename(fileName)[0]) self.loadFile(fileName) @@ -474,6 +488,7 @@ class ServiceManager(QtGui.QWidget): item[u'service_item'].get_service_repr()}) if not item[u'service_item'].uses_file(): continue + skipMissing = False for frame in item[u'service_item'].get_frames(): if item[u'service_item'].is_image(): path_from = frame[u'path'] @@ -482,25 +497,29 @@ class ServiceManager(QtGui.QWidget): # Only write a file once if path_from in write_list: continue - file_size = os.path.getsize(path_from) - size_limit = 52428800 # 50MiB - #if file_size > size_limit: - # # File exeeds size_limit bytes, ask user - # message = unicode(translate('OpenLP.ServiceManager', - # 'Do you want to include \n%.1f MB file "%s"\n' - # 'into the service file?\nThis may take some time.\n\n' - # 'Please note that you need to\ntake care of that file' - # ' yourself,\nif you leave it out.')) % \ - # (file_size/1048576, os.path.split(path_from)[1]) - # ans = QtGui.QMessageBox.question(self.mainwindow, - # translate('OpenLP.ServiceManager', 'Including Large ' - # 'File'), message, QtGui.QMessageBox.StandardButtons( - # QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel), - # QtGui.QMessageBox.Ok) - # if ans == QtGui.QMessageBox.Cancel: - # continue - write_list.append(path_from) - total_size += file_size + if not os.path.exists(path_from): + if not skipMissing: + Receiver.send_message(u'cursor_normal') + title = unicode(translate('OpenLP.ServiceManager', + 'Service File Missing')) + message = unicode(translate('OpenLP.ServiceManager', + 'File missing from service\n\n %s \n\n' + 'Continue saving?' % path_from )) + answer = QtGui.QMessageBox.critical(self, title, + message, + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No | + QtGui.QMessageBox.YesToAll)) + if answer == QtGui.QMessageBox.No: + self.mainwindow.finishedProgressBar() + return False + if answer == QtGui.QMessageBox.YesToAll: + skipMissing = True + Receiver.send_message(u'cursor_busy') + else: + file_size = os.path.getsize(path_from) + write_list.append(path_from) + total_size += file_size log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' % total_size) service_content = cPickle.dumps(service) @@ -701,6 +720,9 @@ class ServiceManager(QtGui.QWidget): self.setModified() def onStartTimeForm(self): + """ + Opens a dialog to type in service item notes. + """ item = self.findServiceItem()[0] self.startTimeForm.item = self.serviceItems[item] if self.startTimeForm.exec_(): @@ -939,11 +961,11 @@ class ServiceManager(QtGui.QWidget): if serviceitem.notes: tips.append(u'%s: %s' % (unicode(translate('OpenLP.ServiceManager', 'Notes')), - unicode(serviceitem.notes))) + cgi.escape(unicode(serviceitem.notes)))) if item[u'service_item'] \ .is_capable(ItemCapabilities.AllowsVariableStartTime): tips.append(item[u'service_item'].get_media_time()) - treewidgetitem.setToolTip(0, u'
'.join(tips)) + treewidgetitem.setToolTip(0, u'
'.join(tips)) treewidgetitem.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(item[u'order'])) treewidgetitem.setSelected(item[u'selected']) @@ -1239,7 +1261,14 @@ class ServiceManager(QtGui.QWidget): Handle of the event pint passed """ link = event.mimeData() - if link.hasText(): + if event.mimeData().hasUrls(): + event.setDropAction(QtCore.Qt.CopyAction) + event.accept() + for url in event.mimeData().urls(): + filename = unicode(url.toLocalFile()) + if filename.endswith(u'.osz'): + self.onLoadServiceClicked(filename) + elif event.mimeData().hasText(): plugin = unicode(event.mimeData().text()) item = self.serviceManagerList.itemAt(event.pos()) # ServiceManager started the drag and drop diff --git a/openlp/core/ui/servicenoteform.py b/openlp/core/ui/servicenoteform.py index 3bc55e242..ddfcb3381 100644 --- a/openlp/core/ui/servicenoteform.py +++ b/openlp/core/ui/servicenoteform.py @@ -27,7 +27,7 @@ from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate +from openlp.core.lib import translate, SpellTextEdit from openlp.core.lib.ui import create_accept_reject_button_box class ServiceNoteForm(QtGui.QDialog): @@ -52,7 +52,7 @@ class ServiceNoteForm(QtGui.QDialog): self.dialogLayout.setContentsMargins(8, 8, 8, 8) self.dialogLayout.setSpacing(8) self.dialogLayout.setObjectName(u'verticalLayout') - self.textEdit = QtGui.QTextEdit(self) + self.textEdit = SpellTextEdit(self, False) self.textEdit.setObjectName(u'textEdit') self.dialogLayout.addWidget(self.textEdit) self.dialogLayout.addWidget(create_accept_reject_button_box(self)) diff --git a/openlp/core/ui/shortcutlistdialog.py b/openlp/core/ui/shortcutlistdialog.py index 6d877358f..a9b9b22cf 100644 --- a/openlp/core/ui/shortcutlistdialog.py +++ b/openlp/core/ui/shortcutlistdialog.py @@ -123,7 +123,7 @@ class Ui_ShortcutListDialog(object): def retranslateUi(self, shortcutListDialog): shortcutListDialog.setWindowTitle( - translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts')) + translate('OpenLP.ShortcutListDialog', 'Configure Shortcuts')) self.descriptionLabel.setText(translate('OpenLP.ShortcutListDialog', 'Select an action and click one of the buttons below to start ' 'capturing a new primary or alternate shortcut, respectively.')) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 9d35c1166..0f83cbc30 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -508,6 +508,11 @@ class SlideController(QtGui.QWidget): self.mediabar.setVisible(False) self.toolbar.makeWidgetsInvisible([u'Song Menu']) self.toolbar.makeWidgetsInvisible(self.loopList) + # Reset the button + self.playSlidesOnce.setChecked(False) + self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png')) + self.playSlidesLoop.setChecked(False) + self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) if item.is_text(): if QtCore.QSettings().value( self.parent().songsSettingsSection + u'/display songbar', diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index 228031842..21db1972a 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -43,7 +43,7 @@ class AlertsPlugin(Plugin): log.info(u'Alerts Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Alerts', plugin_helpers, + Plugin.__init__(self, u'alerts', plugin_helpers, settings_tab_class=AlertsTab) self.weight = -3 self.icon_path = u':/plugins/plugin_alerts.png' diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index da7658c12..619581b17 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -41,7 +41,7 @@ class BiblePlugin(Plugin): log.info(u'Bible Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Bibles', plugin_helpers, + Plugin.__init__(self, u'bibles', plugin_helpers, BibleMediaItem, BiblesTab) self.weight = -9 self.icon_path = u':/plugins/plugin_bibles.png' diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 82ee4430c..e47375298 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -395,6 +395,7 @@ class BibleMediaItem(MediaManagerItem): log.debug(u'Reloading Bibles') self.plugin.manager.reload_bibles() self.loadBibles() + self.updateAutoCompleter() def initialiseAdvancedBible(self, bible): """ diff --git a/openlp/plugins/custom/customplugin.py b/openlp/plugins/custom/customplugin.py index 7b7c939b1..e9260f926 100644 --- a/openlp/plugins/custom/customplugin.py +++ b/openlp/plugins/custom/customplugin.py @@ -46,7 +46,7 @@ class CustomPlugin(Plugin): log.info(u'Custom Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Custom', plugin_helpers, + Plugin.__init__(self, u'custom', plugin_helpers, CustomMediaItem, CustomTab) self.weight = -5 self.manager = Manager(u'custom', init_schema) diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index b92a804fd..1ddbe8357 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -36,7 +36,7 @@ class ImagePlugin(Plugin): log.info(u'Image Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Images', plugin_helpers, ImageMediaItem) + Plugin.__init__(self, u'images', plugin_helpers, ImageMediaItem) self.weight = -7 self.icon_path = u':/plugins/plugin_images.png' self.icon = build_icon(self.icon_path) diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 3c4489bbc..acd420880 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -52,6 +52,8 @@ class ImageMediaItem(MediaManagerItem): self.hasSearch = True QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged) + # Allow DnD from the desktop + self.listView.activateDnD() def retranslateUi(self): self.onNewPrompt = translate('ImagePlugin.MediaItem', @@ -131,6 +133,7 @@ class ImageMediaItem(MediaManagerItem): icon = self.iconFromFile(imageFile, thumb) item_name = QtGui.QListWidgetItem(filename) item_name.setIcon(icon) + item_name.setToolTip(imageFile) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile)) self.listView.addItem(item_name) if not initialLoad: diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 77f91a529..e3c36bd77 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -39,6 +39,8 @@ from PyQt4.phonon import Phonon log = logging.getLogger(__name__) +CLAPPERBOARD = QtGui.QPixmap(u':/media/media_video.png').toImage() + class MediaMediaItem(MediaManagerItem): """ This is the custom media manager item for Media Slides. @@ -48,8 +50,7 @@ class MediaMediaItem(MediaManagerItem): def __init__(self, parent, plugin, icon): self.IconPath = u'images/image' self.background = False - self.PreviewFunction = QtGui.QPixmap( - u':/media/media_video.png').toImage() + self.PreviewFunction = CLAPPERBOARD MediaManagerItem.__init__(self, parent, plugin, icon) self.singleServiceItem = False self.hasSearch = True @@ -60,6 +61,8 @@ class MediaMediaItem(MediaManagerItem): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_phonon_creation'), self.createPhonon) + # Allow DnD from the desktop + self.listView.activateDnD() def retranslateUi(self): self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') @@ -201,17 +204,17 @@ class MediaMediaItem(MediaManagerItem): SettingsManager.set_list(self.settingsSection, u'media', self.getFileList()) - def loadList(self, files): + def loadList(self, media): # Sort the themes by its filename considering language specific # characters. lower() is needed for windows! - files.sort(cmp=locale.strcoll, + media.sort(cmp=locale.strcoll, key=lambda filename: os.path.split(unicode(filename))[1].lower()) - for file in files: - filename = os.path.split(unicode(file))[1] + for track in media: + filename = os.path.split(unicode(track))[1] item_name = QtGui.QListWidgetItem(filename) - img = QtGui.QPixmap(u':/media/media_video.png').toImage() - item_name.setIcon(build_icon(img)) - item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) + item_name.setIcon(build_icon(CLAPPERBOARD)) + item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track)) + item_name.setToolTip(track) self.listView.addItem(item_name) def createPhonon(self): diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 308ebd959..c215b1be0 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -39,7 +39,7 @@ class MediaPlugin(Plugin): log.info(u'%s MediaPlugin loaded', __name__) def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Media', plugin_helpers, + Plugin.__init__(self, u'media', plugin_helpers, MediaMediaItem, MediaTab) self.weight = -6 self.icon_path = u':/plugins/plugin_media.png' diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 07b490d83..85721c65d 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -58,6 +58,8 @@ class PresentationMediaItem(MediaManagerItem): self.hasSearch = True QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) + # Allow DnD from the desktop + self.listView.activateDnD() def retranslateUi(self): """ @@ -205,6 +207,7 @@ class PresentationMediaItem(MediaManagerItem): item_name = QtGui.QListWidgetItem(filename) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setIcon(icon) + item_name.setToolTip(file) self.listView.addItem(item_name) Receiver.send_message(u'cursor_normal') if not initialLoad: diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index 2990862e1..a97f82159 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -52,7 +52,7 @@ class PresentationPlugin(Plugin): """ log.debug(u'Initialised') self.controllers = {} - Plugin.__init__(self, u'Presentations', plugin_helpers) + Plugin.__init__(self, u'presentations', plugin_helpers) self.weight = -8 self.icon_path = u':/plugins/plugin_presentations.png' self.icon = build_icon(self.icon_path) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 836b3d0ae..1545986f0 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -150,13 +150,11 @@ class HttpResponse(object): class HttpServer(object): """ - Ability to control OpenLP via a webbrowser - e.g. http://localhost:4316/send/slidecontroller_live_next - http://localhost:4316/send/alerts_text?q=your%20alert%20text + Ability to control OpenLP via a web browser. """ def __init__(self, plugin): """ - Initialise the httpserver, and start the server + Initialise the httpserver, and start the server. """ log.debug(u'Initialise httpserver') self.plugin = plugin @@ -170,9 +168,9 @@ class HttpServer(object): def start_tcp(self): """ - Start the http server, use the port in the settings default to 4316 + Start the http server, use the port in the settings default to 4316. Listen out for slide and song changes so they can be broadcast to - clients. Listen out for socket connections + clients. Listen out for socket connections. """ log.debug(u'Start TCP server') port = QtCore.QSettings().value( @@ -195,20 +193,20 @@ class HttpServer(object): def slide_change(self, row): """ - Slide change listener. Store the item and tell the clients + Slide change listener. Store the item and tell the clients. """ self.current_slide = row def item_change(self, items): """ - Item (song) change listener. Store the slide and tell the clients + Item (song) change listener. Store the slide and tell the clients. """ self.current_item = items[0] def new_connection(self): """ A new http connection has been made. Create a client object to handle - communication + communication. """ log.debug(u'new http connection') socket = self.server.nextPendingConnection() @@ -225,15 +223,16 @@ class HttpServer(object): def close(self): """ - Close down the http server + Close down the http server. """ log.debug(u'close http server') self.server.close() + class HttpConnection(object): """ A single connection, this handles communication between the server - and the client + and the client. """ def __init__(self, parent, socket): """ @@ -287,9 +286,12 @@ class HttpConnection(object): """ self.template_vars = { 'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.0 Remote'), - 'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.0 Stage View'), - 'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'), - 'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'), + 'stage_title': translate('RemotePlugin.Mobile', + 'OpenLP 2.0 Stage View'), + 'service_manager': translate('RemotePlugin.Mobile', + 'Service Manager'), + 'slide_controller': translate('RemotePlugin.Mobile', + 'Slide Controller'), 'alerts': translate('RemotePlugin.Mobile', 'Alerts'), 'search': translate('RemotePlugin.Mobile', 'Search'), 'back': translate('RemotePlugin.Mobile', 'Back'), @@ -301,7 +303,8 @@ class HttpConnection(object): 'text': translate('RemotePlugin.Mobile', 'Text'), 'show_alert': translate('RemotePlugin.Mobile', 'Show Alert'), 'go_live': translate('RemotePlugin.Mobile', 'Go Live'), - 'add_to_service': translate('RemotePlugin.Mobile', 'Add To Service'), + 'add_to_service': translate('RemotePlugin.Mobile', + 'Add to Service'), 'no_results': translate('RemotePlugin.Mobile', 'No Results'), 'options': translate('RemotePlugin.Mobile', 'Options') } @@ -397,7 +400,7 @@ class HttpConnection(object): if self.parent.current_item else u'' } return HttpResponse(json.dumps({u'results': result}), - {u'Content-Type': u'application/json'}) + {u'Content-Type': u'application/json'}) def display(self, action): """ @@ -483,10 +486,11 @@ class HttpConnection(object): def pluginInfo(self, action): """ - Return plugin related information, based on the action + Return plugin related information, based on the action. - ``action`` - The action to perform - if 'search' return a list of plugin names which support search + ``action`` + The action to perform. If *search* return a list of plugin names + which support search. """ if action == u'search': searches = [] @@ -501,10 +505,10 @@ class HttpConnection(object): def search(self, type): """ - Return a list of items that match the search text + Return a list of items that match the search text. ``type`` - The plugin name to search in. + The plugin name to search in. """ text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) @@ -528,7 +532,7 @@ class HttpConnection(object): def add_to_service(self, type): """ - Add item of type ``type`` to the end of the service + Add item of type ``type`` to the end of the service. """ id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) diff --git a/openlp/plugins/remotes/remoteplugin.py b/openlp/plugins/remotes/remoteplugin.py index a120becba..dfaff9675 100644 --- a/openlp/plugins/remotes/remoteplugin.py +++ b/openlp/plugins/remotes/remoteplugin.py @@ -39,7 +39,7 @@ class RemotesPlugin(Plugin): """ remotes constructor """ - Plugin.__init__(self, u'Remotes', plugin_helpers, + Plugin.__init__(self, u'remotes', plugin_helpers, settings_tab_class=RemoteTab) self.icon_path = u':/plugins/plugin_remote.png' self.icon = build_icon(self.icon_path) diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 6f268bd2f..c7dbf85cf 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -90,7 +90,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.onVerseListViewPressed) QtCore.QObject.connect(self.themeAddButton, QtCore.SIGNAL(u'clicked()'), - self.mediaitem.plugin.renderer.theme_manager.onAddTheme) + self.mediaitem.plugin.renderer.themeManager.onAddTheme) QtCore.QObject.connect(self.maintenanceButton, QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked) QtCore.QObject.connect(Receiver.get_receiver(), diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 3432c8846..90c3b0275 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -28,6 +28,7 @@ The :mod:`songexportform` module provides the wizard for exporting songs to the OpenLyrics format. """ +import locale import logging from PyQt4 import QtCore, QtGui @@ -249,6 +250,7 @@ class SongExportForm(OpenLPWizard): # Load the list of songs. Receiver.send_message(u'cursor_busy') songs = self.plugin.manager.get_all_objects(Song) + songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower()) for song in songs: authors = u', '.join([author.display_name for author in song.authors]) diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 4ab60d360..52524b838 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -699,7 +699,8 @@ class SongImportForm(OpenLPWizard): elif source_format == SongFormat.OpenLP1: # Import an openlp.org database importer = self.plugin.importSongs(SongFormat.OpenLP1, - filename=unicode(self.openLP1FilenameEdit.text()) + filename=unicode(self.openLP1FilenameEdit.text()), + plugin=self.plugin ) elif source_format == SongFormat.OpenLyrics: # Import OpenLyrics songs diff --git a/openlp/plugins/songs/lib/olp1import.py b/openlp/plugins/songs/lib/olp1import.py index 423f5ece0..de7264a5b 100644 --- a/openlp/plugins/songs/lib/olp1import.py +++ b/openlp/plugins/songs/lib/olp1import.py @@ -57,6 +57,8 @@ class OpenLP1SongImport(SongImport): The database providing the data to import. """ SongImport.__init__(self, manager, **kwargs) + self.available_themes = \ + kwargs[u'plugin'].formparent.themeManagerContents.getThemes() def do_import(self): """ @@ -70,27 +72,34 @@ class OpenLP1SongImport(SongImport): encoding = self.get_encoding() if not encoding: return - # Connect to the database + # Connect to the database. connection = sqlite.connect(self.import_source, mode=0444, encoding=(encoding, 'replace')) cursor = connection.cursor() - # Determine if we're using a new or an old DB + # Determine if we're using a new or an old DB. cursor.execute(u'SELECT name FROM sqlite_master ' u'WHERE type = \'table\' AND name = \'tracks\'') new_db = len(cursor.fetchall()) > 0 - # "cache" our list of authors + # "cache" our list of authors. cursor.execute(u'-- types int, unicode') cursor.execute(u'SELECT authorid, authorname FROM authors') authors = cursor.fetchall() if new_db: - # "cache" our list of tracks + # "cache" our list of tracks. cursor.execute(u'-- types int, unicode') cursor.execute(u'SELECT trackid, fulltrackname FROM tracks') tracks = cursor.fetchall() - # Import the songs - cursor.execute(u'-- types int, unicode, unicode, unicode') + # "cache" our list of themes. + cursor.execute(u'-- types int, unicode') + cursor.execute(u'SELECT settingsid, settingsname FROM settings') + themes = {} + for theme_id, theme_name in cursor.fetchall(): + if theme_name in self.available_themes: + themes[theme_id] = theme_name + # Import the songs. + cursor.execute(u'-- types int, unicode, unicode, unicode, int') cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS lyrics, ' - u'copyrightinfo FROM songs') + u'copyrightinfo, settingsid FROM songs') songs = cursor.fetchall() self.import_wizard.progressBar.setMaximum(len(songs)) for song in songs: @@ -101,8 +110,12 @@ class OpenLP1SongImport(SongImport): self.title = song[1] lyrics = song[2].replace(u'\r\n', u'\n') self.add_copyright(song[3]) + if themes.has_key(song[4]): + self.theme_name = themes[song[4]] verses = lyrics.split(u'\n\n') - [self.add_verse(verse.strip()) for verse in verses if verse.strip()] + for verse in verses: + if verse.strip(): + self.add_verse(verse.strip()) cursor.execute(u'-- types int') cursor.execute(u'SELECT authorid FROM songauthors ' u'WHERE songid = %s' % song_id) @@ -137,12 +150,12 @@ class OpenLP1SongImport(SongImport): """ Detect character encoding of an openlp.org 1.x song database. """ - # Connect to the database + # Connect to the database. connection = sqlite.connect(self.import_source, mode=0444) cursor = connection.cursor() detector = UniversalDetector() - # detect charset by authors + # Detect charset by authors. cursor.execute(u'SELECT authorname FROM authors') authors = cursor.fetchall() for author in authors: @@ -150,7 +163,7 @@ class OpenLP1SongImport(SongImport): if detector.done: detector.close() return detector.result[u'encoding'] - # detect charset by songs + # Detect charset by songs. cursor.execute(u'SELECT songtitle, copyrightinfo, ' u'lyrics || \'\' AS lyrics FROM songs') songs = cursor.fetchall() @@ -160,7 +173,7 @@ class OpenLP1SongImport(SongImport): if detector.done: detector.close() return detector.result[u'encoding'] - # detect charset by songs + # Detect charset by songs. cursor.execute(u'SELECT name FROM sqlite_master ' u'WHERE type = \'table\' AND name = \'tracks\'') if len(cursor.fetchall()) > 0: diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py index 7f7527c6d..c50df8752 100644 --- a/openlp/plugins/songs/lib/songshowplusimport.py +++ b/openlp/plugins/songs/lib/songshowplusimport.py @@ -102,7 +102,6 @@ class SongShowPlusImport(SongImport): if not isinstance(self.import_source, list): return self.import_wizard.progressBar.setMaximum(len(self.import_source)) - for file in self.import_source: self.sspVerseOrderList = [] otherCount = 0 @@ -111,7 +110,6 @@ class SongShowPlusImport(SongImport): self.import_wizard.incrementProgressBar( WizardStrings.ImportingType % file_name, 0) songData = open(file, 'rb') - while True: blockKey, = struct.unpack("I", songData.read(4)) # The file ends with 4 NUL's @@ -126,8 +124,9 @@ class SongShowPlusImport(SongImport): songData.read(2)) verseName = songData.read(verseNameLength) lengthDescriptorSize, = struct.unpack("B", songData.read(1)) + log.debug(lengthDescriptorSize) # Detect if/how long the length descriptor is - if lengthDescriptorSize == 12: + if lengthDescriptorSize == 12 or lengthDescriptorSize == 20: lengthDescriptor, = struct.unpack("I", songData.read(4)) elif lengthDescriptorSize == 2: lengthDescriptor = 1 @@ -135,6 +134,7 @@ class SongShowPlusImport(SongImport): lengthDescriptor = 0 else: lengthDescriptor, = struct.unpack("B", songData.read(1)) + log.debug(lengthDescriptorSize) data = songData.read(lengthDescriptor) if blockKey == TITLE: self.title = unicode(data, u'cp1252') diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index e514b2937..8a773be90 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -57,7 +57,7 @@ class SongsPlugin(Plugin): """ Create and set up the Songs plugin. """ - Plugin.__init__(self, u'Songs', plugin_helpers, SongMediaItem, SongsTab) + Plugin.__init__(self, u'songs', plugin_helpers, SongMediaItem, SongsTab) self.weight = -10 self.manager = Manager(u'songs', init_schema) self.icon_path = u':/plugins/plugin_songs.png' diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index cc143b986..4ca23aeb0 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -45,7 +45,7 @@ class SongUsagePlugin(Plugin): log.info(u'SongUsage Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'SongUsage', plugin_helpers) + Plugin.__init__(self, u'songusage', plugin_helpers) self.weight = -4 self.icon = build_icon(u':/plugins/plugin_songusage.png') self.activeIcon = build_icon(u':/songusage/song_usage_active.png') @@ -91,8 +91,8 @@ class SongUsagePlugin(Plugin): self.toolsMenu.addAction(self.songUsageMenu.menuAction()) self.songUsageMenu.addAction(self.songUsageStatus) self.songUsageMenu.addSeparator() - self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageMenu.addAction(self.songUsageReport) + self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageActiveButton = QtGui.QToolButton( self.formparent.statusBar) self.songUsageActiveButton.setCheckable(True) diff --git a/resources/osx/Info.plist.master b/resources/osx/Info.plist.master index 45aab92a5..5fc3aa48f 100755 --- a/resources/osx/Info.plist.master +++ b/resources/osx/Info.plist.master @@ -2,6 +2,99 @@ + + CFBundleDocumentTypes + + + CFBundleTypeExtension + + osz + + CFBundleTypeIconFiles + + openlp-logo-with-text.icns + + CFBundleTypeName + OpenLP Service + CFBundleTypeRole + Viewer + LSHandlerRank + Owner + LSItemContentTypes + + org.openlp.osz + + + + CFBundleTypeExtension + + otz + + CFBundleTypeIconFiles + + openlp-logo-with-text.icns + + CFBundleTypeName + OpenLP Theme + CFBundleTypeRole + Viewer + LSHandlerRank + Owner + LSItemContentTypes + + org.openlp.otz + + + + + UTExportedTypeDeclarations + + + UTTypeIdentifier + org.openlp.osz + UTTypeDescription + OpenLP Service + UTTypeConformsTo + + public.data + public.content + + UTTypeTagSpecification + + public.filename-extension + + osz + + public.mime-type + + application/x-openlp-service + + + + + UTTypeIdentifier + org.openlp.otz + UTTypeDescription + OpenLP Theme + UTTypeConformsTo + + public.data + public.content + + UTTypeTagSpecification + + public.filename-extension + + otz + + public.mime-type + + application/x-openlp-theme + + + + + CFBundleIdentifier org.openlp CFBundleShortVersionString diff --git a/resources/osx/applescript-adjustview-10-5.master b/resources/osx/applescript-adjustview-10-5.master index abc0e5a8d..19be239d0 100755 --- a/resources/osx/applescript-adjustview-10-5.master +++ b/resources/osx/applescript-adjustview-10-5.master @@ -48,7 +48,7 @@ on run set theViewOptions to the icon view options of container window set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 128 - set background picture of theViewOptions to file ".installer-background.png" + set background picture of theViewOptions to file ".background:installer-background.png" if not exists file "Applications" then make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} end if diff --git a/resources/osx/applescript-adjustview-10-6.master b/resources/osx/applescript-adjustview-10-6.master index 2b5a0c000..170842564 100755 --- a/resources/osx/applescript-adjustview-10-6.master +++ b/resources/osx/applescript-adjustview-10-6.master @@ -49,15 +49,19 @@ on run set theViewOptions to the icon view options of container window set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 128 - set background picture of theViewOptions to file ".installer-background.png" - make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} - delay 5 + set background picture of theViewOptions to file ".background:installer-background.png" + if not exists file "Applications" then + make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} + end if + delay 1 set position of item "%s" of container window to {160, 200} set position of item ".Trashes" of container window to {100, 500} - set position of item ".installer-background.png" of container window to {200, 500} + set position of item ".background" of container window to {200, 500} set position of item ".DS_Store" of container window to {400, 500} set position of item "Applications" of container window to {550, 200} - set position of item ".VolumeIcon.icns" of container window to {500, 500} + if exists file ".VolumeIcon.icns" then + set position of item ".VolumeIcon.icns" of container window to {500, 500} + end if set position of item ".fseventsd" of container window to {300, 500} if exists POSIX file ".SymAVx86QSFile" then set position of item ".SymAVx86QSFile" of container window to {600, 500} diff --git a/resources/osx/build.py b/resources/osx/build.py index ff7f6bdfd..38e56e42a 100644 --- a/resources/osx/build.py +++ b/resources/osx/build.py @@ -93,8 +93,12 @@ script_name = "build" def build_application(settings, app_name_lower, app_dir): logging.info('[%s] now building the app with pyinstaller at "%s"...', script_name, settings['pyinstaller_basedir']) - result = os.system('python %s/pyinstaller.py openlp.spec' \ - % settings['pyinstaller_basedir']) + full_python_dir = os.path.join('/opt/local/Library/Frameworks', + 'Python.framework/Versions/2.6/Resources/', + 'Python.app/Contents/MacOS/Python') + result = os.system('arch -i386 %s %s/pyinstaller.py openlp.spec' \ + % ( full_python_dir, + settings['pyinstaller_basedir']) ) if (result != 0): logging.error('[%s] The pyinstaller build reported an error, cannot \ continue!', script_name) @@ -219,10 +223,10 @@ def create_dmg(settings): sys.exit(1) logging.info('[%s] copying the background image...', script_name) - # os.mkdir(volume_basedir + '/.background') + os.mkdir(volume_basedir + '/.background') result = os.system('CpMac %s %s' % (settings['installer_backgroundimage_file'], - volume_basedir + '/.installer-background.png')) + volume_basedir + '/.background/installer-background.png')) if (result != 0): logging.error('[%s] could not copy the background image, dmg creation\ failed!', script_name) diff --git a/resources/osx/openlp-logo-with-text.icns b/resources/osx/openlp-logo-with-text.icns old mode 100755 new mode 100644 diff --git a/resources/osx/openlp.cfg b/resources/osx/openlp.cfg.sample similarity index 81% rename from resources/osx/openlp.cfg rename to resources/osx/openlp.cfg.sample index 3be085dc0..f72a8fca1 100755 --- a/resources/osx/openlp.cfg +++ b/resources/osx/openlp.cfg.sample @@ -1,8 +1,8 @@ [openlp] openlp_appname = OpenLP -openlp_dmgname = OpenLP-1.9.4-bzrXXXX +openlp_dmgname = OpenLP-1.9.6-bzrXXXX openlp_version = XXXX -openlp_basedir = /Users/openlp/trunk +openlp_basedir = /Users/openlp/repo/trunk openlp_icon_file = openlp-logo-with-text.icns openlp_dmg_icon_file = openlp-logo-420x420.png installer_backgroundimage_file = installation-background.png diff --git a/resources/osx/openlp.spec.master b/resources/osx/openlp.spec.master index 94aec2a60..eb743c40b 100755 --- a/resources/osx/openlp.spec.master +++ b/resources/osx/openlp.spec.master @@ -1,5 +1,5 @@ # -*- mode: python -*- -a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'], +a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(CONFIGDIR,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'], pathex=['%(pyinstaller_basedir)s'], hookspath=['%(openlp_basedir)s/resources/pyinstaller']) pyz = PYZ(a.pure) exe = EXE(pyz, diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index 9c96fe251..b7bf70472 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -46,12 +46,6 @@ PyEnchant Inno Setup 5 Inno Setup should be installed into "C:\%PROGRAMFILES%\Inno Setup 5" -UPX - This is used to compress DLLs and EXEs so that they take up less space, but - still function exactly the same. To install UPX, download it from - http://upx.sourceforge.net/, extract it into C:\%PROGRAMFILES%\UPX, and then - add that directory to your PATH environment variable. - Sphinx This is used to build the documentation. The documentation trunk must be at the same directory level as Openlp trunk and named "documentation" @@ -179,6 +173,7 @@ def run_pyinstaller(): pyinstaller = Popen((python_exe, pyi_build, u'--noconfirm', u'--windowed', + u'--noupx', u'-o', branch_path, u'-i', win32_icon, u'-p', branch_path,