Beispiel #1
0
 def on_clone_click(self):
     """
     Clone a Song
     """
     log.debug('on_clone_click')
     if check_item_selected(self.list_view, UiStrings().SelectEdit):
         self.edit_item = self.list_view.currentItem()
         item_id = self.edit_item.data(QtCore.Qt.UserRole)
         old_song = self.plugin.manager.get_object(Song, item_id)
         song_xml = self.open_lyrics.song_to_xml(old_song)
         new_song = self.open_lyrics.xml_to_song(song_xml)
         new_song.title = '{title} <{text}>'.format(title=new_song.title,
                                                    text=translate('SongsPlugin.MediaItem',
                                                                   'copy', 'For song cloning'))
         # Copy audio files from the old to the new song
         if len(old_song.media_files) > 0:
             save_path = AppLocation.get_section_data_path(self.plugin.name) / 'audio' / str(new_song.id)
             create_paths(save_path)
             for media_file in old_song.media_files:
                 new_media_file_path = save_path / media_file.file_path.name
                 copyfile(media_file.file_path, new_media_file_path)
                 new_media_file = MediaFile()
                 new_media_file.file_path = new_media_file_path
                 new_media_file.type = media_file.type
                 new_media_file.weight = media_file.weight
                 new_song.media_files.append(new_media_file)
         self.plugin.manager.save_object(new_song)
     self.on_song_list_load()
Beispiel #2
0
    def _write_theme(self, theme, image_source_path=None, image_destination_path=None):
        """
        Writes the theme to the disk and handles the background image if necessary

        :param Theme theme: The theme data object.
        :param openlp.core.common.path.Path image_source_path: Where the theme image is currently located.
        :param openlp.core.common.path.Path image_destination_path: Where the Theme Image is to be saved to
        :rtype: None
        """
        name = theme.theme_name
        theme_pretty = theme.export_theme(self.theme_path)
        theme_dir = self.theme_path / name
        create_paths(theme_dir)
        theme_path = theme_dir / '{file_name}.json'.format(file_name=name)
        try:
                theme_path.write_text(theme_pretty)
        except OSError:
            self.log_exception('Saving theme to file failed')
        if image_source_path and image_destination_path:
            if self.old_background_image_path and image_destination_path != self.old_background_image_path:
                delete_file(self.old_background_image_path)
            if image_source_path != image_destination_path:
                try:
                    copyfile(image_source_path, image_destination_path)
                except OSError:
                    self.log_exception('Failed to save theme image')
        self.generate_and_save_image(name, theme)
    def __init__(self,
                 plugin=None,
                 name='PresentationController',
                 document_class=PresentationDocument):
        """
        This is the constructor for the presentationcontroller object. This provides an easy way for descendent plugins

        to populate common data. This method *must* be overridden, like so::

            class MyPresentationController(PresentationController):
                def __init__(self, plugin):
                    PresentationController.__init(
                        self, plugin, 'My Presenter App')

        :param plugin:  Defaults to *None*. The presentationplugin object
        :param name: Name of the application, to appear in the application
        :param document_class:
        """
        self.supports = []
        self.also_supports = []
        self.docs = []
        self.plugin = plugin
        self.name = name
        self.document_class = document_class
        self.settings_section = self.plugin.settings_section
        self.available = None
        self.temp_folder = AppLocation.get_section_data_path(
            self.settings_section) / name
        self.thumbnail_folder = AppLocation.get_section_data_path(
            self.settings_section) / 'thumbnails'
        self.thumbnail_prefix = 'slide'
        create_paths(self.thumbnail_folder, self.temp_folder)
Beispiel #4
0
def set_up_fault_handling():
    """
    Set up the Python fault handler
    """
    # Create the cache directory if it doesn't exist, and enable the fault handler to log to an error log file
    create_paths(AppLocation.get_directory(AppLocation.CacheDir))
    faulthandler.enable((AppLocation.get_directory(AppLocation.CacheDir) / 'error.log').open('wb'))
Beispiel #5
0
 def set_defaults(self):
     """
     Set up display at start of theme edit.
     """
     self.restart()
     self.web = 'https://get.openlp.org/ftw/'
     self.currentIdChanged.connect(self.on_current_id_changed)
     Registry().register_function('config_screen_changed', self.screen_selection_widget.load)
     # Check if this is a re-run of the wizard.
     self.has_run_wizard = Settings().value('core/has run wizard')
     create_paths(Path(gettempdir(), 'openlp'))
     self.theme_combo_box.clear()
     self.button(QtWidgets.QWizard.CustomButton1).setVisible(False)
     if self.has_run_wizard:
         self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active())
         self.bible_check_box.setChecked(self.plugin_manager.get_plugin_by_name('bibles').is_active())
         self.presentation_check_box.setChecked(
             self.plugin_manager.get_plugin_by_name('presentations').is_active())
         self.image_check_box.setChecked(self.plugin_manager.get_plugin_by_name('images').is_active())
         self.media_check_box.setChecked(self.plugin_manager.get_plugin_by_name('media').is_active())
         self.custom_check_box.setChecked(self.plugin_manager.get_plugin_by_name('custom').is_active())
         self.song_usage_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songusage').is_active())
         self.alert_check_box.setChecked(self.plugin_manager.get_plugin_by_name('alerts').is_active())
         # Add any existing themes to list.
         self.theme_combo_box.insertSeparator(0)
         self.theme_combo_box.addItems(sorted(self.theme_manager.get_theme_names()))
         default_theme = Settings().value('themes/global theme')
         # Pre-select the current default theme.
         index = self.theme_combo_box.findText(default_theme)
         self.theme_combo_box.setCurrentIndex(index)
Beispiel #6
0
 def _update_background_audio(self, song, item):
     song.media_files = []
     for i, bga in enumerate(item.background_audio):
         dest_path =\
             AppLocation.get_section_data_path(self.plugin.name) / 'audio' / str(song.id) / os.path.split(bga)[1]
         create_paths(dest_path.parent)
         copyfile(AppLocation.get_section_data_path('servicemanager') / bga, dest_path)
         song.media_files.append(MediaFile.populate(weight=i, file_path=dest_path))
     self.plugin.manager.save_object(song, True)
Beispiel #7
0
 def initialise(self):
     """
     Initialize media item.
     """
     self.list_view.clear()
     self.service_path = AppLocation.get_section_data_path(self.settings_section) / 'thumbnails'
     create_paths(self.service_path)
     self.load_list([path_to_str(file) for file in Settings().value(self.settings_section + '/media files')])
     self.rebuild_players()
Beispiel #8
0
    def build_theme_path(self):
        """
        Set up the theme path variables

        :rtype: None
        """
        self.theme_path = AppLocation.get_section_data_path(self.settings_section)
        self.thumb_path = self.theme_path / 'thumbnails'
        create_paths(self.theme_path, self.thumb_path)
Beispiel #9
0
    def get_section_data_path(section):
        """
        Return the path a particular module stores its data under.

        :param str section:
        :rtype: openlp.core.common.path.Path
        """
        path = AppLocation.get_data_path() / section
        create_paths(path)
        return 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 openlp.core.common.path.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())
Beispiel #11
0
 def initialise():
     """
     Create the internal file structure if it does not exist
     :return:
     """
     create_paths(
         AppLocation.get_section_data_path('remotes') / 'assets',
         AppLocation.get_section_data_path('remotes') / 'images',
         AppLocation.get_section_data_path('remotes') / 'static',
         AppLocation.get_section_data_path('remotes') / 'static' / 'index',
         AppLocation.get_section_data_path('remotes') / 'templates')
Beispiel #12
0
 def initialise(self):
     log.debug('initialise')
     self.list_view.clear()
     self.list_view.setIconSize(QtCore.QSize(88, 50))
     self.list_view.setIndentation(self.list_view.default_indentation)
     self.list_view.allow_internal_dnd = True
     self.service_path = AppLocation.get_section_data_path(
         self.settings_section) / 'thumbnails'
     create_paths(self.service_path)
     # Load images from the database
     self.load_full_list(self.manager.get_all_objects(
         ImageFilenames, order_by_ref=ImageFilenames.file_path),
                         initial_load=True)
Beispiel #13
0
    def __init__(self, parent, songs, save_path):
        """
        Initialise the export.

        :param pathlib.Path save_path: The directory to save the exported songs in
        :rtype: None
        """
        log.debug('initialise OpenLyricsExport')
        self.parent = parent
        self.manager = parent.plugin.manager
        self.songs = songs
        self.save_path = save_path
        create_paths(self.save_path)
Beispiel #14
0
    def test_create_paths_dir_io_error(self, mocked_logger):
        """
        Test the create_paths() when an OSError is raised
        """
        # GIVEN: A `Path` to check with patched out mkdir and exists methods
        mocked_path = MagicMock()
        mocked_path.exists.side_effect = OSError('Cannot make directory')

        # WHEN: An OSError is raised when checking the if the path exists.
        create_paths(mocked_path)

        # THEN: The Error should have been logged
        mocked_logger.exception.assert_called_once_with(
            'failed to check if directory exists or create directory')
Beispiel #15
0
    def test_create_paths_dir_doesnt_exists(self):
        """
        Test the create_paths() function when the path does not already exist
        """
        # GIVEN: A `Path` to check with patched out mkdir and exists methods
        mocked_path = MagicMock()
        mocked_path.exists.return_value = False

        # WHEN: `create_paths` is called and the path does not exist
        create_paths(mocked_path)

        # THEN: The directory should have been created
        mocked_path.exists.assert_called_once_with()
        mocked_path.mkdir.assert_called_once_with(parents=True)
Beispiel #16
0
    def test_create_paths_dir_exists(self):
        """
        Test the create_paths() function when the path already exists
        """
        # GIVEN: A `Path` to check with patched out mkdir and exists methods
        mocked_path = MagicMock()
        mocked_path.exists.return_value = True

        # WHEN: `create_paths` is called and the path exists
        create_paths(mocked_path)

        # THEN: The function should not attempt to create the directory
        mocked_path.exists.assert_called_once_with()
        assert mocked_path.mkdir.call_count == 0, 'mkdir should not have been called'
Beispiel #17
0
    def get_data_path():
        """
        Return the path OpenLP stores all its data under.

        :return: The data path to use.
        :rtype: openlp.core.common.path.Path
        """
        # Check if we have a different data location.
        if Settings().contains('advanced/data path'):
            path = Path(Settings().value('advanced/data path'))
        else:
            path = AppLocation.get_directory(AppLocation.DataDir)
            create_paths(path)
        return path
Beispiel #18
0
    def test_create_paths_dir_value_error(self):
        """
        Test the create_paths() when an error other than OSError is raised
        """
        # GIVEN: A `Path` to check with patched out mkdir and exists methods
        mocked_path = MagicMock()
        mocked_path.exists.side_effect = ValueError('Some other error')

        # WHEN: Some other exception is raised
        try:
            create_paths(mocked_path)
            assert False, 'create_paths should have thrown an exception'
        except:
            # THEN: `create_paths` raises an exception
            pass
Beispiel #19
0
def set_up_logging(log_path):
    """
    Setup our logging using log_path

    :param openlp.core.common.path.Path log_path: The file to save the log to.
    :rtype: None
    """
    create_paths(log_path, do_not_log=True)
    file_path = log_path / 'openlp.log'
    # TODO: FileHandler accepts a Path object in Py3.6
    logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8')
    logfile.setFormatter(
        logging.Formatter(
            '%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
    log.addHandler(logfile)
    if log.isEnabledFor(logging.DEBUG):
        print('Logging to: {name}'.format(name=file_path))
Beispiel #20
0
 def accept(self):
     """
     Ok was triggered so lets save the data and run the report
     """
     log.debug('accept')
     path = self.report_path_edit.path
     if not path:
         self.main_window.error_message(
             translate('SongUsagePlugin.SongUsageDetailForm', 'Output Path Not Selected'),
             translate('SongUsagePlugin.SongUsageDetailForm', 'You have not set a valid output location for your'
                       ' song usage report.\nPlease select an existing path on your computer.')
         )
         return
     create_paths(path)
     file_name = translate('SongUsagePlugin.SongUsageDetailForm',
                           'usage_detail_{old}_{new}.txt'
                           ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
                                    new=self.to_date_calendar.selectedDate().toString('ddMMyyyy'))
     self.settings.setValue(self.plugin.settings_section + '/from date', self.from_date_calendar.selectedDate())
     self.settings.setValue(self.plugin.settings_section + '/to date', self.to_date_calendar.selectedDate())
     usage = self.plugin.manager.get_all_objects(
         SongUsageItem, and_(SongUsageItem.usagedate >= self.from_date_calendar.selectedDate().toPyDate(),
                             SongUsageItem.usagedate < self.to_date_calendar.selectedDate().toPyDate()),
         [SongUsageItem.usagedate, SongUsageItem.usagetime])
     report_file_name = path / file_name
     try:
         with report_file_name.open('wb') as file_handle:
             for instance in usage:
                 record = ('\"{date}\",\"{time}\",\"{title}\",\"{copyright}\",\"{ccli}\",\"{authors}\",'
                           '\"{name}\",\"{source}\"\n').format(date=instance.usagedate, time=instance.usagetime,
                                                               title=instance.title, copyright=instance.copyright,
                                                               ccli=instance.ccl_number, authors=instance.authors,
                                                               name=instance.plugin_name, source=instance.source)
                 file_handle.write(record.encode('utf-8'))
             self.main_window.information_message(
                 translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation'),
                 translate('SongUsagePlugin.SongUsageDetailForm',
                           'Report\n{name}\nhas been successfully created.').format(name=report_file_name)
             )
     except OSError as ose:
         log.exception('Failed to write out song usage records')
         critical_error_message_box(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation Failed'),
                                    translate('SongUsagePlugin.SongUsageDetailForm',
                                              'An error occurred while creating the report: {error}'
                                              ).format(error=ose.strerror))
     self.close()
Beispiel #21
0
def set_up_fault_handling():
    """
    Set up the Python fault handler
    """
    global error_log_file
    # Create the cache directory if it doesn't exist, and enable the fault handler to log to an error log file
    try:
        create_paths(AppLocation.get_directory(AppLocation.CacheDir))
        error_log_file = (AppLocation.get_directory(AppLocation.CacheDir) /
                          'error.log').open('wb')
        atexit.register(tear_down_fault_handling)
        faulthandler.enable(error_log_file)
    except OSError:
        log.exception('An exception occurred when enabling the fault handler')
        atexit.unregister(tear_down_fault_handling)
        if error_log_file:
            error_log_file.close()
Beispiel #22
0
    def copy_media_file(self, song_id, file_path):
        """
        This method copies the media file to the correct location and returns
        the new file location.

        :param song_id:
        :param openlp.core.common.path.Path file_path: The file to copy.
        :return: The new location of the file
        :rtype: openlp.core.common.path.Path
        """
        if not hasattr(self, 'save_path'):
            self.save_path = AppLocation.get_section_data_path(
                self.import_wizard.plugin.name) / 'audio' / str(song_id)
        create_paths(self.save_path)
        if self.save_path not in file_path.parents:
            old_path, file_path = file_path, self.save_path / file_path.name
            copyfile(old_path, file_path)
        return file_path
Beispiel #23
0
 def set_defaults(self):
     """
     Set up display at start of theme edit.
     """
     self.restart()
     self.web = 'http://openlp.org/files/frw/'
     self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
     self.no_internet_finish_button.clicked.connect(
         self.on_no_internet_finish_button_clicked)
     self.no_internet_cancel_button.clicked.connect(
         self.on_no_internet_cancel_button_clicked)
     self.currentIdChanged.connect(self.on_current_id_changed)
     Registry().register_function('config_screen_changed',
                                  self.update_screen_list_combo)
     self.no_internet_finish_button.setVisible(False)
     self.no_internet_cancel_button.setVisible(False)
     # Check if this is a re-run of the wizard.
     self.has_run_wizard = Settings().value('core/has run wizard')
     create_paths(Path(gettempdir(), 'openlp'))
Beispiel #24
0
    def save_theme(self, theme, image=None, background_override=None):
        """
        Writes the theme to the disk and including the background image and thumbnail if necessary

        :param Theme theme: The theme data object.
        :param image: The theme thumbnail. Optionally.
        :param background_override: Background to use rather than background_source. Optionally.
        :rtype: None
        """
        name = theme.theme_name
        theme_pretty = theme.export_theme(self.theme_path)
        theme_dir = self.theme_path / name
        create_paths(theme_dir)
        theme_path = theme_dir / '{file_name}.json'.format(file_name=name)
        try:
            theme_path.write_text(theme_pretty)
        except OSError:
            self.log_exception('Saving theme to file failed')
        if theme.background_source and theme.background_filename:
            background_file = background_override
            # Use theme source image if override doesn't exist
            if not background_file or not background_file.exists():
                background_file = theme.background_source
            if self.old_background_image_path and theme.background_filename != self.old_background_image_path:
                delete_file(self.old_background_image_path)
            if not background_file.exists():
                self.log_warning(
                    'Background does not exist, retaining cached background')
            elif background_file != theme.background_filename:
                try:
                    shutil.copyfile(background_file, theme.background_filename)
                except OSError:
                    self.log_exception('Failed to save theme image')
        if image:
            sample_path_name = self.theme_path / '{file_name}.png'.format(
                file_name=name)
            if sample_path_name.exists():
                sample_path_name.unlink()
            image.save(str(sample_path_name), 'png')
            thumb_path = self.thumb_path / '{name}.png'.format(name=name)
            create_thumb(sample_path_name, thumb_path, False)
        else:
            self.update_preview_images([name])
Beispiel #25
0
 def unzip_theme(self, file_path, directory_path):
     """
     Unzip the theme, remove the preview file if stored. Generate a new preview file. Check the XML theme version
     and upgrade if necessary.
     :param Path file_path:
     :param Path directory_path:
     """
     self.log_debug('Unzipping theme {name}'.format(name=file_path))
     file_xml = None
     abort_import = True
     json_theme = False
     theme_name = ""
     try:
         with zipfile.ZipFile(file_path) as theme_zip:
             json_file = [
                 name for name in theme_zip.namelist()
                 if os.path.splitext(name)[1].lower() == '.json'
             ]
             if len(json_file) != 1:
                 # TODO: remove XML handling after once the upgrade path from 2.4 is no longer required
                 xml_file = [
                     name for name in theme_zip.namelist()
                     if os.path.splitext(name)[1].lower() == '.xml'
                 ]
                 if len(xml_file) != 1:
                     self.log_error(
                         'Theme contains "{val:d}" theme files'.format(
                             val=len(xml_file)))
                     raise ValidationError
                 xml_tree = ElementTree(
                     element=XML(theme_zip.read(xml_file[0]))).getroot()
                 theme_version = xml_tree.get('version', default=None)
                 if not theme_version or float(theme_version) < 2.0:
                     self.log_error('Theme version is less than 2.0')
                     raise ValidationError
                 theme_name = xml_tree.find('name').text.strip()
             else:
                 new_theme = Theme()
                 new_theme.load_theme(
                     theme_zip.read(json_file[0]).decode("utf-8"))
                 theme_name = new_theme.theme_name
                 json_theme = True
             theme_folder = directory_path / theme_name
             if theme_folder.exists(
             ) and not self.over_write_message_box(theme_name):
                 abort_import = True
                 return
             else:
                 abort_import = False
             for zipped_file in theme_zip.namelist():
                 zipped_file_rel_path = Path(zipped_file)
                 split_name = zipped_file_rel_path.parts
                 if split_name[-1] == '' or len(split_name) == 1:
                     # is directory or preview file
                     continue
                 full_name = directory_path / zipped_file_rel_path
                 create_paths(full_name.parent)
                 if zipped_file_rel_path.suffix.lower(
                 ) == '.xml' or zipped_file_rel_path.suffix.lower(
                 ) == '.json':
                     file_xml = str(theme_zip.read(zipped_file), 'utf-8')
                     with full_name.open('w', encoding='utf-8') as out_file:
                         out_file.write(file_xml)
                 else:
                     with full_name.open('wb') as out_file:
                         out_file.write(theme_zip.read(zipped_file))
     except (OSError, ValidationError, zipfile.BadZipFile):
         self.log_exception('Importing theme from zip failed {name}'.format(
             name=file_path))
         critical_error_message_box(
             translate('OpenLP.ThemeManager', 'Import Error'),
             translate(
                 'OpenLP.ThemeManager',
                 'There was a problem importing {file_name}.\n\nIt is corrupt, '
                 'inaccessible or not a valid theme.').format(
                     file_name=file_path))
     finally:
         if not abort_import:
             # As all files are closed, we can create the Theme.
             if file_xml:
                 if json_theme:
                     self._create_theme_from_json(file_xml, self.theme_path)
                 else:
                     self._create_theme_from_xml(file_xml, self.theme_path)
             return theme_name
         else:
             return None