示例#1
0
    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 = os.path.join(AppLocation.get_section_data_path(self.settings_section), name)
        self.thumbnail_folder = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
        self.thumbnail_prefix = 'slide'
        check_directory_exists(self.thumbnail_folder)
        check_directory_exists(self.temp_folder)
示例#2
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 = '%s <%s>' % \
                          (new_song.title, 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 = os.path.join(AppLocation.get_section_data_path(self.plugin.name), 'audio', str(new_song.id))
             check_directory_exists(save_path)
             for media_file in old_song.media_files:
                 new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name))
                 shutil.copyfile(media_file.file_name, new_media_file_name)
                 new_media_file = MediaFile()
                 new_media_file.file_name = new_media_file_name
                 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()
示例#3
0
 def _setup(self, name):
     """
     Run some initial setup. This method is separate from __init__ in order to mock it out in tests.
     """
     self.slide_number = 0
     self.file_path = name
     check_directory_exists(self.get_thumbnail_folder())
 def _setup(self, name):
     """
     Run some initial setup. This method is separate from __init__ in order to mock it out in tests.
     """
     self.slide_number = 0
     self.file_path = name
     check_directory_exists(self.get_thumbnail_folder())
    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 = os.path.join(AppLocation.get_section_data_path(self.settings_section), name)
        self.thumbnail_folder = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
        self.thumbnail_prefix = 'slide'
        check_directory_exists(self.thumbnail_folder)
        check_directory_exists(self.temp_folder)
示例#6
0
 def accept(self):
     """
     Ok was triggered so lets save the data and run the report
     """
     log.debug('accept')
     path = self.file_line_edit.text()
     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
     check_directory_exists(path)
     file_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.txt') % \
         (self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
          self.to_date_calendar.selectedDate().toString('ddMMyyyy'))
     Settings().setValue(self.plugin.settings_section + '/from date',
                         self.from_date_calendar.selectedDate())
     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 = os.path.join(path, file_name)
     file_handle = None
     try:
         file_handle = open(report_file_name, 'wb')
         for instance in usage:
             record = '\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \
                 '\"%s\",\"%s\"\n' % \
                      (instance.usagedate, instance.usagetime, instance.title, instance.copyright,
                       instance.ccl_number, instance.authors, instance.plugin_name, instance.source)
             file_handle.write(record.encode('utf-8'))
         self.main_window.information_message(
             translate('SongUsagePlugin.SongUsageDetailForm',
                       'Report Creation'),
             translate('SongUsagePlugin.SongUsageDetailForm',
                       'Report \n%s \nhas been successfully created. ') %
             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: %s') %
             ose.strerror)
     finally:
         if file_handle:
             file_handle.close()
     self.close()
示例#7
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 = os.path.join(AppLocation.get_section_data_path(self.plugin.name), 'audio', str(new_song.id))
             check_directory_exists(save_path)
             for media_file in old_song.media_files:
                 new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name))
                 shutil.copyfile(media_file.file_name, new_media_file_name)
                 new_media_file = MediaFile()
                 new_media_file.file_name = new_media_file_name
                 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()
示例#8
0
 def get_section_data_path(section):
     """
     Return the path a particular module stores its data under.
     """
     data_path = AppLocation.get_data_path()
     path = os.path.join(data_path, section)
     check_directory_exists(path)
     return path
示例#9
0
 def build_theme_path(self):
     """
     Set up the theme path variables
     """
     self.path = AppLocation.get_section_data_path(self.settings_section)
     check_directory_exists(self.path)
     self.thumb_path = os.path.join(self.path, 'thumbnails')
     check_directory_exists(self.thumb_path)
示例#10
0
 def get_section_data_path(section):
     """
     Return the path a particular module stores its data under.
     """
     data_path = AppLocation.get_data_path()
     path = os.path.join(data_path, section)
     check_directory_exists(path)
     return path
示例#11
0
 def build_loop_path(self):
     """
     Set up the loop path variables
     """
     self.path = AppLocation.get_section_data_path(self.settings_section)
     check_directory_exists(self.path)
     self.thumb_path = os.path.join(self.path, 'thumbnails')
     check_directory_exists(self.thumb_path)
示例#12
0
 def _update_background_audio(self, song, item):
     song.media_files = []
     for i, bga in enumerate(item.background_audio):
         dest_file = os.path.join(
             AppLocation.get_section_data_path(self.plugin.name), 'audio', str(song.id), os.path.split(bga)[1])
         check_directory_exists(os.path.split(dest_file)[0])
         shutil.copyfile(os.path.join(AppLocation.get_section_data_path('servicemanager'), bga), dest_file)
         song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))
     self.plugin.manager.save_object(song, True)
示例#13
0
 def _update_background_audio(self, song, item):
     song.media_files = []
     for i, bga in enumerate(item.background_audio):
         dest_file = os.path.join(
             AppLocation.get_section_data_path(self.plugin.name), 'audio', str(song.id), os.path.split(bga)[1])
         check_directory_exists(os.path.split(dest_file)[0])
         shutil.copyfile(os.path.join(AppLocation.get_section_data_path('servicemanager'), bga), dest_file)
         song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))
     self.plugin.manager.save_object(song, True)
示例#14
0
 def initialise(self):
     """
     Initialize media item.
     """
     self.list_view.clear()
     self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
     check_directory_exists(self.service_path)
     self.load_list(Settings().value(self.settings_section + '/media files'))
     self.rebuild_players()
示例#15
0
 def __init__(self, parent, songs, save_path):
     """
     Initialise the export.
     """
     log.debug('initialise OpenLyricsExport')
     self.parent = parent
     self.manager = parent.plugin.manager
     self.songs = songs
     self.save_path = save_path
     check_directory_exists(self.save_path)
示例#16
0
 def __init__(self, parent, songs, save_path):
     """
     Initialise the export.
     """
     log.debug('initialise OpenLyricsExport')
     self.parent = parent
     self.manager = parent.plugin.manager
     self.songs = songs
     self.save_path = save_path
     check_directory_exists(self.save_path)
示例#17
0
 def get_data_path():
     """
     Return the path OpenLP stores all its data under.
     """
     # Check if we have a different data location.
     if Settings().contains('advanced/data path'):
         path = Settings().value('advanced/data path')
     else:
         path = AppLocation.get_directory(AppLocation.DataDir)
         check_directory_exists(path)
     return os.path.normpath(path)
示例#18
0
 def get_data_path():
     """
     Return the path OpenLP stores all its data under.
     """
     # Check if we have a different data location.
     if Settings().contains('advanced/data path'):
         path = Settings().value('advanced/data path')
     else:
         path = AppLocation.get_directory(AppLocation.DataDir)
         check_directory_exists(path)
     return os.path.normpath(path)
示例#19
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 = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
     check_directory_exists(self.service_path)
     # Load images from the database
     self.load_full_list(
         self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True)
示例#20
0
 def backup_old_bibles(self, backup_directory):
     """
     Backup old bible databases in a given folder.
     """
     check_directory_exists(backup_directory)
     success = True
     for filename in self.files:
         try:
             shutil.copy(os.path.join(self.path, filename[0]), backup_directory)
         except:
             success = False
     return success
示例#21
0
 def initialise(self):
     """
     Initialize media item.
     """
     self.list_view.clear()
     self.service_path = os.path.join(
         AppLocation.get_section_data_path(self.settings_section),
         'thumbnails')
     check_directory_exists(self.service_path)
     self.load_list(Settings().value(self.settings_section +
                                     '/media files'))
     self.rebuild_players()
示例#22
0
def set_up_logging(log_path):
    """
    Setup our logging using log_path

    :param log_path: the path
    """
    check_directory_exists(log_path, True)
    filename = os.path.join(log_path, 'openlp.log')
    logfile = logging.FileHandler(filename, '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: %s' % filename)
 def backup_old_bibles(self, backup_directory):
     """
     Backup old bible databases in a given folder.
     """
     check_directory_exists(backup_directory)
     success = True
     for filename in self.files:
         try:
             shutil.copy(os.path.join(self.path, filename[0]),
                         backup_directory)
         except:
             success = False
     return success
示例#24
0
 def accept(self):
     """
     Ok was triggered so lets save the data and run the report
     """
     log.debug('accept')
     path = self.file_line_edit.text()
     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
     check_directory_exists(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'))
     Settings().setValue(self.plugin.settings_section + '/from date', self.from_date_calendar.selectedDate())
     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 = os.path.join(path, file_name)
     file_handle = None
     try:
         file_handle = open(report_file_name, 'wb')
         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))
     finally:
         if file_handle:
             file_handle.close()
     self.close()
示例#25
0
def set_up_logging(log_path):
    """
    Setup our logging using log_path

    :param log_path: the path
    """
    check_directory_exists(log_path, True)
    filename = os.path.join(log_path, 'openlp.log')
    logfile = logging.FileHandler(filename, '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: %s' % filename)
示例#26
0
    def copy_media_file(self, song_id, filename):
        """
        This method copies the media file to the correct location and returns
        the new file location.

        :param song_id:
        :param filename: The file to copy.
        """
        if not hasattr(self, 'save_path'):
            self.save_path = os.path.join(AppLocation.get_section_data_path(self.import_wizard.plugin.name),
                                          'audio', str(song_id))
        check_directory_exists(self.save_path)
        if not filename.startswith(self.save_path):
            old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1])
            shutil.copyfile(old_file, filename)
        return filename
示例#27
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')
     check_directory_exists(os.path.join(gettempdir(), 'openlp'))
示例#28
0
    def copy_media_file(self, song_id, filename):
        """
        This method copies the media file to the correct location and returns
        the new file location.

        :param song_id:
        :param filename: The file to copy.
        """
        if not hasattr(self, 'save_path'):
            self.save_path = os.path.join(AppLocation.get_section_data_path(self.import_wizard.plugin.name),
                                          'audio', str(song_id))
        check_directory_exists(self.save_path)
        if not filename.startswith(self.save_path):
            old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1])
            shutil.copyfile(old_file, filename)
        return filename
示例#29
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')
     check_directory_exists(os.path.join(gettempdir(), 'openlp'))
 def validateCurrentPage(self):
     """
     Validate the current page before moving on to the next page.
     """
     if self.currentPage() == self.welcome_page:
         return True
     elif self.currentPage() == self.backup_page:
         if not self.noBackupCheckBox.checkState() == QtCore.Qt.Checked:
             backup_path = self.backupDirectoryEdit.text()
             if not backup_path:
                 critical_error_message_box(
                     UiStrings().EmptyField,
                     translate(
                         'BiblesPlugin.UpgradeWizardForm',
                         'You need to specify a backup directory for '
                         'your Bibles.'))
                 self.backupDirectoryEdit.setFocus()
                 return False
             else:
                 if not self.backup_old_bibles(backup_path):
                     critical_error_message_box(
                         UiStrings().Error,
                         translate(
                             'BiblesPlugin.UpgradeWizardForm',
                             'The backup was not successful.\nTo backup '
                             'your Bibles you need permission to write to the given directory.'
                         ))
                     return False
         return True
     elif self.currentPage() == self.selectPage:
         check_directory_exists(self.temp_dir)
         for number, filename in enumerate(self.files):
             if not self.checkBox[number].checkState() == QtCore.Qt.Checked:
                 continue
             # Move bibles to temp dir.
             if not os.path.exists(os.path.join(self.temp_dir,
                                                filename[0])):
                 shutil.move(os.path.join(self.path, filename[0]),
                             self.temp_dir)
             else:
                 delete_file(os.path.join(self.path, filename[0]))
         return True
     if self.currentPage() == self.progress_page:
         return True
示例#31
0
    def _write_theme(self, theme, image_from, image_to):
        """
        Writes the theme to the disk and handles the background image if necessary

        :param theme: The theme data object.
        :param image_from: Where the theme image is currently located.
        :param image_to: Where the Theme Image is to be saved to
        """
        name = theme.theme_name
        theme_pretty_xml = theme.extract_formatted_xml()
        theme_dir = os.path.join(self.path, name)
        check_directory_exists(theme_dir)
        theme_file = os.path.join(theme_dir, name + '.xml')
        if self.old_background_image and image_to != self.old_background_image:
            delete_file(self.old_background_image)
        out_file = None
        try:
            out_file = open(theme_file, 'w', encoding='utf-8')
            out_file.write(theme_pretty_xml.decode('utf-8'))
        except IOError:
            self.log_exception('Saving theme to file failed')
        finally:
            if out_file:
                out_file.close()
        if image_from and os.path.abspath(image_from) != os.path.abspath(
                image_to):
            try:
                # Windows is always unicode, so no need to encode filenames
                if is_win():
                    shutil.copyfile(image_from, image_to)
                else:
                    encoding = get_filesystem_encoding()
                    shutil.copyfile(image_from.encode(encoding),
                                    image_to.encode(encoding))
            except IOError as xxx_todo_changeme:
                shutil.Error = xxx_todo_changeme
                self.log_exception('Failed to save theme image')
        self.generate_and_save_image(name, theme)
示例#32
0
 def validateCurrentPage(self):
     """
     Validate the current page before moving on to the next page.
     """
     if self.currentPage() == self.welcome_page:
         return True
     elif self.currentPage() == self.backup_page:
         if not self.noBackupCheckBox.checkState() == QtCore.Qt.Checked:
             backup_path = self.backupDirectoryEdit.text()
             if not backup_path:
                 critical_error_message_box(
                     UiStrings().EmptyField,
                     translate('BiblesPlugin.UpgradeWizardForm', 'You need to specify a backup directory for '
                                                                 'your Bibles.'))
                 self.backupDirectoryEdit.setFocus()
                 return False
             else:
                 if not self.backup_old_bibles(backup_path):
                     critical_error_message_box(
                         UiStrings().Error,
                         translate('BiblesPlugin.UpgradeWizardForm', 'The backup was not successful.\nTo backup '
                                   'your Bibles you need permission to write to the given directory.'))
                     return False
         return True
     elif self.currentPage() == self.selectPage:
         check_directory_exists(self.temp_dir)
         for number, filename in enumerate(self.files):
             if not self.checkBox[number].checkState() == QtCore.Qt.Checked:
                 continue
             # Move bibles to temp dir.
             if not os.path.exists(os.path.join(self.temp_dir, filename[0])):
                 shutil.move(os.path.join(self.path, filename[0]), self.temp_dir)
             else:
                 delete_file(os.path.join(self.path, filename[0]))
         return True
     if self.currentPage() == self.progress_page:
         return True
示例#33
0
    def _write_theme(self, theme, image_from, image_to):
        """
        Writes the theme to the disk and handles the background image if necessary

        :param theme: The theme data object.
        :param image_from: Where the theme image is currently located.
        :param image_to: Where the Theme Image is to be saved to
        """
        name = theme.theme_name
        theme_pretty_xml = theme.extract_formatted_xml()
        theme_dir = os.path.join(self.path, name)
        check_directory_exists(theme_dir)
        theme_file = os.path.join(theme_dir, name + '.xml')
        if self.old_background_image and image_to != self.old_background_image:
            delete_file(self.old_background_image)
        out_file = None
        try:
            out_file = open(theme_file, 'w', encoding='utf-8')
            out_file.write(theme_pretty_xml.decode('utf-8'))
        except IOError:
            self.log_exception('Saving theme to file failed')
        finally:
            if out_file:
                out_file.close()
        if image_from and os.path.abspath(image_from) != os.path.abspath(image_to):
            try:
                # Windows is always unicode, so no need to encode filenames
                if is_win():
                    shutil.copyfile(image_from, image_to)
                else:
                    encoding = get_filesystem_encoding()
                    shutil.copyfile(image_from.encode(encoding), image_to.encode(encoding))
            except IOError as xxx_todo_changeme:
                shutil.Error = xxx_todo_changeme
                self.log_exception('Failed to save theme image')
        self.generate_and_save_image(name, theme)
示例#34
0
    def check_directory_exists_test(self):
        """
        Test the check_directory_exists() function
        """
        with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
                patch('openlp.core.lib.os.makedirs') as mocked_makedirs:
            # GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
            directory_to_check = 'existing/directory'

            # WHEN: os.path.exists returns True and we check to see if the directory exists
            mocked_exists.return_value = True
            check_directory_exists(directory_to_check)

            # THEN: Only os.path.exists should have been called
            mocked_exists.assert_called_with(directory_to_check)
            self.assertIsNot(mocked_makedirs.called,
                             'os.makedirs should not have been called')

            # WHEN: os.path.exists returns False and we check the directory exists
            mocked_exists.return_value = False
            check_directory_exists(directory_to_check)

            # THEN: Both the mocked functions should have been called
            mocked_exists.assert_called_with(directory_to_check)
            mocked_makedirs.assert_called_with(directory_to_check)

            # WHEN: os.path.exists raises an IOError
            mocked_exists.side_effect = IOError()
            check_directory_exists(directory_to_check)

            # THEN: We shouldn't get an exception though the mocked exists has been called
            mocked_exists.assert_called_with(directory_to_check)

            # WHEN: Some other exception is raised
            mocked_exists.side_effect = ValueError()

            # THEN: check_directory_exists raises an exception
            mocked_exists.assert_called_with(directory_to_check)
            self.assertRaises(ValueError, check_directory_exists,
                              directory_to_check)
示例#35
0
    def test_check_directory_exists(self):
        """
        Test the check_directory_exists() function
        """
        with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
                patch('openlp.core.lib.os.makedirs') as mocked_makedirs:
            # GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
            directory_to_check = 'existing/directory'

            # WHEN: os.path.exists returns True and we check to see if the directory exists
            mocked_exists.return_value = True
            check_directory_exists(directory_to_check)

            # THEN: Only os.path.exists should have been called
            mocked_exists.assert_called_with(directory_to_check)
            self.assertIsNot(mocked_makedirs.called, 'os.makedirs should not have been called')

            # WHEN: os.path.exists returns False and we check the directory exists
            mocked_exists.return_value = False
            check_directory_exists(directory_to_check)

            # THEN: Both the mocked functions should have been called
            mocked_exists.assert_called_with(directory_to_check)
            mocked_makedirs.assert_called_with(directory_to_check)

            # WHEN: os.path.exists raises an IOError
            mocked_exists.side_effect = IOError()
            check_directory_exists(directory_to_check)

            # THEN: We shouldn't get an exception though the mocked exists has been called
            mocked_exists.assert_called_with(directory_to_check)

            # WHEN: Some other exception is raised
            mocked_exists.side_effect = ValueError()

            # THEN: check_directory_exists raises an exception
            mocked_exists.assert_called_with(directory_to_check)
            self.assertRaises(ValueError, check_directory_exists, directory_to_check)
示例#36
0
 def unzip_theme(self, file_name, directory):
     """
     Unzip the theme, remove the preview file if stored. Generate a new preview file. Check the XML theme version
     and upgrade if necessary.
     :param file_name:
     :param directory:
     """
     self.log_debug('Unzipping theme %s' % file_name)
     theme_zip = None
     out_file = None
     file_xml = None
     abort_import = True
     try:
         theme_zip = zipfile.ZipFile(file_name)
         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 "%s" XML files' % 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()
         theme_folder = os.path.join(directory, theme_name)
         theme_exists = os.path.exists(theme_folder)
         if theme_exists and not self.over_write_message_box(theme_name):
             abort_import = True
             return
         else:
             abort_import = False
         for name in theme_zip.namelist():
             out_name = name.replace('/', os.path.sep)
             split_name = out_name.split(os.path.sep)
             if split_name[-1] == '' or len(split_name) == 1:
                 # is directory or preview file
                 continue
             full_name = os.path.join(directory, out_name)
             check_directory_exists(os.path.dirname(full_name))
             if os.path.splitext(name)[1].lower() == '.xml':
                 file_xml = str(theme_zip.read(name), 'utf-8')
                 out_file = open(full_name, 'w', encoding='utf-8')
                 out_file.write(file_xml)
             else:
                 out_file = open(full_name, 'wb')
                 out_file.write(theme_zip.read(name))
             out_file.close()
     except (IOError, zipfile.BadZipfile):
         self.log_exception('Importing theme from zip failed %s' %
                            file_name)
         raise ValidationError
     except ValidationError:
         critical_error_message_box(
             translate('OpenLP.ThemeManager', 'Validation Error'),
             translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
     finally:
         # Close the files, to be able to continue creating the theme.
         if theme_zip:
             theme_zip.close()
         if out_file:
             out_file.close()
         if not abort_import:
             # As all files are closed, we can create the Theme.
             if file_xml:
                 theme = self._create_theme_from_xml(file_xml, self.path)
                 self.generate_and_save_image(theme_name, theme)
             # Only show the error message, when IOError was not raised (in
             # this case the error message has already been shown).
             elif theme_zip is not None:
                 critical_error_message_box(
                     translate('OpenLP.ThemeManager', 'Validation Error'),
                     translate('OpenLP.ThemeManager',
                               'File is not a valid theme.'))
                 self.log_error('Theme file does not contain XML data %s' %
                                file_name)
示例#37
0
 def unzip_theme(self, file_name, directory):
     """
     Unzip the theme, remove the preview file if stored. Generate a new preview file. Check the XML theme version
     and upgrade if necessary.
     :param file_name:
     :param directory:
     """
     self.log_debug('Unzipping theme {name}'.format(name=file_name))
     theme_zip = None
     out_file = None
     file_xml = None
     abort_import = True
     try:
         theme_zip = zipfile.ZipFile(file_name)
         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}" XML 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()
         theme_folder = os.path.join(directory, theme_name)
         theme_exists = os.path.exists(theme_folder)
         if theme_exists and not self.over_write_message_box(theme_name):
             abort_import = True
             return
         else:
             abort_import = False
         for name in theme_zip.namelist():
             out_name = name.replace('/', os.path.sep)
             split_name = out_name.split(os.path.sep)
             if split_name[-1] == '' or len(split_name) == 1:
                 # is directory or preview file
                 continue
             full_name = os.path.join(directory, out_name)
             check_directory_exists(os.path.dirname(full_name))
             if os.path.splitext(name)[1].lower() == '.xml':
                 file_xml = str(theme_zip.read(name), 'utf-8')
                 out_file = open(full_name, 'w', encoding='utf-8')
                 out_file.write(file_xml)
             else:
                 out_file = open(full_name, 'wb')
                 out_file.write(theme_zip.read(name))
             out_file.close()
     except (IOError, zipfile.BadZipfile):
         self.log_exception('Importing theme from zip failed {name}'.format(name=file_name))
         raise ValidationError
     except ValidationError:
         critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'),
                                    translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
     finally:
         # Close the files, to be able to continue creating the theme.
         if theme_zip:
             theme_zip.close()
         if out_file:
             out_file.close()
         if not abort_import:
             # As all files are closed, we can create the Theme.
             if file_xml:
                 theme = self._create_theme_from_xml(file_xml, self.path)
                 self.generate_and_save_image(theme_name, theme)
             # Only show the error message, when IOError was not raised (in
             # this case the error message has already been shown).
             elif theme_zip is not None:
                 critical_error_message_box(
                     translate('OpenLP.ThemeManager', 'Validation Error'),
                     translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
                 self.log_error('Theme file does not contain XML data {name}'.format(name=file_name))
示例#38
0
    def accept(self):
        """
        Ok was triggered so lets save the data and run the report
        """
        log.debug('accept')
        path = self.file_line_edit.text()
        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
        check_directory_exists(path)
        file_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.txt') % \
            (self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
             self.to_date_calendar.selectedDate().toString('ddMMyyyy'))
        xls_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.xls') % \
            (self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
             self.to_date_calendar.selectedDate().toString('ddMMyyyy'))
        Settings().setValue(self.plugin.settings_section + '/from date',
                            self.from_date_calendar.selectedDate())
        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 = os.path.join(path, file_name)
        xls_file_name = os.path.join(path, xls_name)
        file_handle = None
        try:
            file_handle = open(report_file_name, 'wb')
            for instance in usage:
                record = '\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \
                    '\"%s\",\"%s\"\n' % \
                         (instance.usagedate, instance.usagetime, instance.title, instance.copyright,
                          instance.ccl_number, instance.authors, instance.plugin_name, instance.source)
                file_handle.write(record.encode('utf-8'))

            wb = xlwt.Workbook()
            ws = wb.add_sheet("Song Usage")

            # Add headings with styling and froszen first row
            heading_format = xlwt.easyxf(
                'font: bold on; align: vert centre, horiz centre')
            date_format = xlwt.XFStyle()
            date_format.num_format_str = 'dd/mm/yyyy'
            time_format = xlwt.XFStyle()
            time_format.num_format_str = 'hh:mm'
            ws.write_merge(
                0, 0, 0, 6, 'CCLI Report data (%s - %s)' %
                (self.from_date_calendar.selectedDate().toString('dd/MM/yyyy'),
                 self.to_date_calendar.selectedDate().toString('dd/MM/yyyy')),
                heading_format)
            headings = [
                'Date', 'Time', 'Song title', 'Copyright', 'CCL No.',
                'Authors', 'Usage type'
            ]
            row = 2
            ws.set_panes_frozen(True)  # frozen headings instead of split panes
            ws.set_horz_split_pos(row + 1)  # freeze after last heading row
            ws.set_remove_splits(
                True)  # if user does unfreeze, don't leave a split there
            for col, value in enumerate(headings):
                ws.write(row, col, value, heading_format)
            for instance in usage:
                row = row + 1
                ws.write(row, 0, instance.usagedate, date_format)
                ws.write(row, 1, instance.usagetime, time_format)
                ws.write(row, 2, instance.title)
                ws.write(row, 3, instance.copyright)
                ws.write(row, 4, instance.ccl_number)
                ws.write(row, 5, instance.authors)
                ws.write(row, 6, instance.source)
            ws.col(2).width = 256 * (
                1 + max([len(instance.title) for instance in usage]))
            ws.col(3).width = 256 * (
                1 + max([len(instance.copyright) for instance in usage]))
            ws.col(5).width = 256 * (
                1 + max([len(instance.authors) for instance in usage]))
            wb.save(xls_file_name)

            self.main_window.information_message(
                translate('SongUsagePlugin.SongUsageDetailForm',
                          'Report Creation'),
                translate(
                    'SongUsagePlugin.SongUsageDetailForm',
                    'Reports \n%s and\n%s\nhave been successfully created. ') %
                (report_file_name, xls_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: %s') %
                ose.strerror)
        finally:
            if file_handle:
                file_handle.close()
        self.close()