openlp/openlp/core/ui/listpreviewwidget.py

223 lines
9.8 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2015-12-31 22:46:06 +00:00
# Copyright (c) 2008-2016 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 #
###############################################################################
"""
The :mod:`listpreviewwidget` is a widget that lists the slides in the slide controller.
It is based on a QTableWidget but represents its contents in list form.
"""
2013-08-31 18:17:38 +00:00
2015-11-07 00:49:40 +00:00
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import RegistryProperties, Settings
2013-12-13 17:44:05 +00:00
from openlp.core.lib import ImageSource, ServiceItem
2015-11-07 00:49:40 +00:00
class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
"""
A special type of QTableWidget which lists the slides in the slide controller
:param parent:
:param screen_ratio:
"""
def __init__(self, parent, screen_ratio):
"""
Initializes the widget to default state.
An empty ``ServiceItem`` is used by default. replace_service_manager_item() needs to be called to make this
widget display something.
"""
2015-11-07 00:49:40 +00:00
super(QtWidgets.QTableWidget, self).__init__(parent)
self._setup(screen_ratio)
def _setup(self, screen_ratio):
"""
Set up the widget
"""
self.setColumnCount(1)
self.horizontalHeader().setVisible(False)
self.setColumnWidth(0, self.parent().width())
2015-11-07 00:49:40 +00:00
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setAlternatingRowColors(True)
# Initialize variables.
self.service_item = ServiceItem()
self.screen_ratio = screen_ratio
# Connect signals
self.verticalHeader().sectionResized.connect(self.row_resized)
def resizeEvent(self, event):
"""
Overloaded method from QTableWidget. Will recalculate the layout.
"""
self.__recalculate_layout()
def __recalculate_layout(self):
"""
Recalculates the layout of the table widget. It will set height and width
of the table cells. QTableWidget does not adapt the cells to the widget size on its own.
"""
self.setColumnWidth(0, self.viewport().width())
if self.service_item:
# Sort out songs, bibles, etc.
if self.service_item.is_text():
self.resizeRowsToContents()
# Sort out image heights.
else:
height = self.viewport().width() // self.screen_ratio
max_img_row_height = Settings().value('advanced/slide max height')
# Adjust for row height cap if in use.
if max_img_row_height > 0 and height > max_img_row_height:
height = max_img_row_height
# Apply new height to slides
2013-12-24 15:55:01 +00:00
for frame_number in range(len(self.service_item.get_frames())):
self.setRowHeight(frame_number, height)
def row_resized(self, row, old_height, new_height):
"""
Will scale non-image slides.
"""
# Only for non-text slides when row height cap in use
if self.service_item.is_text() or Settings().value('advanced/slide max height') <= 0:
return
# Get and validate label widget containing slide & adjust max width
try:
self.cellWidget(row, 0).children()[1].setMaximumWidth(new_height * self.screen_ratio)
except:
return
def screen_size_changed(self, screen_ratio):
"""
This method is called whenever the live screen size changes, which then makes a layout recalculation necessary
:param screen_ratio: The new screen ratio
"""
self.screen_ratio = screen_ratio
self.__recalculate_layout()
2013-12-24 15:55:01 +00:00
def replace_service_item(self, service_item, width, slide_number):
"""
Replace the current preview items with the ones in service_item and display the given slide
:param service_item: The service item to insert
:param width: The width of the column
:param slide_number: The slide number to pre-select
"""
self.service_item = service_item
self.setRowCount(0)
2014-01-09 19:52:20 +00:00
self.clear()
self.setColumnWidth(0, width)
row = 0
text = []
2013-12-24 15:55:01 +00:00
for frame_number, frame in enumerate(self.service_item.get_frames()):
self.setRowCount(self.slide_count() + 1)
2015-11-07 00:49:40 +00:00
item = QtWidgets.QTableWidgetItem()
2013-06-18 09:12:49 +00:00
slide_height = 0
if self.service_item.is_text():
2013-08-31 18:17:38 +00:00
if frame['verseTag']:
# These tags are already translated.
2013-08-31 18:17:38 +00:00
verse_def = frame['verseTag']
verse_def = '%s%s' % (verse_def[0], verse_def[1:])
two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:])
row = two_line_def
else:
row += 1
2013-08-31 18:17:38 +00:00
item.setText(frame['text'])
else:
2015-11-07 00:49:40 +00:00
label = QtWidgets.QLabel()
label.setContentsMargins(4, 4, 4, 4)
if self.service_item.is_media():
label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
else:
label.setScaledContents(True)
if self.service_item.is_command():
pixmap = QtGui.QPixmap(frame['image'])
pixmap.setDevicePixelRatio(label.devicePixelRatio())
label.setPixmap(pixmap)
else:
2013-08-31 18:17:38 +00:00
image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin)
pixmap = QtGui.QPixmap.fromImage(image)
pixmap.setDevicePixelRatio(label.devicePixelRatio())
label.setPixmap(pixmap)
2013-06-18 09:12:49 +00:00
slide_height = width // self.screen_ratio
# Setup row height cap if in use.
max_img_row_height = Settings().value('advanced/slide max height')
if max_img_row_height > 0:
if slide_height > max_img_row_height:
slide_height = max_img_row_height
label.setMaximumWidth(max_img_row_height * self.screen_ratio)
label.resize(max_img_row_height * self.screen_ratio, max_img_row_height)
# Build widget with stretch padding
container = QtWidgets.QWidget()
hbox = QtWidgets.QHBoxLayout()
hbox.setContentsMargins(0, 0, 0, 0)
hbox.addWidget(label, stretch=1)
hbox.addStretch(0)
container.setLayout(hbox)
# Add to table
self.setCellWidget(frame_number, 0, container)
else:
# Add to table
self.setCellWidget(frame_number, 0, label)
row += 1
2013-08-31 18:17:38 +00:00
text.append(str(row))
2013-12-24 15:55:01 +00:00
self.setItem(frame_number, 0, item)
2013-06-18 09:12:49 +00:00
if slide_height:
2013-12-24 15:55:01 +00:00
self.setRowHeight(frame_number, slide_height)
self.setVerticalHeaderLabels(text)
if self.service_item.is_text():
self.resizeRowsToContents()
self.setColumnWidth(0, self.viewport().width())
2013-12-24 15:55:01 +00:00
self.change_slide(slide_number)
def change_slide(self, slide):
"""
Switches to the given row.
"""
2016-04-16 06:53:01 +00:00
# Retrieve setting
autoscrolling = Settings().value('advanced/autoscrolling')
# Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos'
if (not isinstance(autoscrolling, dict)) or ('dist' not in autoscrolling) or ('pos' not in autoscrolling):
return
# prevent scrolling past list bounds
scroll_to_slide = slide + autoscrolling['dist']
if scroll_to_slide < 0:
scroll_to_slide = 0
if scroll_to_slide >= self.slide_count():
scroll_to_slide = self.slide_count() - 1
# Scroll to item if possible.
self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos'])
self.selectRow(slide)
def current_slide_number(self):
"""
Returns the position of the currently active item. Will return -1 if the widget is empty.
"""
return super(ListPreviewWidget, self).currentRow()
def slide_count(self):
"""
Returns the number of slides this widget holds.
"""
2014-03-20 19:10:31 +00:00
return super(ListPreviewWidget, self).rowCount()