openlp/openlp/plugins/images/lib/mediaitem.py

731 lines
36 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
2013-01-01 16:33:41 +00:00
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2017-12-29 09:15:48 +00:00
# Copyright (c) 2008-2018 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
2015-11-07 00:49:40 +00:00
from PyQt5 import QtCore, QtGui, QtWidgets
2010-04-27 16:27:57 +00:00
2017-10-07 07:05:07 +00:00
from openlp.core.common import delete_file, get_images_filter
from openlp.core.common.applocation import AppLocation
2018-10-02 04:39:42 +00:00
from openlp.core.common.i18n import UiStrings, get_natural_key, translate
2017-10-07 07:05:07 +00:00
from openlp.core.common.path import Path, create_paths
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
2018-10-02 04:39:42 +00:00
from openlp.core.lib import ServiceItemContext, build_icon, check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.plugin import StringContent
2018-10-02 04:39:42 +00:00
from openlp.core.lib.serviceitem import ItemCapabilities
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
2018-04-13 18:54:42 +00:00
from openlp.core.ui.icons import UiIcons
2017-10-23 22:09:57 +00:00
from openlp.core.widgets.views import TreeWidgetWithDnD
from openlp.plugins.images.forms.addgroupform import AddGroupForm
from openlp.plugins.images.forms.choosegroupform import ChooseGroupForm
2013-01-25 14:06:49 +00:00
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
2018-10-02 04:39:42 +00:00
2010-02-27 15:31:23 +00:00
log = logging.getLogger(__name__)
2013-01-30 10:57:06 +00:00
class ImageMediaItem(MediaManagerItem):
"""
This is the custom media manager item for images.
"""
2015-11-07 00:49:40 +00:00
images_go_live = QtCore.pyqtSignal(list)
images_add_to_service = QtCore.pyqtSignal(list)
2013-08-31 18:17:38 +00:00
log.info('Image Media Item loaded')
2013-03-07 13:14:31 +00:00
def __init__(self, parent, plugin):
2017-09-25 16:59:31 +00:00
self.icon_path = 'images/image'
self.manager = None
self.choose_group_form = None
self.add_group_form = None
2013-07-18 19:36:52 +00:00
super(ImageMediaItem, self).__init__(parent, plugin)
def setup_item(self):
"""
Do some additional setup.
"""
2015-11-07 00:49:40 +00:00
self.images_go_live.connect(self.go_live_remote)
self.images_add_to_service.connect(self.add_to_service_remote)
2013-03-19 22:00:50 +00:00
self.quick_preview_allowed = True
2013-03-23 06:46:41 +00:00
self.has_search = True
self.manager = self.plugin.manager
self.choose_group_form = ChooseGroupForm(self)
self.add_group_form = AddGroupForm(self)
self.fill_groups_combobox(self.choose_group_form.group_combobox)
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
2013-08-31 18:17:38 +00:00
Registry().register_function('live_theme_changed', self.live_theme_changed)
2013-04-19 19:03:16 +00:00
# Allow DnD from the desktop.
2013-03-19 22:00:50 +00:00
self.list_view.activateDnD()
def retranslate_ui(self):
2013-04-19 19:03:16 +00:00
self.on_new_prompt = translate('ImagePlugin.MediaItem', 'Select Image(s)')
file_formats = get_images_filter()
2016-05-21 18:19:18 +00:00
self.on_new_file_masks = '{formats};;{files} (*)'.format(formats=file_formats, files=UiStrings().AllFiles)
self.add_group_action.setText(UiStrings().AddGroupDot)
self.add_group_action.setToolTip(UiStrings().AddGroupDot)
2013-04-19 19:15:12 +00:00
self.replace_action.setText(UiStrings().ReplaceBG)
self.replace_action.setToolTip(UiStrings().ReplaceLiveBG)
self.replace_action_context.setText(UiStrings().ReplaceBG)
self.replace_action_context.setToolTip(UiStrings().ReplaceLiveBG)
2013-04-19 19:15:12 +00:00
self.reset_action.setText(UiStrings().ResetBG)
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
self.reset_action_context.setText(UiStrings().ResetBG)
self.reset_action_context.setToolTip(UiStrings().ResetLiveBG)
2013-03-19 22:00:50 +00:00
def required_icons(self):
"""
2013-04-19 19:03:16 +00:00
Set which icons the media manager tab should show.
2013-03-19 22:00:50 +00:00
"""
MediaManagerItem.required_icons(self)
self.has_file_icon = True
self.has_new_icon = False
self.has_edit_icon = False
self.add_to_service_item = True
2009-09-26 09:11:39 +00:00
2009-06-27 05:46:05 +00:00
def initialise(self):
2013-08-31 18:17:38 +00:00
log.debug('initialise')
2013-03-19 22:00:50 +00:00
self.list_view.clear()
self.list_view.setIconSize(QtCore.QSize(88, 50))
2013-03-23 07:07:06 +00:00
self.list_view.setIndentation(self.list_view.default_indentation)
2013-03-19 22:00:50 +00:00
self.list_view.allow_internal_dnd = True
self.service_path = AppLocation.get_section_data_path(self.settings_section) / 'thumbnails'
2017-10-07 07:05:07 +00:00
create_paths(self.service_path)
# Load images from the database
2013-04-19 19:07:25 +00:00
self.load_full_list(
self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.file_path), initial_load=True)
2009-06-27 05:46:05 +00:00
2013-03-19 22:00:50 +00:00
def add_list_view_to_toolbar(self):
"""
2013-04-19 19:03:16 +00:00
Creates the main widget for listing items the media item is tracking. This method overloads
MediaManagerItem.add_list_view_to_toolbar.
"""
# Add the List widget
2013-03-19 22:00:50 +00:00
self.list_view = TreeWidgetWithDnD(self, self.plugin.name)
2015-11-07 00:49:40 +00:00
self.list_view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
2013-03-19 22:00:50 +00:00
self.list_view.setAlternatingRowColors(True)
2016-05-21 18:19:18 +00:00
self.list_view.setObjectName('{name}TreeView'.format(name=self.plugin.name))
# Add to pageLayout
2013-03-19 22:00:50 +00:00
self.page_layout.addWidget(self.list_view)
# define and add the context menu
2013-03-19 22:00:50 +00:00
self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
if self.has_edit_icon:
2014-03-08 20:39:36 +00:00
create_widget_action(
self.list_view,
2013-08-31 18:17:38 +00:00
text=self.plugin.get_string(StringContent.Edit)['title'],
2018-04-13 18:54:42 +00:00
icon=UiIcons().edit,
2013-03-19 22:00:50 +00:00
triggers=self.on_edit_click)
create_widget_action(self.list_view, separator=True)
2014-03-08 20:39:36 +00:00
create_widget_action(
self.list_view,
2016-05-21 18:19:18 +00:00
'listView{name}{preview}Item'.format(name=self.plugin.name.title(), preview=StringContent.Preview.title()),
2013-08-31 18:17:38 +00:00
text=self.plugin.get_string(StringContent.Preview)['title'],
2018-04-13 18:54:42 +00:00
icon=UiIcons().preview,
can_shortcuts=True,
2013-03-19 22:00:50 +00:00
triggers=self.on_preview_click)
2014-03-08 20:39:36 +00:00
create_widget_action(
self.list_view,
2016-05-21 18:19:18 +00:00
'listView{name}{live}Item'.format(name=self.plugin.name.title(), live=StringContent.Live.title()),
2013-08-31 18:17:38 +00:00
text=self.plugin.get_string(StringContent.Live)['title'],
2018-04-13 18:54:42 +00:00
icon=UiIcons().live,
can_shortcuts=True,
2013-03-19 22:00:50 +00:00
triggers=self.on_live_click)
2014-03-08 20:39:36 +00:00
create_widget_action(
self.list_view,
2016-05-21 18:19:18 +00:00
'listView{name}{service}Item'.format(name=self.plugin.name.title(), service=StringContent.Service.title()),
can_shortcuts=True,
2013-08-31 18:17:38 +00:00
text=self.plugin.get_string(StringContent.Service)['title'],
2018-04-13 18:54:42 +00:00
icon=UiIcons().add,
2013-03-19 22:00:50 +00:00
triggers=self.on_add_click)
if self.add_to_service_item:
create_widget_action(self.list_view, separator=True)
2014-03-08 20:39:36 +00:00
create_widget_action(
self.list_view,
text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'),
2018-04-13 18:54:42 +00:00
icon=UiIcons().add,
2013-03-19 22:00:50 +00:00
triggers=self.on_add_edit_click)
2015-10-16 16:49:58 +00:00
create_widget_action(self.list_view, separator=True)
if self.has_delete_icon:
create_widget_action(
self.list_view,
2016-05-21 18:19:18 +00:00
'listView{name}{delete}Item'.format(name=self.plugin.name.title(), delete=StringContent.Delete.title()),
2015-10-16 16:49:58 +00:00
text=self.plugin.get_string(StringContent.Delete)['title'],
2018-04-13 18:54:42 +00:00
icon=UiIcons().delete,
2015-10-16 16:49:58 +00:00
can_shortcuts=True, triggers=self.on_delete_click)
2013-03-19 22:00:50 +00:00
self.add_custom_context_actions()
# Create the context menu and add all actions from the list_view.
2015-11-07 00:49:40 +00:00
self.menu = QtWidgets.QMenu()
2013-03-19 22:00:50 +00:00
self.menu.addActions(self.list_view.actions())
self.list_view.doubleClicked.connect(self.on_double_clicked)
self.list_view.itemSelectionChanged.connect(self.on_selection_change)
self.list_view.customContextMenuRequested.connect(self.context_menu)
2013-04-19 19:15:12 +00:00
self.list_view.addAction(self.replace_action)
2010-03-26 20:20:09 +00:00
2013-03-19 22:00:50 +00:00
def add_custom_context_actions(self):
"""
2013-04-19 19:03:16 +00:00
Add custom actions to the context menu.
"""
2013-03-19 22:00:50 +00:00
create_widget_action(self.list_view, separator=True)
2014-03-08 20:39:36 +00:00
create_widget_action(
self.list_view,
2018-04-22 06:59:35 +00:00
text=UiStrings().AddGroup, icon=UiIcons().group, triggers=self.on_add_group_click)
2014-03-08 20:39:36 +00:00
create_widget_action(
self.list_view,
text=translate('ImagePlugin', 'Add new image(s)'),
2018-04-13 18:54:42 +00:00
icon=UiIcons().open, triggers=self.on_file_click)
create_widget_action(self.list_view, separator=True)
self.replace_action_context = create_widget_action(
2018-06-02 06:37:31 +00:00
self.list_view, text=UiStrings().ReplaceBG, icon=UiIcons().theme, triggers=self.on_replace_click)
self.reset_action_context = create_widget_action(
2018-05-08 19:45:34 +00:00
self.list_view, text=UiStrings().ReplaceLiveBG, icon=UiIcons().close,
visible=False, triggers=self.on_reset_click)
2013-03-19 22:00:50 +00:00
def add_start_header_bar(self):
"""
2013-04-19 19:03:16 +00:00
Add custom buttons to the start of the toolbar.
"""
2014-03-08 20:39:36 +00:00
self.add_group_action = self.toolbar.add_toolbar_action('add_group_action',
2018-04-22 06:59:35 +00:00
icon=UiIcons().group,
2014-03-08 20:39:36 +00:00
triggers=self.on_add_group_click)
2013-01-25 14:06:49 +00:00
2013-03-19 22:00:50 +00:00
def add_end_header_bar(self):
"""
Add custom buttons to the end of the toolbar
"""
2013-08-31 18:17:38 +00:00
self.replace_action = self.toolbar.add_toolbar_action('replace_action',
2018-06-02 06:37:31 +00:00
icon=UiIcons().theme,
2014-03-08 20:39:36 +00:00
triggers=self.on_replace_click)
2013-08-31 18:17:38 +00:00
self.reset_action = self.toolbar.add_toolbar_action('reset_action',
2018-05-08 19:45:34 +00:00
icon=UiIcons().close,
2014-03-08 20:39:36 +00:00
visible=False, triggers=self.on_reset_click)
2013-03-11 15:23:43 +00:00
def recursively_delete_group(self, image_group):
"""
2013-04-19 19:03:16 +00:00
Recursively deletes a group and all groups and images in it.
2014-03-08 20:53:22 +00:00
:param image_group: The ImageGroups instance of the group that will be deleted.
"""
images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id)
for image in images:
delete_file(self.service_path / image.file_path.name)
delete_file(self.generate_thumbnail_path(image))
self.manager.delete_object(ImageFilenames, image.id)
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id)
for group in image_groups:
2013-03-11 15:23:43 +00:00
self.recursively_delete_group(group)
self.manager.delete_object(ImageGroups, group.id)
2013-03-19 22:00:50 +00:00
def on_delete_click(self):
"""
2013-04-19 19:03:16 +00:00
Remove an image item from the list.
"""
# Turn off auto preview triggers.
2013-03-19 22:00:50 +00:00
self.list_view.blockSignals(True)
if check_item_selected(self.list_view, translate('ImagePlugin.MediaItem',
2014-03-08 20:39:36 +00:00
'You must select an image or group to delete.')):
2013-03-19 22:00:50 +00:00
item_list = self.list_view.selectedItems()
2013-02-03 19:23:12 +00:00
self.application.set_busy_cursor()
2013-03-18 14:11:58 +00:00
self.main_window.display_progress_bar(len(item_list))
2013-01-25 14:06:49 +00:00
for row_item in item_list:
if row_item:
item_data = row_item.data(0, QtCore.Qt.UserRole)
if isinstance(item_data, ImageFilenames):
delete_file(self.service_path / row_item.text(0))
delete_file(self.generate_thumbnail_path(item_data))
if item_data.group_id == 0:
2013-03-19 22:00:50 +00:00
self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item))
else:
row_item.parent().removeChild(row_item)
self.manager.delete_object(ImageFilenames, row_item.data(0, QtCore.Qt.UserRole).id)
elif isinstance(item_data, ImageGroups):
2015-11-07 00:49:40 +00:00
if QtWidgets.QMessageBox.question(
2014-03-08 20:39:36 +00:00
self.list_view.parent(),
2013-04-19 19:03:16 +00:00
translate('ImagePlugin.MediaItem', 'Remove group'),
translate('ImagePlugin.MediaItem',
2016-05-21 18:19:18 +00:00
'Are you sure you want to remove "{name}" and everything in it?'
).format(name=item_data.group_name)
2015-11-07 00:49:40 +00:00
) == QtWidgets.QMessageBox.Yes:
2013-03-11 15:23:43 +00:00
self.recursively_delete_group(item_data)
self.manager.delete_object(ImageGroups, row_item.data(0, QtCore.Qt.UserRole).id)
if item_data.parent_id == 0:
2013-03-19 22:00:50 +00:00
self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item))
else:
row_item.parent().removeChild(row_item)
self.fill_groups_combobox(self.choose_group_form.group_combobox)
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
2013-03-07 08:05:43 +00:00
self.main_window.increment_progress_bar()
2013-03-16 11:05:52 +00:00
self.main_window.finished_progress_bar()
2013-02-03 19:23:12 +00:00
self.application.set_normal_cursor()
2013-03-19 22:00:50 +00:00
self.list_view.blockSignals(False)
2009-06-27 19:55:55 +00:00
def add_sub_groups(self, group_list, parent_group_id):
2013-01-25 14:06:49 +00:00
"""
2013-04-19 19:03:16 +00:00
Recursively add subgroups to the given parent group in a QTreeWidget.
2014-03-08 20:39:36 +00:00
:param group_list: The List object that contains all QTreeWidgetItems.
:param parent_group_id: The ID of the group that will be added recursively.
2013-01-25 14:06:49 +00:00
"""
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
image_groups.sort(key=lambda group_object: get_natural_key(group_object.group_name))
2018-04-22 06:59:35 +00:00
folder_icon = UiIcons().group
2013-01-25 14:06:49 +00:00
for image_group in image_groups:
2015-11-07 00:49:40 +00:00
group = QtWidgets.QTreeWidgetItem()
2013-01-25 14:06:49 +00:00
group.setText(0, image_group.group_name)
group.setData(0, QtCore.Qt.UserRole, image_group)
group.setIcon(0, folder_icon)
if parent_group_id == 0:
2013-03-19 22:00:50 +00:00
self.list_view.addTopLevelItem(group)
2013-01-25 14:06:49 +00:00
else:
group_list[parent_group_id].addChild(group)
group_list[image_group.id] = group
self.add_sub_groups(group_list, image_group.id)
2013-01-25 14:06:49 +00:00
def fill_groups_combobox(self, combobox, parent_group_id=0, prefix=''):
2013-01-25 14:06:49 +00:00
"""
2013-04-19 19:03:16 +00:00
Recursively add groups to the combobox in the 'Add group' dialog.
2014-03-08 20:39:36 +00:00
:param combobox: The QComboBox to add the options to.
:param parent_group_id: The ID of the group that will be added.
:param prefix: A string containing the prefix that will be added in front of the groupname for each level of
2015-09-08 19:13:59 +00:00
the tree.
2013-01-25 14:06:49 +00:00
"""
if parent_group_id == 0:
combobox.clear()
combobox.top_level_group_added = False
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
image_groups.sort(key=lambda group_object: get_natural_key(group_object.group_name))
2013-01-25 14:06:49 +00:00
for image_group in image_groups:
combobox.addItem(prefix + image_group.group_name, image_group.id)
self.fill_groups_combobox(combobox, image_group.id, prefix + ' ')
def expand_group(self, group_id, root_item=None):
"""
2013-04-19 19:03:16 +00:00
Expand groups in the widget recursively.
2014-03-08 20:39:36 +00:00
:param group_id: The ID of the group that will be expanded.
:param root_item: This option is only used for recursion purposes.
"""
return_value = False
if root_item is None:
2013-03-19 22:00:50 +00:00
root_item = self.list_view.invisibleRootItem()
for i in range(root_item.childCount()):
child = root_item.child(i)
if self.expand_group(group_id, child):
child.setExpanded(True)
return_value = True
if isinstance(root_item.data(0, QtCore.Qt.UserRole), ImageGroups):
if root_item.data(0, QtCore.Qt.UserRole).id == group_id:
return True
return return_value
2013-01-25 14:06:49 +00:00
2015-01-28 20:41:42 +00:00
def generate_thumbnail_path(self, image):
"""
Generate a path to the thumbnail
:param openlp.plugins.images.lib.db.ImageFilenames image: The image to generate the thumbnail path for.
:return: A path to the thumbnail
:rtype: openlp.core.common.path.Path
2015-01-28 20:41:42 +00:00
"""
ext = image.file_path.suffix.lower()
return self.service_path / '{name:d}{ext}'.format(name=image.id, ext=ext)
2015-01-28 20:41:42 +00:00
2013-04-19 19:07:25 +00:00
def load_full_list(self, images, initial_load=False, open_group=None):
2013-01-25 14:06:49 +00:00
"""
Replace the list of images and groups in the interface.
:param list[openlp.plugins.images.lib.db.ImageFilenames] images: A List of Image Filenames objects that will be
used to reload the mediamanager list.
2014-03-08 20:39:36 +00:00
:param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images.
2014-03-21 18:23:35 +00:00
:param open_group: ImageGroups object of the group that must be expanded after reloading the list in the
2015-09-08 19:13:59 +00:00
interface.
2013-01-25 14:06:49 +00:00
"""
if not initial_load:
2013-02-11 09:21:46 +00:00
self.application.set_busy_cursor()
2013-03-16 11:05:52 +00:00
self.main_window.display_progress_bar(len(images))
2013-03-19 22:00:50 +00:00
self.list_view.clear()
2013-04-19 19:07:25 +00:00
# Load the list of groups and add them to the treeView.
2013-01-25 14:06:49 +00:00
group_items = {}
self.add_sub_groups(group_items, parent_group_id=0)
if open_group is not None:
self.expand_group(open_group.id)
2013-04-19 19:07:25 +00:00
# Sort the images by its filename considering language specific.
# characters.
images.sort(key=lambda image_object: get_natural_key(image_object.file_path.name))
for image in images:
log.debug('Loading image: {name}'.format(name=image.file_path))
file_name = image.file_path.name
thumbnail_path = self.generate_thumbnail_path(image)
if not image.file_path.exists():
2018-04-13 18:54:42 +00:00
icon = UiIcons().delete
2011-06-12 15:17:01 +00:00
else:
if validate_thumb(image.file_path, thumbnail_path):
icon = build_icon(thumbnail_path)
2010-04-19 16:45:13 +00:00
else:
2017-11-21 07:23:02 +00:00
icon = create_thumb(image.file_path, thumbnail_path)
item_name = QtWidgets.QTreeWidgetItem([file_name])
item_name.setText(0, file_name)
item_name.setIcon(0, icon)
item_name.setToolTip(0, str(image.file_path))
item_name.setData(0, QtCore.Qt.UserRole, image)
if image.group_id == 0:
2013-03-19 22:00:50 +00:00
self.list_view.addTopLevelItem(item_name)
else:
group_items[image.group_id].addChild(item_name)
if not initial_load:
2013-03-07 08:05:43 +00:00
self.main_window.increment_progress_bar()
if not initial_load:
2013-03-16 11:05:52 +00:00
self.main_window.finished_progress_bar()
2013-02-03 19:23:12 +00:00
self.application.set_normal_cursor()
2009-06-27 15:33:03 +00:00
def validate_and_load(self, file_paths, target_group=None):
"""
Process a list for files either from the File Dialog or from Drag and Drop.
This method is overloaded from MediaManagerItem.
2014-03-08 20:39:36 +00:00
:param files: A List of strings containing the filenames of the files to be loaded
:param target_group: The QTreeWidgetItem of the group that will be the parent of the added files
"""
file_paths = [Path(file) for file in file_paths]
self.application.set_normal_cursor()
self.load_list(file_paths, target_group)
last_dir = file_paths[0].parent
Settings().setValue(self.settings_section + '/last directory', last_dir)
def load_list(self, image_paths, target_group=None, initial_load=False):
2013-01-25 14:06:49 +00:00
"""
Add new images to the database. This method is called when adding images using the Add button or DnD.
:param list[openlp.core.common.Path] image_paths: A list of file paths to the images to be loaded
2014-03-08 20:39:36 +00:00
:param target_group: The QTreeWidgetItem of the group that will be the parent of the added files
:param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images
2013-01-25 14:06:49 +00:00
"""
parent_group = None
if target_group is None:
# Find out if a group must be pre-selected
preselect_group = None
2013-03-19 22:00:50 +00:00
selected_items = self.list_view.selectedItems()
if selected_items:
selected_item = selected_items[0]
if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageFilenames):
selected_item = selected_item.parent()
2015-11-07 00:49:40 +00:00
if isinstance(selected_item, QtWidgets.QTreeWidgetItem):
if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups):
preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id
# Enable and disable parts of the 'choose group' form
if self.manager.get_object_count(ImageGroups) == 0:
self.choose_group_form.existing_radio_button.setDisabled(True)
self.choose_group_form.group_combobox.setDisabled(True)
else:
self.choose_group_form.existing_radio_button.setDisabled(False)
self.choose_group_form.group_combobox.setDisabled(False)
# Ask which group the image_paths should be saved in
2015-11-07 00:49:40 +00:00
if self.choose_group_form.exec(selected_group=preselect_group):
if self.choose_group_form.nogroup_radio_button.isChecked():
# User chose 'No group'
parent_group = ImageGroups()
parent_group.id = 0
elif self.choose_group_form.existing_radio_button.isChecked():
# User chose 'Existing group'
group_id = self.choose_group_form.group_combobox.itemData(
self.choose_group_form.group_combobox.currentIndex(), QtCore.Qt.UserRole)
parent_group = self.manager.get_object_filtered(ImageGroups, ImageGroups.id == group_id)
elif self.choose_group_form.new_radio_button.isChecked():
# User chose 'New group'
parent_group = ImageGroups()
parent_group.parent_id = 0
parent_group.group_name = self.choose_group_form.new_group_edit.text()
self.manager.save_object(parent_group)
self.fill_groups_combobox(self.choose_group_form.group_combobox)
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
else:
parent_group = target_group.data(0, QtCore.Qt.UserRole)
if isinstance(parent_group, ImageFilenames):
if parent_group.group_id == 0:
parent_group = ImageGroups()
parent_group.id = 0
else:
parent_group = target_group.parent().data(0, QtCore.Qt.UserRole)
# If no valid parent group is found, do nothing
if not isinstance(parent_group, ImageGroups):
return
# Initialize busy cursor and progress bar
self.application.set_busy_cursor()
self.main_window.display_progress_bar(len(image_paths))
# Save the new image_paths in the database
self.save_new_images_list(image_paths, group_id=parent_group.id, reload_list=False)
self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.file_path),
2014-03-08 20:39:36 +00:00
initial_load=initial_load, open_group=parent_group)
self.application.set_normal_cursor()
def save_new_images_list(self, image_paths, group_id=0, reload_list=True):
"""
Convert a list of image filenames to ImageFilenames objects and save them in the database.
:param list[Path] image_paths: A List of file paths to image
2014-03-08 20:39:36 +00:00
:param group_id: The ID of the group to save the images in
2014-03-21 18:23:35 +00:00
:param reload_list: This boolean is set to True when the list in the interface should be reloaded after saving
2015-09-08 19:13:59 +00:00
the new images
"""
for image_path in image_paths:
if not isinstance(image_path, Path):
continue
log.debug('Adding new image: {name}'.format(name=image_path))
2014-03-08 20:39:36 +00:00
image_file = ImageFilenames()
image_file.group_id = group_id
image_file.file_path = image_path
2014-03-08 20:39:36 +00:00
self.manager.save_object(image_file)
2013-03-11 15:23:43 +00:00
self.main_window.increment_progress_bar()
if reload_list and image_paths:
self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.file_path))
2013-01-25 14:06:49 +00:00
2013-01-30 10:57:06 +00:00
def dnd_move_internal(self, target):
"""
Handle drag-and-drop moving of images within the media manager
2014-03-08 20:39:36 +00:00
:param target: This contains the QTreeWidget that is the target of the DnD action
"""
2013-03-19 22:00:50 +00:00
items_to_move = self.list_view.selectedItems()
# Determine group to move images to
target_group = target
2013-03-04 14:29:31 +00:00
if target_group is not None and isinstance(target_group.data(0, QtCore.Qt.UserRole), ImageFilenames):
target_group = target.parent()
2013-03-04 14:29:31 +00:00
# Move to toplevel
if target_group is None:
2013-03-19 22:00:50 +00:00
target_group = self.list_view.invisibleRootItem()
2013-03-04 14:29:31 +00:00
target_group.setData(0, QtCore.Qt.UserRole, ImageGroups())
target_group.data(0, QtCore.Qt.UserRole).id = 0
# Move images in the treeview
items_to_save = []
for item in items_to_move:
if isinstance(item.data(0, QtCore.Qt.UserRole), ImageFilenames):
2015-11-07 00:49:40 +00:00
if isinstance(item.parent(), QtWidgets.QTreeWidgetItem):
2013-03-04 14:29:31 +00:00
item.parent().removeChild(item)
else:
2013-03-19 22:00:50 +00:00
self.list_view.invisibleRootItem().removeChild(item)
target_group.addChild(item)
item.setSelected(True)
item_data = item.data(0, QtCore.Qt.UserRole)
item_data.group_id = target_group.data(0, QtCore.Qt.UserRole).id
items_to_save.append(item_data)
target_group.setExpanded(True)
# Update the group ID's of the images in the database
self.manager.save_objects(items_to_save)
# Sort the target group
group_items = []
image_items = []
for item in target_group.takeChildren():
if isinstance(item.data(0, QtCore.Qt.UserRole), ImageGroups):
group_items.append(item)
if isinstance(item.data(0, QtCore.Qt.UserRole), ImageFilenames):
image_items.append(item)
group_items.sort(key=lambda item: get_natural_key(item.text(0)))
target_group.addChildren(group_items)
image_items.sort(key=lambda item: get_natural_key(item.text(0)))
target_group.addChildren(image_items)
2014-03-08 20:39:36 +00:00
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
context=ServiceItemContext.Service):
2013-03-19 22:00:50 +00:00
"""
Generate the slide data. Needs to be implemented by the plugin.
2014-03-08 20:39:36 +00:00
:param service_item: The service item to be built on
:param item: The Song item to be used
:param xml_version: The xml version (not used)
:param remote: Triggered from remote
:param context: Why is it being generated
2013-03-19 22:00:50 +00:00
"""
2013-08-31 18:17:38 +00:00
background = QtGui.QColor(Settings().value(self.settings_section + '/background color'))
if item:
items = [item]
else:
2013-03-19 22:00:50 +00:00
items = self.list_view.selectedItems()
2011-01-02 10:29:18 +00:00
if not items:
2011-01-02 07:57:05 +00:00
return False
# Determine service item title
if isinstance(items[0].data(0, QtCore.Qt.UserRole), ImageGroups) or len(items) == 1:
service_item.title = items[0].text(0)
2013-05-16 05:05:41 +00:00
else:
2013-08-31 18:17:38 +00:00
service_item.title = str(self.plugin.name_strings['plural'])
2011-08-28 17:45:13 +00:00
service_item.add_capability(ItemCapabilities.CanMaintain)
service_item.add_capability(ItemCapabilities.CanPreview)
service_item.add_capability(ItemCapabilities.CanLoop)
service_item.add_capability(ItemCapabilities.CanAppend)
service_item.add_capability(ItemCapabilities.CanEditTitle)
service_item.add_capability(ItemCapabilities.HasThumbnails)
# force a nonexistent theme
service_item.theme = -1
2014-03-08 20:39:36 +00:00
missing_items_file_names = []
2015-01-28 20:41:42 +00:00
images = []
# Expand groups to images
for bitem in items:
if isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageGroups) or bitem.data(0, QtCore.Qt.UserRole) is None:
for index in range(0, bitem.childCount()):
if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames):
2015-01-28 20:41:42 +00:00
images.append(bitem.child(index).data(0, QtCore.Qt.UserRole))
2013-05-14 15:05:41 +00:00
elif isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
2015-01-28 20:41:42 +00:00
images.append(bitem.data(0, QtCore.Qt.UserRole))
# Don't try to display empty groups
2015-01-28 20:41:42 +00:00
if not images:
return False
# Find missing files
2015-01-28 20:41:42 +00:00
for image in images:
if not image.file_path.exists():
missing_items_file_names.append(str(image.file_path))
# We cannot continue, as all images do not exist.
2015-01-28 20:41:42 +00:00
if not images:
if not remote:
critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
2016-05-21 18:19:18 +00:00
translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: {names}'
).format(names='\n'.join(missing_items_file_names)))
return False
# We have missing as well as existing images. We ask what to do.
2015-11-07 00:49:40 +00:00
elif missing_items_file_names and QtWidgets.QMessageBox.question(
2014-03-08 20:39:36 +00:00
self, translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
2016-05-21 18:19:18 +00:00
translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: {names}\n'
'Do you want to add the other images anyway?'
).format(names='\n'.join(missing_items_file_names))) == \
2015-11-07 00:49:40 +00:00
QtWidgets.QMessageBox.No:
return False
# Continue with the existing images.
2015-01-28 20:41:42 +00:00
for image in images:
name = image.file_path.name
thumbnail_path = self.generate_thumbnail_path(image)
service_item.add_from_image(str(image.file_path), name, background, str(thumbnail_path))
return True
def check_group_exists(self, new_group):
2013-01-25 14:06:49 +00:00
"""
Returns *True* if the given Group already exists in the database, otherwise *False*.
2013-01-25 14:06:49 +00:00
2014-03-08 20:39:36 +00:00
:param new_group: The ImageGroups object that contains the name of the group that will be checked
2013-01-25 14:06:49 +00:00
"""
groups = self.manager.get_all_objects(ImageGroups, ImageGroups.group_name == new_group.group_name)
if groups:
2013-01-25 14:06:49 +00:00
return True
else:
return False
2013-01-25 14:06:49 +00:00
2013-04-19 19:07:25 +00:00
def on_add_group_click(self):
2013-01-25 14:06:49 +00:00
"""
Called to add a new group
"""
# Find out if a group must be pre-selected
preselect_group = 0
2013-03-19 22:00:50 +00:00
selected_items = self.list_view.selectedItems()
if selected_items:
selected_item = selected_items[0]
if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageFilenames):
selected_item = selected_item.parent()
2015-11-07 00:49:40 +00:00
if isinstance(selected_item, QtWidgets.QTreeWidgetItem):
if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups):
preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id
# Show 'add group' dialog
2015-11-07 00:49:40 +00:00
if self.add_group_form.exec(show_top_level_group=True, selected_group=preselect_group):
new_group = ImageGroups.populate(parent_id=self.add_group_form.parent_group_combobox.itemData(
self.add_group_form.parent_group_combobox.currentIndex(), QtCore.Qt.UserRole),
group_name=self.add_group_form.name_edit.text())
if not self.check_group_exists(new_group):
2013-01-25 14:06:49 +00:00
if self.manager.save_object(new_group):
2014-03-08 20:39:36 +00:00
self.load_full_list(self.manager.get_all_objects(
ImageFilenames, order_by_ref=ImageFilenames.file_path))
2013-03-11 15:26:41 +00:00
self.expand_group(new_group.id)
self.fill_groups_combobox(self.choose_group_form.group_combobox)
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
2013-01-25 14:06:49 +00:00
else:
critical_error_message_box(
message=translate('ImagePlugin.AddGroupForm', 'Could not add the new group.'))
else:
2013-04-19 19:07:25 +00:00
critical_error_message_box(message=translate('ImagePlugin.AddGroupForm', 'This group already exists.'))
2013-01-25 14:06:49 +00:00
2013-04-19 19:07:25 +00:00
def on_reset_click(self):
"""
2013-04-19 19:07:25 +00:00
Called to reset the Live background with the image selected.
"""
2013-04-19 19:15:12 +00:00
self.reset_action.setVisible(False)
self.reset_action_context.setVisible(False)
2013-02-20 19:31:51 +00:00
self.live_controller.display.reset_image()
2013-02-07 11:33:47 +00:00
def live_theme_changed(self):
"""
2013-04-19 19:07:25 +00:00
Triggered by the change of theme in the slide controller.
"""
2013-04-19 19:15:12 +00:00
self.reset_action.setVisible(False)
self.reset_action_context.setVisible(False)
2013-04-19 19:07:25 +00:00
def on_replace_click(self):
2011-01-04 17:36:22 +00:00
"""
2014-03-08 20:39:36 +00:00
Called to replace Live background with the image selected.
2011-01-04 17:36:22 +00:00
"""
2014-03-08 20:39:36 +00:00
if check_item_selected(
self.list_view,
2013-01-01 16:33:41 +00:00
translate('ImagePlugin.MediaItem', 'You must select an image to replace the background with.')):
2013-08-31 18:17:38 +00:00
background = QtGui.QColor(Settings().value(self.settings_section + '/background color'))
2013-03-19 22:00:50 +00:00
bitem = self.list_view.selectedItems()[0]
if not isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
2013-04-19 19:07:25 +00:00
# Only continue when an image is selected.
return
file_path = bitem.data(0, QtCore.Qt.UserRole).file_path
if file_path.exists():
if self.live_controller.display.direct_image(str(file_path), background):
2013-04-19 19:15:12 +00:00
self.reset_action.setVisible(True)
self.reset_action_context.setVisible(True)
else:
2014-03-08 20:39:36 +00:00
critical_error_message_box(
UiStrings().LiveBGError,
2013-01-01 16:33:41 +00:00
translate('ImagePlugin.MediaItem', 'There was no display item to amend.'))
else:
2014-03-08 20:39:36 +00:00
critical_error_message_box(
UiStrings().LiveBGError,
2013-01-01 16:33:41 +00:00
translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, '
'the image file "{name}" no longer exists.').format(name=file_path))
def search(self, string, show_error=True):
"""
Perform a search on the image file names.
:param str string: The glob to search for
:param bool show_error: Unused.
"""
2014-03-08 20:39:36 +00:00
files = self.manager.get_all_objects(
ImageFilenames, filter_clause=ImageFilenames.file_path.contains(string),
order_by_ref=ImageFilenames.file_path)
results = []
2013-01-30 10:57:06 +00:00
for file_object in files:
file_name = file_object.file_path.name
results.append([str(file_object.file_path), file_name])
return results
def create_item_from_id(self, item_id):
"""
Create a media item from an item id. Overridden from the parent method to change the item type.
:param item_id: Id to make live
"""
item_id = Path(item_id)
2015-11-07 00:49:40 +00:00
item = QtWidgets.QTreeWidgetItem()
item_data = self.manager.get_object_filtered(ImageFilenames, ImageFilenames.file_path == item_id)
item.setText(0, item_data.file_path.name)
item.setData(0, QtCore.Qt.UserRole, item_data)
return item