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)
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()
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 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()
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()
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
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)
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)
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)
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()
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)
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)
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)
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
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()
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 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()
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 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
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
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)
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
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)
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)
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)
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)
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))
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()