forked from openlp/openlp
Merge branch 'media_sept_19' into 'master'
Media sept 19 See merge request openlp/openlp!21
This commit is contained in:
commit
cdba0e9235
@ -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')
|
||||||
|
@ -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,6 +415,8 @@ 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)
|
||||||
|
# This is added as start of OpenLP each time
|
||||||
|
if file_path != UiStrings().LiveStream:
|
||||||
file_paths.append(file_path)
|
file_paths.append(file_path)
|
||||||
return file_paths
|
return file_paths
|
||||||
|
|
||||||
@ -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,7 +636,6 @@ 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):
|
||||||
|
@ -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)
|
||||||
|
@ -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,7 +132,6 @@ 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)
|
||||||
|
@ -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()
|
||||||
|
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 = 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,6 +212,9 @@ class VlcPlayer(MediaPlayer):
|
|||||||
:param output_display: The display where the media is
|
:param output_display: The display where the media is
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
if output_display.is_display:
|
||||||
|
output_display.vlc_widget.setGeometry(ScreenList().current.display_geometry)
|
||||||
|
else:
|
||||||
output_display.vlc_widget.resize(output_display.size())
|
output_display.vlc_widget.resize(output_display.size())
|
||||||
|
|
||||||
def play(self, controller, output_display):
|
def play(self, controller, output_display):
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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'))
|
|
@ -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)
|
|
@ -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()
|
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user