Merge branch 'media_sept_19' into 'master'

Media sept 19

See merge request openlp/openlp!21
This commit is contained in:
Raoul Snyman 2019-09-21 04:56:43 +00:00
commit cdba0e9235
11 changed files with 43 additions and 627 deletions

View File

@ -33,7 +33,6 @@ from openlp.core.common import Singleton, is_macosx, is_win
from openlp.core.common.applocation import AppLocation from openlp.core.common.applocation import AppLocation
from openlp.core.common.settings import Settings from openlp.core.common.settings import Settings
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -385,6 +384,7 @@ class UiStrings(metaclass=Singleton):
self.Import = translate('OpenLP.Ui', 'Import') self.Import = translate('OpenLP.Ui', 'Import')
self.LayoutStyle = translate('OpenLP.Ui', 'Layout style:') self.LayoutStyle = translate('OpenLP.Ui', 'Layout style:')
self.Live = translate('OpenLP.Ui', 'Live') self.Live = translate('OpenLP.Ui', 'Live')
self.LiveStream = translate('OpenLP.Ui', 'Live Stream')
self.LiveBGError = translate('OpenLP.Ui', 'Live Background Error') self.LiveBGError = translate('OpenLP.Ui', 'Live Background Error')
self.LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar') self.LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar')
self.Load = translate('OpenLP.Ui', 'Load') self.Load = translate('OpenLP.Ui', 'Load')

View File

@ -41,7 +41,6 @@ from openlp.core.widgets.edits import SearchEdit
from openlp.core.widgets.toolbar import OpenLPToolbar from openlp.core.widgets.toolbar import OpenLPToolbar
from openlp.core.widgets.views import ListWidgetWithDnD from openlp.core.widgets.views import ListWidgetWithDnD
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -416,7 +415,9 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
for index in range(self.list_view.count()): for index in range(self.list_view.count()):
list_item = self.list_view.item(index) list_item = self.list_view.item(index)
file_path = list_item.data(QtCore.Qt.UserRole) file_path = list_item.data(QtCore.Qt.UserRole)
file_paths.append(file_path) # This is added as start of OpenLP each time
if file_path != UiStrings().LiveStream:
file_paths.append(file_path)
return file_paths return file_paths
def load_list(self, load_list, target_group): def load_list(self, load_list, target_group):
@ -497,7 +498,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'You must select one or more items to preview.')) 'You must select one or more items to preview.'))
else: else:
log.debug('%s Preview requested' % self.plugin.name) log.debug('{plug} Preview requested'.format(plug=self.plugin.name))
Registry().set_flag('has doubleclick added item to service', False) Registry().set_flag('has doubleclick added item to service', False)
service_item = self.build_service_item() service_item = self.build_service_item()
if service_item: if service_item:
@ -635,8 +636,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
service_item.add_icon() service_item.add_icon()
if self.generate_slide_data(service_item, item=item, remote=remote, context=context): if self.generate_slide_data(service_item, item=item, remote=remote, context=context):
return service_item return service_item
else: return None
return None
def service_load(self, item): def service_load(self, item):
""" """

View File

@ -112,7 +112,7 @@ class UiAboutDialog(object):
'<p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ' '<p>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. ' 'without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. '
'See the GNU General Public License for more details.</p>' 'See the GNU General Public License for more details.</p>'
'<p>You should have received a copy of the GNU General Public License' '<p>You should have received a copy of the GNU General Public License '
'along with this program. If not, see <a href="https://www.gnu.org/licenses/">' 'along with this program. If not, see <a href="https://www.gnu.org/licenses/">'
'https://www.gnu.org/licenses/</a>.</p>').format(crs='\xa9', yr=datetime.date.today().year)) 'https://www.gnu.org/licenses/</a>.</p>').format(crs='\xa9', yr=datetime.date.today().year))
self.about_notebook.setTabText(self.about_notebook.indexOf(self.about_tab), UiStrings().About) self.about_notebook.setTabText(self.about_notebook.indexOf(self.about_tab), UiStrings().About)

View File

@ -54,16 +54,7 @@ TICK_TIME = 200
class MediaController(RegistryBase, LogMixin, RegistryProperties): class MediaController(RegistryBase, LogMixin, RegistryProperties):
""" """
The implementation of the Media Controller. The Media Controller adds an own class for every Player. The implementation of the Media Controller which manages how media is played.
Currently these are QtWebkit, Phonon and Vlc. display_controllers are an array of controllers keyed on the
slidecontroller or plugin which built them.
ControllerType is the class containing the key values.
media_players are an array of media players keyed on player name.
current_media_players is an array of player instances keyed on ControllerType.
""" """
def setup(self): def setup(self):
@ -100,14 +91,23 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
self.vlc_player = VlcPlayer(self) self.vlc_player = VlcPlayer(self)
State().add_service('mediacontroller', 0) State().add_service('mediacontroller', 0)
State().add_service('media_live', 0) State().add_service('media_live', 0)
if get_vlc() and pymediainfo_available: getvlc = get_vlc()
if getvlc and pymediainfo_available:
State().update_pre_conditions('mediacontroller', True) State().update_pre_conditions('mediacontroller', True)
State().update_pre_conditions('media_live', True) State().update_pre_conditions('media_live', True)
else: else:
if hasattr(self.main_window, 'splash') and self.main_window.splash.isVisible(): if hasattr(self.main_window, 'splash') and self.main_window.splash.isVisible():
self.main_window.splash.hide() self.main_window.splash.hide()
State().missing_text('media_live', translate('OpenLP.SlideController', text_vlc = translate('OpenLP.MediaController',
'VLC or pymediainfo are missing, so you are unable to play any media')) 'The media integration library is missing (python - vlc is not installed)')
text_info = translate('OpenLP.MediaController',
'The media integration library is missing (python - pymediainfo is not installed)')
if not getvlc and not pymediainfo_available:
State().missing_text('media_live', "{text}\n{base}".format(text=text_vlc, base=text_info))
if getvlc and not pymediainfo_available:
State().missing_text('media_live', "{text}".format(text=text_info))
if not getvlc and pymediainfo_available:
State().missing_text('media_live', "{text}".format(text=text_vlc))
return True return True
def bootstrap_post_set_up(self): def bootstrap_post_set_up(self):
@ -120,7 +120,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
self.setup_display(self.live_controller.display, False) self.setup_display(self.live_controller.display, False)
except AttributeError: except AttributeError:
State().update_pre_conditions('media_live', False) State().update_pre_conditions('media_live', False)
State().missing_text('media_live', translate('OpenLP.SlideController', State().missing_text('media_live', translate('OpenLP.MediaController',
'No Displays configure so Live Media has been disabled')) 'No Displays configure so Live Media has been disabled'))
self.setup_display(self.preview_controller.preview_display, True) self.setup_display(self.preview_controller.preview_display, True)
@ -132,8 +132,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
""" """
if controller_type == DisplayControllerType.Live: if controller_type == DisplayControllerType.Live:
return self.live_controller return self.live_controller
else: return self.preview_controller
return self.preview_controller
def media_state_live(self): def media_state_live(self):
""" """
@ -271,10 +270,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File')) translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False return False
log.debug('video media type: ' + str(controller.media_info.media_type)) log.debug('video media type: {tpe} '.format(tpe=str(controller.media_info.media_type)))
# dont care about actual theme, set a black background # dont care about actual theme, set a black background
# if controller.is_live and not controller.media_info.is_background:
# display.frame.runJavaScript('show_video("setBackBoard", null, null,"visible");')
# now start playing - Preview is autoplay! # now start playing - Preview is autoplay!
autoplay = False autoplay = False
if service_item.is_capable(ItemCapabilities.CanStream): if service_item.is_capable(ItemCapabilities.CanStream):
@ -294,7 +291,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
translate('MediaPlugin.MediaItem', 'Unsupported File')) translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False return False
self.set_controls_visible(controller, True) self.set_controls_visible(controller, True)
log.debug('use %s controller' % self.current_media_players[controller.controller_type].display_name) log.debug('use {nm} controller'.format(nm=self.current_media_players[controller.controller_type].display_name))
return True return True
@staticmethod @staticmethod
@ -580,7 +577,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
:param controller: The Controller to use :param controller: The Controller to use
:param volume: The volume to be set :param volume: The volume to be set
""" """
log.debug('media_volume %d' % volume) log.debug('media_volume {vol}'.format(vol=volume))
display = self._define_display(controller) display = self._define_display(controller)
self.current_media_players[controller.controller_type].volume(display, volume) self.current_media_players[controller.controller_type].volume(display, volume)
controller.volume_slider.setValue(volume) controller.volume_slider.setValue(volume)

View File

@ -29,14 +29,14 @@ import sys
import threading import threading
from datetime import datetime from datetime import datetime
from PyQt5 import QtWidgets from PyQt5 import QtCore, QtWidgets
from openlp.core.common import is_linux, is_macosx, is_win from openlp.core.common import is_linux, is_macosx, is_win
from openlp.core.common.settings import Settings from openlp.core.common.settings import Settings
from openlp.core.display.screens import ScreenList
from openlp.core.ui.media import MediaState, MediaType from openlp.core.ui.media import MediaState, MediaType
from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.ui.media.mediaplayer import MediaPlayer
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# Audio and video extensions copied from 'include/vlc_interface.h' from vlc 2.2.0 source # Audio and video extensions copied from 'include/vlc_interface.h' from vlc 2.2.0 source
@ -105,8 +105,14 @@ class VlcPlayer(MediaPlayer):
:return: :return:
""" """
vlc = get_vlc() vlc = get_vlc()
output_display.vlc_widget = QtWidgets.QFrame(output_display) if output_display.is_display:
output_display.vlc_widget = QtWidgets.QFrame()
output_display.vlc_widget.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool |
QtCore.Qt.WindowStaysOnTopHint)
else:
output_display.vlc_widget = QtWidgets.QFrame(output_display)
output_display.vlc_widget.setFrameStyle(QtWidgets.QFrame.NoFrame) output_display.vlc_widget.setFrameStyle(QtWidgets.QFrame.NoFrame)
# creating a basic vlc instance # creating a basic vlc instance
command_line_options = '--no-video-title-show ' command_line_options = '--no-video-title-show '
if Settings().value('advanced/hide mouse') and live_display: if Settings().value('advanced/hide mouse') and live_display:
@ -206,7 +212,10 @@ class VlcPlayer(MediaPlayer):
:param output_display: The display where the media is :param output_display: The display where the media is
:return: :return:
""" """
output_display.vlc_widget.resize(output_display.size()) if output_display.is_display:
output_display.vlc_widget.setGeometry(ScreenList().current.display_geometry)
else:
output_display.vlc_widget.resize(output_display.size())
def play(self, controller, output_display): def play(self, controller, output_display):
""" """

View File

@ -47,7 +47,6 @@ from openlp.core.widgets.layouts import AspectRatioLayout
from openlp.core.widgets.toolbar import OpenLPToolbar from openlp.core.widgets.toolbar import OpenLPToolbar
from openlp.core.widgets.views import ListPreviewWidget from openlp.core.widgets.views import ListPreviewWidget
# Threshold which has to be trespassed to toggle. # Threshold which has to be trespassed to toggle.
HIDE_MENU_THRESHOLD = 27 HIDE_MENU_THRESHOLD = 27
@ -863,6 +862,7 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
[self.service_item, self.is_live, self.hide_mode(), slide_no]) [self.service_item, self.is_live, self.hide_mode(), slide_no])
else: else:
# Get theme # Get theme
# TODO this is wrong!!!
theme_name = service_item.theme if service_item.theme else Registry().get('theme_manager').global_theme theme_name = service_item.theme if service_item.theme else Registry().get('theme_manager').global_theme
theme_data = Registry().get('theme_manager').get_theme_data(theme_name) theme_data = Registry().get('theme_manager').get_theme_data(theme_name)
# Set theme for preview # Set theme for preview

View File

@ -25,7 +25,6 @@ import os
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets
from openlp.core.state import State
from openlp.core.common.applocation import AppLocation from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, get_natural_key, translate from openlp.core.common.i18n import UiStrings, get_natural_key, translate
from openlp.core.common.mixins import RegistryProperties from openlp.core.common.mixins import RegistryProperties
@ -36,11 +35,11 @@ from openlp.core.lib import MediaType, ServiceItemContext, check_item_selected
from openlp.core.lib.mediamanageritem import MediaManagerItem from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.serviceitem import ItemCapabilities from openlp.core.lib.serviceitem import ItemCapabilities
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.state import State
from openlp.core.ui.icons import UiIcons from openlp.core.ui.icons import UiIcons
from openlp.core.ui.media import parse_optical_path, format_milliseconds, AUDIO_EXT, VIDEO_EXT from openlp.core.ui.media import parse_optical_path, format_milliseconds, AUDIO_EXT, VIDEO_EXT
from openlp.core.ui.media.vlcplayer import get_vlc from openlp.core.ui.media.vlcplayer import get_vlc
if get_vlc() is not None: if get_vlc() is not None:
from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm
@ -128,36 +127,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
tooltip=optical_button_tooltip, tooltip=optical_button_tooltip,
triggers=self.on_load_optical) triggers=self.on_load_optical)
def add_end_header_bar(self):
"""
Adds buttons to the end of the header bar.
"""
# Replace backgrounds do not work at present so remove functionality.
# self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=UiIcons().theme,
# triggers=self.on_replace_click)
# if 'webkit' not in get_media_players()[0]:
# self.replace_action.setDisabled(True)
# if hasattr(self, 'replace_action_context'):
# self.replace_action_context.setDisabled(True)
# self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=UiIcons().close,
# visible=False, triggers=self.on_reset_click)
# self.media_widget = QtWidgets.QWidget(self)
# self.media_widget.setObjectName('media_widget')
# self.display_layout = QtWidgets.QFormLayout(self.media_widget)
# self.display_layout.setContentsMargins(self.display_layout.spacing(), self.display_layout.spacing(),
# self.display_layout.spacing(), self.display_layout.spacing())
# self.display_layout.setObjectName('display_layout')
# self.display_type_label = QtWidgets.QLabel(self.media_widget)
# self.display_type_label.setObjectName('display_type_label')
# self.display_type_combo_box = create_horizontal_adjusting_combo_box(
# self.media_widget, 'display_type_combo_box')
# self.display_type_label.setBuddy(self.display_type_combo_box)
# self.display_layout.addRow(self.display_type_label, self.display_type_combo_box)
# Add the Media widget to the page layout.
# self.page_layout.addWidget(self.media_widget)
# self.display_type_combo_box.currentIndexChanged.connect(self.override_player_changed)
pass
def generate_slide_data(self, service_item, *, item=None, remote=False, context=ServiceItemContext.Service, def generate_slide_data(self, service_item, *, item=None, remote=False, context=ServiceItemContext.Service,
**kwargs): **kwargs):
""" """
@ -175,7 +144,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
return False return False
filename = str(item.data(QtCore.Qt.UserRole)) filename = str(item.data(QtCore.Qt.UserRole))
# Special handling if the filename is a optical clip # Special handling if the filename is a optical clip
if filename == 'live': if filename == UiStrings().LiveStream:
service_item.processor = 'vlc' service_item.processor = 'vlc'
service_item.title = filename service_item.title = filename
service_item.add_capability(ItemCapabilities.CanStream) service_item.add_capability(ItemCapabilities.CanStream)
@ -265,7 +234,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
file_name = translate('MediaPlugin.MediaItem', 'Live Stream') file_name = translate('MediaPlugin.MediaItem', 'Live Stream')
item_name = QtWidgets.QListWidgetItem(file_name) item_name = QtWidgets.QListWidgetItem(file_name)
item_name.setIcon(UiIcons().video) item_name.setIcon(UiIcons().video)
item_name.setData(QtCore.Qt.UserRole, 'live') item_name.setData(QtCore.Qt.UserRole, UiStrings().LiveStream)
item_name.setToolTip(translate('MediaPlugin.MediaItem', 'Show Live Stream')) item_name.setToolTip(translate('MediaPlugin.MediaItem', 'Show Live Stream'))
self.list_view.addItem(item_name) self.list_view.addItem(item_name)
for track in media: for track in media:

View File

@ -1,181 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'auditdetaildialog.ui'
#
# Created: Sun Oct 11 11:40:02 2009
# by: PyQt4 UI code generator 4.5.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_AuditDetailDialog(object):
def setupUi(self, AuditDetailDialog):
AuditDetailDialog.setObjectName(u'AuditDetailDialog')
AuditDetailDialog.resize(593, 501)
self.buttonBox = QtGui.QDialogButtonBox(AuditDetailDialog)
self.buttonBox.setGeometry(QtCore.QRect(420, 470, 170, 25))
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(u'buttonBox')
self.FileGroupBox = QtGui.QGroupBox(AuditDetailDialog)
self.FileGroupBox.setGeometry(QtCore.QRect(10, 370, 571, 70))
self.FileGroupBox.setObjectName(u'FileGroupBox')
self.verticalLayout_4 = QtGui.QVBoxLayout(self.FileGroupBox)
self.verticalLayout_4.setObjectName(u'verticalLayout_4')
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(u'horizontalLayout')
self.FileLineEdit = QtGui.QLineEdit(self.FileGroupBox)
self.FileLineEdit.setObjectName(u'FileLineEdit')
self.horizontalLayout.addWidget(self.FileLineEdit)
self.SaveFilePushButton = QtGui.QPushButton(self.FileGroupBox)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(u':/exports/export_load.png'),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.SaveFilePushButton.setIcon(icon)
self.SaveFilePushButton.setObjectName(u'SaveFilePushButton')
self.horizontalLayout.addWidget(self.SaveFilePushButton)
self.verticalLayout_4.addLayout(self.horizontalLayout)
self.layoutWidget = QtGui.QWidget(AuditDetailDialog)
self.layoutWidget.setGeometry(QtCore.QRect(10, 10, 561, 361))
self.layoutWidget.setObjectName(u'layoutWidget')
self.verticalLayout_3 = QtGui.QVBoxLayout(self.layoutWidget)
self.verticalLayout_3.setObjectName(u'verticalLayout_3')
self.ReportTypeGroup = QtGui.QGroupBox(self.layoutWidget)
self.ReportTypeGroup.setObjectName(u'ReportTypeGroup')
self.layoutWidget1 = QtGui.QWidget(self.ReportTypeGroup)
self.layoutWidget1.setGeometry(QtCore.QRect(50, 40, 481, 23))
self.layoutWidget1.setObjectName(u'layoutWidget1')
self.ReportHorizontalLayout = QtGui.QHBoxLayout(self.layoutWidget1)
self.ReportHorizontalLayout.setObjectName(u'ReportHorizontalLayout')
self.SummaryReport = QtGui.QRadioButton(self.layoutWidget1)
self.SummaryReport.setObjectName(u'SummaryReport')
self.ReportHorizontalLayout.addWidget(self.SummaryReport)
self.DetailedReport = QtGui.QRadioButton(self.layoutWidget1)
self.DetailedReport.setChecked(True)
self.DetailedReport.setObjectName(u'DetailedReport')
self.ReportHorizontalLayout.addWidget(self.DetailedReport)
self.verticalLayout_3.addWidget(self.ReportTypeGroup)
self.DateRangeGroupBox = QtGui.QGroupBox(self.layoutWidget)
self.DateRangeGroupBox.setObjectName(u'DateRangeGroupBox')
self.verticalLayout_2 = QtGui.QVBoxLayout(self.DateRangeGroupBox)
self.verticalLayout_2.setObjectName(u'verticalLayout_2')
self.DateHorizontalLayout = QtGui.QHBoxLayout()
self.DateHorizontalLayout.setObjectName(u'DateHorizontalLayout')
self.FromDateEdit = QtGui.QDateEdit(self.DateRangeGroupBox)
self.FromDateEdit.setCalendarPopup(True)
self.FromDateEdit.setObjectName(u'FromDateEdit')
self.DateHorizontalLayout.addWidget(self.FromDateEdit)
self.To = QtGui.QLabel(self.DateRangeGroupBox)
self.To.setObjectName(u'To')
self.DateHorizontalLayout.addWidget(self.To)
self.ToDateEdit = QtGui.QDateEdit(self.DateRangeGroupBox)
self.ToDateEdit.setCalendarPopup(True)
self.ToDateEdit.setObjectName(u'ToDateEdit')
self.DateHorizontalLayout.addWidget(self.ToDateEdit)
self.verticalLayout_2.addLayout(self.DateHorizontalLayout)
self.verticalLayout_3.addWidget(self.DateRangeGroupBox)
self.TimePeriodGroupBox = QtGui.QGroupBox(self.layoutWidget)
self.TimePeriodGroupBox.setObjectName(u'TimePeriodGroupBox')
self.verticalLayout = QtGui.QVBoxLayout(self.TimePeriodGroupBox)
self.verticalLayout.setObjectName(u'verticalLayout')
self.FirstHorizontalLayout = QtGui.QHBoxLayout()
self.FirstHorizontalLayout.setObjectName(u'FirstHorizontalLayout')
self.FirstCheckBox = QtGui.QCheckBox(self.TimePeriodGroupBox)
self.FirstCheckBox.setChecked(True)
self.FirstCheckBox.setObjectName(u'FirstCheckBox')
self.FirstHorizontalLayout.addWidget(self.FirstCheckBox)
self.FirstFromTimeEdit = QtGui.QTimeEdit(self.TimePeriodGroupBox)
self.FirstFromTimeEdit.setTime(QtCore.QTime(9, 0, 0))
self.FirstFromTimeEdit.setObjectName(u'FirstFromTimeEdit')
self.FirstHorizontalLayout.addWidget(self.FirstFromTimeEdit)
self.FirstTo = QtGui.QLabel(self.TimePeriodGroupBox)
self.FirstTo.setObjectName(u'FirstTo')
self.FirstHorizontalLayout.addWidget(self.FirstTo)
self.FirstToTimeEdit = QtGui.QTimeEdit(self.TimePeriodGroupBox)
self.FirstToTimeEdit.setCalendarPopup(True)
self.FirstToTimeEdit.setTime(QtCore.QTime(10, 0, 0))
self.FirstToTimeEdit.setObjectName(u'FirstToTimeEdit')
self.FirstHorizontalLayout.addWidget(self.FirstToTimeEdit)
self.verticalLayout.addLayout(self.FirstHorizontalLayout)
self.SecondHorizontalLayout = QtGui.QHBoxLayout()
self.SecondHorizontalLayout.setObjectName(u'SecondHorizontalLayout')
self.SecondCheckBox = QtGui.QCheckBox(self.TimePeriodGroupBox)
self.SecondCheckBox.setChecked(True)
self.SecondCheckBox.setObjectName(u'SecondCheckBox')
self.SecondHorizontalLayout.addWidget(self.SecondCheckBox)
self.SecondFromTimeEdit = QtGui.QTimeEdit(self.TimePeriodGroupBox)
self.SecondFromTimeEdit.setTime(QtCore.QTime(10, 45, 0))
self.SecondFromTimeEdit.setObjectName(u'SecondFromTimeEdit')
self.SecondHorizontalLayout.addWidget(self.SecondFromTimeEdit)
self.SecondTo = QtGui.QLabel(self.TimePeriodGroupBox)
self.SecondTo.setObjectName(u'SecondTo')
self.SecondHorizontalLayout.addWidget(self.SecondTo)
self.SecondToTimeEdit = QtGui.QTimeEdit(self.TimePeriodGroupBox)
self.SecondToTimeEdit.setObjectName(u'SecondToTimeEdit')
self.SecondHorizontalLayout.addWidget(self.SecondToTimeEdit)
self.verticalLayout.addLayout(self.SecondHorizontalLayout)
self.ThirdHorizontalLayout = QtGui.QHBoxLayout()
self.ThirdHorizontalLayout.setObjectName(u'ThirdHorizontalLayout')
self.ThirdCheckBox = QtGui.QCheckBox(self.TimePeriodGroupBox)
self.ThirdCheckBox.setChecked(True)
self.ThirdCheckBox.setObjectName(u'ThirdCheckBox')
self.ThirdHorizontalLayout.addWidget(self.ThirdCheckBox)
self.ThirdFromTimeEdit = QtGui.QTimeEdit(self.TimePeriodGroupBox)
self.ThirdFromTimeEdit.setTime(QtCore.QTime(18, 30, 0))
self.ThirdFromTimeEdit.setObjectName(u'ThirdFromTimeEdit')
self.ThirdHorizontalLayout.addWidget(self.ThirdFromTimeEdit)
self.ThirdTo = QtGui.QLabel(self.TimePeriodGroupBox)
self.ThirdTo.setObjectName(u'ThirdTo')
self.ThirdHorizontalLayout.addWidget(self.ThirdTo)
self.ThirdToTimeEdit = QtGui.QTimeEdit(self.TimePeriodGroupBox)
self.ThirdToTimeEdit.setTime(QtCore.QTime(19, 30, 0))
self.ThirdToTimeEdit.setObjectName(u'ThirdToTimeEdit')
self.ThirdHorizontalLayout.addWidget(self.ThirdToTimeEdit)
self.verticalLayout.addLayout(self.ThirdHorizontalLayout)
self.verticalLayout_3.addWidget(self.TimePeriodGroupBox)
self.retranslateUi(AuditDetailDialog)
QtCore.QObject.connect(
self.buttonBox, QtCore.SIGNAL(u'accepted()'),
AuditDetailDialog.accept)
QtCore.QObject.connect(
self.buttonBox, QtCore.SIGNAL(u'rejected()'),
AuditDetailDialog.close)
QtCore.QObject.connect(
self.FirstCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
AuditDetailDialog.changeFirstService)
QtCore.QObject.connect(
self.SecondCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
AuditDetailDialog.changeSecondService)
QtCore.QObject.connect(
self.ThirdCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
AuditDetailDialog.changeThirdService)
QtCore.QObject.connect(
self.SaveFilePushButton, QtCore.SIGNAL(u'pressed()'),
AuditDetailDialog.defineOutputLocation)
QtCore.QMetaObject.connectSlotsByName(AuditDetailDialog)
def retranslateUi(self, AuditDetailDialog):
AuditDetailDialog.setWindowTitle(self.trUtf8(u'Audit Detail Extraction'))
self.FileGroupBox.setTitle(self.trUtf8(u'Report Location'))
self.ReportTypeGroup.setTitle(self.trUtf8(u'Report Type'))
self.SummaryReport.setText(self.trUtf8(u'Summary'))
self.DetailedReport.setText(self.trUtf8(u'Detailed'))
self.DateRangeGroupBox.setTitle(self.trUtf8(u'Select Date Range'))
self.FromDateEdit.setDisplayFormat(self.trUtf8(u'dd/MM/yyyy'))
self.To.setText(self.trUtf8(u'to'))
self.ToDateEdit.setDisplayFormat(self.trUtf8(u'dd/MM/yyyy'))
self.TimePeriodGroupBox.setTitle(self.trUtf8(u'Select Time Periods'))
self.FirstCheckBox.setText(self.trUtf8(u'First Service'))
self.FirstFromTimeEdit.setDisplayFormat(self.trUtf8(u'hh:mm AP'))
self.FirstTo.setText(self.trUtf8(u'to'))
self.FirstToTimeEdit.setDisplayFormat(self.trUtf8(u'hh:mm AP'))
self.SecondCheckBox.setText(self.trUtf8(u'Second Service'))
self.SecondFromTimeEdit.setDisplayFormat(self.trUtf8(u'hh:mm AP'))
self.SecondTo.setText(self.trUtf8(u'to'))
self.SecondToTimeEdit.setDisplayFormat(self.trUtf8(u'hh:mm AP'))
self.ThirdCheckBox.setText(self.trUtf8(u'Third Service'))
self.ThirdFromTimeEdit.setDisplayFormat(self.trUtf8(u'hh:mm AP'))
self.ThirdTo.setText(self.trUtf8(u'to'))
self.ThirdToTimeEdit.setDisplayFormat(self.trUtf8(u'hh:mm AP'))

View File

@ -1,121 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2009 Raoul Snyman #
# Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Carsten #
# Tinggaard, Jon Tibble, Jonathan Corwin, Maikel Stuivenberg, Scott Guerrieri #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
from PyQt4 import QtCore, QtGui
from auditdetaildialog import Ui_AuditDetailDialog
class AuditDetailForm(QtGui.QDialog, Ui_AuditDetailDialog):
"""
Class documentation goes here.
"""
def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, None)
self.parent = parent
self.setupUi(self)
def initialise(self):
self.FirstCheckBox.setCheckState(
int(self.parent.config.get_config(u'first service', QtCore.Qt.Checked)))
self.SecondCheckBox.setCheckState(
int(self.parent.config.get_config(u'second service', QtCore.Qt.Checked)))
self.ThirdCheckBox.setCheckState(
int(self.parent.config.get_config(u'third service', QtCore.Qt.Checked)))
year = QtCore.QDate().currentDate().year()
if QtCore.QDate().currentDate().month() < 9:
year -= 1
toDate = QtCore.QDate(year, 8, 31)
fromDate = QtCore.QDate(year - 1, 9, 1)
self.FromDateEdit.setDate(fromDate)
self.ToDateEdit.setDate(toDate)
self.FileLineEdit.setText(self.parent.config.get_last_dir(1))
self.resetWindow()
def changeFirstService(self, value):
self.parent.config.set_config(u'first service', value)
self.resetWindow()
def changeSecondService(self, value):
self.parent.config.set_config(u'second service', value)
self.resetWindow()
def changeThirdService(self, value):
self.parent.config.set_config(u'third service', value)
self.resetWindow()
def defineOutputLocation(self):
path = QtGui.QFileDialog.getExistingDirectory(self, self.trUtf8(u'Output File Location'),
self.parent.config.get_last_dir(1))
if path != u'':
self.parent.config.set_last_dir(path, 1)
self.FileLineEdit.setText(path)
def resetWindow(self):
if self.FirstCheckBox.checkState() == QtCore.Qt.Unchecked:
self.FirstFromTimeEdit.setEnabled(False)
self.FirstToTimeEdit.setEnabled(False)
else:
self.FirstFromTimeEdit.setEnabled(True)
self.FirstToTimeEdit.setEnabled(True)
if self.SecondCheckBox.checkState() == QtCore.Qt.Unchecked:
self.SecondFromTimeEdit.setEnabled(False)
self.SecondToTimeEdit.setEnabled(False)
else:
self.SecondFromTimeEdit.setEnabled(True)
self.SecondToTimeEdit.setEnabled(True)
if self.ThirdCheckBox.checkState() == QtCore.Qt.Unchecked:
self.ThirdFromTimeEdit.setEnabled(False)
self.ThirdToTimeEdit.setEnabled(False)
else:
self.ThirdFromTimeEdit.setEnabled(True)
self.ThirdToTimeEdit.setEnabled(True)
def accept(self):
print(self.DetailedReport.isChecked())
print(self.SummaryReport.isChecked())
print(self.FromDateEdit.date())
print(self.ToDateEdit.date())
if self.DetailedReport.isChecked():
self.detailedReport()
else:
self.summaryReport()
self.close()
def detailedReport(self):
print("detailed")
filename = u'audit_det_%s_%s.txt' % \
(self.FromDateEdit.date().toString(u'ddMMyyyy'),
self.ToDateEdit.date().toString(u'ddMMyyyy'))
print(filename)
def summaryReport(self):
print("summary")
filename = u'audit_sum_%s_%s.txt' % \
(self.FromDateEdit.date().toString(u'ddMMyyyy'),
self.ToDateEdit.date().toString(u'ddMMyyyy'))
print(filename)

View File

@ -1,258 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2019 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, either version 3 of the License, or #
# (at your option) any later version. #
# #
# 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, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
This script helps to trigger builds of branches. To use it you have to install the python-jenkins module. On Fedora
and Ubuntu/Debian, it is available as the ``python3-jenkins`` package::
$ sudo dnf/apt install python3-jenkins
To make it easier to run you may want to create a shell script or an alias. To create an alias, add this to your
``~/.bashrc`` (or ``~/.zshrc``) file and then log out and log back in again (to apply the alias)::
alias ci="python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD"
To create a shell script, create the following file in a location in your ``$PATH`` (I called mine ``ci``)::
#!/bin/bash
python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD
``USERNAME`` is your Jenkins username, and ``PASSWORD`` is your Jenkins password or personal token.
An older version of this script used to use a shared TOKEN, but this has been replaced with the username and password.
"""
import os
import re
import time
from argparse import ArgumentParser
from subprocess import PIPE, Popen
from jenkins import Jenkins
JENKINS_URL = 'https://ci.openlp.io/'
REPO_REGEX = r'(.*/+)(~.*)'
class OpenLPJobs(object):
"""
This class holds any jobs we have on jenkins and we actually need in this script.
"""
Branch_Pull = 'Branch-01-Pull'
Branch_Linux_Tests = 'Branch-02a-Linux-Tests'
Branch_macOS_Tests = 'Branch-02b-macOS-Tests'
Branch_Build_Source = 'Branch-03a-Build-Source'
Branch_Build_macOS = 'Branch-03b-Build-macOS'
Branch_Code_Analysis = 'Branch-04a-Code-Lint'
Branch_Test_Coverage = 'Branch-04b-Test-Coverage'
Branch_Lint_Check = 'Branch-04c-Lint-Check'
Branch_AppVeyor_Tests = 'Branch-05-AppVeyor-Tests'
Jobs = [Branch_Pull, Branch_Linux_Tests, Branch_macOS_Tests, Branch_Build_Source, Branch_Build_macOS,
Branch_Code_Analysis, Branch_Test_Coverage, Branch_AppVeyor_Tests]
class Colour(object):
"""
This class holds values which can be used to print coloured text.
"""
RED_START = '\033[1;31m'
RED_END = '\033[1;m'
GREEN_START = '\033[1;32m'
GREEN_END = '\033[1;m'
class JenkinsTrigger(object):
"""
A class to trigger builds on Jenkins and print the results.
"""
def __init__(self, username, password, can_use_colour):
"""
Create the JenkinsTrigger instance.
"""
self.jobs = {}
self.can_use_colour = can_use_colour and not os.name.startswith('nt')
self.repo_name = get_repo_name()
self.server = Jenkins(JENKINS_URL, username=username, password=password)
def fetch_jobs(self):
"""
Get the job info for all the jobs
"""
for job_name in OpenLPJobs.Jobs:
try:
job_info = self.server.get_job_info(job_name)
self.jobs[job_name] = job_info
self.jobs[job_name]['nextBuildUrl'] = '{url}{nextBuildNumber}/'.format(**job_info)
except Exception:
pass
def trigger_build(self):
"""
Ask our jenkins server to build the "Branch-01-Pull" job.
"""
bzr = Popen(('bzr', 'whoami'), stdout=PIPE, stderr=PIPE)
raw_output, error = bzr.communicate()
# We just want the name (not the email).
name = ' '.join(raw_output.decode().split()[:-1])
cause = 'Build triggered by %s (%s)' % (name, self.repo_name)
self.fetch_jobs()
self.server.build_job(OpenLPJobs.Branch_Pull, {'BRANCH_NAME': self.repo_name, 'cause': cause})
def print_output(self, can_continue=False):
"""
Print the status information of the build triggered.
"""
print('Add this to your merge proposal:')
print('-' * 80)
bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE)
raw_output, error = bzr.communicate()
revno = raw_output.decode().strip()
print('%s (revision %s)' % (get_repo_name(), revno))
failed_builds = []
for job in OpenLPJobs.Jobs:
if not self.__print_build_info(job):
if self.current_build:
failed_builds.append((self.current_build['fullDisplayName'], self.current_build['url']))
if not can_continue:
print('Stopping after failure')
break
print('')
if failed_builds:
print('Failed builds:')
for build_name, url in failed_builds:
print(' - {}: {}console'.format(build_name, url))
else:
print('All builds passed')
def open_browser(self):
"""
Opens the browser.
"""
url = self.jenkins_instance.job(OpenLPJobs.Branch_Pull).info['url']
# Open the url
Popen(('xdg-open', url), stderr=PIPE)
def _get_build_info(self, job_name, build_number):
"""
Get the build info from the server. This method will check the queue and wait for the build.
"""
queue_info = self.server.get_queue_info()
tries = 0
loop_count = 100
while queue_info and tries < loop_count:
tries += 1
time.sleep(1)
queue_info = self.server.get_queue_info()
if tries >= loop_count:
raise Exception('Build has not started yet, it may be stuck in the queue.')
return self.server.get_build_info(job_name, build_number)
def __print_build_info(self, job_name):
"""
This helper method prints the job information of the given ``job_name``
:param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class
variables from the :class:`OpenLPJobs` class.
"""
job = self.jobs[job_name]
print('{:<70} [WAITING]'.format(job['nextBuildUrl']), end='', flush=True)
self.current_build = self._get_build_info(job_name, job['nextBuildNumber'])
print('\b\b\b\b\b\b\b\b\b[RUNNING]', end='', flush=True)
while self.current_build['building'] is True:
time.sleep(0.5)
self.current_build = self.server.get_build_info(job_name, job['nextBuildNumber'])
result_string = self.current_build['result']
is_success = result_string == 'SUCCESS'
if self.can_use_colour:
if is_success:
# Make 'SUCCESS' green.
result_string = '{}{}{}'.format(Colour.GREEN_START, result_string, Colour.GREEN_END)
else:
# Make 'FAILURE' red.
result_string = '{}{}{}'.format(Colour.RED_START, result_string, Colour.RED_END)
print('\b\b\b\b\b\b\b\b\b[{:>7}]'.format(result_string))
return is_success
def get_repo_name():
"""
This returns the name of branch of the working directory. For example it returns *lp:~googol/openlp/render*.
"""
# Run the bzr command.
bzr = Popen(('bzr', 'info'), stdout=PIPE, stderr=PIPE)
raw_output, error = bzr.communicate()
# Detect any errors
if error:
print('This is not a branch.')
return
# Clean the output.
raw_output = raw_output.decode()
output_list = list(map(str.strip, raw_output.split('\n')))
# Determine the branch's name
repo_name = ''
for line in output_list:
# Check if it is api branch.
if 'push branch' in line:
match = re.match(REPO_REGEX, line)
if match:
repo_name = 'lp:%s' % match.group(2)
break
elif 'checkout of branch' in line:
match = re.match(REPO_REGEX, line)
if match:
repo_name = 'lp:%s' % match.group(2)
break
return repo_name.strip('/')
def main():
"""
Run the script
"""
parser = ArgumentParser()
parser.add_argument('-d', '--disable-output', action='store_true', default=False, help='Disable output')
parser.add_argument('-b', '--open-browser', action='store_true', default=False,
help='Opens the jenkins page in your browser')
parser.add_argument('-n', '--no-colour', action='store_true', default=False,
help='Disable coloured output (always disabled on Windows)')
parser.add_argument('-u', '--username', required=True, help='Your Jenkins username')
parser.add_argument('-p', '--password', required=True, help='Your Jenkins password or personal token')
parser.add_argument('-c', '--always-continue', action='store_true', default=False, help='Continue despite failure')
args = parser.parse_args()
if not get_repo_name():
print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?')
return
jenkins_trigger = JenkinsTrigger(args.username, args.password, not args.no_colour)
jenkins_trigger.trigger_build()
# Open the browser before printing the output.
if args.open_browser:
jenkins_trigger.open_browser()
if not args.disable_output:
jenkins_trigger.print_output(can_continue=args.always_continue)
if __name__ == '__main__':
main()

View File

@ -565,6 +565,7 @@ class TestVLCPlayer(TestCase, TestMixin):
# GIVEN: A display object and a VlcPlayer instance # GIVEN: A display object and a VlcPlayer instance
mocked_display = MagicMock() mocked_display = MagicMock()
mocked_display.size.return_value = (10, 10) mocked_display.size.return_value = (10, 10)
mocked_display.is_display = False
vlc_player = VlcPlayer(None) vlc_player = VlcPlayer(None)
# WHEN: resize is called # WHEN: resize is called