Beispiel #1
0
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)
Beispiel #3
0
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']))