def upgrade_2(session, metadata): """ Remove the individual proxy settings, after the implementation of central proxy settings. Added in 2.5 (3.0 development) """ settings = Registry().get('settings') op = get_upgrade_op(session) metadata_table = Table('metadata', metadata, autoload=True) proxy, = session.execute( select([metadata_table.c.value], metadata_table.c.key == 'proxy_server')).first() or ('', ) if proxy and not \ (proxy == settings.value('advanced/proxy http') or proxy == settings.value('advanced/proxy https')): http_proxy = '' https_proxy = '' name, = session.execute( select([metadata_table.c.value], metadata_table.c.key == 'name')).first() msg_box = QtWidgets.QMessageBox() msg_box.setText( translate( 'BiblesPlugin', f'The proxy server {proxy} was found in the bible {name}.<br>' f'Would you like to set it as the proxy for OpenLP?')) msg_box.setIcon(QtWidgets.QMessageBox.Question) msg_box.addButton(QtWidgets.QMessageBox.No) http_button = msg_box.addButton('http', QtWidgets.QMessageBox.ActionRole) both_button = msg_box.addButton(translate('BiblesPlugin', 'both'), QtWidgets.QMessageBox.ActionRole) https_button = msg_box.addButton('https', QtWidgets.QMessageBox.ActionRole) msg_box.setDefaultButton(both_button) msg_box.exec() clicked_button = msg_box.clickedButton() if clicked_button in [http_button, both_button]: http_proxy = proxy settings.setValue('advanced/proxy http', proxy) if clicked_button in [https_button, both_button]: https_proxy = proxy settings.setValue('advanced/proxy https', proxy) if http_proxy or https_proxy: username, = session.execute( select([metadata_table.c.value], metadata_table.c.key == 'proxy_username')).first() proxy, = session.execute( select([metadata_table.c.value], metadata_table.c.key == 'proxy_password')).first() settings.setValue('advanced/proxy username', username) settings.setValue('advanced/proxy password', proxy) settings.setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY) op.execute(delete(metadata_table, metadata_table.c.key == 'proxy_server')) op.execute(delete(metadata_table, metadata_table.c.key == 'proxy_username')) op.execute(delete(metadata_table, metadata_table.c.key == 'proxy_password'))
class PresentationDocument(object): """ Base class for presentation documents to inherit from. Loads and closes the presentation as well as triggering the correct activities based on the users input **Hook Functions** ``load_presentation()`` Load a presentation file ``close_presentation()`` Close presentation and clean up objects ``presentation_loaded()`` Returns True if presentation is currently loaded ``is_active()`` Returns True if a presentation is currently running ``blank_screen()`` Blanks the screen, making it black. ``unblank_screen()`` Unblanks the screen, restoring the output ``is_blank`` Returns true if screen is blank ``stop_presentation()`` Stops the presentation, removing it from the output display ``start_presentation()`` Starts the presentation from the beginning ``get_slide_number()`` Returns the current slide number, from 1 ``get_slide_count()`` Returns total number of slides ``goto_slide(slide_no)`` Jumps directly to the requested slide. ``next_step()`` Triggers the next effect of slide on the running presentation ``previous_step()`` Triggers the previous slide on the running presentation ``get_thumbnail_path(slide_no, check_exists)`` Returns a path to an image containing a preview for the requested slide """ def __init__(self, controller, document_path): """ Constructor for the PresentationController class :param controller: :param Path document_path: Path to the document to load. :rtype: None """ self.controller = controller self.settings = Registry().get('settings') self._setup(document_path) def _setup(self, document_path): """ Run some initial setup. This method is separate from __init__ in order to mock it out in tests. :param Path document_path: Path to the document to load. :rtype: None """ self.slide_number = 0 self.file_path = document_path create_paths(self.get_thumbnail_folder()) def load_presentation(self): """ Called when a presentation is added to the SlideController. Loads the presentation and starts it. Returns False if the file could not be opened """ return False def presentation_deleted(self): """ Cleans up/deletes any controller specific files created for a file, e.g. thumbnails """ try: thumbnail_folder_path = self.get_thumbnail_folder() temp_folder_path = self.get_temp_folder() if thumbnail_folder_path.exists(): shutil.rmtree(thumbnail_folder_path) if temp_folder_path.exists(): shutil.rmtree(temp_folder_path) except OSError: log.exception('Failed to delete presentation controller files') def get_thumbnail_folder(self): """ The location where thumbnail images will be stored :return: The path to the thumbnail :rtype: Path """ # TODO: Can be removed when the upgrade path to OpenLP 3.0 is no longer needed, also ensure code in # get_temp_folder and PresentationPluginapp_startup is removed if self.settings.value('presentations/thumbnail_scheme') == 'md5': folder = md5_hash(bytes(self.file_path)) else: folder = self.file_path.name return Path(self.controller.thumbnail_folder, folder) def get_temp_folder(self): """ The location where thumbnail images will be stored :return: The path to the temporary file folder :rtype: Path """ # TODO: Can be removed when the upgrade path to OpenLP 3.0 is no longer needed, also ensure code in # get_thumbnail_folder and PresentationPluginapp_startup is removed if self.settings.value('presentations/thumbnail_scheme') == 'md5': folder = md5_hash(bytes(self.file_path)) else: folder = self.file_path.name return Path(self.controller.temp_folder, folder) def check_thumbnails(self): """ Check that the last thumbnail image exists and is valid and are more recent than the powerpoint file. :return: If the thumbnail is valid :rtype: bool """ last_image_path = self.get_thumbnail_path(self.get_slide_count(), True) if not (last_image_path and last_image_path.is_file()): return False return validate_thumb(Path(self.file_path), Path(last_image_path)) def close_presentation(self): """ Close presentation and clean up objects. Triggered by new object being added to SlideController """ self.controller.close_presentation() def is_active(self): """ Returns True if a presentation is currently running """ return False def is_loaded(self): """ Returns true if a presentation is loaded """ return False def blank_screen(self): """ Blanks the screen, making it black. """ pass def unblank_screen(self): """ Unblanks (restores) the presentation """ pass def is_blank(self): """ Returns true if screen is blank """ return False def stop_presentation(self): """ Stops the presentation, removing it from the output display """ pass def start_presentation(self): """ Starts the presentation from the beginning """ pass def get_slide_number(self): """ Returns the current slide number, from 1 """ return 0 def get_slide_count(self): """ Returns total number of slides """ return 0 def goto_slide(self, slide_no): """ Jumps directly to the requested slide. :param slide_no: The slide to jump to, starting at 1 """ pass def next_step(self): """ Triggers the next effect of slide on the running presentation. This might be the next animation on the current slide, or the next slide. :rtype bool: True if we stepped beyond the slides of the presentation """ return False def previous_step(self): """ Triggers the previous slide on the running presentation :rtype bool: True if we stepped beyond the slides of the presentation """ return False def convert_thumbnail(self, image_path, index): """ Convert the slide image the application made to a scaled 360px height .png image. :param Path image_path: Path to the image to create a thumbnail of :param int index: The index of the slide to create the thumbnail for. :rtype: None """ if self.check_thumbnails(): return if image_path.is_file(): thumb_path = self.get_thumbnail_path(index, False) create_thumb(image_path, thumb_path, False, QtCore.QSize(-1, 360)) def get_thumbnail_path(self, slide_no, check_exists=False): """ Returns an image path containing a preview for the requested slide :param int slide_no: The slide an image is required for, starting at 1 :param bool check_exists: Check if the generated path exists :return: The path, or None if the :param:`check_exists` is True and the file does not exist :rtype: Path | None """ path = self.get_thumbnail_folder() / ( self.controller.thumbnail_prefix + str(slide_no) + '.png') if path.is_file() or not check_exists: return path else: return None def poll_slidenumber(self, is_live, hide_mode): """ Check the current slide number """ if not self.is_active(): return if not hide_mode: current = self.get_slide_number() if current == self.slide_number: return self.slide_number = current if is_live: prefix = 'live' else: prefix = 'preview' Registry().execute( 'slidecontroller_{prefix}_change'.format(prefix=prefix), self.slide_number - 1) def get_slide_text(self, slide_no): """ Returns the text on the slide :param slide_no: The slide the text is required for, starting at 1 """ return '' def get_slide_notes(self, slide_no): """ Returns the text on the slide :param slide_no: The slide the text is required for, starting at 1 """ return '' def get_titles_and_notes(self): """ Reads the titles from the titles file and the notes files and returns the content in two lists """ notes = [] titles_path = self.get_thumbnail_folder() / 'titles.txt' try: titles = titles_path.read_text().splitlines() except Exception: log.exception('Failed to open/read existing titles file') titles = [] for slide_no, title in enumerate(titles, 1): notes_path = self.get_thumbnail_folder( ) / 'slideNotes{number:d}.txt'.format(number=slide_no) try: note = notes_path.read_text() except Exception: log.exception('Failed to open/read notes file') note = '' notes.append(note) return titles, notes def save_titles_and_notes(self, titles, notes): """ Performs the actual persisting of titles to the titles.txt and notes to the slideNote%.txt :param list[str] titles: The titles to save :param list[str] notes: The notes to save :rtype: None """ if titles: titles_path = self.get_thumbnail_folder() / 'titles.txt' titles_path.write_text('\n'.join(titles)) if notes: for slide_no, note in enumerate(notes, 1): notes_path = self.get_thumbnail_folder( ) / 'slideNotes{number:d}.txt'.format(number=slide_no) notes_path.write_text(note)
def update_reference_separators(): """ Updates separators and matches for parsing and formatting scripture references. """ default_separators = [ '|'.join([ translate( 'BiblesPlugin', ':', 'Verse identifier e.g. Genesis 1 : 1 = Genesis Chapter 1 Verse 1' ), translate( 'BiblesPlugin', 'v', 'Verse identifier e.g. Genesis 1 v 1 = Genesis Chapter 1 Verse 1' ), translate( 'BiblesPlugin', 'V', 'Verse identifier e.g. Genesis 1 V 1 = Genesis Chapter 1 Verse 1' ), translate( 'BiblesPlugin', 'verse', 'Verse identifier e.g. Genesis 1 verse 1 = Genesis Chapter 1 Verse 1' ), translate( 'BiblesPlugin', 'verses', 'Verse identifier e.g. Genesis 1 verses 1 - 2 = Genesis Chapter 1 Verses 1 to 2' ) ]), '|'.join([ translate( 'BiblesPlugin', '-', 'range identifier e.g. Genesis 1 verse 1 - 2 = Genesis Chapter 1 Verses 1 To 2' ), translate( 'BiblesPlugin', 'to', 'range identifier e.g. Genesis 1 verse 1 - 2 = Genesis Chapter 1 Verses 1 To 2' ) ]), '|'.join([ translate( 'BiblesPlugin', ',', 'connecting identifier e.g. Genesis 1 verse 1 - 2, 4 - 5 = ' 'Genesis Chapter 1 Verses 1 To 2 And Verses 4 To 5'), translate( 'BiblesPlugin', 'and', 'connecting identifier e.g. Genesis 1 verse 1 - 2 and 4 - 5 = ' 'Genesis Chapter 1 Verses 1 To 2 And Verses 4 To 5') ]), '|'.join([ translate( 'BiblesPlugin', 'end', 'ending identifier e.g. Genesis 1 verse 1 - end = ' 'Genesis Chapter 1 Verses 1 To The Last Verse') ]) ] settings = Registry().get('settings') custom_separators = [ settings.value('verse separator'), settings.value('range separator'), settings.value('list separator'), settings.value('end separator') ] for index, role in enumerate(['v', 'r', 'l', 'e']): if custom_separators[index].strip('|') == '': source_string = default_separators[index].strip('|') else: source_string = custom_separators[index].strip('|') while '||' in source_string: source_string = source_string.replace('||', '|') if role != 'e': REFERENCE_SEPARATORS['sep_{role}_display'.format( role=role)] = source_string.split('|')[0] # escape reserved characters for character in '\\.^$*+?{}[]()': source_string = source_string.replace(character, '\\' + character) # add various Unicode alternatives source_string = source_string.replace( '-', '(?:[-\u00AD\u2010\u2011\u2012\u2014\u2014\u2212\uFE63\uFF0D])') source_string = source_string.replace(',', '(?:[,\u201A])') REFERENCE_SEPARATORS['sep_{role}'.format( role=role)] = r'\s*(?:{source})\s*'.format(source=source_string) REFERENCE_SEPARATORS['sep_{role}_default'.format( role=role)] = default_separators[index] # verse range match: (<chapter>:)?<verse>(-((<chapter>:)?<verse>|end)?)? range_regex = '(?:(?P<from_chapter>[0-9]+){sep_v})?' \ '(?P<from_verse>[0-9]+)(?P<range_to>{sep_r}(?:(?:(?P<to_chapter>' \ '[0-9]+){sep_v})?(?P<to_verse>[0-9]+)|{sep_e})?)?'.format_map(REFERENCE_SEPARATORS) REFERENCE_MATCHES['range'] = re.compile( r'^\s*{range}\s*$'.format(range=range_regex)) REFERENCE_MATCHES['range_separator'] = re.compile( REFERENCE_SEPARATORS['sep_l']) # full reference match: <book>(<range>(,(?!$)|(?=$)))+ REFERENCE_MATCHES['full'] = \ re.compile(r'^\s*(?!\s)(?P<book>[\d]*[.]?[^\d\.]+)\.*(?<!\s)\s*' r'(?P<ranges>(?:{range_regex}(?:{sep_l}(?!\s*$)|(?=\s*$)))+)\s*$'.format( range_regex=range_regex, sep_l=REFERENCE_SEPARATORS['sep_l']))