From 365a4c62cf41a6760a3960d9cd07c755d7138b94 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 24 Jan 2014 19:43:02 +0000 Subject: [PATCH 01/44] Created GUI for mediaclip selection from DVD. --- .../media/forms/mediaclipselectordialog.py | 190 +++++++++ .../media/forms/mediaclipselectorform.py | 276 ++++++++++++++ openlp/plugins/media/lib/mediaitem.py | 8 + resources/forms/mediaclipselector.ui | 359 ++++++++++++++++++ 4 files changed, 833 insertions(+) create mode 100644 openlp/plugins/media/forms/mediaclipselectordialog.py create mode 100644 openlp/plugins/media/forms/mediaclipselectorform.py create mode 100644 resources/forms/mediaclipselector.ui diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py new file mode 100644 index 000000000..a6718fbf2 --- /dev/null +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -0,0 +1,190 @@ +from PyQt4 import QtCore, QtGui +from openlp.core.common import translate + +class Ui_MediaClipSelector(object): + def setupUi(self, MediaClipSelector): + MediaClipSelector.setObjectName("MediaClipSelector") + MediaClipSelector.resize(683, 739) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MediaClipSelector.sizePolicy().hasHeightForWidth()) + MediaClipSelector.setSizePolicy(sizePolicy) + MediaClipSelector.setMinimumSize(QtCore.QSize(683, 686)) + MediaClipSelector.setFocusPolicy(QtCore.Qt.NoFocus) + MediaClipSelector.setAutoFillBackground(False) + MediaClipSelector.setInputMethodHints(QtCore.Qt.ImhNone) + self.centralwidget = QtGui.QWidget(MediaClipSelector) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) + self.centralwidget.setSizePolicy(sizePolicy) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtGui.QGridLayout(self.centralwidget) + self.gridLayout.setObjectName("gridLayout") + self.close_pushbutton = QtGui.QPushButton(self.centralwidget) + self.close_pushbutton.setEnabled(True) + self.close_pushbutton.setObjectName("close_pushbutton") + self.gridLayout.addWidget(self.close_pushbutton, 10, 4, 1, 1) + self.pause_pushbutton = QtGui.QPushButton(self.centralwidget) + self.pause_pushbutton.setEnabled(True) + self.pause_pushbutton.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_pause.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pause_pushbutton.setIcon(icon) + self.pause_pushbutton.setObjectName("pause_pushbutton") + self.gridLayout.addWidget(self.pause_pushbutton, 6, 1, 1, 1) + self.play_pushbutton = QtGui.QPushButton(self.centralwidget) + self.play_pushbutton.setEnabled(True) + self.play_pushbutton.setText("") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.play_pushbutton.setIcon(icon1) + self.play_pushbutton.setObjectName("play_pushbutton") + self.gridLayout.addWidget(self.play_pushbutton, 6, 0, 1, 1) + self.media_path_label = QtGui.QLabel(self.centralwidget) + self.media_path_label.setEnabled(True) + self.media_path_label.setObjectName("media_path_label") + self.gridLayout.addWidget(self.media_path_label, 0, 0, 1, 2) + self.preview_pushbutton = QtGui.QPushButton(self.centralwidget) + self.preview_pushbutton.setEnabled(True) + self.preview_pushbutton.setObjectName("preview_pushbutton") + self.gridLayout.addWidget(self.preview_pushbutton, 10, 2, 1, 1) + self.start_point_label = QtGui.QLabel(self.centralwidget) + self.start_point_label.setEnabled(True) + self.start_point_label.setObjectName("start_point_label") + self.gridLayout.addWidget(self.start_point_label, 7, 0, 1, 2) + spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 9, 3, 1, 1) + self.start_timeedit = QtGui.QTimeEdit(self.centralwidget) + self.start_timeedit.setEnabled(True) + self.start_timeedit.setObjectName("start_timeedit") + self.gridLayout.addWidget(self.start_timeedit, 7, 2, 1, 1) + self.jump_end_pushbutton = QtGui.QPushButton(self.centralwidget) + self.jump_end_pushbutton.setEnabled(True) + self.jump_end_pushbutton.setObjectName("jump_end_pushbutton") + self.gridLayout.addWidget(self.jump_end_pushbutton, 8, 4, 1, 1) + self.subtitle_track_label = QtGui.QLabel(self.centralwidget) + self.subtitle_track_label.setEnabled(True) + self.subtitle_track_label.setObjectName("subtitle_track_label") + self.gridLayout.addWidget(self.subtitle_track_label, 4, 0, 1, 2) + self.set_end_pushbutton = QtGui.QPushButton(self.centralwidget) + self.set_end_pushbutton.setEnabled(True) + self.set_end_pushbutton.setObjectName("set_end_pushbutton") + self.gridLayout.addWidget(self.set_end_pushbutton, 8, 3, 1, 1) + self.set_start_pushbutton = QtGui.QPushButton(self.centralwidget) + self.set_start_pushbutton.setEnabled(True) + self.set_start_pushbutton.setObjectName("set_start_pushbutton") + self.gridLayout.addWidget(self.set_start_pushbutton, 7, 3, 1, 1) + self.audio_track_label = QtGui.QLabel(self.centralwidget) + self.audio_track_label.setEnabled(True) + self.audio_track_label.setObjectName("audio_track_label") + self.gridLayout.addWidget(self.audio_track_label, 3, 0, 1, 2) + self.load_disc_pushbutton = QtGui.QPushButton(self.centralwidget) + self.load_disc_pushbutton.setEnabled(True) + self.load_disc_pushbutton.setObjectName("load_disc_pushbutton") + self.gridLayout.addWidget(self.load_disc_pushbutton, 0, 4, 1, 1) + self.media_position_timeedit = QtGui.QTimeEdit(self.centralwidget) + self.media_position_timeedit.setEnabled(True) + self.media_position_timeedit.setObjectName("media_position_timeedit") + self.gridLayout.addWidget(self.media_position_timeedit, 6, 4, 1, 1) + self.end_point_label = QtGui.QLabel(self.centralwidget) + self.end_point_label.setEnabled(True) + self.end_point_label.setObjectName("end_point_label") + self.gridLayout.addWidget(self.end_point_label, 8, 0, 1, 1) + self.jump_start_pushbutton = QtGui.QPushButton(self.centralwidget) + self.jump_start_pushbutton.setEnabled(True) + self.jump_start_pushbutton.setObjectName("jump_start_pushbutton") + self.gridLayout.addWidget(self.jump_start_pushbutton, 7, 4, 1, 1) + self.end_timeedit = QtGui.QTimeEdit(self.centralwidget) + self.end_timeedit.setEnabled(True) + self.end_timeedit.setObjectName("end_timeedit") + self.gridLayout.addWidget(self.end_timeedit, 8, 2, 1, 1) + self.title_label = QtGui.QLabel(self.centralwidget) + self.title_label.setEnabled(True) + self.title_label.setObjectName("title_label") + self.gridLayout.addWidget(self.title_label, 2, 0, 1, 1) + self.save_pushbutton = QtGui.QPushButton(self.centralwidget) + self.save_pushbutton.setEnabled(True) + self.save_pushbutton.setObjectName("save_pushbutton") + self.gridLayout.addWidget(self.save_pushbutton, 10, 3, 1, 1) + self.media_path_combobox = QtGui.QComboBox(self.centralwidget) + self.media_path_combobox.setEnabled(True) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.media_path_combobox.sizePolicy().hasHeightForWidth()) + self.media_path_combobox.setSizePolicy(sizePolicy) + self.media_path_combobox.setEditable(True) + self.media_path_combobox.setObjectName("media_path_combobox") + self.gridLayout.addWidget(self.media_path_combobox, 0, 2, 1, 2) + self.position_horizontalslider = QtGui.QSlider(self.centralwidget) + self.position_horizontalslider.setEnabled(True) + self.position_horizontalslider.setTracking(False) + self.position_horizontalslider.setOrientation(QtCore.Qt.Horizontal) + self.position_horizontalslider.setInvertedAppearance(False) + self.position_horizontalslider.setObjectName("position_horizontalslider") + self.gridLayout.addWidget(self.position_horizontalslider, 6, 2, 1, 2) + self.title_combo_box = QtGui.QComboBox(self.centralwidget) + self.title_combo_box.setEnabled(True) + self.title_combo_box.setProperty("currentText", "") + self.title_combo_box.setObjectName("title_combo_box") + self.gridLayout.addWidget(self.title_combo_box, 2, 2, 1, 2) + self.audio_tracks_combobox = QtGui.QComboBox(self.centralwidget) + self.audio_tracks_combobox.setEnabled(True) + self.audio_tracks_combobox.setObjectName("audio_tracks_combobox") + self.gridLayout.addWidget(self.audio_tracks_combobox, 3, 2, 1, 2) + self.subtitle_tracks_combobox = QtGui.QComboBox(self.centralwidget) + self.subtitle_tracks_combobox.setEnabled(True) + self.subtitle_tracks_combobox.setObjectName("subtitle_tracks_combobox") + self.gridLayout.addWidget(self.subtitle_tracks_combobox, 4, 2, 1, 2) + self.media_view_frame = QtGui.QFrame(self.centralwidget) + self.media_view_frame.setMinimumSize(QtCore.QSize(665, 375)) + self.media_view_frame.setStyleSheet("background-color:black;") + self.media_view_frame.setFrameShape(QtGui.QFrame.StyledPanel) + self.media_view_frame.setFrameShadow(QtGui.QFrame.Raised) + self.media_view_frame.setObjectName("media_view_frame") + self.gridLayout.addWidget(self.media_view_frame, 5, 0, 1, 5) + #MediaClipSelector.setCentralWidget(self.centralwidget) + + self.retranslateUi(MediaClipSelector) + QtCore.QMetaObject.connectSlotsByName(MediaClipSelector) + MediaClipSelector.setTabOrder(self.media_path_combobox, self.load_disc_pushbutton) + MediaClipSelector.setTabOrder(self.load_disc_pushbutton, self.title_combo_box) + MediaClipSelector.setTabOrder(self.title_combo_box, self.audio_tracks_combobox) + MediaClipSelector.setTabOrder(self.audio_tracks_combobox, self.subtitle_tracks_combobox) + MediaClipSelector.setTabOrder(self.subtitle_tracks_combobox, self.play_pushbutton) + MediaClipSelector.setTabOrder(self.play_pushbutton, self.pause_pushbutton) + MediaClipSelector.setTabOrder(self.pause_pushbutton, self.position_horizontalslider) + MediaClipSelector.setTabOrder(self.position_horizontalslider, self.media_position_timeedit) + MediaClipSelector.setTabOrder(self.media_position_timeedit, self.start_timeedit) + MediaClipSelector.setTabOrder(self.start_timeedit, self.set_start_pushbutton) + MediaClipSelector.setTabOrder(self.set_start_pushbutton, self.jump_start_pushbutton) + MediaClipSelector.setTabOrder(self.jump_start_pushbutton, self.end_timeedit) + MediaClipSelector.setTabOrder(self.end_timeedit, self.set_end_pushbutton) + MediaClipSelector.setTabOrder(self.set_end_pushbutton, self.jump_end_pushbutton) + MediaClipSelector.setTabOrder(self.jump_end_pushbutton, self.preview_pushbutton) + MediaClipSelector.setTabOrder(self.preview_pushbutton, self.save_pushbutton) + MediaClipSelector.setTabOrder(self.save_pushbutton, self.close_pushbutton) + + def retranslateUi(self, MediaClipSelector): + MediaClipSelector.setWindowTitle(translate("MediaPlugin.MediaClipSelector", "Select media clip", None)) + self.close_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Close", None)) + self.media_path_label.setText(translate("MediaPlugin.MediaClipSelector", "Media path", None)) + self.preview_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Preview current clip", None)) + self.start_point_label.setText(translate("MediaPlugin.MediaClipSelector", "Start point", None)) + self.start_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) + self.jump_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to end point", None)) + self.subtitle_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Subtitle track", None)) + self.set_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as end point", None)) + self.set_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as start point", None)) + self.audio_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Audio track", None)) + self.load_disc_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Load disc", None)) + self.media_position_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) + self.end_point_label.setText(translate("MediaPlugin.MediaClipSelector", "End point", None)) + self.jump_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to start point", None)) + self.end_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) + self.title_label.setText(translate("MediaPlugin.MediaClipSelector", "Title", None)) + self.save_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Save current clip", None)) + diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py new file mode 100644 index 000000000..6f7f22c57 --- /dev/null +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +import os +import sys +import logging +import time + +from PyQt4 import QtCore, QtGui + +from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector +from openlp.core.ui.media.vendor import vlc + +log = logging.getLogger(__name__) + + +class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): + """ + Class to manage the clip selection + """ + log.info('%s MediaClipSelectorForm loaded', __name__) + + def __init__(self, media_item, parent, manager): + """ + Constructor + """ + super(MediaClipSelectorForm, self).__init__(parent) + self.media_item = media_item + self.setupUi(self) + self.playback_length = 0 + self.position_horizontalslider.setMinimum(0) + self.disable_all() + self.toggle_disable_load_media(False) + # most actions auto-connect due to the functions name, so only a few left to do + self.close_pushbutton.clicked.connect(self.reject) + #self.load_disc_pushbutton.clicked.connect(self.on_load_disc_pushbutton_clicked) + #self.pause_pushbutton.clicked.connect(self.on_pause_pushbutton_clicked) + #self.play_pushbutton.clicked.connect(self.on_play_pushbutton_clicked) + + def reject(self): + """ + Exit Dialog and do not save + """ + log.debug ('MediaClipSelectorForm.reject') + self.vlc_media_player.stop() + QtGui.QDialog.reject(self) + + def exec_(self): + self.setup_vlc() + return QtGui.QDialog.exec_(self) + + def setup_vlc(self): + self.vlc_instance = vlc.Instance() + # creating an empty vlc media player + self.vlc_media_player = self.vlc_instance.media_player_new() + # The media player has to be 'connected' to the QFrame. + # (otherwise a video would be displayed in it's own window) + # This is platform specific! + # You have to give the id of the QFrame (or similar object) + # to vlc, different platforms have different functions for this. + win_id = int(self.media_view_frame.winId()) + if sys.platform == "win32": + self.vlc_media_player.set_hwnd(win_id) + elif sys.platform == "darwin": + # We have to use 'set_nsobject' since Qt4 on OSX uses Cocoa + # framework and not the old Carbon. + self.vlc_media_player.set_nsobject(win_id) + else: + # for Linux using the X Server + self.vlc_media_player.set_xwindow(win_id) + self.vlc_media = None + # Setup timer every 100 ms to update position + self.timer = QtCore.QTimer(self) + self.timer.timeout.connect(self.update_position) + self.timer.start(100) + + @QtCore.pyqtSlot(bool) + def on_load_disc_pushbutton_clicked(self, clicked): + self.disable_all() + path = self.media_path_combobox.currentText() + if path == '': + print('no given path') + # TODO: Error message + self.toggle_disable_load_media(False) + return + self.vlc_media = self.vlc_instance.media_new_path(path) + if not self.vlc_media: + print('media player is none') + # TODO: Error message + self.toggle_disable_load_media(False) + return + # put the media in the media player + self.vlc_media_player.set_media(self.vlc_media) + self.vlc_media_player.audio_set_mute(True) + # start playback to get vlc to parse the media + if self.vlc_media_player.play() < 0: + print('play returned error') + # TODO: Error message + self.toggle_disable_load_media(False) + return + self.vlc_media_player.audio_set_mute(True) + while self.vlc_media_player.get_time() == 0: + if self.vlc_media_player.get_state() == vlc.State.Error: + print('player in error state') + self.toggle_disable_load_media(False) + return + time.sleep(0.1) + self.vlc_media_player.pause() + self.vlc_media_player.set_time(0) + # Get titles, insert in combobox + titles = self.vlc_media_player.video_get_title_description() + self.title_combo_box.clear() + for title in titles: + self.title_combo_box.addItem(title[1].decode(), title[0]) + # Main title is usually title #1 + if len(titles) > 1: + self.title_combo_box.setCurrentIndex(1) + else: + self.title_combo_box.setCurrentIndex(0) + # Enable audio track combobox if anything is in it + if len(titles) > 0: + self.title_combo_box.setDisabled(False) + self.toggle_disable_load_media(False) + + def on_pause_pushbutton_clicked(self): + self.vlc_media_player.pause() + + def on_play_pushbutton_clicked(self): + self.vlc_media_player.play() + + def on_set_start_pushbutton_clicked(self): + vlc_ms_pos = self.vlc_media_player.get_time() + time = QtCore.QTime() + new_pos_time = time.addMSecs(vlc_ms_pos) + self.start_timeedit.setTime(new_pos_time) + + def on_set_end_pushbutton_clicked(self): + vlc_ms_pos = self.vlc_media_player.get_time() + time = QtCore.QTime() + new_pos_time = time.addMSecs(vlc_ms_pos) + self.end_timeedit.setTime(new_pos_time) + + def on_jump_end_pushbutton_clicked(self): + end_time = self.end_timeedit.time() + end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ + end_time.minute() * 60 * 1000 + \ + end_time.second() * 1000 + \ + end_time.msec() + self.vlc_media_player.set_time(end_time_ms) + + def on_jump_start_pushbutton_clicked(self): + start_time = self.start_timeedit.time() + start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ + start_time.minute() * 60 * 1000 + \ + start_time.second() * 1000 + \ + start_time.msec() + self.vlc_media_player.set_time(start_time_ms) + + @QtCore.pyqtSlot(int) + def on_title_combo_box_currentIndexChanged(self, index): + print('in on_title_combo_box_changed, index: ', str(index)) + self.vlc_media_player.set_title(index) + self.vlc_media_player.set_time(0) + self.vlc_media_player.play() + self.vlc_media_player.audio_set_mute(True) + while self.vlc_media_player.get_time() == 0: + time.sleep(0.1) + # pause + self.vlc_media_player.pause() + self.vlc_media_player.set_time(0) + # Get audio tracks, insert in combobox + audio_tracks = self.vlc_media_player.audio_get_track_description() + self.audio_tracks_combobox.clear() + for audio_track in audio_tracks: + self.audio_tracks_combobox.addItem(audio_track[1].decode(),audio_track[0]) + # Enable audio track combobox if anything is in it + if len(audio_tracks) > 0: + self.audio_tracks_combobox.setDisabled(False) + # First track is "deactivated", so set to next if it exists + if len(audio_tracks) > 1: + self.audio_tracks_combobox.setCurrentIndex(1) + # Get subtitle tracks, insert in combobox + subtitles_tracks = self.vlc_media_player.video_get_spu_description() + self.subtitle_tracks_combobox.clear() + for subtitle_track in subtitles_tracks: + self.subtitle_tracks_combobox.addItem(subtitle_track[1].decode(), subtitle_track[0]) + # Enable subtitle track combobox is anything in it + if len(subtitles_tracks) > 0: + self.subtitle_tracks_combobox.setDisabled(False) + # First track is "deactivated", so set to next if it exists + if len(subtitles_tracks) > 1: + self.subtitle_tracks_combobox.setCurrentIndex(1) + self.vlc_media_player.audio_set_mute(False) + self.playback_length = self.vlc_media_player.get_length() + self.position_horizontalslider.setMaximum(self.playback_length) + # If a title or audio track is available the player is enabled + if self.title_combo_box.count() > 0 or len(audio_tracks) > 0: + self.toggle_disable_player(False) + + @QtCore.pyqtSlot(int) + def on_audio_tracks_combobox_currentIndexChanged(self, index): + audio_track = self.audio_tracks_combobox.itemData(index) + print('in on_audio_tracks_combobox_currentIndexChanged, index: ', str(index), ' audio_track: ', audio_track) + if audio_track and int(audio_track) > 0: + self.vlc_media_player.audio_set_track(int(audio_track)) + + @QtCore.pyqtSlot(int) + def on_subtitle_tracks_combobox_currentIndexChanged(self, index): + subtitle_track = self.subtitle_tracks_combobox.itemData(index) + print('in on_subtitle_tracks_combobox_currentIndexChanged, index: ', str(index), ' subtitle_track: ', subtitle_track) + if subtitle_track: + self.vlc_media_player.video_set_spu(int(subtitle_track)) + + def on_position_horizontalslider_sliderMoved(self, position): + self.vlc_media_player.set_time(position) + + def update_position(self): + if self.vlc_media_player: + vlc_ms_pos = self.vlc_media_player.get_time() + #print('in update_position, time: ', vlc_ms_pos) + rounded_vlc_ms_pos = int(round(vlc_ms_pos / 100.0) * 100.0) + time = QtCore.QTime() + new_pos_time = time.addMSecs(rounded_vlc_ms_pos) + self.media_position_timeedit.setTime(new_pos_time) + self.position_horizontalslider.setSliderPosition(vlc_ms_pos) + + def disable_all(self): + self.toggle_disable_load_media(True) + self.title_combo_box.setDisabled(True) + self.audio_tracks_combobox.setDisabled(True) + self.subtitle_tracks_combobox.setDisabled(True) + self.toggle_disable_player(True) + + def toggle_disable_load_media(self, action): + self.media_path_combobox.setDisabled(action) + self.load_disc_pushbutton.setDisabled(action) + + def toggle_disable_player(self, action): + self.play_pushbutton.setDisabled(action) + self.pause_pushbutton.setDisabled(action) + self.position_horizontalslider.setDisabled(action) + self.media_position_timeedit.setDisabled(action) + self.start_timeedit.setDisabled(action) + self.set_start_pushbutton.setDisabled(action) + self.jump_start_pushbutton.setDisabled(action) + self.end_timeedit.setDisabled(action) + self.set_end_pushbutton.setDisabled(action) + self.jump_end_pushbutton.setDisabled(action) + self.preview_pushbutton.setDisabled(action) + self.save_pushbutton.setDisabled(action) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index c9ba6a47d..58dec0dac 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -39,6 +39,8 @@ from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adj from openlp.core.ui import DisplayController, Display, DisplayControllerType from openlp.core.ui.media import get_media_players, set_media_players from openlp.core.utils import get_locale_key +from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm + log = logging.getLogger(__name__) @@ -115,6 +117,7 @@ class MediaMediaItem(MediaManagerItem): triggers=self.onReplaceClick) self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png', visible=False, triggers=self.onResetClick) + self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=':/songs/song_maintenance.png', triggers=self.on_load_optical) self.media_widget = QtGui.QWidget(self) self.media_widget.setObjectName('media_widget') self.display_layout = QtGui.QFormLayout(self.media_widget) @@ -215,6 +218,7 @@ class MediaMediaItem(MediaManagerItem): check_directory_exists(self.servicePath) self.load_list(Settings().value(self.settings_section + '/media files')) self.populateDisplayTypes() + self.media_clip_selector_form = MediaClipSelectorForm(self, self.main_window, None) def rebuild_players(self): """ @@ -311,3 +315,7 @@ class MediaMediaItem(MediaManagerItem): if filename.lower().find(string) > -1: results.append([file, filename]) return results + + def on_load_optical(self): + log.debug('in on_load_optical') + self.media_clip_selector_form.exec_() diff --git a/resources/forms/mediaclipselector.ui b/resources/forms/mediaclipselector.ui new file mode 100644 index 000000000..4cd8f518d --- /dev/null +++ b/resources/forms/mediaclipselector.ui @@ -0,0 +1,359 @@ + + + MediaClipSelector + + + + 0 + 0 + 683 + 739 + + + + + 0 + 0 + + + + + 683 + 686 + + + + Qt::NoFocus + + + Select media clip + + + false + + + Qt::ImhNone + + + + + 0 + 0 + + + + + + + true + + + Close + + + + + + + true + + + + + + + ../images/media_playback_pause.png../images/media_playback_pause.png + + + + + + + true + + + + + + + ../images/media_playback_start.png../images/media_playback_start.png + + + + + + + true + + + Media path + + + + + + + true + + + Preview current clip + + + + + + + true + + + Start point + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 40 + + + + + + + + true + + + HH:mm:ss.z + + + + + + + true + + + Jump to end point + + + + + + + true + + + Subtitle track + + + + + + + true + + + Set current position as end point + + + + + + + true + + + Set current position as start point + + + + + + + true + + + Audio track + + + + + + + true + + + Load disc + + + + + + + true + + + HH:mm:ss.z + + + + + + + true + + + End point + + + + + + + true + + + Jump to start point + + + + + + + true + + + HH:mm:ss.z + + + + + + + true + + + Title + + + + + + + true + + + Save current clip + + + + + + + true + + + + 0 + 0 + + + + true + + + + + + + true + + + false + + + Qt::Horizontal + + + false + + + + + + + true + + + + + + + + + + true + + + + + + + true + + + + + + + + 665 + 375 + + + + background-color:black; + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + media_path_combobox + load_disc_pushbutton + title_combo_box + audio_tracks_combobox + subtitle_tracks_combobox + play_pushbutton + pause_pushbutton + position_horizontalslider + media_position_timeedit + start_timeedit + set_start_pushbutton + jump_start_pushbutton + end_timeedit + set_end_pushbutton + jump_end_pushbutton + preview_pushbutton + save_pushbutton + close_pushbutton + + + + From 6d21a326edd01f7568456049cebd095541b0c280 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 17 Feb 2014 23:29:52 +0100 Subject: [PATCH 02/44] Made it possible to save a selected clip to the mediamanager. --- .../media/forms/mediaclipselectorform.py | 124 +++++++++++++++--- openlp/plugins/media/lib/mediaitem.py | 48 +++++-- resources/images/media_optical.png | Bin 0 -> 2056 bytes resources/images/openlp-2.qrc | 1 + 4 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 resources/images/media_optical.png diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 6f7f22c57..688d879d4 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -35,6 +35,7 @@ import time from PyQt4 import QtCore, QtGui from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector +from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.media.vendor import vlc log = logging.getLogger(__name__) @@ -59,9 +60,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_load_media(False) # most actions auto-connect due to the functions name, so only a few left to do self.close_pushbutton.clicked.connect(self.reject) - #self.load_disc_pushbutton.clicked.connect(self.on_load_disc_pushbutton_clicked) - #self.pause_pushbutton.clicked.connect(self.on_pause_pushbutton_clicked) - #self.play_pushbutton.clicked.connect(self.on_play_pushbutton_clicked) def reject(self): """ @@ -72,10 +70,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): QtGui.QDialog.reject(self) def exec_(self): + """ + Start dialog + """ self.setup_vlc() return QtGui.QDialog.exec_(self) def setup_vlc(self): + """ + Setup VLC instance and mediaplayer + """ self.vlc_instance = vlc.Instance() # creating an empty vlc media player self.vlc_media_player = self.vlc_instance.media_player_new() @@ -102,17 +106,20 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): @QtCore.pyqtSlot(bool) def on_load_disc_pushbutton_clicked(self, clicked): + """ + Load the media when the load-button has been clicked + """ self.disable_all() path = self.media_path_combobox.currentText() if path == '': - print('no given path') - # TODO: Error message + log.debug('no given path') + critical_error_message_box('Error', 'No path was given') self.toggle_disable_load_media(False) return self.vlc_media = self.vlc_instance.media_new_path(path) if not self.vlc_media: - print('media player is none') - # TODO: Error message + log.debug('vlc media player is none') + critical_error_message_box('Error', 'An error happened during initialization of VLC player') self.toggle_disable_load_media(False) return # put the media in the media player @@ -120,14 +127,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.audio_set_mute(True) # start playback to get vlc to parse the media if self.vlc_media_player.play() < 0: - print('play returned error') - # TODO: Error message + log.debug('vlc play returned error') + critical_error_message_box('Error', 'An error happen when starting VLC player') self.toggle_disable_load_media(False) return self.vlc_media_player.audio_set_mute(True) while self.vlc_media_player.get_time() == 0: if self.vlc_media_player.get_state() == vlc.State.Error: - print('player in error state') + log.debug('player in error state') self.toggle_disable_load_media(False) return time.sleep(0.1) @@ -148,25 +155,45 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.title_combo_box.setDisabled(False) self.toggle_disable_load_media(False) - def on_pause_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_pause_pushbutton_clicked(self, clicked): + """ + Pause the playback + """ self.vlc_media_player.pause() - def on_play_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_play_pushbutton_clicked(self, clicked): + """ + Start the playback + """ self.vlc_media_player.play() - def on_set_start_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_set_start_pushbutton_clicked(self, clicked): + """ + Copy the current player position to start_timeedit + """ vlc_ms_pos = self.vlc_media_player.get_time() time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) self.start_timeedit.setTime(new_pos_time) - def on_set_end_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_set_end_pushbutton_clicked(self, clicked): + """ + Copy the current player position to end_timeedit + """ vlc_ms_pos = self.vlc_media_player.get_time() time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) self.end_timeedit.setTime(new_pos_time) - def on_jump_end_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_jump_end_pushbutton_clicked(self, clicked): + """ + Set the player position to the position stored in end_timeedit + """ end_time = self.end_timeedit.time() end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ end_time.minute() * 60 * 1000 + \ @@ -174,7 +201,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): end_time.msec() self.vlc_media_player.set_time(end_time_ms) - def on_jump_start_pushbutton_clicked(self): + @QtCore.pyqtSlot(bool) + def on_jump_start_pushbutton_clicked(self, clicked): + """ + Set the player position to the position stored in start_timeedit + """ start_time = self.start_timeedit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ start_time.minute() * 60 * 1000 + \ @@ -184,12 +215,18 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): @QtCore.pyqtSlot(int) def on_title_combo_box_currentIndexChanged(self, index): - print('in on_title_combo_box_changed, index: ', str(index)) + """ + When a new title is chosen, it is loaded by VLC and info about audio and subtitle tracks is reloaded + """ + log.debug('in on_title_combo_box_changed, index: ', str(index)) self.vlc_media_player.set_title(index) self.vlc_media_player.set_time(0) self.vlc_media_player.play() self.vlc_media_player.audio_set_mute(True) while self.vlc_media_player.get_time() == 0: + if self.vlc_media_player.get_state() == vlc.State.Error: + log.debug('player in error state') + return time.sleep(0.1) # pause self.vlc_media_player.pause() @@ -225,25 +262,36 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): @QtCore.pyqtSlot(int) def on_audio_tracks_combobox_currentIndexChanged(self, index): + """ + When a new audio track is chosen update audio track bing played by VLC + """ audio_track = self.audio_tracks_combobox.itemData(index) - print('in on_audio_tracks_combobox_currentIndexChanged, index: ', str(index), ' audio_track: ', audio_track) + log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: ', str(index), ' audio_track: ', audio_track) if audio_track and int(audio_track) > 0: self.vlc_media_player.audio_set_track(int(audio_track)) @QtCore.pyqtSlot(int) def on_subtitle_tracks_combobox_currentIndexChanged(self, index): + """ + When a new subtitle track is chosen update subtitle track bing played by VLC + """ subtitle_track = self.subtitle_tracks_combobox.itemData(index) - print('in on_subtitle_tracks_combobox_currentIndexChanged, index: ', str(index), ' subtitle_track: ', subtitle_track) + log.debug('in on_subtitle_tracks_combobox_currentIndexChanged, index: ', str(index), ' subtitle_track: ', subtitle_track) if subtitle_track: self.vlc_media_player.video_set_spu(int(subtitle_track)) def on_position_horizontalslider_sliderMoved(self, position): + """ + Set player position according to new slider position. + """ self.vlc_media_player.set_time(position) def update_position(self): + """ + Update slider position and displayed time according to VLC player position. + """ if self.vlc_media_player: vlc_ms_pos = self.vlc_media_player.get_time() - #print('in update_position, time: ', vlc_ms_pos) rounded_vlc_ms_pos = int(round(vlc_ms_pos / 100.0) * 100.0) time = QtCore.QTime() new_pos_time = time.addMSecs(rounded_vlc_ms_pos) @@ -251,6 +299,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.position_horizontalslider.setSliderPosition(vlc_ms_pos) def disable_all(self): + """ + Disable all elements in the dialog + """ self.toggle_disable_load_media(True) self.title_combo_box.setDisabled(True) self.audio_tracks_combobox.setDisabled(True) @@ -258,10 +309,20 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_player(True) def toggle_disable_load_media(self, action): + """ + Enable/disable load media combobox and button. + + @param action: If True elements are disabled, if False they are enabled. + """ self.media_path_combobox.setDisabled(action) self.load_disc_pushbutton.setDisabled(action) def toggle_disable_player(self, action): + """ + Enable/disable player elementa. + + @param action: If True elements are disabled, if False they are enabled. + """ self.play_pushbutton.setDisabled(action) self.pause_pushbutton.setDisabled(action) self.position_horizontalslider.setDisabled(action) @@ -274,3 +335,26 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.jump_end_pushbutton.setDisabled(action) self.preview_pushbutton.setDisabled(action) self.save_pushbutton.setDisabled(action) + + @QtCore.pyqtSlot(bool) + def on_save_pushbutton_clicked(self, checked): + """ + Saves the current media and trackinfo as a clip to the mediamanager + """ + log.debug('in on_save_pushbutton_clicked') + start_time = self.start_timeedit.time() + start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ + start_time.minute() * 60 * 1000 + \ + start_time.second() * 1000 + \ + start_time.msec() + end_time = self.end_timeedit.time() + end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ + end_time.minute() * 60 * 1000 + \ + end_time.second() * 1000 + \ + end_time.msec() + title = self.title_combo_box.itemData(self.title_combo_box.currentIndex()) + audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) + subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) + path = self.media_path_combobox.currentText() + optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + path + self.media_item.add_optical_clip(optical) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 58dec0dac..33b983dad 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -40,6 +40,7 @@ from openlp.core.ui import DisplayController, Display, DisplayControllerType from openlp.core.ui.media import get_media_players, set_media_players from openlp.core.utils import get_locale_key from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm +from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE @@ -49,7 +50,7 @@ log = logging.getLogger(__name__) CLAPPERBOARD = ':/media/slidecontroller_multimedia.png' VIDEO_ICON = build_icon(':/media/media_video.png') AUDIO_ICON = build_icon(':/media/media_audio.png') -DVD_ICON = build_icon(':/media/media_video.png') +OPTICAL_ICON = build_icon(':/media/media_optical.png') ERROR_ICON = build_icon(':/general/general_delete.png') @@ -111,13 +112,18 @@ class MediaMediaItem(MediaManagerItem): MediaManagerItem.add_list_view_to_toolbar(self) self.list_view.addAction(self.replace_action) + def add_start_header_bar(self): + self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text='Load optical disc', + tooltip='Load optical disc', triggers=self.on_load_optical) + if not VLC_AVAILABLE: + self.load_optical.setDisabled(True) + def add_end_header_bar(self): # Replace backgrounds do not work at present so remove functionality. self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=':/slides/slide_blank.png', triggers=self.onReplaceClick) self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png', visible=False, triggers=self.onResetClick) - self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=':/songs/song_maintenance.png', triggers=self.on_load_optical) self.media_widget = QtGui.QWidget(self) self.media_widget.setObjectName('media_widget') self.display_layout = QtGui.QFormLayout(self.media_widget) @@ -269,15 +275,23 @@ class MediaMediaItem(MediaManagerItem): Settings().setValue(self.settings_section + '/media files', self.get_file_list()) def load_list(self, media, target_group=None): - # Sort the media by its filename considering language specific characters. + # Sort the media by its filename considering language specific characters. media.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1])) for track in media: track_info = QtCore.QFileInfo(track) - if not os.path.exists(track): + if track.startswith('optical:'): + (filename, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(track) + optical = filename + '@' + str(title) + ':' + str(start) + '-' + str(end) + item_name = QtGui.QListWidgetItem(optical) + item_name.setIcon(build_icon(OPTICAL_ICON)) + item_name.setData(QtCore.Qt.UserRole, track) + item_name.setToolTip(optical) + elif not os.path.exists(track): filename = os.path.split(str(track))[1] item_name = QtGui.QListWidgetItem(filename) item_name.setIcon(ERROR_ICON) item_name.setData(QtCore.Qt.UserRole, track) + item_name.setToolTip(track) elif track_info.isFile(): filename = os.path.split(str(track))[1] item_name = QtGui.QListWidgetItem(filename) @@ -286,12 +300,7 @@ class MediaMediaItem(MediaManagerItem): else: item_name.setIcon(VIDEO_ICON) item_name.setData(QtCore.Qt.UserRole, track) - else: - filename = os.path.split(str(track))[1] - item_name = QtGui.QListWidgetItem(filename) - item_name.setIcon(build_icon(DVD_ICON)) - item_name.setData(QtCore.Qt.UserRole, track) - item_name.setToolTip(track) + item_name.setToolTip(track) self.list_view.addItem(item_name) def get_list(self, type=MediaType.Audio): @@ -319,3 +328,22 @@ class MediaMediaItem(MediaManagerItem): def on_load_optical(self): log.debug('in on_load_optical') self.media_clip_selector_form.exec_() + + def parse_optical_path(self, input): + # split the clip info + clip_info = input.split(sep=':') + title = int(clip_info[1]) + audio_track = int(clip_info[2]) + subtitle_track = int(clip_info[3]) + start = float(clip_info[4]) + end = float(clip_info[5]) + filename = clip_info[6] + if len(clip_info) > 7: + filename += clip_info[7] + return filename, title, audio_track, subtitle_track, start, end + + def add_optical_clip(self, optical): + full_list = self.get_file_list() + full_list.append(optical) + self.load_list([optical]) + Settings().setValue(self.settings_section + '/media files', self.get_file_list()) diff --git a/resources/images/media_optical.png b/resources/images/media_optical.png new file mode 100644 index 0000000000000000000000000000000000000000..033b9847299474a3e3d6f6076a5c1b874b070705 GIT binary patch literal 2056 zcmV+j2>17iP)Px#32;bRa{vGa>;M1;>;WEiI5hwO00(qQO+^RU1qTr>5T}NKfdBvi24YJ`L;(K) z{{a7>y{D4^00)RkL_t(|+SQg>ZyVK{1&_RH!W@79Q@Dj!LN=z{lA==;c}eK2T@Ex5;JNvnnf&@Lo&I5 zOs0s1g^F4#tstJr(lzqJjNbe!cCXH8{m%t_+HwDTBctY&(-nnZh^fI~9N{ntkTU!5 zL}CHybP>5+8HGXxi;GoMDyvvsU03V%2Bc^_Gcm3E{+XZv_K&xFhtG{@{otK3)$LW_ z54;J!jHRU&tgO_rw${ML#wND6chuF@8f?7t1NO|8mX_0rcrtSDw$o*U!7ix=dmJ7i zfk2SK(VYQ1iI=){k7yrw9g(YDly|jPMAG z0a!?YAm$KNUJtL;)(_x2JG+PATU$GHeoL)XmNBb0zr)SDju$c4KUR@=y($G~5RI51 z%XY*RH$+*2J&=c-C?cIb4!(i)^-Tt0aDpC!)9#SCC&QtNC1k%8^4pUm!76G#Z;KrTtj= zT8+WiP^~i2HFc@7yn6`#`R#|_antT2t`KB*7;&$Nls}A|Cy1iYjbf5Vspvte6oC*? z5Q-*h)#}Q#&CShr+If4ew)U)8EY{Z6)(+r}Mib65#cWB}QU+EbhGXcy-}mhU0sRBx z7b2k~A^`=lpn^mwhBQS^jG+*TVks0xHSR?&X{AhvK>&ZJxI}TC;u^&#>|CX?NIhS}mqcTfM-0|C7c2Yy&Cudoy|C_x%5n4j71*-U5kr{CLZp|D8STFf^Zjk^Fo zqWGAmT(1<8^L}>_2|1|7V;tnD0ilo{Ucm$>=YrkngGJ|oVaA222^&7S^7-3`reQ8u z*rl|q^j2dvKMZfaQfZXcb-Pc7 z-y>4E;PX-jyc2M`#$e;0!aO$y{j?c3KkNCk=C~y*iFGQ0dLq0+@KW`t&n1EfXvlaX z@Hs+o+5B+YdCc=O;2qDX{!GBIIyBtX&>XwIb%U~C`e}WA<4o}8cqN|;5`3;OTwDN- zIWIV)3l^gl7V{*`<`HOT`|-t>SKib7;n`7sb0)a2sZh@XZw?s``P@Npix)P73v;s$ z7^m&fO`D*fouJOYbyIVi;4xND$XLVdvJ8Q)hHQ4C5zB)8KCEn?I(sAkXjdwNw mt97oc>y6j^;9S?4p7}2y|J`56Sngr~0000media_stop.png media_audio.png media_video.png + media_optical.png slidecontroller_multimedia.png auto-start_active.png auto-start_inactive.png From 67acb9d8247d5dc48d4aacbda47d0438e7c8c4d8 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 4 Mar 2014 22:33:50 +0000 Subject: [PATCH 03/44] Implemented DVD clip selection and playback, still needs a lot of cleanups. --- openlp/core/lib/serviceitem.py | 5 +- openlp/core/ui/media/__init__.py | 3 + openlp/core/ui/media/mediacontroller.py | 74 ++++++++++++++++++- openlp/core/ui/media/vlcplayer.py | 30 +++++++- .../media/forms/mediaclipselectorform.py | 41 +++++++--- openlp/plugins/media/lib/mediaitem.py | 71 ++++++++++++------ 6 files changed, 181 insertions(+), 43 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 738e23464..1849c3dca 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -108,6 +108,8 @@ class ItemCapabilities(object): ``CanAutoStartForLive`` The capability to ignore the do not play if display blank flag. + ``IsOptical`` + .Determines is the service_item is based on an optical device """ CanPreview = 1 CanEdit = 2 @@ -125,6 +127,7 @@ class ItemCapabilities(object): CanWordSplit = 14 HasBackgroundAudio = 15 CanAutoStartForLive = 16 + IsOptical = 17 class ServiceItem(object): @@ -573,7 +576,7 @@ class ServiceItem(object): frame = self._raw_frames[row] except IndexError: return '' - if self.is_image(): + if self.is_image() or self.is_capable(ItemCapabilities.IsOptical): path_from = frame['path'] else: path_from = os.path.join(frame['path'], frame['title']) diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 31a27b620..4c6ede2e8 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -72,6 +72,9 @@ class MediaInfo(object): length = 0 start_time = 0 end_time = 0 + title_track = 0 + audio_track = 0 + subtitle_track = 0 media_type = MediaType() diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 50db35602..a886ac1b3 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -36,7 +36,7 @@ import datetime from PyQt4 import QtCore, QtGui from openlp.core.common import Registry, Settings, UiStrings, translate -from openlp.core.lib import OpenLPToolbar +from openlp.core.lib import OpenLPToolbar, ItemCapabilities from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players from openlp.core.ui.media.mediaplayer import MediaPlayer @@ -387,7 +387,15 @@ class MediaController(object): controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path()) display = self._define_display(controller) if controller.is_live: - is_valid = self._check_file_type(controller, display, service_item) + # if this is an optical device use special handling + if service_item.is_capable(ItemCapabilities.IsOptical): + log.debug('video is optical and live') + path = service_item.get_frame_path() + (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(path) + is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) + else : + log.debug('video is not optical and live') + is_valid = self._check_file_type(controller, display, service_item) display.override['theme'] = '' display.override['video'] = True if controller.media_info.is_background: @@ -398,12 +406,20 @@ class MediaController(object): controller.media_info.start_time = service_item.start_time controller.media_info.end_time = service_item.end_time elif controller.preview_display: - is_valid = self._check_file_type(controller, display, service_item) + if service_item.is_capable(ItemCapabilities.IsOptical): + log.debug('video is optical and preview') + path = service_item.get_frame_path() + (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(path) + is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) + else : + log.debug('video is not optical and preview') + is_valid = self._check_file_type(controller, display, service_item) if not is_valid: # Media could not be loaded correctly critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), translate('MediaPlugin.MediaItem', 'Unsupported File')) return False + log.debug('video mediatype: ' +str(controller.media_info.media_type)) # dont care about actual theme, set a black background if controller.is_live and not controller.media_info.is_background: display.frame.evaluateJavaScript('show_video( "setBackBoard", null, null, null,"visible");') @@ -456,6 +472,44 @@ class MediaController(object): log.debug('use %s controller' % self.current_media_players[controller.controller_type]) return True + def media_setup_optical(self, filename, title, audio_track, subtitle_track, start, end, display, controller): + log.debug('media_setup_optical') + if controller is None: + controller = self.display_controllers[DisplayControllerType.Plugin] + # stop running videos + self.media_reset(controller) + # Setup media info + controller.media_info = MediaInfo() + #controller.media_info.volume = 0 + controller.media_info.file_info = QtCore.QFileInfo(filename) + controller.media_info.media_type = MediaType.DVD + controller.media_info.start_time = start/1000 + controller.media_info.end_time = end/1000 + controller.media_info.length = (end - start)/1000 + controller.media_info.title_track = title + controller.media_info.audio_track = audio_track + controller.media_info.subtitle_track = subtitle_track + # When called from mediaitem display is None + if display is None: + display = controller.preview_display + # Find vlc player + used_players = get_media_players()[0] + vlc_player = None + for title in used_players: + player = self.media_players[title] + if player.name == 'vlc': + vlc_player = player + if vlc_player is None: + critical_error_message_box(translate('MediaPlugin.MediaItem', 'VLC player required'), + translate('MediaPlugin.MediaItem', 'VLC player required for playback of optical devices')) + return False + vlc_player.load(display) + self.resize(display, vlc_player) + self.current_media_players[controller.controller_type] = vlc_player + controller.media_info.media_type = MediaType.DVD + return True + + def _check_file_type(self, controller, display, service_item): """ Select the correct media Player type from the prioritized Player list @@ -758,3 +812,17 @@ class MediaController(object): return self._live_controller live_controller = property(_get_live_controller) + + @staticmethod + def parse_optical_path(input): + # split the clip info + clip_info = input.split(sep=':') + title = int(clip_info[1]) + audio_track = int(clip_info[2]) + subtitle_track = int(clip_info[3]) + start = float(clip_info[4]) + end = float(clip_info[5]) + filename = clip_info[6] + if len(clip_info) > 7: + filename += clip_info[7] + return filename, title, audio_track, subtitle_track, start, end diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index bf6374473..4e1654c31 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -39,7 +39,7 @@ from PyQt4 import QtGui from openlp.core.common import Settings from openlp.core.lib import translate -from openlp.core.ui.media import MediaState +from openlp.core.ui.media import MediaState, MediaType from openlp.core.ui.media.mediaplayer import MediaPlayer log = logging.getLogger(__name__) @@ -205,14 +205,35 @@ class VlcPlayer(MediaPlayer): """ controller = display.controller start_time = 0 - if self.state != MediaState.Paused and controller.media_info.start_time > 0: - start_time = controller.media_info.start_time + log.debug('vlc play') display.vlcMediaPlayer.play() if not self.media_state_wait(display, vlc.State.Playing): return False + if self.state != MediaState.Paused and controller.media_info.start_time > 0: + log.debug('vlc play, starttime set') + start_time = controller.media_info.start_time + log.debug('mediatype: ' +str(controller.media_info.media_type)) + # Set tracks for the optical device + if controller.media_info.media_type == MediaType.DVD: + log.debug('vlc play, playing started') + if controller.media_info.title_track > 0: + log.debug('vlc play, title_track set: ' + str(controller.media_info.title_track)) + display.vlcMediaPlayer.set_title(controller.media_info.title_track) + display.vlcMediaPlayer.play() + if not self.media_state_wait(display, vlc.State.Playing): + return False + if controller.media_info.audio_track > 0: + display.vlcMediaPlayer.audio_set_track(controller.media_info.audio_track) + log.debug('vlc play, audio_track set: ' + str(controller.media_info.audio_track)) + if controller.media_info.subtitle_track > 0: + display.vlcMediaPlayer.video_set_spu(controller.media_info.subtitle_track) + log.debug('vlc play, subtitle_track set: ' + str(controller.media_info.subtitle_track)) + if controller.media_info.start_time > 0: + log.debug('vlc play, starttime set: ' + str(controller.media_info.start_time)) + start_time = controller.media_info.start_time self.volume(display, controller.media_info.volume) if start_time > 0: - self.seek(display, controller.media_info.start_time * 1000) + self.seek(display, int(start_time * 1000)) controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000) controller.seek_slider.setMaximum(controller.media_info.length * 1000) self.state = MediaState.Playing @@ -248,6 +269,7 @@ class VlcPlayer(MediaPlayer): Go to a particular position """ if display.vlcMediaPlayer.is_seekable(): + log.debug('vlc seek to: ' + str(seek_value)) display.vlcMediaPlayer.set_time(seek_value) def reset(self, display): diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 688d879d4..115e6690b 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -31,6 +31,8 @@ import os import sys import logging import time +from datetime import datetime + from PyQt4 import QtCore, QtGui @@ -132,12 +134,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_load_media(False) return self.vlc_media_player.audio_set_mute(True) - while self.vlc_media_player.get_time() == 0: - if self.vlc_media_player.get_state() == vlc.State.Error: - log.debug('player in error state') - self.toggle_disable_load_media(False) - return - time.sleep(0.1) + #while self.vlc_media_player.get_time() == 0: + # if self.vlc_media_player.get_state() == vlc.State.Error: + # log.debug('player in error state') + # self.toggle_disable_load_media(False) + # return + # time.sleep(0.1) + if not self.media_state_wait(vlc.State.Playing): + return self.vlc_media_player.pause() self.vlc_media_player.set_time(0) # Get titles, insert in combobox @@ -223,11 +227,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.set_time(0) self.vlc_media_player.play() self.vlc_media_player.audio_set_mute(True) - while self.vlc_media_player.get_time() == 0: - if self.vlc_media_player.get_state() == vlc.State.Error: - log.debug('player in error state') - return - time.sleep(0.1) + #while self.vlc_media_player.get_time() == 0: + # if self.vlc_media_player.get_state() == vlc.State.Error: + # log.debug('player in error state') + # return + # time.sleep(0.1) + if not self.media_state_wait(vlc.State.Playing): + return # pause self.vlc_media_player.pause() self.vlc_media_player.set_time(0) @@ -358,3 +364,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): path = self.media_path_combobox.currentText() optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + path self.media_item.add_optical_clip(optical) + + def media_state_wait(self, media_state): + """ + Wait for the video to change its state + Wait no longer than 15 seconds. (loading an iso file needs a long time) + """ + start = datetime.now() + while not media_state == self.vlc_media.get_state(): + if self.vlc_media.get_state() == vlc.State.Error: + return False + if (datetime.now() - start).seconds > 15: + return False + return True diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 33b983dad..80e96f08b 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -33,7 +33,7 @@ import os from PyQt4 import QtCore, QtGui from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate -from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, ServiceItem, ServiceItemContext, \ +from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, ServiceItem, ServiceItemContext, \ build_icon, check_item_selected from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box from openlp.core.ui import DisplayController, Display, DisplayControllerType @@ -43,7 +43,6 @@ from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorFo from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE - log = logging.getLogger(__name__) @@ -193,22 +192,45 @@ class MediaMediaItem(MediaManagerItem): if item is None: return False filename = item.data(QtCore.Qt.UserRole) - if not os.path.exists(filename): - if not remote: - # File is no longer present - critical_error_message_box( - translate('MediaPlugin.MediaItem', 'Missing Media File'), - translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) - return False - (path, name) = os.path.split(filename) - service_item.title = name - service_item.processor = self.display_type_combo_box.currentText() - service_item.add_from_command(path, name, CLAPPERBOARD) - # Only get start and end times if going to a service - if context == ServiceItemContext.Service: - # Start media and obtain the length - if not self.media_controller.media_length(service_item): + log.debug('generate_slide_data, filename: ' + filename) + if filename.startswith('optical:'): + (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(filename) + log.debug('generate_slide_data, optical name: ' + name) + if not os.path.exists(name): + if not remote: + # Optical disc is no longer present + critical_error_message_box( + translate('MediaPlugin.MediaItem', 'Missing Media File'), + translate('MediaPlugin.MediaItem', 'The optical disc %s is no longer available.') % name) return False + service_item.title = name + service_item.processor = self.display_type_combo_box.currentText() + service_item.add_from_command(filename, name, OPTICAL_ICON) + # Only set start and end times if going to a service + #if context == ServiceItemContext.Service: + # Set the length + self.media_controller.media_setup_optical(name, title, audio_track, subtitle_track, start, end, None, None) + service_item.set_media_length((end - start)/1000) + service_item.start_time = start/1000 + service_item.end_time = end/1000 + service_item.add_capability(ItemCapabilities.IsOptical) + else: + if not os.path.exists(filename): + if not remote: + # File is no longer present + critical_error_message_box( + translate('MediaPlugin.MediaItem', 'Missing Media File'), + translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) + return False + (path, name) = os.path.split(filename) + service_item.title = name + service_item.processor = self.display_type_combo_box.currentText() + service_item.add_from_command(path, name, CLAPPERBOARD) + # Only get start and end times if going to a service + if context == ServiceItemContext.Service: + # Start media and obtain the length + if not self.media_controller.media_length(service_item): + return False service_item.add_capability(ItemCapabilities.CanAutoStartForLive) service_item.add_capability(ItemCapabilities.RequiresMedia) if Settings().value(self.settings_section + '/media auto start') == QtCore.Qt.Checked: @@ -329,7 +351,14 @@ class MediaMediaItem(MediaManagerItem): log.debug('in on_load_optical') self.media_clip_selector_form.exec_() - def parse_optical_path(self, input): + def add_optical_clip(self, optical): + full_list = self.get_file_list() + full_list.append(optical) + self.load_list([optical]) + Settings().setValue(self.settings_section + '/media files', self.get_file_list()) + + @staticmethod + def parse_optical_path(input): # split the clip info clip_info = input.split(sep=':') title = int(clip_info[1]) @@ -341,9 +370,3 @@ class MediaMediaItem(MediaManagerItem): if len(clip_info) > 7: filename += clip_info[7] return filename, title, audio_track, subtitle_track, start, end - - def add_optical_clip(self, optical): - full_list = self.get_file_list() - full_list.append(optical) - self.load_list([optical]) - Settings().setValue(self.settings_section + '/media files', self.get_file_list()) From 3988aacfbd7d12c50d20ea42b8685c9c80986719 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 8 Mar 2014 21:14:04 +0000 Subject: [PATCH 04/44] Made it possible to save and load optical clip to servicefile. Also some pep8 and general cleanup. --- openlp/core/lib/serviceitem.py | 29 +++-- openlp/core/ui/media/__init__.py | 25 +++- openlp/core/ui/media/mediacontroller.py | 19 +-- .../media/forms/mediaclipselectorform.py | 62 +++++++--- openlp/plugins/media/lib/mediaitem.py | 114 +++++++++++++----- 5 files changed, 167 insertions(+), 82 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index cb03d981f..694bb139f 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -435,7 +435,10 @@ class ServiceItem(object): for text_image in serviceitem['serviceitem']['data']: if not self.title: self.title = text_image['title'] - if path: + if self.is_capable(ItemCapabilities.IsOptical): + self.has_original_files = False + self.add_from_command(text_image['path'], text_image['title'], text_image['image']) + elif path: self.has_original_files = False self.add_from_command(path, text_image['title'], text_image['image']) else: @@ -446,7 +449,7 @@ class ServiceItem(object): """ Returns the title of the service item. """ - if self.is_text(): + if self.is_text() or self.is_capable(ItemCapabilities.IsOptical): return self.title else: if len(self._raw_frames) > 1: @@ -516,7 +519,8 @@ class ServiceItem(object): """ Confirms if the ServiceItem uses a file """ - return self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command + return self.service_item_type == ServiceItemType.Image or \ + (self.service_item_type == ServiceItemType.Command and not self.is_capable(ItemCapabilities.IsOptical)) def is_text(self): """ @@ -646,15 +650,20 @@ class ServiceItem(object): self.is_valid = False break elif self.is_command(): - file_name = os.path.join(frame['path'], frame['title']) - if not os.path.exists(file_name): - self.is_valid = False - break - if suffix_list and not self.is_text(): - file_suffix = frame['title'].split('.')[-1] - if file_suffix.lower() not in suffix_list: + if self.is_capable(ItemCapabilities.IsOptical): + if not os.path.exists(frame['title']): self.is_valid = False break + else: + file_name = os.path.join(frame['path'], frame['title']) + if not os.path.exists(file_name): + self.is_valid = False + break + if suffix_list and not self.is_text(): + file_suffix = frame['title'].split('.')[-1] + if file_suffix.lower() not in suffix_list: + self.is_valid = False + break def _get_renderer(self): """ diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index aa2819450..8223ed694 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -102,11 +102,8 @@ def set_media_players(players_list, overridden_player='auto'): This method saves the configured media players and overridden player to the settings - ``players_list`` - A list with all active media players. - - ``overridden_player`` - Here an special media player is chosen for all media actions. + :param players_list: A list with all active media players. + :param overridden_player: Here an special media player is chosen for all media actions. """ log.debug('set_media_players') players = ','.join(players_list) @@ -114,6 +111,24 @@ def set_media_players(players_list, overridden_player='auto'): players = players.replace(overridden_player, '[%s]' % overridden_player) Settings().setValue('media/players', players) +def parse_optical_path(input): + """ + Split the optical path info. + + :param input: The string to parse + :return: The elements extracted from the string: filename, title, audio_track, subtitle_track, start, end + """ + clip_info = input.split(sep=':') + title = int(clip_info[1]) + audio_track = int(clip_info[2]) + subtitle_track = int(clip_info[3]) + start = float(clip_info[4]) + end = float(clip_info[5]) + filename = clip_info[6] + if len(clip_info) > 7: + filename += clip_info[7] + return filename, title, audio_track, subtitle_track, start, end + from .mediacontroller import MediaController from .playertab import PlayerTab diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 26e153503..8f782ce24 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -38,7 +38,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.common import Registry, RegistryMixin, Settings, UiStrings, translate from openlp.core.lib import OpenLPToolbar, ItemCapabilities from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players +from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players, parse_optical_path from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.common import AppLocation from openlp.core.ui import DisplayControllerType @@ -397,7 +397,7 @@ class MediaController(object): if service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and live') path = service_item.get_frame_path() - (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(path) + (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(path) is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) else : log.debug('video is not optical and live') @@ -415,7 +415,7 @@ class MediaController(object): if service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and preview') path = service_item.get_frame_path() - (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(path) + (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(path) is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) else : log.debug('video is not optical and preview') @@ -819,16 +819,3 @@ class MediaController(object): live_controller = property(_get_live_controller) - @staticmethod - def parse_optical_path(input): - # split the clip info - clip_info = input.split(sep=':') - title = int(clip_info[1]) - audio_track = int(clip_info[2]) - subtitle_track = int(clip_info[3]) - start = float(clip_info[4]) - end = float(clip_info[5]) - filename = clip_info[6] - if len(clip_info) > 7: - filename += clip_info[7] - return filename, title, audio_track, subtitle_track, start, end diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 115e6690b..34a228136 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -67,7 +67,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ Exit Dialog and do not save """ - log.debug ('MediaClipSelectorForm.reject') + log.debug('MediaClipSelectorForm.reject') self.vlc_media_player.stop() QtGui.QDialog.reject(self) @@ -110,6 +110,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_load_disc_pushbutton_clicked(self, clicked): """ Load the media when the load-button has been clicked + + :param clicked: Given from signal, not used. """ self.disable_all() path = self.media_path_combobox.currentText() @@ -134,12 +136,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_load_media(False) return self.vlc_media_player.audio_set_mute(True) - #while self.vlc_media_player.get_time() == 0: - # if self.vlc_media_player.get_state() == vlc.State.Error: - # log.debug('player in error state') - # self.toggle_disable_load_media(False) - # return - # time.sleep(0.1) if not self.media_state_wait(vlc.State.Playing): return self.vlc_media_player.pause() @@ -163,6 +159,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_pause_pushbutton_clicked(self, clicked): """ Pause the playback + + :param clicked: Given from signal, not used. """ self.vlc_media_player.pause() @@ -170,6 +168,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_play_pushbutton_clicked(self, clicked): """ Start the playback + + :param clicked: Given from signal, not used. """ self.vlc_media_player.play() @@ -177,26 +177,40 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_set_start_pushbutton_clicked(self, clicked): """ Copy the current player position to start_timeedit + + :param clicked: Given from signal, not used. """ vlc_ms_pos = self.vlc_media_player.get_time() time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) self.start_timeedit.setTime(new_pos_time) + # If start time is after end time, update end time. + end_time = self.end_timeedit.time() + if end_time < new_pos_time: + self.end_timeedit.setTime(new_pos_time) @QtCore.pyqtSlot(bool) def on_set_end_pushbutton_clicked(self, clicked): """ Copy the current player position to end_timeedit + + :param clicked: Given from signal, not used. """ vlc_ms_pos = self.vlc_media_player.get_time() time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) self.end_timeedit.setTime(new_pos_time) + # If start time is after end time, update end time. + start_time = self.start_timeedit.time() + if start_time > new_pos_time: + self.start_timeedit.setTime(new_pos_time) @QtCore.pyqtSlot(bool) def on_jump_end_pushbutton_clicked(self, clicked): """ Set the player position to the position stored in end_timeedit + + :param clicked: Given from signal, not used. """ end_time = self.end_timeedit.time() end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ @@ -209,6 +223,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_jump_start_pushbutton_clicked(self, clicked): """ Set the player position to the position stored in start_timeedit + + :param clicked: Given from signal, not used. """ start_time = self.start_timeedit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ @@ -221,17 +237,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_title_combo_box_currentIndexChanged(self, index): """ When a new title is chosen, it is loaded by VLC and info about audio and subtitle tracks is reloaded + + :param index: The index of the newly chosen title track. """ log.debug('in on_title_combo_box_changed, index: ', str(index)) self.vlc_media_player.set_title(index) self.vlc_media_player.set_time(0) self.vlc_media_player.play() self.vlc_media_player.audio_set_mute(True) - #while self.vlc_media_player.get_time() == 0: - # if self.vlc_media_player.get_state() == vlc.State.Error: - # log.debug('player in error state') - # return - # time.sleep(0.1) if not self.media_state_wait(vlc.State.Playing): return # pause @@ -241,7 +254,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): audio_tracks = self.vlc_media_player.audio_get_track_description() self.audio_tracks_combobox.clear() for audio_track in audio_tracks: - self.audio_tracks_combobox.addItem(audio_track[1].decode(),audio_track[0]) + self.audio_tracks_combobox.addItem(audio_track[1].decode(), audio_track[0]) # Enable audio track combobox if anything is in it if len(audio_tracks) > 0: self.audio_tracks_combobox.setDisabled(False) @@ -270,6 +283,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_audio_tracks_combobox_currentIndexChanged(self, index): """ When a new audio track is chosen update audio track bing played by VLC + + :param index: The index of the newly chosen audio track. """ audio_track = self.audio_tracks_combobox.itemData(index) log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: ', str(index), ' audio_track: ', audio_track) @@ -280,15 +295,18 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def on_subtitle_tracks_combobox_currentIndexChanged(self, index): """ When a new subtitle track is chosen update subtitle track bing played by VLC + + :param index: The index of the newly chosen subtitle. """ subtitle_track = self.subtitle_tracks_combobox.itemData(index) - log.debug('in on_subtitle_tracks_combobox_currentIndexChanged, index: ', str(index), ' subtitle_track: ', subtitle_track) if subtitle_track: self.vlc_media_player.video_set_spu(int(subtitle_track)) def on_position_horizontalslider_sliderMoved(self, position): """ Set player position according to new slider position. + + :param position: Position to seek to. """ self.vlc_media_player.set_time(position) @@ -318,16 +336,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ Enable/disable load media combobox and button. - @param action: If True elements are disabled, if False they are enabled. + :param action: If True elements are disabled, if False they are enabled. """ self.media_path_combobox.setDisabled(action) self.load_disc_pushbutton.setDisabled(action) def toggle_disable_player(self, action): """ - Enable/disable player elementa. + Enable/disable player elements. - @param action: If True elements are disabled, if False they are enabled. + :param action: If True elements are disabled, if False they are enabled. """ self.play_pushbutton.setDisabled(action) self.pause_pushbutton.setDisabled(action) @@ -343,9 +361,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.save_pushbutton.setDisabled(action) @QtCore.pyqtSlot(bool) - def on_save_pushbutton_clicked(self, checked): + def on_save_pushbutton_clicked(self, clicked): """ Saves the current media and trackinfo as a clip to the mediamanager + + :param clicked: Given from signal, not used. """ log.debug('in on_save_pushbutton_clicked') start_time = self.start_timeedit.time() @@ -362,13 +382,17 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) path = self.media_path_combobox.currentText() - optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + path + optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str( + start_time_ms) + ':' + str(end_time_ms) + ':' + path self.media_item.add_optical_clip(optical) def media_state_wait(self, media_state): """ Wait for the video to change its state Wait no longer than 15 seconds. (loading an iso file needs a long time) + + :param media_state: VLC media state to wait for. + :return: True if state was reached within 15 seconds, False if not or error occurred. """ start = datetime.now() while not media_state == self.vlc_media.get_state(): diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 7f06a392f..86d6d38ac 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -29,6 +29,7 @@ import logging import os +from datetime import time from PyQt4 import QtCore, QtGui @@ -37,7 +38,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, Servi build_icon, check_item_selected from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box from openlp.core.ui import DisplayController, Display, DisplayControllerType -from openlp.core.ui.media import get_media_players, set_media_players +from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path from openlp.core.utils import get_locale_key from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE @@ -47,9 +48,10 @@ log = logging.getLogger(__name__) CLAPPERBOARD = ':/media/slidecontroller_multimedia.png' +OPTICAL = ':/media/media_optical.png' VIDEO_ICON = build_icon(':/media/media_video.png') AUDIO_ICON = build_icon(':/media/media_audio.png') -OPTICAL_ICON = build_icon(':/media/media_optical.png') +OPTICAL_ICON = build_icon(OPTICAL) ERROR_ICON = build_icon(':/general/general_delete.png') @@ -89,6 +91,10 @@ class MediaMediaItem(MediaManagerItem): self.list_view.activateDnD() def retranslateUi(self): + """ + This method is called automatically to provide OpenLP with the opportunity to translate the ``MediaManagerItem`` + to another language. + """ self.on_new_prompt = translate('MediaPlugin.MediaItem', 'Select Media') self.replace_action.setText(UiStrings().ReplaceBG) self.replace_action.setToolTip(UiStrings().ReplaceLiveBG) @@ -108,16 +114,25 @@ class MediaMediaItem(MediaManagerItem): self.has_edit_icon = False def add_list_view_to_toolbar(self): + """ + Creates the main widget for listing items. + """ MediaManagerItem.add_list_view_to_toolbar(self) self.list_view.addAction(self.replace_action) def add_start_header_bar(self): + """ + Adds buttons to the start of the header bar. + """ self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text='Load optical disc', tooltip='Load optical disc', triggers=self.on_load_optical) if not VLC_AVAILABLE: self.load_optical.setDisabled(True) 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=':/slides/slide_blank.png', triggers=self.on_replace_click) @@ -139,6 +154,11 @@ class MediaMediaItem(MediaManagerItem): self.display_type_combo_box.currentIndexChanged.connect(self.override_player_changed) def override_player_changed(self, index): + """ + Change to the selected override media player + + :param index: Index of the new selected player. + """ player = get_media_players()[0] if index == 0: set_media_players(player) @@ -163,7 +183,7 @@ class MediaMediaItem(MediaManagerItem): Called to replace Live background with the media selected. """ if check_item_selected(self.list_view, - translate('MediaPlugin.MediaItem', + translate('MediaPlugin.MediaItem', 'You must select a media file to replace the background with.')): item = self.list_view.currentItem() filename = item.data(QtCore.Qt.UserRole) @@ -172,12 +192,12 @@ class MediaMediaItem(MediaManagerItem): service_item.title = 'webkit' service_item.processor = 'webkit' (path, name) = os.path.split(filename) - service_item.add_from_command(path, name,CLAPPERBOARD) + service_item.add_from_command(path, name, CLAPPERBOARD) if self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True): self.reset_action.setVisible(True) else: critical_error_message_box(UiStrings().LiveBGError, - translate('MediaPlugin.MediaItem', + translate('MediaPlugin.MediaItem', 'There was no display item to amend.')) else: critical_error_message_box(UiStrings().LiveBGError, @@ -195,10 +215,9 @@ class MediaMediaItem(MediaManagerItem): if item is None: return False filename = item.data(QtCore.Qt.UserRole) - log.debug('generate_slide_data, filename: ' + filename) + # Special handling if the filename is a optical clip if filename.startswith('optical:'): - (name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(filename) - log.debug('generate_slide_data, optical name: ' + name) + (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(filename) if not os.path.exists(name): if not remote: # Optical disc is no longer present @@ -206,16 +225,16 @@ class MediaMediaItem(MediaManagerItem): translate('MediaPlugin.MediaItem', 'Missing Media File'), translate('MediaPlugin.MediaItem', 'The optical disc %s is no longer available.') % name) return False - service_item.title = name service_item.processor = self.display_type_combo_box.currentText() - service_item.add_from_command(filename, name, OPTICAL_ICON) + service_item.add_from_command(filename, name, CLAPPERBOARD) + service_item.title = name + '@' + self.format_milliseconds(start) + '-' + self.format_milliseconds(end) # Only set start and end times if going to a service #if context == ServiceItemContext.Service: # Set the length self.media_controller.media_setup_optical(name, title, audio_track, subtitle_track, start, end, None, None) - service_item.set_media_length((end - start)/1000) - service_item.start_time = start/1000 - service_item.end_time = end/1000 + service_item.set_media_length((end - start) / 1000) + service_item.start_time = start / 1000 + service_item.end_time = end / 1000 service_item.add_capability(ItemCapabilities.IsOptical) else: if not os.path.exists(filename): @@ -243,12 +262,15 @@ class MediaMediaItem(MediaManagerItem): return True def initialise(self): + """ + Initialize media item. + """ self.list_view.clear() self.list_view.setIconSize(QtCore.QSize(88, 50)) self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails') check_directory_exists(self.service_path) self.load_list(Settings().value(self.settings_section + '/media files')) - self.populate_display_types() + self.rebuild_players() self.media_clip_selector_form = MediaClipSelectorForm(self, self.main_window, None) def rebuild_players(self): @@ -261,6 +283,9 @@ class MediaMediaItem(MediaManagerItem): ' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles) def display_setup(self): + """ + Setup media controller display. + """ self.media_controller.setup_display(self.display_controller.preview_display, False) def populate_display_types(self): @@ -300,24 +325,32 @@ class MediaMediaItem(MediaManagerItem): Settings().setValue(self.settings_section + '/media files', self.get_file_list()) def load_list(self, media, target_group=None): - # Sort the media by its filename considering language specific characters. + """ + Sort the media by its filename considering language specific characters. + + :param media: List if media to sort and list. + :param target_group: Not used in media. + """ media.sort(key=lambda file_name: get_locale_key(os.path.split(str(file_name))[1])) for track in media: track_info = QtCore.QFileInfo(track) if track.startswith('optical:'): - (file_name, title, audio_track, subtitle_track, start, end) = self.parse_optical_path(track) - optical = file_name + '@' + str(title) + ':' + str(start) + '-' + str(end) + # Handle optical based item + (file_name, title, audio_track, subtitle_track, start, end) = parse_optical_path(track) + optical = file_name + '@' + self.format_milliseconds(start) + '-' + self.format_milliseconds(end) item_name = QtGui.QListWidgetItem(optical) - item_name.setIcon(build_icon(OPTICAL_ICON)) + item_name.setIcon(OPTICAL_ICON) item_name.setData(QtCore.Qt.UserRole, track) item_name.setToolTip(optical) elif not os.path.exists(track): + # File doesn't exist, mark as error. file_name = os.path.split(str(track))[1] item_name = QtGui.QListWidgetItem(file_name) item_name.setIcon(ERROR_ICON) item_name.setData(QtCore.Qt.UserRole, track) item_name.setToolTip(track) elif track_info.isFile(): + # Normal media file handling. file_name = os.path.split(str(track))[1] item_name = QtGui.QListWidgetItem(file_name) if '*.%s' % (file_name.split('.')[-1].lower()) in self.media_controller.audio_extensions_list: @@ -329,6 +362,12 @@ class MediaMediaItem(MediaManagerItem): self.list_view.addItem(item_name) def get_list(self, type=MediaType.Audio): + """ + Get the list of media, optional select media type. + + :param type: Type to get, defaults to audio. + :return: The media list + """ media = Settings().value(self.settings_section + '/media files') media.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1])) extension = [] @@ -341,6 +380,13 @@ class MediaMediaItem(MediaManagerItem): return media def search(self, string, show_error): + """ + Performs a search for items containing ``string`` + + :param string: String to be displayed + :param show_error: Should the error be shown (True) + :return: The search result. + """ files = Settings().value(self.settings_section + '/media files') results = [] string = string.lower() @@ -351,25 +397,29 @@ class MediaMediaItem(MediaManagerItem): return results def on_load_optical(self): - log.debug('in on_load_optical') + """ + When the load optical button is clicked, open the clip selector window. + """ self.media_clip_selector_form.exec_() def add_optical_clip(self, optical): + """ + Add a optical based clip to the mediamanager, called from media_clip_selector_form. + + :param optical: The clip to add. + """ full_list = self.get_file_list() full_list.append(optical) self.load_list([optical]) Settings().setValue(self.settings_section + '/media files', self.get_file_list()) - @staticmethod - def parse_optical_path(input): - # split the clip info - clip_info = input.split(sep=':') - title = int(clip_info[1]) - audio_track = int(clip_info[2]) - subtitle_track = int(clip_info[3]) - start = float(clip_info[4]) - end = float(clip_info[5]) - filename = clip_info[6] - if len(clip_info) > 7: - filename += clip_info[7] - return filename, title, audio_track, subtitle_track, start, end + def format_milliseconds(self, milliseconds): + """ + Format milliseconds into a human readable time string. + :param milliseconds: Milliseconds to format + :return: Time string in format: hh.mm.ss,ttt + """ + seconds, millis = divmod(milliseconds, 1000) + minutes, seconds = divmod(millis, 60) + hours, minutes = divmod(minutes, 60) + return "%02d:%02d:%02d,%03d" % (hours, minutes, seconds, millis) From 51ea57f35e8053fe69f8e0f557f4254e2cc8351f Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 17 Mar 2014 21:59:58 +0100 Subject: [PATCH 05/44] Added a test for loading serviceitem with optical media item. --- .../openlp_core_lib/test_serviceitem.py | 21 +++++++++++++++++++ tests/resources/serviceitem-dvd.osj | 1 + 2 files changed, 22 insertions(+) create mode 100644 tests/resources/serviceitem-dvd.osj diff --git a/tests/functional/openlp_core_lib/test_serviceitem.py b/tests/functional/openlp_core_lib/test_serviceitem.py index d75e94040..4fd6f6b83 100644 --- a/tests/functional/openlp_core_lib/test_serviceitem.py +++ b/tests/functional/openlp_core_lib/test_serviceitem.py @@ -206,3 +206,24 @@ class TestServiceItem(TestCase): 'This service item should be able to be run in a can be made to Loop') self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend), 'This service item should be able to have new items added to it') + + def service_item_load_optical_media_from_service_test(self): + """ + Test the Service Item - load an optical media item + """ + # GIVEN: A new service item and a mocked add icon function + service_item = ServiceItem(None) + service_item.add_icon = MagicMock() + + # WHEN: We load a serviceitem with optical media + line = convert_file_service_item(TEST_PATH, 'serviceitem-dvd.osj') + with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists: + mocked_exists.return_value = True + service_item.set_from_service(line) + + # THEN: We should get back a valid service item with optical media info + self.assertTrue(service_item.is_valid, 'The service item should be valid') + self.assertTrue(service_item.is_capable(ItemCapabilities.IsOptical), 'The item should be Optical') + self.assertEqual(service_item.start_time, 654.375, 'Start time should be 654.375') + self.assertEqual(service_item.end_time, 672.069, 'End time should be 672.069') + self.assertEqual(service_item.media_length, 17.694, 'Media length should be 17.694') diff --git a/tests/resources/serviceitem-dvd.osj b/tests/resources/serviceitem-dvd.osj new file mode 100644 index 000000000..d3d224bff --- /dev/null +++ b/tests/resources/serviceitem-dvd.osj @@ -0,0 +1 @@ +[{"serviceitem": {"header": {"auto_play_slides_once": false, "data": "", "processor": "Automatic", "theme": -1, "theme_overwritten": false, "end_time": 672.069, "start_time": 654.375, "capabilities": [12, 17, 16, 4], "media_length": 17.694, "audit": "", "xml_version": null, "title": "/dev/sr0@00:06:15,375-00:01:09,069", "auto_play_slides_loop": false, "notes": "", "icon": ":/plugins/plugin_media.png", "type": 3, "background_audio": [], "plugin": "media", "from_plugin": false, "search": "", "will_auto_start": false, "name": "media", "footer": [], "timed_slide_interval": 0}, "data": [{"image": ":/media/slidecontroller_multimedia.png", "path": "optical:1:5:3:654375:672069:/dev/sr0", "title": "/dev/sr0"}]}}] From 3608ad4fcdddb8842034e31828af510d66dce3b1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 20 Mar 2014 22:52:53 +0100 Subject: [PATCH 06/44] Added first tests for mediaclipselectorform.py --- openlp/plugins/media/forms/__init__.py | 28 +++++ .../media/forms/mediaclipselectorform.py | 9 +- .../openlp_plugins/media/__init__.py | 0 .../media/forms/test_mediaclipselectorform.py | 102 ++++++++++++++++++ 4 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 openlp/plugins/media/forms/__init__.py create mode 100644 tests/interfaces/openlp_plugins/media/__init__.py create mode 100644 tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py diff --git a/openlp/plugins/media/forms/__init__.py b/openlp/plugins/media/forms/__init__.py new file mode 100644 index 000000000..6b241e7fc --- /dev/null +++ b/openlp/plugins/media/forms/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 34a228136..d013cacd7 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -36,6 +36,7 @@ from datetime import datetime from PyQt4 import QtCore, QtGui +from openlp.core.common import translate from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.media.vendor import vlc @@ -117,13 +118,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): path = self.media_path_combobox.currentText() if path == '': log.debug('no given path') - critical_error_message_box('Error', 'No path was given') + critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'No path was given')) self.toggle_disable_load_media(False) return self.vlc_media = self.vlc_instance.media_new_path(path) if not self.vlc_media: log.debug('vlc media player is none') - critical_error_message_box('Error', 'An error happened during initialization of VLC player') + critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', + 'An error happened during initialization of VLC player')) self.toggle_disable_load_media(False) return # put the media in the media player @@ -132,7 +134,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # start playback to get vlc to parse the media if self.vlc_media_player.play() < 0: log.debug('vlc play returned error') - critical_error_message_box('Error', 'An error happen when starting VLC player') + critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', + 'An error happen when starting VLC player')) self.toggle_disable_load_media(False) return self.vlc_media_player.audio_set_mute(True) diff --git a/tests/interfaces/openlp_plugins/media/__init__.py b/tests/interfaces/openlp_plugins/media/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py new file mode 100644 index 000000000..b4dbf70cd --- /dev/null +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +Module to test the MediaClipSelectorForm. +""" +from unittest import TestCase + +from PyQt4 import QtGui, QtTest, QtCore + +from openlp.core.common import Registry +from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm +from tests.interfaces import MagicMock, patch +from tests.helpers.testmixin import TestMixin + + +class TestMediaClipSelectorForm(TestCase, TestMixin): + """ + Test the EditCustomSlideForm. + """ + def setUp(self): + """ + Create the UI + """ + Registry.create() + self.get_application() + self.main_window = QtGui.QMainWindow() + Registry().register('main_window', self.main_window) + # Mock VLC so we don't actually use it + self.vlc_patcher = patch('openlp.plugins.media.forms.mediaclipselectorform.vlc') + self.vlc_patcher.start() + # Mock the media item + self.mock_media_item = MagicMock() + # Mock media_state_wait to avoid waiting for VLC playing state + #self.mock_media_state_wait = patch('openlp.plugins.media.forms.mediaclipselectorform.media_state_wait') + #self.mock_media_state_wait.return_value = True + #self.mock_media_state_wait.start() + # create form to test + self.form = MediaClipSelectorForm(self.mock_media_item, self.main_window, None) + mock_media_state_wait = MagicMock() + mock_media_state_wait.return_value = True + self.form.media_state_wait = mock_media_state_wait + + def tearDown(self): + """ + Delete all the C++ objects at the end so that we don't have a segfault + """ + #self.mock_media_state_wait.stop() + self.vlc_patcher.stop() + del self.form + del self.main_window + + def basic_test(self): + """ + Test if the dialog is correctly set up. + """ + # GIVEN: A mocked QDialog.exec_() method + with patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec: + # WHEN: Show the dialog. + self.form.exec_() + + # THEN: The media path should be empty. + assert self.form.media_path_combobox.currentText() == '', 'There should not be any text in the media path.' + + def click_load_button_test(self): + """ + Test that the correct function is called when load is clicked + """ + # GIVEN: Mocked methods. + with patch('openlp.plugins.media.forms.mediaclipselectorform.critical_error_message_box') as \ + mocked_critical_error_message_box: + + # WHEN: The load button is clicked with no path set + QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) + + # THEN: we should get an error + mocked_critical_error_message_box.assert_called_with(message='No path was given') From 4b83741b36d3869db977d506917d2d9b356e1347 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 30 Mar 2014 20:11:39 +0200 Subject: [PATCH 07/44] Added autodetection of optical drives and some small fixes. --- .../media/forms/mediaclipselectorform.py | 80 +++++++++++++++---- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index d013cacd7..f1c25b378 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -28,7 +28,12 @@ ############################################################################### import os +if os.name == 'nt': + from ctypes import windll + import string import sys +if sys.platform.startswith('linux'): + import dbus import logging import time from datetime import datetime @@ -106,6 +111,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_position) self.timer.start(100) + self.find_optical_devices() @QtCore.pyqtSlot(bool) def on_load_disc_pushbutton_clicked(self, clicked): @@ -140,6 +146,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): return self.vlc_media_player.audio_set_mute(True) if not self.media_state_wait(vlc.State.Playing): + self.toggle_disable_load_media(False) return self.vlc_media_player.pause() self.vlc_media_player.set_time(0) @@ -217,9 +224,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ end_time = self.end_timeedit.time() end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ - end_time.minute() * 60 * 1000 + \ - end_time.second() * 1000 + \ - end_time.msec() + end_time.minute() * 60 * 1000 + \ + end_time.second() * 1000 + \ + end_time.msec() self.vlc_media_player.set_time(end_time_ms) @QtCore.pyqtSlot(bool) @@ -231,9 +238,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ start_time = self.start_timeedit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ - start_time.minute() * 60 * 1000 + \ - start_time.second() * 1000 + \ - start_time.msec() + start_time.minute() * 60 * 1000 + \ + start_time.second() * 1000 + \ + start_time.msec() self.vlc_media_player.set_time(start_time_ms) @QtCore.pyqtSlot(int) @@ -373,14 +380,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): log.debug('in on_save_pushbutton_clicked') start_time = self.start_timeedit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ - start_time.minute() * 60 * 1000 + \ - start_time.second() * 1000 + \ - start_time.msec() + start_time.minute() * 60 * 1000 + \ + start_time.second() * 1000 + \ + start_time.msec() end_time = self.end_timeedit.time() end_time_ms = end_time.hour() * 60 * 60 * 1000 + \ - end_time.minute() * 60 * 1000 + \ - end_time.second() * 1000 + \ - end_time.msec() + end_time.minute() * 60 * 1000 + \ + end_time.second() * 1000 + \ + end_time.msec() title = self.title_combo_box.itemData(self.title_combo_box.currentIndex()) audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) @@ -392,15 +399,58 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def media_state_wait(self, media_state): """ Wait for the video to change its state - Wait no longer than 15 seconds. (loading an iso file needs a long time) + Wait no longer than 15 seconds. (loading an optical disc takes some time) :param media_state: VLC media state to wait for. :return: True if state was reached within 15 seconds, False if not or error occurred. """ start = datetime.now() - while not media_state == self.vlc_media.get_state(): - if self.vlc_media.get_state() == vlc.State.Error: + while media_state != self.vlc_media_player.get_state(): + if self.vlc_media_player.get_state() == vlc.State.Error: return False if (datetime.now() - start).seconds > 15: return False return True + + def find_optical_devices(self): + """ + Attempt to autodetect optical devices on the computer, and add them to the media-dropdown + :return: + """ + # Clear list first + self.media_path_combobox.clear() + # insert empty string as first item + self.media_path_combobox.addItem('') + if os.name == 'nt': + # use win api to fine optical drives + bitmask = windll.kernel32.GetLogicalDrives() + for letter in string.uppercase: + if bitmask & 1: + try: + type = windll.kernel32.GetDriveTypeW('%s:\\' % letter) + # if type is 5, it is a cd-rom drive + if type == 5: + self.media_path_combobox.addItem('%s:\\' % letter) + except Exception as e: + log.debug("Exception while looking for optical drives: ", e) + bitmask >>= 1 + elif sys.platform.startswith('linux'): + # Get disc devices from dbus and find the ones that are optical + bus = dbus.SystemBus() + udev_manager_obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks") + udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.UDisks') + for dev in udev_manager.EnumerateDevices(): + device_obj = bus.get_object("org.freedesktop.UDisks", dev) + device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE) + if device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsOpticalDisc"): + self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device', "DeviceFile")) + elif sys.platform.startswith('darwin'): + # Look for DVD folders in devices to find optical devices + volumes = os.listdir('/Volumes') + candidates = list() + for volume in volumes: + if volume.startswith('.'): + continue + dirs = os.listdir('/Volumes/' + volume) + if 'VIDEO_TS' in dirs: + self.media_path_combobox.addItem() From 73304d7ec372f39157fccfa7a432de40613e3876 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 30 Mar 2014 21:32:41 +0200 Subject: [PATCH 08/44] Added check to see if given path exists. --- .../plugins/media/forms/mediaclipselectorform.py | 15 ++++++++++++--- .../media/forms/test_mediaclipselectorform.py | 5 ----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index f1c25b378..1472052a1 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -122,16 +122,23 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ self.disable_all() path = self.media_path_combobox.currentText() + # Check if given path is non-empty and exists before starting VLC if path == '': log.debug('no given path') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'No path was given')) self.toggle_disable_load_media(False) return + if not os.path.exists(path): + log.debug('vlc media player is none') + critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', + 'Given path does not exists')) + self.toggle_disable_load_media(False) + return self.vlc_media = self.vlc_instance.media_new_path(path) if not self.vlc_media: log.debug('vlc media player is none') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', - 'An error happened during initialization of VLC player')) + 'An error happened during initialization of VLC player')) self.toggle_disable_load_media(False) return # put the media in the media player @@ -141,11 +148,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if self.vlc_media_player.play() < 0: log.debug('vlc play returned error') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', - 'An error happen when starting VLC player')) + 'VLC player failed playing the media')) self.toggle_disable_load_media(False) return self.vlc_media_player.audio_set_mute(True) if not self.media_state_wait(vlc.State.Playing): + critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', + 'VLC player failed playing the media')) self.toggle_disable_load_media(False) return self.vlc_media_player.pause() @@ -453,4 +462,4 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): continue dirs = os.listdir('/Volumes/' + volume) if 'VIDEO_TS' in dirs: - self.media_path_combobox.addItem() + self.media_path_combobox.addItem('/Volumes/' + volume) diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index b4dbf70cd..5939a5e05 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -56,10 +56,6 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.vlc_patcher.start() # Mock the media item self.mock_media_item = MagicMock() - # Mock media_state_wait to avoid waiting for VLC playing state - #self.mock_media_state_wait = patch('openlp.plugins.media.forms.mediaclipselectorform.media_state_wait') - #self.mock_media_state_wait.return_value = True - #self.mock_media_state_wait.start() # create form to test self.form = MediaClipSelectorForm(self.mock_media_item, self.main_window, None) mock_media_state_wait = MagicMock() @@ -70,7 +66,6 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): """ Delete all the C++ objects at the end so that we don't have a segfault """ - #self.mock_media_state_wait.stop() self.vlc_patcher.stop() del self.form del self.main_window From 6e90904d91606c62bec8bab2ae0d5424dd76506c Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 1 Apr 2014 21:48:46 +0200 Subject: [PATCH 09/44] Fix for autodetection of optical devices --- openlp/plugins/media/forms/mediaclipselectorform.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 1472052a1..005f821a4 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -441,18 +441,20 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if type == 5: self.media_path_combobox.addItem('%s:\\' % letter) except Exception as e: - log.debug("Exception while looking for optical drives: ", e) + log.debug('Exception while looking for optical drives: ', e) bitmask >>= 1 elif sys.platform.startswith('linux'): # Get disc devices from dbus and find the ones that are optical bus = dbus.SystemBus() - udev_manager_obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks") + udev_manager_obj = bus.get_object('org.freedesktop.UDisks', '/org/freedesktop/UDisks') udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.UDisks') for dev in udev_manager.EnumerateDevices(): device_obj = bus.get_object("org.freedesktop.UDisks", dev) device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE) - if device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsOpticalDisc"): - self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device', "DeviceFile")) + if device_props.Get('org.freedesktop.UDisks.Device', 'DeviceIsDrive'): + drive_props = device_props.Get('org.freedesktop.UDisks.Device', 'DriveMediaCompatibility') + if any('optical' in prop for prop in drive_props): + self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device', 'DeviceFile')) elif sys.platform.startswith('darwin'): # Look for DVD folders in devices to find optical devices volumes = os.listdir('/Volumes') From 43f18ee2c9f8cfe0cb0ec99504042763363346c1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 5 Apr 2014 09:46:35 +0200 Subject: [PATCH 10/44] Added some tests. --- .../media/forms/mediaclipselectorform.py | 6 +- .../media/forms/test_mediaclipselectorform.py | 59 ++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 005f821a4..bbc525834 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -129,7 +129,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_load_media(False) return if not os.path.exists(path): - log.debug('vlc media player is none') + log.debug('Given path does not exists') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'Given path does not exists')) self.toggle_disable_load_media(False) @@ -259,7 +259,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param index: The index of the newly chosen title track. """ - log.debug('in on_title_combo_box_changed, index: ', str(index)) + log.debug('in on_title_combo_box_changed, index: %d', index) self.vlc_media_player.set_title(index) self.vlc_media_player.set_time(0) self.vlc_media_player.play() @@ -306,7 +306,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param index: The index of the newly chosen audio track. """ audio_track = self.audio_tracks_combobox.itemData(index) - log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: ', str(index), ' audio_track: ', audio_track) + log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: %d audio_track: %s' % (index, audio_track)) if audio_track and int(audio_track) > 0: self.vlc_media_player.audio_set_track(int(audio_track)) diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index 5939a5e05..fb7519057 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -84,14 +84,69 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): def click_load_button_test(self): """ - Test that the correct function is called when load is clicked + Test that the correct function is called when load is clicked, and that it behaves as expected. """ # GIVEN: Mocked methods. with patch('openlp.plugins.media.forms.mediaclipselectorform.critical_error_message_box') as \ - mocked_critical_error_message_box: + mocked_critical_error_message_box,\ + patch('openlp.plugins.media.forms.mediaclipselectorform.os.path.exists') as mocked_os_path_exists,\ + patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec: + self.form.exec_() # WHEN: The load button is clicked with no path set QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) # THEN: we should get an error mocked_critical_error_message_box.assert_called_with(message='No path was given') + + # WHEN: The load button is clicked with a non-existing path + mocked_os_path_exists.return_value = False + self.form.media_path_combobox.insertItem (0, '/non-existing/test-path.test') + self.form.media_path_combobox.setCurrentIndex(0) + QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) + + # THEN: we should get an error + assert self.form.media_path_combobox.currentText() == '/non-existing/test-path.test',\ + 'The media path should be the given one.' + mocked_critical_error_message_box.assert_called_with(message='Given path does not exists') + + # WHEN: The load button is clicked with a mocked existing path + mocked_os_path_exists.return_value = True + self.form.vlc_media_player = MagicMock() + self.form.vlc_media_player.play.return_value = -1 + self.form.media_path_combobox.insertItem (0, '/existing/test-path.test') + self.form.media_path_combobox.setCurrentIndex(0) + QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) + + # THEN: we should get an error + assert self.form.media_path_combobox.currentText() == '/existing/test-path.test',\ + 'The media path should be the given one.' + mocked_critical_error_message_box.assert_called_with(message='VLC player failed playing the media') + + def title_combobox_test(self): + """ + Test the behavior when the title combobox is updated + """ + # GIVEN: Mocked methods and some entries in the title combobox. + with patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec: + self.form.exec_() + self.form.audio_tracks_combobox.itemData = MagicMock() + self.form.subtitle_tracks_combobox.itemData = MagicMock() + self.form.audio_tracks_combobox.itemData.return_value = None + self.form.subtitle_tracks_combobox.itemData.return_value = None + self.form.title_combo_box.insertItem(0, 'Test Title 0') + self.form.title_combo_box.insertItem(1, 'Test Title 1') + + + # WHEN: There exists audio and subtitle tracks and the index is updated. + self.form.vlc_media_player.audio_get_track_description.return_value = [(-1, b'Disabled'), + (0, b'Audio Track 1')] + self.form.vlc_media_player.video_get_spu_description.return_value = [(-1, b'Disabled'), + (0, b'Subtitle Track 1')] + self.form.title_combo_box.setCurrentIndex(1) + + # THEN: The subtitle and audio track comboboxes should be updated and get signals and call itemData. + self.form.audio_tracks_combobox.itemData.assert_any_call(0) + self.form.audio_tracks_combobox.itemData.assert_any_call(1) + self.form.subtitle_tracks_combobox.itemData.assert_any_call(0) + From aefef04d97734a7d2c5c15656e1aced87c3a9031 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 7 Apr 2014 23:08:48 +0200 Subject: [PATCH 11/44] Small fixes. Added checks of start/end times. --- .../media/forms/mediaclipselectorform.py | 35 ++++++++++++++++--- openlp/plugins/media/lib/mediaitem.py | 4 +-- .../media/forms/test_mediaclipselectorform.py | 22 ++++++------ 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index bbc525834..7e912ab05 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -219,11 +219,35 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) self.end_timeedit.setTime(new_pos_time) - # If start time is after end time, update end time. + # If start time is after end time, update start time. start_time = self.start_timeedit.time() if start_time > new_pos_time: self.start_timeedit.setTime(new_pos_time) + @QtCore.pyqtSlot(QtCore.QTime) + def on_start_timeedit_timeChanged(self, new_time): + """ + Called when start_timeedit is changed manually + + :param new_time: The new time + """ + # If start time is after end time, update end time. + end_time = self.end_timeedit.time() + if end_time < new_time: + self.end_timeedit.setTime(new_time) + + @QtCore.pyqtSlot(QtCore.QTime) + def on_end_timeedit_timeChanged(self, new_time): + """ + Called when end_timeedit is changed manually + + :param new_time: The new time + """ + # If start time is after end time, update start time. + start_time = self.start_timeedit.time() + if start_time > new_time: + self.start_timeedit.setTime(new_time) + @QtCore.pyqtSlot(bool) def on_jump_end_pushbutton_clicked(self, clicked): """ @@ -288,12 +312,15 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # Enable subtitle track combobox is anything in it if len(subtitles_tracks) > 0: self.subtitle_tracks_combobox.setDisabled(False) - # First track is "deactivated", so set to next if it exists - if len(subtitles_tracks) > 1: - self.subtitle_tracks_combobox.setCurrentIndex(1) self.vlc_media_player.audio_set_mute(False) self.playback_length = self.vlc_media_player.get_length() self.position_horizontalslider.setMaximum(self.playback_length) + # setup start and end time + rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0) + time = QtCore.QTime() + playback_length_time = time.addMSecs(rounded_vlc_ms_length) + self.start_timeedit.setMaximumTime(playback_length_time) + self.end_timeedit.setMaximumTime(playback_length_time) # If a title or audio track is available the player is enabled if self.title_combo_box.count() > 0 or len(audio_tracks) > 0: self.toggle_disable_player(False) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 1b91c1554..c2af902d4 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -125,8 +125,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ Adds buttons to the start of the header bar. """ - self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text='Load optical disc', - tooltip='Load optical disc', triggers=self.on_load_optical) + self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text='Load CD/DVD', + tooltip='Load CD/DVD', triggers=self.on_load_optical) if not VLC_AVAILABLE: self.load_optical.setDisabled(True) diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index fb7519057..16670232c 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -88,9 +88,9 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): """ # GIVEN: Mocked methods. with patch('openlp.plugins.media.forms.mediaclipselectorform.critical_error_message_box') as \ - mocked_critical_error_message_box,\ - patch('openlp.plugins.media.forms.mediaclipselectorform.os.path.exists') as mocked_os_path_exists,\ - patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec: + mocked_critical_error_message_box,\ + patch('openlp.plugins.media.forms.mediaclipselectorform.os.path.exists') as mocked_os_path_exists,\ + patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec: self.form.exec_() # WHEN: The load button is clicked with no path set @@ -101,10 +101,10 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): # WHEN: The load button is clicked with a non-existing path mocked_os_path_exists.return_value = False - self.form.media_path_combobox.insertItem (0, '/non-existing/test-path.test') + self.form.media_path_combobox.insertItem(0, '/non-existing/test-path.test') self.form.media_path_combobox.setCurrentIndex(0) QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) - + # THEN: we should get an error assert self.form.media_path_combobox.currentText() == '/non-existing/test-path.test',\ 'The media path should be the given one.' @@ -114,10 +114,10 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): mocked_os_path_exists.return_value = True self.form.vlc_media_player = MagicMock() self.form.vlc_media_player.play.return_value = -1 - self.form.media_path_combobox.insertItem (0, '/existing/test-path.test') + self.form.media_path_combobox.insertItem(0, '/existing/test-path.test') self.form.media_path_combobox.setCurrentIndex(0) QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) - + # THEN: we should get an error assert self.form.media_path_combobox.currentText() == '/existing/test-path.test',\ 'The media path should be the given one.' @@ -136,17 +136,15 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.subtitle_tracks_combobox.itemData.return_value = None self.form.title_combo_box.insertItem(0, 'Test Title 0') self.form.title_combo_box.insertItem(1, 'Test Title 1') - # WHEN: There exists audio and subtitle tracks and the index is updated. - self.form.vlc_media_player.audio_get_track_description.return_value = [(-1, b'Disabled'), - (0, b'Audio Track 1')] + self.form.vlc_media_player.audio_get_track_description.return_value = [(-1, b'Disabled'), + (0, b'Audio Track 1')] self.form.vlc_media_player.video_get_spu_description.return_value = [(-1, b'Disabled'), - (0, b'Subtitle Track 1')] + (0, b'Subtitle Track 1')] self.form.title_combo_box.setCurrentIndex(1) # THEN: The subtitle and audio track comboboxes should be updated and get signals and call itemData. self.form.audio_tracks_combobox.itemData.assert_any_call(0) self.form.audio_tracks_combobox.itemData.assert_any_call(1) self.form.subtitle_tracks_combobox.itemData.assert_any_call(0) - From f16a781309f00872e20d1ec8e600f459ccb11347 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 9 Apr 2014 22:24:19 +0200 Subject: [PATCH 12/44] Changed the clipselector gui a bit. --- .../media/forms/mediaclipselectordialog.py | 251 ++++++++-------- .../media/forms/mediaclipselectorform.py | 26 +- resources/forms/mediaclipselector.ui | 280 ++++++++---------- .../media/forms/test_mediaclipselectorform.py | 3 +- 4 files changed, 274 insertions(+), 286 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index a6718fbf2..921c68a8d 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -1,3 +1,31 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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 openlp.core.common import translate @@ -23,92 +51,6 @@ class Ui_MediaClipSelector(object): self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtGui.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.close_pushbutton = QtGui.QPushButton(self.centralwidget) - self.close_pushbutton.setEnabled(True) - self.close_pushbutton.setObjectName("close_pushbutton") - self.gridLayout.addWidget(self.close_pushbutton, 10, 4, 1, 1) - self.pause_pushbutton = QtGui.QPushButton(self.centralwidget) - self.pause_pushbutton.setEnabled(True) - self.pause_pushbutton.setText("") - icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_pause.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.pause_pushbutton.setIcon(icon) - self.pause_pushbutton.setObjectName("pause_pushbutton") - self.gridLayout.addWidget(self.pause_pushbutton, 6, 1, 1, 1) - self.play_pushbutton = QtGui.QPushButton(self.centralwidget) - self.play_pushbutton.setEnabled(True) - self.play_pushbutton.setText("") - icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.play_pushbutton.setIcon(icon1) - self.play_pushbutton.setObjectName("play_pushbutton") - self.gridLayout.addWidget(self.play_pushbutton, 6, 0, 1, 1) - self.media_path_label = QtGui.QLabel(self.centralwidget) - self.media_path_label.setEnabled(True) - self.media_path_label.setObjectName("media_path_label") - self.gridLayout.addWidget(self.media_path_label, 0, 0, 1, 2) - self.preview_pushbutton = QtGui.QPushButton(self.centralwidget) - self.preview_pushbutton.setEnabled(True) - self.preview_pushbutton.setObjectName("preview_pushbutton") - self.gridLayout.addWidget(self.preview_pushbutton, 10, 2, 1, 1) - self.start_point_label = QtGui.QLabel(self.centralwidget) - self.start_point_label.setEnabled(True) - self.start_point_label.setObjectName("start_point_label") - self.gridLayout.addWidget(self.start_point_label, 7, 0, 1, 2) - spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) - self.gridLayout.addItem(spacerItem, 9, 3, 1, 1) - self.start_timeedit = QtGui.QTimeEdit(self.centralwidget) - self.start_timeedit.setEnabled(True) - self.start_timeedit.setObjectName("start_timeedit") - self.gridLayout.addWidget(self.start_timeedit, 7, 2, 1, 1) - self.jump_end_pushbutton = QtGui.QPushButton(self.centralwidget) - self.jump_end_pushbutton.setEnabled(True) - self.jump_end_pushbutton.setObjectName("jump_end_pushbutton") - self.gridLayout.addWidget(self.jump_end_pushbutton, 8, 4, 1, 1) - self.subtitle_track_label = QtGui.QLabel(self.centralwidget) - self.subtitle_track_label.setEnabled(True) - self.subtitle_track_label.setObjectName("subtitle_track_label") - self.gridLayout.addWidget(self.subtitle_track_label, 4, 0, 1, 2) - self.set_end_pushbutton = QtGui.QPushButton(self.centralwidget) - self.set_end_pushbutton.setEnabled(True) - self.set_end_pushbutton.setObjectName("set_end_pushbutton") - self.gridLayout.addWidget(self.set_end_pushbutton, 8, 3, 1, 1) - self.set_start_pushbutton = QtGui.QPushButton(self.centralwidget) - self.set_start_pushbutton.setEnabled(True) - self.set_start_pushbutton.setObjectName("set_start_pushbutton") - self.gridLayout.addWidget(self.set_start_pushbutton, 7, 3, 1, 1) - self.audio_track_label = QtGui.QLabel(self.centralwidget) - self.audio_track_label.setEnabled(True) - self.audio_track_label.setObjectName("audio_track_label") - self.gridLayout.addWidget(self.audio_track_label, 3, 0, 1, 2) - self.load_disc_pushbutton = QtGui.QPushButton(self.centralwidget) - self.load_disc_pushbutton.setEnabled(True) - self.load_disc_pushbutton.setObjectName("load_disc_pushbutton") - self.gridLayout.addWidget(self.load_disc_pushbutton, 0, 4, 1, 1) - self.media_position_timeedit = QtGui.QTimeEdit(self.centralwidget) - self.media_position_timeedit.setEnabled(True) - self.media_position_timeedit.setObjectName("media_position_timeedit") - self.gridLayout.addWidget(self.media_position_timeedit, 6, 4, 1, 1) - self.end_point_label = QtGui.QLabel(self.centralwidget) - self.end_point_label.setEnabled(True) - self.end_point_label.setObjectName("end_point_label") - self.gridLayout.addWidget(self.end_point_label, 8, 0, 1, 1) - self.jump_start_pushbutton = QtGui.QPushButton(self.centralwidget) - self.jump_start_pushbutton.setEnabled(True) - self.jump_start_pushbutton.setObjectName("jump_start_pushbutton") - self.gridLayout.addWidget(self.jump_start_pushbutton, 7, 4, 1, 1) - self.end_timeedit = QtGui.QTimeEdit(self.centralwidget) - self.end_timeedit.setEnabled(True) - self.end_timeedit.setObjectName("end_timeedit") - self.gridLayout.addWidget(self.end_timeedit, 8, 2, 1, 1) - self.title_label = QtGui.QLabel(self.centralwidget) - self.title_label.setEnabled(True) - self.title_label.setObjectName("title_label") - self.gridLayout.addWidget(self.title_label, 2, 0, 1, 1) - self.save_pushbutton = QtGui.QPushButton(self.centralwidget) - self.save_pushbutton.setEnabled(True) - self.save_pushbutton.setObjectName("save_pushbutton") - self.gridLayout.addWidget(self.save_pushbutton, 10, 3, 1, 1) self.media_path_combobox = QtGui.QComboBox(self.centralwidget) self.media_path_combobox.setEnabled(True) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) @@ -119,26 +61,76 @@ class Ui_MediaClipSelector(object): self.media_path_combobox.setEditable(True) self.media_path_combobox.setObjectName("media_path_combobox") self.gridLayout.addWidget(self.media_path_combobox, 0, 2, 1, 2) - self.position_horizontalslider = QtGui.QSlider(self.centralwidget) - self.position_horizontalslider.setEnabled(True) - self.position_horizontalslider.setTracking(False) - self.position_horizontalslider.setOrientation(QtCore.Qt.Horizontal) - self.position_horizontalslider.setInvertedAppearance(False) - self.position_horizontalslider.setObjectName("position_horizontalslider") - self.gridLayout.addWidget(self.position_horizontalslider, 6, 2, 1, 2) - self.title_combo_box = QtGui.QComboBox(self.centralwidget) - self.title_combo_box.setEnabled(True) - self.title_combo_box.setProperty("currentText", "") - self.title_combo_box.setObjectName("title_combo_box") - self.gridLayout.addWidget(self.title_combo_box, 2, 2, 1, 2) - self.audio_tracks_combobox = QtGui.QComboBox(self.centralwidget) - self.audio_tracks_combobox.setEnabled(True) - self.audio_tracks_combobox.setObjectName("audio_tracks_combobox") - self.gridLayout.addWidget(self.audio_tracks_combobox, 3, 2, 1, 2) + self.start_timeedit = QtGui.QTimeEdit(self.centralwidget) + self.start_timeedit.setEnabled(True) + self.start_timeedit.setObjectName("start_timeedit") + self.gridLayout.addWidget(self.start_timeedit, 7, 2, 1, 1) + self.end_timeedit = QtGui.QTimeEdit(self.centralwidget) + self.end_timeedit.setEnabled(True) + self.end_timeedit.setObjectName("end_timeedit") + self.gridLayout.addWidget(self.end_timeedit, 8, 2, 1, 1) + self.set_start_pushbutton = QtGui.QPushButton(self.centralwidget) + self.set_start_pushbutton.setEnabled(True) + self.set_start_pushbutton.setObjectName("set_start_pushbutton") + self.gridLayout.addWidget(self.set_start_pushbutton, 7, 3, 1, 1) + self.load_disc_pushbutton = QtGui.QPushButton(self.centralwidget) + self.load_disc_pushbutton.setEnabled(True) + self.load_disc_pushbutton.setObjectName("load_disc_pushbutton") + self.gridLayout.addWidget(self.load_disc_pushbutton, 0, 4, 1, 1) + spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 9, 3, 1, 1) + self.play_pushbutton = QtGui.QPushButton(self.centralwidget) + self.play_pushbutton.setEnabled(True) + self.play_pushbutton.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.play_pushbutton.setIcon(icon) + self.play_pushbutton.setObjectName("play_pushbutton") + self.gridLayout.addWidget(self.play_pushbutton, 6, 0, 1, 1) + self.end_point_label = QtGui.QLabel(self.centralwidget) + self.end_point_label.setEnabled(True) + self.end_point_label.setObjectName("end_point_label") + self.gridLayout.addWidget(self.end_point_label, 8, 0, 1, 1) self.subtitle_tracks_combobox = QtGui.QComboBox(self.centralwidget) self.subtitle_tracks_combobox.setEnabled(True) self.subtitle_tracks_combobox.setObjectName("subtitle_tracks_combobox") self.gridLayout.addWidget(self.subtitle_tracks_combobox, 4, 2, 1, 2) + self.title_label = QtGui.QLabel(self.centralwidget) + self.title_label.setEnabled(True) + self.title_label.setObjectName("title_label") + self.gridLayout.addWidget(self.title_label, 2, 0, 1, 1) + self.audio_tracks_combobox = QtGui.QComboBox(self.centralwidget) + self.audio_tracks_combobox.setEnabled(True) + self.audio_tracks_combobox.setObjectName("audio_tracks_combobox") + self.gridLayout.addWidget(self.audio_tracks_combobox, 3, 2, 1, 2) + self.set_end_pushbutton = QtGui.QPushButton(self.centralwidget) + self.set_end_pushbutton.setEnabled(True) + self.set_end_pushbutton.setObjectName("set_end_pushbutton") + self.gridLayout.addWidget(self.set_end_pushbutton, 8, 3, 1, 1) + self.save_pushbutton = QtGui.QPushButton(self.centralwidget) + self.save_pushbutton.setEnabled(True) + self.save_pushbutton.setObjectName("save_pushbutton") + self.gridLayout.addWidget(self.save_pushbutton, 10, 3, 1, 1) + self.close_pushbutton = QtGui.QPushButton(self.centralwidget) + self.close_pushbutton.setEnabled(True) + self.close_pushbutton.setObjectName("close_pushbutton") + self.gridLayout.addWidget(self.close_pushbutton, 10, 4, 1, 1) + self.start_point_label = QtGui.QLabel(self.centralwidget) + self.start_point_label.setEnabled(True) + self.start_point_label.setObjectName("start_point_label") + self.gridLayout.addWidget(self.start_point_label, 7, 0, 1, 2) + self.jump_start_pushbutton = QtGui.QPushButton(self.centralwidget) + self.jump_start_pushbutton.setEnabled(True) + self.jump_start_pushbutton.setObjectName("jump_start_pushbutton") + self.gridLayout.addWidget(self.jump_start_pushbutton, 7, 4, 1, 1) + self.audio_track_label = QtGui.QLabel(self.centralwidget) + self.audio_track_label.setEnabled(True) + self.audio_track_label.setObjectName("audio_track_label") + self.gridLayout.addWidget(self.audio_track_label, 3, 0, 1, 2) + self.media_position_timeedit = QtGui.QTimeEdit(self.centralwidget) + self.media_position_timeedit.setEnabled(True) + self.media_position_timeedit.setObjectName("media_position_timeedit") + self.gridLayout.addWidget(self.media_position_timeedit, 6, 4, 1, 1) self.media_view_frame = QtGui.QFrame(self.centralwidget) self.media_view_frame.setMinimumSize(QtCore.QSize(665, 375)) self.media_view_frame.setStyleSheet("background-color:black;") @@ -146,6 +138,30 @@ class Ui_MediaClipSelector(object): self.media_view_frame.setFrameShadow(QtGui.QFrame.Raised) self.media_view_frame.setObjectName("media_view_frame") self.gridLayout.addWidget(self.media_view_frame, 5, 0, 1, 5) + self.subtitle_track_label = QtGui.QLabel(self.centralwidget) + self.subtitle_track_label.setEnabled(True) + self.subtitle_track_label.setObjectName("subtitle_track_label") + self.gridLayout.addWidget(self.subtitle_track_label, 4, 0, 1, 2) + self.jump_end_pushbutton = QtGui.QPushButton(self.centralwidget) + self.jump_end_pushbutton.setEnabled(True) + self.jump_end_pushbutton.setObjectName("jump_end_pushbutton") + self.gridLayout.addWidget(self.jump_end_pushbutton, 8, 4, 1, 1) + self.media_path_label = QtGui.QLabel(self.centralwidget) + self.media_path_label.setEnabled(True) + self.media_path_label.setObjectName("media_path_label") + self.gridLayout.addWidget(self.media_path_label, 0, 0, 1, 2) + self.title_combo_box = QtGui.QComboBox(self.centralwidget) + self.title_combo_box.setEnabled(True) + self.title_combo_box.setProperty("currentText", "") + self.title_combo_box.setObjectName("title_combo_box") + self.gridLayout.addWidget(self.title_combo_box, 2, 2, 1, 2) + self.position_horizontalslider = QtGui.QSlider(self.centralwidget) + self.position_horizontalslider.setEnabled(True) + self.position_horizontalslider.setTracking(False) + self.position_horizontalslider.setOrientation(QtCore.Qt.Horizontal) + self.position_horizontalslider.setInvertedAppearance(False) + self.position_horizontalslider.setObjectName("position_horizontalslider") + self.gridLayout.addWidget(self.position_horizontalslider, 6, 1, 1, 3) #MediaClipSelector.setCentralWidget(self.centralwidget) self.retranslateUi(MediaClipSelector) @@ -155,8 +171,7 @@ class Ui_MediaClipSelector(object): MediaClipSelector.setTabOrder(self.title_combo_box, self.audio_tracks_combobox) MediaClipSelector.setTabOrder(self.audio_tracks_combobox, self.subtitle_tracks_combobox) MediaClipSelector.setTabOrder(self.subtitle_tracks_combobox, self.play_pushbutton) - MediaClipSelector.setTabOrder(self.play_pushbutton, self.pause_pushbutton) - MediaClipSelector.setTabOrder(self.pause_pushbutton, self.position_horizontalslider) + MediaClipSelector.setTabOrder(self.play_pushbutton, self.position_horizontalslider) MediaClipSelector.setTabOrder(self.position_horizontalslider, self.media_position_timeedit) MediaClipSelector.setTabOrder(self.media_position_timeedit, self.start_timeedit) MediaClipSelector.setTabOrder(self.start_timeedit, self.set_start_pushbutton) @@ -164,27 +179,25 @@ class Ui_MediaClipSelector(object): MediaClipSelector.setTabOrder(self.jump_start_pushbutton, self.end_timeedit) MediaClipSelector.setTabOrder(self.end_timeedit, self.set_end_pushbutton) MediaClipSelector.setTabOrder(self.set_end_pushbutton, self.jump_end_pushbutton) - MediaClipSelector.setTabOrder(self.jump_end_pushbutton, self.preview_pushbutton) - MediaClipSelector.setTabOrder(self.preview_pushbutton, self.save_pushbutton) + MediaClipSelector.setTabOrder(self.jump_end_pushbutton, self.save_pushbutton) MediaClipSelector.setTabOrder(self.save_pushbutton, self.close_pushbutton) def retranslateUi(self, MediaClipSelector): MediaClipSelector.setWindowTitle(translate("MediaPlugin.MediaClipSelector", "Select media clip", None)) - self.close_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Close", None)) - self.media_path_label.setText(translate("MediaPlugin.MediaClipSelector", "Media path", None)) - self.preview_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Preview current clip", None)) - self.start_point_label.setText(translate("MediaPlugin.MediaClipSelector", "Start point", None)) self.start_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) - self.jump_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to end point", None)) - self.subtitle_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Subtitle track", None)) - self.set_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as end point", None)) - self.set_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as start point", None)) - self.audio_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Audio track", None)) - self.load_disc_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Load disc", None)) - self.media_position_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) - self.end_point_label.setText(translate("MediaPlugin.MediaClipSelector", "End point", None)) - self.jump_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to start point", None)) self.end_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) + self.set_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as start point", None)) + self.load_disc_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Load disc", None)) + self.end_point_label.setText(translate("MediaPlugin.MediaClipSelector", "End point", None)) self.title_label.setText(translate("MediaPlugin.MediaClipSelector", "Title", None)) + self.set_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as end point", None)) self.save_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Save current clip", None)) + self.close_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Close", None)) + self.start_point_label.setText(translate("MediaPlugin.MediaClipSelector", "Start point", None)) + self.jump_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to start point", None)) + self.audio_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Audio track", None)) + self.media_position_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) + self.subtitle_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Subtitle track", None)) + self.jump_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to end point", None)) + self.media_path_label.setText(translate("MediaPlugin.MediaClipSelector", "Media path", None)) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 7e912ab05..6cda4a494 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -68,6 +68,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_load_media(False) # most actions auto-connect due to the functions name, so only a few left to do self.close_pushbutton.clicked.connect(self.reject) + # setup play/pause icon + self.play_icon = QtGui.QIcon() + self.play_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pause_icon = QtGui.QIcon() + self.pause_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_pause.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) def reject(self): """ @@ -174,23 +179,20 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.title_combo_box.setDisabled(False) self.toggle_disable_load_media(False) - @QtCore.pyqtSlot(bool) - def on_pause_pushbutton_clicked(self, clicked): - """ - Pause the playback - - :param clicked: Given from signal, not used. - """ - self.vlc_media_player.pause() - @QtCore.pyqtSlot(bool) def on_play_pushbutton_clicked(self, clicked): """ - Start the playback + Toggle the playback :param clicked: Given from signal, not used. """ - self.vlc_media_player.play() + if self.vlc_media_player.get_state() == vlc.State.Playing: + self.vlc_media_player.pause() + self.play_pushbutton.setIcon(self.play_icon) + else: + self.vlc_media_player.play() + self.media_state_wait(vlc.State.Playing) + self.play_pushbutton.setIcon(self.pause_icon) @QtCore.pyqtSlot(bool) def on_set_start_pushbutton_clicked(self, clicked): @@ -394,7 +396,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param action: If True elements are disabled, if False they are enabled. """ self.play_pushbutton.setDisabled(action) - self.pause_pushbutton.setDisabled(action) self.position_horizontalslider.setDisabled(action) self.media_position_timeedit.setDisabled(action) self.start_timeedit.setDisabled(action) @@ -403,7 +404,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.end_timeedit.setDisabled(action) self.set_end_pushbutton.setDisabled(action) self.jump_end_pushbutton.setDisabled(action) - self.preview_pushbutton.setDisabled(action) self.save_pushbutton.setDisabled(action) @QtCore.pyqtSlot(bool) diff --git a/resources/forms/mediaclipselector.ui b/resources/forms/mediaclipselector.ui index 4cd8f518d..754161eae 100644 --- a/resources/forms/mediaclipselector.ui +++ b/resources/forms/mediaclipselector.ui @@ -42,71 +42,59 @@ - - + + true - - Close + + + 0 + 0 + + + + true - - + + true - - - - - - ../images/media_playback_pause.png../images/media_playback_pause.png + + HH:mm:ss.z - - + + true - - - - - - ../images/media_playback_start.png../images/media_playback_start.png + + HH:mm:ss.z - - + + true - Media path + Set current position as start point - - + + true - Preview current clip - - - - - - - true - - - Start point + Load disc @@ -126,83 +114,17 @@ - - - - true - - - HH:mm:ss.z - - - - - + + true - Jump to end point + - - - - - - true - - - Subtitle track - - - - - - - true - - - Set current position as end point - - - - - - - true - - - Set current position as start point - - - - - - - true - - - Audio track - - - - - - - true - - - Load disc - - - - - - - true - - - HH:mm:ss.z + + + ../images/media_playback_start.png../images/media_playback_start.png @@ -216,24 +138,11 @@ - - + + true - - Jump to start point - - - - - - - true - - - HH:mm:ss.z - @@ -246,6 +155,23 @@ + + + + true + + + + + + + true + + + Set current position as end point + + + @@ -256,60 +182,54 @@ - - + + true - - - 0 - 0 - - - - true + + Close - - + + true - - false - - - Qt::Horizontal - - - false + + Start point - - + + true - - + + Jump to start point - - + + true + + Audio track + - - + + true + + HH:mm:ss.z + @@ -331,6 +251,62 @@ + + + + true + + + Subtitle track + + + + + + + true + + + Jump to end point + + + + + + + true + + + Media path + + + + + + + true + + + + + + + + + + true + + + false + + + Qt::Horizontal + + + false + + + @@ -341,7 +317,6 @@ audio_tracks_combobox subtitle_tracks_combobox play_pushbutton - pause_pushbutton position_horizontalslider media_position_timeedit start_timeedit @@ -350,7 +325,6 @@ end_timeedit set_end_pushbutton jump_end_pushbutton - preview_pushbutton save_pushbutton close_pushbutton diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index 16670232c..9484e92a7 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -130,6 +130,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): # GIVEN: Mocked methods and some entries in the title combobox. with patch('PyQt4.QtGui.QDialog.exec_') as mocked_exec: self.form.exec_() + self.form.vlc_media_player.get_length.return_value = 1000 self.form.audio_tracks_combobox.itemData = MagicMock() self.form.subtitle_tracks_combobox.itemData = MagicMock() self.form.audio_tracks_combobox.itemData.return_value = None @@ -138,7 +139,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.title_combo_box.insertItem(1, 'Test Title 1') # WHEN: There exists audio and subtitle tracks and the index is updated. - self.form.vlc_media_player.audio_get_track_description.return_value = [(-1, b'Disabled'), + self.form.vlc_media_player.audio_get_track_description.return_value = [(-1, b'Disabled'), (0, b'Audio Track 1')] self.form.vlc_media_player.video_get_spu_description.return_value = [(-1, b'Disabled'), (0, b'Subtitle Track 1')] From a999e59a4f36503f36d51700042a4628ad2af9b1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 20 Apr 2014 16:36:56 +0200 Subject: [PATCH 13/44] Fixes for merge --- openlp/core/lib/serviceitem.py | 2 +- tests/resources/serviceitem-dvd.osj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index b1e254f82..7e9528503 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -435,7 +435,7 @@ class ServiceItem(RegistryProperties): Returns the title of the service item. """ if self.is_text() or self.is_capable(ItemCapabilities.IsOptical) \ - or self.is_capable(temCapabilities.CanEditTitle): + or self.is_capable(ItemCapabilities.CanEditTitle): return self.title else: if len(self._raw_frames) > 1: diff --git a/tests/resources/serviceitem-dvd.osj b/tests/resources/serviceitem-dvd.osj index d3d224bff..cda95e592 100644 --- a/tests/resources/serviceitem-dvd.osj +++ b/tests/resources/serviceitem-dvd.osj @@ -1 +1 @@ -[{"serviceitem": {"header": {"auto_play_slides_once": false, "data": "", "processor": "Automatic", "theme": -1, "theme_overwritten": false, "end_time": 672.069, "start_time": 654.375, "capabilities": [12, 17, 16, 4], "media_length": 17.694, "audit": "", "xml_version": null, "title": "/dev/sr0@00:06:15,375-00:01:09,069", "auto_play_slides_loop": false, "notes": "", "icon": ":/plugins/plugin_media.png", "type": 3, "background_audio": [], "plugin": "media", "from_plugin": false, "search": "", "will_auto_start": false, "name": "media", "footer": [], "timed_slide_interval": 0}, "data": [{"image": ":/media/slidecontroller_multimedia.png", "path": "optical:1:5:3:654375:672069:/dev/sr0", "title": "/dev/sr0"}]}}] +[{"serviceitem": {"header": {"auto_play_slides_once": false, "data": "", "processor": "Automatic", "theme": -1, "theme_overwritten": false, "end_time": 672.069, "start_time": 654.375, "capabilities": [12, 18, 16, 4], "media_length": 17.694, "audit": "", "xml_version": null, "title": "/dev/sr0@00:06:15,375-00:01:09,069", "auto_play_slides_loop": false, "notes": "", "icon": ":/plugins/plugin_media.png", "type": 3, "background_audio": [], "plugin": "media", "from_plugin": false, "search": "", "will_auto_start": false, "name": "media", "footer": [], "timed_slide_interval": 0}, "data": [{"image": ":/media/slidecontroller_multimedia.png", "path": "optical:1:5:3:654375:672069:/dev/sr0", "title": "/dev/sr0"}]}}] From 87e7310e2bf32c2e47236c32d8ce71afee94f9bb Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Apr 2014 19:23:54 +0200 Subject: [PATCH 14/44] Reset the clipselector on each load. --- .../media/forms/mediaclipselectordialog.py | 3 ++ .../media/forms/mediaclipselectorform.py | 41 ++++++++++++++++--- resources/forms/mediaclipselector.ui | 3 ++ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index 921c68a8d..beed9e8e3 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -26,6 +26,8 @@ # 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 openlp.core.common import translate @@ -129,6 +131,7 @@ class Ui_MediaClipSelector(object): self.gridLayout.addWidget(self.audio_track_label, 3, 0, 1, 2) self.media_position_timeedit = QtGui.QTimeEdit(self.centralwidget) self.media_position_timeedit.setEnabled(True) + self.media_position_timeedit.setReadOnly(True) self.media_position_timeedit.setObjectName("media_position_timeedit") self.gridLayout.addWidget(self.media_position_timeedit, 6, 4, 1, 1) self.media_view_frame = QtGui.QFrame(self.centralwidget) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 6cda4a494..11986acf5 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -35,7 +35,6 @@ import sys if sys.platform.startswith('linux'): import dbus import logging -import time from datetime import datetime @@ -62,10 +61,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): super(MediaClipSelectorForm, self).__init__(parent) self.media_item = media_item self.setupUi(self) - self.playback_length = 0 - self.position_horizontalslider.setMinimum(0) - self.disable_all() - self.toggle_disable_load_media(False) # most actions auto-connect due to the functions name, so only a few left to do self.close_pushbutton.clicked.connect(self.reject) # setup play/pause icon @@ -79,16 +74,43 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): Exit Dialog and do not save """ log.debug('MediaClipSelectorForm.reject') - self.vlc_media_player.stop() + # Tear down vlc + if self.vlc_media_player: + self.vlc_media_player.stop() + self.vlc_media_player.release() + self.vlc_media_player = None + if self.vlc_instance: + self.vlc_instance.release() + self.vlc_instance = None + if self.vlc_media: + self.vlc_media.release() + self.vlc_media = None QtGui.QDialog.reject(self) def exec_(self): """ Start dialog """ + self.reset_ui() self.setup_vlc() return QtGui.QDialog.exec_(self) + def reset_ui(self): + """ + Reset the UI to default values + """ + self.playback_length = 0 + self.position_horizontalslider.setMinimum(0) + self.disable_all() + self.toggle_disable_load_media(False) + self.subtitle_tracks_combobox.clear() + self.audio_tracks_combobox.clear() + self.title_combo_box.clear() + time = QtCore.QTime() + self.start_timeedit.setTime(time) + self.end_timeedit.setTime(time) + self.media_position_timeedit.setTime(time) + def setup_vlc(self): """ Setup VLC instance and mediaplayer @@ -286,6 +308,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param index: The index of the newly chosen title track. """ log.debug('in on_title_combo_box_changed, index: %d', index) + if not self.vlc_media_player: + return self.vlc_media_player.set_title(index) self.vlc_media_player.set_time(0) self.vlc_media_player.play() @@ -323,6 +347,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): playback_length_time = time.addMSecs(rounded_vlc_ms_length) self.start_timeedit.setMaximumTime(playback_length_time) self.end_timeedit.setMaximumTime(playback_length_time) + self.end_timeedit.setTime(playback_length_time) # If a title or audio track is available the player is enabled if self.title_combo_box.count() > 0 or len(audio_tracks) > 0: self.toggle_disable_player(False) @@ -334,6 +359,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param index: The index of the newly chosen audio track. """ + if not self.vlc_media_player: + return audio_track = self.audio_tracks_combobox.itemData(index) log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: %d audio_track: %s' % (index, audio_track)) if audio_track and int(audio_track) > 0: @@ -346,6 +373,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param index: The index of the newly chosen subtitle. """ + if not self.vlc_media_player: + return subtitle_track = self.subtitle_tracks_combobox.itemData(index) if subtitle_track: self.vlc_media_player.video_set_spu(int(subtitle_track)) diff --git a/resources/forms/mediaclipselector.ui b/resources/forms/mediaclipselector.ui index 754161eae..b3f22e678 100644 --- a/resources/forms/mediaclipselector.ui +++ b/resources/forms/mediaclipselector.ui @@ -227,6 +227,9 @@ true + + true + HH:mm:ss.z From 7980231273ede4a4dfe50459885d80a96083459d Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Apr 2014 22:13:36 +0200 Subject: [PATCH 15/44] Skip tests on windows. --- openlp/plugins/media/forms/mediaclipselectorform.py | 11 ++++++++++- openlp/plugins/media/lib/mediaitem.py | 3 ++- .../media/forms/test_mediaclipselectorform.py | 8 +++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 11986acf5..653cfdae2 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -43,7 +43,16 @@ from PyQt4 import QtCore, QtGui from openlp.core.common import translate from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.media.vendor import vlc +try: + from openlp.core.ui.media.vendor import vlc +except (ImportError, NameError, NotImplementedError): + pass +except OSError as e: + if sys.platform.startswith('win'): + if not isinstance(e, WindowsError) and e.winerror != 126: + raise + else: + raise log = logging.getLogger(__name__) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 74e6750d7..9be15dbb5 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -278,7 +278,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): check_directory_exists(self.service_path) self.load_list(Settings().value(self.settings_section + '/media files')) self.rebuild_players() - self.media_clip_selector_form = MediaClipSelectorForm(self, self.main_window, None) + if VLC_AVAILABLE: + self.media_clip_selector_form = MediaClipSelectorForm(self, self.main_window, None) def rebuild_players(self): """ diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index 9484e92a7..241ef26c3 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -29,7 +29,13 @@ """ Module to test the MediaClipSelectorForm. """ -from unittest import TestCase + +import os +from unittest import TestCase, SkipTest +from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE + +if os.name == 'nt' and not VLC_AVAILABLE: + raise SkipTest('Windows without VLC, skipping this test since it cannot run without vlc') from PyQt4 import QtGui, QtTest, QtCore From c6d85ff5236073ce2970bdcdc7dd8c29b6b3d279 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Apr 2014 22:27:15 +0200 Subject: [PATCH 16/44] Fix for tests on windows --- openlp/plugins/media/lib/mediaitem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 9be15dbb5..c5510b7e4 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -41,8 +41,9 @@ from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adj from openlp.core.ui import DisplayController, Display, DisplayControllerType from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path from openlp.core.utils import get_locale_key -from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE +if VLC_AVAILABLE: + from openlp.plugins.media.forms.mediaclipselectorform import MediaClipSelectorForm log = logging.getLogger(__name__) From 817fe854e48cf14b9dc0efc961e30930f17e207c Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Apr 2014 22:42:07 +0200 Subject: [PATCH 17/44] PEP8 fixes --- openlp/core/lib/serviceitem.py | 5 ++--- openlp/core/ui/media/mediacontroller.py | 10 ++++++---- openlp/core/ui/media/vlcplayer.py | 2 +- openlp/plugins/media/forms/mediaclipselectorform.py | 9 ++++++--- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 7e9528503..6aba66252 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -504,7 +504,7 @@ class ServiceItem(RegistryProperties): Confirms if the ServiceItem uses a file """ return self.service_item_type == ServiceItemType.Image or \ - (self.service_item_type == ServiceItemType.Command and not self.is_capable(ItemCapabilities.IsOptical)) + (self.service_item_type == ServiceItemType.Command and not self.is_capable(ItemCapabilities.IsOptical)) def is_text(self): """ @@ -645,5 +645,4 @@ class ServiceItem(RegistryProperties): file_suffix = frame['title'].split('.')[-1] if file_suffix.lower() not in suffix_list: self.is_valid = False - break - + break \ No newline at end of file diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index c720c22d0..993172354 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -38,7 +38,8 @@ from PyQt4 import QtCore, QtGui from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties, Settings, UiStrings, translate from openlp.core.lib import OpenLPToolbar, ItemCapabilities from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players, parse_optical_path +from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\ + parse_optical_path from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.common import AppLocation from openlp.core.ui import DisplayControllerType @@ -373,7 +374,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): log.debug('video is optical and live') path = service_item.get_frame_path() (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(path) - is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) + is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, + controller) else: log.debug('video is not optical and live') is_valid = self._check_file_type(controller, display, service_item) @@ -391,7 +393,8 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): log.debug('video is optical and preview') path = service_item.get_frame_path() (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(path) - is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) + is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, + controller) else: log.debug('video is not optical and preview') is_valid = self._check_file_type(controller, display, service_item) @@ -460,7 +463,6 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): self.media_reset(controller) # Setup media info controller.media_info = MediaInfo() - #controller.media_info.volume = 0 controller.media_info.file_info = QtCore.QFileInfo(filename) controller.media_info.media_type = MediaType.DVD controller.media_info.start_time = start/1000 diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 8f8aa1ac1..9f060a2dc 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -212,7 +212,7 @@ class VlcPlayer(MediaPlayer): if self.state != MediaState.Paused and controller.media_info.start_time > 0: log.debug('vlc play, starttime set') start_time = controller.media_info.start_time - log.debug('mediatype: ' +str(controller.media_info.media_type)) + log.debug('mediatype: ' + str(controller.media_info.media_type)) # Set tracks for the optical device if controller.media_info.media_type == MediaType.DVD: log.debug('vlc play, playing started') diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 653cfdae2..e9f46d9d1 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -74,9 +74,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.close_pushbutton.clicked.connect(self.reject) # setup play/pause icon self.play_icon = QtGui.QIcon() - self.play_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.play_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, + QtGui.QIcon.Off) self.pause_icon = QtGui.QIcon() - self.pause_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_pause.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pause_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_pause.png"), QtGui.QIcon.Normal, + QtGui.QIcon.Off) def reject(self): """ @@ -519,7 +521,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if device_props.Get('org.freedesktop.UDisks.Device', 'DeviceIsDrive'): drive_props = device_props.Get('org.freedesktop.UDisks.Device', 'DriveMediaCompatibility') if any('optical' in prop for prop in drive_props): - self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device', 'DeviceFile')) + self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device', + 'DeviceFile')) elif sys.platform.startswith('darwin'): # Look for DVD folders in devices to find optical devices volumes = os.listdir('/Volumes') From 06825e4aeb8810217f1587984c1f3d86854be94e Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 23 May 2014 15:39:25 +0200 Subject: [PATCH 18/44] Added support for audio cds and udisks2 --- openlp/core/ui/media/mediacontroller.py | 10 +- openlp/core/ui/media/vlcplayer.py | 14 +- .../media/forms/mediaclipselectorform.py | 202 ++++++++++++------ openlp/plugins/media/lib/mediaitem.py | 2 +- 4 files changed, 160 insertions(+), 68 deletions(-) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 993172354..b25556e73 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -464,7 +464,10 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): # Setup media info controller.media_info = MediaInfo() controller.media_info.file_info = QtCore.QFileInfo(filename) - controller.media_info.media_type = MediaType.DVD + if audio_track == -1 and subtitle_track == -1: + controller.media_info.media_type = MediaType.CD + else: + controller.media_info.media_type = MediaType.DVD controller.media_info.start_time = start/1000 controller.media_info.end_time = end/1000 controller.media_info.length = (end - start)/1000 @@ -489,7 +492,10 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): vlc_player.load(display) self.resize(display, vlc_player) self.current_media_players[controller.controller_type] = vlc_player - controller.media_info.media_type = MediaType.DVD + if audio_track == -1 and subtitle_track == -1: + controller.media_info.media_type = MediaType.CD + else: + controller.media_info.media_type = MediaType.DVD return True def _check_file_type(self, controller, display, service_item): diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 6fd9bafd3..0c6d91078 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -166,7 +166,19 @@ class VlcPlayer(MediaPlayer): file_path = str(controller.media_info.file_info.absoluteFilePath()) path = os.path.normcase(file_path) # create the media - display.vlc_media = display.vlc_instance.media_new_path(path) + if controller.media_info.media_type == MediaType.CD: + display.vlc_media = display.vlc_instance.media_new_location('cdda://' + path) + display.vlc_media_player.set_media(display.vlc_media) + display.vlc_media_player.play() + # Wait for media to start playing. In this case VLC actually returns an error. + self.media_state_wait(display, vlc.State.Playing) + # If subitems exists, this is a CD + audio_cd_tracks = display.vlc_media.subitems() + if not audio_cd_tracks or audio_cd_tracks.count() < 1: + return False + display.vlc_media = audio_cd_tracks.item_at_index(controller.media_info.title_track) + else: + display.vlc_media = display.vlc_instance.media_new_path(path) # put the media in the media player display.vlc_media_player.set_media(display.vlc_media) # parse the metadata of the file diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index e9f46d9d1..82b3cd9ea 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -150,6 +150,40 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.timer.timeout.connect(self.update_position) self.timer.start(100) self.find_optical_devices() + self.audio_cd = False + self.audio_cd_tracks = None + + def detect_audio_cd(self, path): + """ + Detects is the given path is an audio CD + + :param path: Path to the device to be tested. + :return: True if it was an audio CD else False. + """ + # Detect by trying to play it as a CD + self.vlc_media = self.vlc_instance.media_new_location('cdda://' + path) + self.vlc_media_player.set_media(self.vlc_media) + self.vlc_media_player.play() + # Wait for media to start playing. In this case VLC actually returns an error. + self.media_state_wait(vlc.State.Playing) + self.vlc_media_player.pause() + # If subitems exists, this is a CD + self.audio_cd_tracks = self.vlc_media.subitems() + if not self.audio_cd_tracks or self.audio_cd_tracks.count() < 1: + return False + # Insert into title_combo_box + self.title_combo_box.clear() + for i in range(self.audio_cd_tracks.count()): + item = self.audio_cd_tracks.item_at_index(i) + item_title = item.get_meta(vlc.Meta.Title) + self.title_combo_box.addItem(item_title, i) + self.vlc_media_player.set_media(self.audio_cd_tracks.item_at_index(0)) + self.audio_cd = True + self.title_combo_box.setDisabled(False) + self.title_combo_box.setCurrentIndex(0) + self.on_title_combo_box_currentIndexChanged(0) + + return True @QtCore.pyqtSlot(bool) def on_load_disc_pushbutton_clicked(self, clicked): @@ -172,7 +206,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): 'Given path does not exists')) self.toggle_disable_load_media(False) return - self.vlc_media = self.vlc_instance.media_new_path(path) + self.vlc_media = self.vlc_instance.media_new_location(path) if not self.vlc_media: log.debug('vlc media player is none') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', @@ -191,25 +225,28 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): return self.vlc_media_player.audio_set_mute(True) if not self.media_state_wait(vlc.State.Playing): - critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', - 'VLC player failed playing the media')) - self.toggle_disable_load_media(False) - return + # Tests if this is an audio CD + if not self.detect_audio_cd(path): + critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', + 'VLC player failed playing the media')) + self.toggle_disable_load_media(False) + return self.vlc_media_player.pause() self.vlc_media_player.set_time(0) - # Get titles, insert in combobox - titles = self.vlc_media_player.video_get_title_description() - self.title_combo_box.clear() - for title in titles: - self.title_combo_box.addItem(title[1].decode(), title[0]) - # Main title is usually title #1 - if len(titles) > 1: - self.title_combo_box.setCurrentIndex(1) - else: - self.title_combo_box.setCurrentIndex(0) - # Enable audio track combobox if anything is in it - if len(titles) > 0: - self.title_combo_box.setDisabled(False) + if not self.audio_cd: + # Get titles, insert in combobox + titles = self.vlc_media_player.video_get_title_description() + self.title_combo_box.clear() + for title in titles: + self.title_combo_box.addItem(title[1].decode(), title[0]) + # Main title is usually title #1 + if len(titles) > 1: + self.title_combo_box.setCurrentIndex(1) + else: + self.title_combo_box.setCurrentIndex(0) + # Enable audio track combobox if anything is in it + if len(titles) > 0: + self.title_combo_box.setDisabled(False) self.toggle_disable_load_media(False) @QtCore.pyqtSlot(bool) @@ -321,35 +358,53 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): log.debug('in on_title_combo_box_changed, index: %d', index) if not self.vlc_media_player: return - self.vlc_media_player.set_title(index) - self.vlc_media_player.set_time(0) - self.vlc_media_player.play() - self.vlc_media_player.audio_set_mute(True) - if not self.media_state_wait(vlc.State.Playing): - return - # pause - self.vlc_media_player.pause() - self.vlc_media_player.set_time(0) - # Get audio tracks, insert in combobox - audio_tracks = self.vlc_media_player.audio_get_track_description() - self.audio_tracks_combobox.clear() - for audio_track in audio_tracks: - self.audio_tracks_combobox.addItem(audio_track[1].decode(), audio_track[0]) - # Enable audio track combobox if anything is in it - if len(audio_tracks) > 0: - self.audio_tracks_combobox.setDisabled(False) - # First track is "deactivated", so set to next if it exists - if len(audio_tracks) > 1: - self.audio_tracks_combobox.setCurrentIndex(1) - # Get subtitle tracks, insert in combobox - subtitles_tracks = self.vlc_media_player.video_get_spu_description() - self.subtitle_tracks_combobox.clear() - for subtitle_track in subtitles_tracks: - self.subtitle_tracks_combobox.addItem(subtitle_track[1].decode(), subtitle_track[0]) - # Enable subtitle track combobox is anything in it - if len(subtitles_tracks) > 0: - self.subtitle_tracks_combobox.setDisabled(False) - self.vlc_media_player.audio_set_mute(False) + if self.audio_cd: + self.vlc_media = self.audio_cd_tracks.item_at_index(index) + self.vlc_media_player.set_media(self.vlc_media) + self.vlc_media_player.set_time(0) + self.vlc_media_player.play() + self.vlc_media_player.audio_set_mute(True) + if not self.media_state_wait(vlc.State.Playing): + return + # pause + self.vlc_media_player.pause() + self.vlc_media_player.set_time(0) + self.vlc_media_player.audio_set_mute(False) + self.toggle_disable_player(False) + else: + self.vlc_media_player.set_title(index) + self.vlc_media_player.set_time(0) + self.vlc_media_player.play() + self.vlc_media_player.audio_set_mute(True) + if not self.media_state_wait(vlc.State.Playing): + return + # pause + self.vlc_media_player.pause() + self.vlc_media_player.set_time(0) + # Get audio tracks, insert in combobox + audio_tracks = self.vlc_media_player.audio_get_track_description() + self.audio_tracks_combobox.clear() + for audio_track in audio_tracks: + self.audio_tracks_combobox.addItem(audio_track[1].decode(), audio_track[0]) + # Enable audio track combobox if anything is in it + if len(audio_tracks) > 0: + self.audio_tracks_combobox.setDisabled(False) + # First track is "deactivated", so set to next if it exists + if len(audio_tracks) > 1: + self.audio_tracks_combobox.setCurrentIndex(1) + # Get subtitle tracks, insert in combobox + subtitles_tracks = self.vlc_media_player.video_get_spu_description() + self.subtitle_tracks_combobox.clear() + for subtitle_track in subtitles_tracks: + self.subtitle_tracks_combobox.addItem(subtitle_track[1].decode(), subtitle_track[0]) + # Enable subtitle track combobox is anything in it + if len(subtitles_tracks) > 0: + self.subtitle_tracks_combobox.setDisabled(False) + self.vlc_media_player.audio_set_mute(False) + # If a title or audio track is available the player is enabled + if self.title_combo_box.count() > 0 or len(audio_tracks) > 0: + self.toggle_disable_player(False) + # Set media length info self.playback_length = self.vlc_media_player.get_length() self.position_horizontalslider.setMaximum(self.playback_length) # setup start and end time @@ -359,9 +414,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.start_timeedit.setMaximumTime(playback_length_time) self.end_timeedit.setMaximumTime(playback_length_time) self.end_timeedit.setTime(playback_length_time) - # If a title or audio track is available the player is enabled - if self.title_combo_box.count() > 0 or len(audio_tracks) > 0: - self.toggle_disable_player(False) @QtCore.pyqtSlot(int) def on_audio_tracks_combobox_currentIndexChanged(self, index): @@ -465,11 +517,15 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): end_time.second() * 1000 + \ end_time.msec() title = self.title_combo_box.itemData(self.title_combo_box.currentIndex()) - audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) - subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) path = self.media_path_combobox.currentText() - optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str( - start_time_ms) + ':' + str(end_time_ms) + ':' + path + optical = '' + if self.audio_cd: + optical = 'optical:' + str(title) + ':-1:-1:' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + path + else: + audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) + subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) + optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str( + start_time_ms) + ':' + str(end_time_ms) + ':' + path self.media_item.add_optical_clip(optical) def media_state_wait(self, media_state): @@ -513,16 +569,34 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): elif sys.platform.startswith('linux'): # Get disc devices from dbus and find the ones that are optical bus = dbus.SystemBus() - udev_manager_obj = bus.get_object('org.freedesktop.UDisks', '/org/freedesktop/UDisks') - udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.UDisks') - for dev in udev_manager.EnumerateDevices(): - device_obj = bus.get_object("org.freedesktop.UDisks", dev) - device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE) - if device_props.Get('org.freedesktop.UDisks.Device', 'DeviceIsDrive'): - drive_props = device_props.Get('org.freedesktop.UDisks.Device', 'DriveMediaCompatibility') - if any('optical' in prop for prop in drive_props): - self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device', - 'DeviceFile')) + try: + udev_manager_obj = bus.get_object('org.freedesktop.UDisks', '/org/freedesktop/UDisks') + udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.UDisks') + for dev in udev_manager.EnumerateDevices(): + device_obj = bus.get_object("org.freedesktop.UDisks", dev) + device_props = dbus.Interface(device_obj, dbus.PROPERTIES_IFACE) + if device_props.Get('org.freedesktop.UDisks.Device', 'DeviceIsDrive'): + drive_props = device_props.Get('org.freedesktop.UDisks.Device', 'DriveMediaCompatibility') + if any('optical' in prop for prop in drive_props): + self.media_path_combobox.addItem(device_props.Get('org.freedesktop.UDisks.Device', + 'DeviceFile')) + return + except dbus.exceptions.DBusException: + log.debug('could not use udisks, will try udisks2') + udev_manager_obj = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2') + udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.DBus.ObjectManager') + for k,v in udev_manager.GetManagedObjects().items(): + drive_info = v.get('org.freedesktop.UDisks2.Drive', {}) + drive_props = drive_info.get('MediaCompatibility') + if drive_props and any('optical' in prop for prop in drive_props): + for device in udev_manager.GetManagedObjects().values(): + if dbus.String('org.freedesktop.UDisks2.Block') in device: + if device[dbus.String('org.freedesktop.UDisks2.Block')][dbus.String('Drive')] == k: + block_file = '' + for c in device[dbus.String('org.freedesktop.UDisks2.Block')][dbus.String('PreferredDevice')]: + if chr(c) != '\x00': + block_file += chr(c) + self.media_path_combobox.addItem(block_file) elif sys.platform.startswith('darwin'): # Look for DVD folders in devices to find optical devices volumes = os.listdir('/Volumes') diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 626ef36c9..ca8690d75 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -428,6 +428,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): :return: Time string in format: hh.mm.ss,ttt """ seconds, millis = divmod(milliseconds, 1000) - minutes, seconds = divmod(millis, 60) + minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) return "%02d:%02d:%02d,%03d" % (hours, minutes, seconds, millis) From 2a1a93d319221f5335e7451d12b34400ae71e312 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 14 Jun 2014 23:48:07 +0200 Subject: [PATCH 19/44] Made it possible to name optical clips, and fixed some issues. --- openlp/core/ui/media/__init__.py | 23 ++++++-- openlp/core/ui/media/mediacontroller.py | 17 +++++- .../media/forms/mediaclipselectorform.py | 54 +++++++++++++++---- openlp/plugins/media/lib/mediaitem.py | 47 ++++++++-------- 4 files changed, 105 insertions(+), 36 deletions(-) diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 1d8ee3a4c..9248d03cf 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -110,6 +110,7 @@ def set_media_players(players_list, overridden_player='auto'): players = players.replace(overridden_player, '[%s]' % overridden_player) Settings().setValue('media/players', players) + def parse_optical_path(input): """ Split the optical path info. @@ -123,10 +124,24 @@ def parse_optical_path(input): subtitle_track = int(clip_info[3]) start = float(clip_info[4]) end = float(clip_info[5]) - filename = clip_info[6] - if len(clip_info) > 7: - filename += clip_info[7] - return filename, title, audio_track, subtitle_track, start, end + clip_name = clip_info[6] + filename = clip_info[7] + # Windows path usually contains a colon after the drive letter + if len(clip_info) > 8: + filename += clip_info[8] + return filename, title, audio_track, subtitle_track, start, end, clip_name + + +def format_milliseconds(milliseconds): + """ + Format milliseconds into a human readable time string. + :param milliseconds: Milliseconds to format + :return: Time string in format: hh.mm.ss,ttt + """ + seconds, millis = divmod(milliseconds, 1000) + minutes, seconds = divmod(seconds, 60) + hours, minutes = divmod(minutes, 60) + return "%02d:%02d:%02d,%03d" % (hours, minutes, seconds, millis) from .mediacontroller import MediaController from .playertab import PlayerTab diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index b25556e73..a62a9465c 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -373,7 +373,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): if service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and live') path = service_item.get_frame_path() - (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(path) + (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path) is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) else: @@ -392,7 +392,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): if service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and preview') path = service_item.get_frame_path() - (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(path) + (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path) is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) else: @@ -456,6 +456,19 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): return True def media_setup_optical(self, filename, title, audio_track, subtitle_track, start, end, display, controller): + """ + Setup playback of optical media + + :param filename: Path of the optical device/drive. + :param title: The main/title track to play. + :param audio_track: The audio track to play. + :param subtitle_track: The subtitle track to play. + :param start: Start position in miliseconds. + :param end: End position in miliseconds. + :param display: The display to play the media. + :param controller: The media contraoller. + :return: True if setup succeded else False. + """ log.debug('media_setup_optical') if controller is None: controller = self.display_controllers[DisplayControllerType.Plugin] diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 82b3cd9ea..06f583a3e 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -43,6 +43,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.common import translate from openlp.plugins.media.forms.mediaclipselectordialog import Ui_MediaClipSelector from openlp.core.lib.ui import critical_error_message_box +from openlp.core.ui.media import format_milliseconds try: from openlp.core.ui.media.vendor import vlc except (ImportError, NameError, NotImplementedError): @@ -156,7 +157,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): def detect_audio_cd(self, path): """ Detects is the given path is an audio CD - + :param path: Path to the device to be tested. :return: True if it was an audio CD else False. """ @@ -166,7 +167,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.play() # Wait for media to start playing. In this case VLC actually returns an error. self.media_state_wait(vlc.State.Playing) - self.vlc_media_player.pause() + self.vlc_media_player.set_pause(1) # If subitems exists, this is a CD self.audio_cd_tracks = self.vlc_media.subitems() if not self.audio_cd_tracks or self.audio_cd_tracks.count() < 1: @@ -231,7 +232,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): 'VLC player failed playing the media')) self.toggle_disable_load_media(False) return - self.vlc_media_player.pause() + self.vlc_media_player.set_pause(1) self.vlc_media_player.set_time(0) if not self.audio_cd: # Get titles, insert in combobox @@ -247,6 +248,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # Enable audio track combobox if anything is in it if len(titles) > 0: self.title_combo_box.setDisabled(False) + self.vlc_media_player.set_pause(1) self.toggle_disable_load_media(False) @QtCore.pyqtSlot(bool) @@ -367,7 +369,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if not self.media_state_wait(vlc.State.Playing): return # pause - self.vlc_media_player.pause() + self.vlc_media_player.set_pause(1) self.vlc_media_player.set_time(0) self.vlc_media_player.audio_set_mute(False) self.toggle_disable_player(False) @@ -379,7 +381,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if not self.media_state_wait(vlc.State.Playing): return # pause - self.vlc_media_player.pause() + self.vlc_media_player.set_pause(1) self.vlc_media_player.set_time(0) # Get audio tracks, insert in combobox audio_tracks = self.vlc_media_player.audio_get_track_description() @@ -520,12 +522,38 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): path = self.media_path_combobox.currentText() optical = '' if self.audio_cd: - optical = 'optical:' + str(title) + ':-1:-1:' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + path + optical = 'optical:' + str(title) + ':-1:-1:' + str(start_time_ms) + ':' + str(end_time_ms) + ':' else: audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str( - start_time_ms) + ':' + str(end_time_ms) + ':' + path + start_time_ms) + ':' + str(end_time_ms) + ':' + # Ask for an alternative name for the mediaclip + while True: + new_optical_name, ok = QtGui.QInputDialog.getText(self, translate('MediaPlugin.MediaClipSelectorForm', + 'Set name of mediaclip'), + translate('MediaPlugin.MediaClipSelectorForm', + 'Name of mediaclip:'), + QtGui.QLineEdit.Normal) + # User pressed cancel, don't save the clip + if not ok: + return + # User pressed ok, but the input text is blank + if not new_optical_name: + critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm', + 'Enter a valid name or cancel'), + translate('MediaPlugin.MediaClipSelectorForm', + 'Enter a valid name or cancel')) + # The entered new name contains a colon, which we don't allow because colons is used to seperate clip info + elif new_optical_name.find(':') >= 0: + critical_error_message_box(translate('MediaPlugin.MediaClipSelectorForm', 'Invalid character'), + translate('MediaPlugin.MediaClipSelectorForm', + 'The name of the mediaclip must not contain the character ":"')) + # New name entered and we use it + else: + break + # Append the new name to the optical string and the path + optical += new_optical_name + ':' + path self.media_item.add_optical_clip(optical) def media_state_wait(self, media_state): @@ -585,7 +613,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): log.debug('could not use udisks, will try udisks2') udev_manager_obj = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2') udev_manager = dbus.Interface(udev_manager_obj, 'org.freedesktop.DBus.ObjectManager') - for k,v in udev_manager.GetManagedObjects().items(): + for k, v in udev_manager.GetManagedObjects().items(): drive_info = v.get('org.freedesktop.UDisks2.Drive', {}) drive_props = drive_info.get('MediaCompatibility') if drive_props and any('optical' in prop for prop in drive_props): @@ -593,7 +621,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if dbus.String('org.freedesktop.UDisks2.Block') in device: if device[dbus.String('org.freedesktop.UDisks2.Block')][dbus.String('Drive')] == k: block_file = '' - for c in device[dbus.String('org.freedesktop.UDisks2.Block')][dbus.String('PreferredDevice')]: + for c in device[dbus.String('org.freedesktop.UDisks2.Block')][ + dbus.String('PreferredDevice')]: if chr(c) != '\x00': block_file += chr(c) self.media_path_combobox.addItem(block_file) @@ -605,5 +634,12 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if volume.startswith('.'): continue dirs = os.listdir('/Volumes/' + volume) + # Detect DVD if 'VIDEO_TS' in dirs: self.media_path_combobox.addItem('/Volumes/' + volume) + # Detect audio cd + files = [f for f in dirs if os.path.isfile(f)] + for file in files: + if file.endswith('aiff'): + self.media_path_combobox.addItem('/Volumes/' + volume) + break diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index ca8690d75..a47609ea1 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -39,7 +39,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, Servi build_icon, check_item_selected from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box from openlp.core.ui import DisplayController, Display, DisplayControllerType -from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path +from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path, format_milliseconds from openlp.core.utils import get_locale_key from openlp.core.ui.media.vlcplayer import VLC_AVAILABLE if VLC_AVAILABLE: @@ -125,9 +125,20 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ Adds buttons to the start of the header bar. """ - self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text='Load CD/DVD', - tooltip='Load CD/DVD', triggers=self.on_load_optical) - if not VLC_AVAILABLE: + print(get_media_players()[0]) + if 'vlc' in get_media_players()[0]: + diable_optical_button_text = False + optical_button_text = translate('MediaPlugin.MediaItem', 'Load CD/DVD') + optical_button_tooltip = translate('MediaPlugin.MediaItem', 'Load CD/DVD') + else: + diable_optical_button_text = True + optical_button_text = translate('MediaPlugin.MediaItem', 'Load CD/DVD') + optical_button_tooltip = translate('MediaPlugin.MediaItem', + 'Load CD/DVD - only supported when VLC is installed and enabled') + self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text=optical_button_text, + tooltip=optical_button_tooltip, + triggers=self.on_load_optical) + if diable_optical_button_text: self.load_optical.setDisabled(True) def add_end_header_bar(self): @@ -224,7 +235,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): filename = item.data(QtCore.Qt.UserRole) # Special handling if the filename is a optical clip if filename.startswith('optical:'): - (name, title, audio_track, subtitle_track, start, end) = parse_optical_path(filename) + (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(filename) if not os.path.exists(name): if not remote: # Optical disc is no longer present @@ -234,7 +245,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): return False service_item.processor = self.display_type_combo_box.currentText() service_item.add_from_command(filename, name, CLAPPERBOARD) - service_item.title = name + '@' + self.format_milliseconds(start) + '-' + self.format_milliseconds(end) + service_item.title = clip_name # Only set start and end times if going to a service #if context == ServiceItemContext.Service: # Set the length @@ -345,12 +356,11 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): track_info = QtCore.QFileInfo(track) if track.startswith('optical:'): # Handle optical based item - (file_name, title, audio_track, subtitle_track, start, end) = parse_optical_path(track) - optical = file_name + '@' + self.format_milliseconds(start) + '-' + self.format_milliseconds(end) - item_name = QtGui.QListWidgetItem(optical) + (file_name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(track) + item_name = QtGui.QListWidgetItem(clip_name) item_name.setIcon(OPTICAL_ICON) item_name.setData(QtCore.Qt.UserRole, track) - item_name.setToolTip(optical) + item_name.setToolTip(file_name + '@' + format_milliseconds(start) + '-' + format_milliseconds(end)) elif not os.path.exists(track): # File doesn't exist, mark as error. file_name = os.path.split(str(track))[1] @@ -417,17 +427,12 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): :param optical: The clip to add. """ full_list = self.get_file_list() + # If the clip already is in the media list it isn't added and an error message is displayed. + if optical in full_list: + critical_error_message_box(translate('MediaPlugin.MediaItem', 'Mediaclip already saved'), + translate('MediaPlugin.MediaItem', 'This mediaclip has already been saved')) + return + # Append the optical string to the media list full_list.append(optical) self.load_list([optical]) Settings().setValue(self.settings_section + '/media files', self.get_file_list()) - - def format_milliseconds(self, milliseconds): - """ - Format milliseconds into a human readable time string. - :param milliseconds: Milliseconds to format - :return: Time string in format: hh.mm.ss,ttt - """ - seconds, millis = divmod(milliseconds, 1000) - minutes, seconds = divmod(seconds, 60) - hours, minutes = divmod(minutes, 60) - return "%02d:%02d:%02d,%03d" % (hours, minutes, seconds, millis) From 346c9e475a68bdfd51850174caa646fc41318ee1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 15 Jun 2014 21:33:05 +0200 Subject: [PATCH 20/44] updated test --- tests/resources/serviceitem-dvd.osj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/serviceitem-dvd.osj b/tests/resources/serviceitem-dvd.osj index cda95e592..997dbd539 100644 --- a/tests/resources/serviceitem-dvd.osj +++ b/tests/resources/serviceitem-dvd.osj @@ -1 +1 @@ -[{"serviceitem": {"header": {"auto_play_slides_once": false, "data": "", "processor": "Automatic", "theme": -1, "theme_overwritten": false, "end_time": 672.069, "start_time": 654.375, "capabilities": [12, 18, 16, 4], "media_length": 17.694, "audit": "", "xml_version": null, "title": "/dev/sr0@00:06:15,375-00:01:09,069", "auto_play_slides_loop": false, "notes": "", "icon": ":/plugins/plugin_media.png", "type": 3, "background_audio": [], "plugin": "media", "from_plugin": false, "search": "", "will_auto_start": false, "name": "media", "footer": [], "timed_slide_interval": 0}, "data": [{"image": ":/media/slidecontroller_multimedia.png", "path": "optical:1:5:3:654375:672069:/dev/sr0", "title": "/dev/sr0"}]}}] +[{"serviceitem": {"header": {"auto_play_slides_once": false, "data": "", "processor": "Automatic", "theme": -1, "theme_overwritten": false, "end_time": 672.069, "start_time": 654.375, "capabilities": [12, 18, 16, 4], "media_length": 17.694, "audit": "", "xml_version": null, "title": "First DVD Clip", "auto_play_slides_loop": false, "notes": "", "icon": ":/plugins/plugin_media.png", "type": 3, "background_audio": [], "plugin": "media", "from_plugin": false, "search": "", "will_auto_start": false, "name": "media", "footer": [], "timed_slide_interval": 0}, "data": [{"image": ":/media/slidecontroller_multimedia.png", "path": "optical:1:5:3:654375:672069:First DVD Clip:/dev/sr0", "title": "/dev/sr0"}]}}] From 956af8706bde2fc24c4b4d92e3149947f7b56a56 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 17 Jun 2014 09:27:12 +0200 Subject: [PATCH 21/44] Small suggested changes --- openlp/core/lib/serviceitem.py | 2 +- openlp/core/ui/media/__init__.py | 1 + openlp/plugins/media/forms/mediaclipselectordialog.py | 9 +++++---- openlp/plugins/media/forms/mediaclipselectorform.py | 7 +++---- openlp/plugins/media/lib/mediaitem.py | 5 +---- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 6aba66252..ecd6ca5bd 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -645,4 +645,4 @@ class ServiceItem(RegistryProperties): file_suffix = frame['title'].split('.')[-1] if file_suffix.lower() not in suffix_list: self.is_valid = False - break \ No newline at end of file + break diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 9248d03cf..2c422dbd0 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -118,6 +118,7 @@ def parse_optical_path(input): :param input: The string to parse :return: The elements extracted from the string: filename, title, audio_track, subtitle_track, start, end """ + log.debug('parse_optical_path, about to parse: "%s"' % input) clip_info = input.split(sep=':') title = int(clip_info[1]) audio_track = int(clip_info[2]) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index beed9e8e3..ad23aa83e 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.common import translate + class Ui_MediaClipSelector(object): def setupUi(self, MediaClipSelector): MediaClipSelector.setObjectName("MediaClipSelector") @@ -165,7 +166,6 @@ class Ui_MediaClipSelector(object): self.position_horizontalslider.setInvertedAppearance(False) self.position_horizontalslider.setObjectName("position_horizontalslider") self.gridLayout.addWidget(self.position_horizontalslider, 6, 1, 1, 3) - #MediaClipSelector.setCentralWidget(self.centralwidget) self.retranslateUi(MediaClipSelector) QtCore.QMetaObject.connectSlotsByName(MediaClipSelector) @@ -189,11 +189,13 @@ class Ui_MediaClipSelector(object): MediaClipSelector.setWindowTitle(translate("MediaPlugin.MediaClipSelector", "Select media clip", None)) self.start_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) self.end_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) - self.set_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as start point", None)) + self.set_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", + "Set current position as start point", None)) self.load_disc_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Load disc", None)) self.end_point_label.setText(translate("MediaPlugin.MediaClipSelector", "End point", None)) self.title_label.setText(translate("MediaPlugin.MediaClipSelector", "Title", None)) - self.set_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Set current position as end point", None)) + self.set_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", + "Set current position as end point", None)) self.save_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Save current clip", None)) self.close_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Close", None)) self.start_point_label.setText(translate("MediaPlugin.MediaClipSelector", "Start point", None)) @@ -203,4 +205,3 @@ class Ui_MediaClipSelector(object): self.subtitle_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Subtitle track", None)) self.jump_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to end point", None)) self.media_path_label.setText(translate("MediaPlugin.MediaClipSelector", "Media path", None)) - diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 06f583a3e..045fb390d 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -196,7 +196,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.disable_all() path = self.media_path_combobox.currentText() # Check if given path is non-empty and exists before starting VLC - if path == '': + if not path: log.debug('no given path') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', 'No path was given')) self.toggle_disable_load_media(False) @@ -522,12 +522,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): path = self.media_path_combobox.currentText() optical = '' if self.audio_cd: - optical = 'optical:' + str(title) + ':-1:-1:' + str(start_time_ms) + ':' + str(end_time_ms) + ':' + optical = 'optical:%d:-1:-1:%d:%d:' % (title, start_time_ms, end_time_ms) else: audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) - optical = 'optical:' + str(title) + ':' + str(audio_track) + ':' + str(subtitle_track) + ':' + str( - start_time_ms) + ':' + str(end_time_ms) + ':' + optical = 'optical:%d:%d:%d:%d:%d:' % (title, audio_track, subtitle_track, start_time_ms, end_time_ms) # Ask for an alternative name for the mediaclip while True: new_optical_name, ok = QtGui.QInputDialog.getText(self, translate('MediaPlugin.MediaClipSelectorForm', diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index a47609ea1..5bdbe4d33 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -125,7 +125,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ Adds buttons to the start of the header bar. """ - print(get_media_players()[0]) if 'vlc' in get_media_players()[0]: diable_optical_button_text = False optical_button_text = translate('MediaPlugin.MediaItem', 'Load CD/DVD') @@ -246,8 +245,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): service_item.processor = self.display_type_combo_box.currentText() service_item.add_from_command(filename, name, CLAPPERBOARD) service_item.title = clip_name - # Only set start and end times if going to a service - #if context == ServiceItemContext.Service: # Set the length self.media_controller.media_setup_optical(name, title, audio_track, subtitle_track, start, end, None, None) service_item.set_media_length((end - start) / 1000) @@ -360,7 +357,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): item_name = QtGui.QListWidgetItem(clip_name) item_name.setIcon(OPTICAL_ICON) item_name.setData(QtCore.Qt.UserRole, track) - item_name.setToolTip(file_name + '@' + format_milliseconds(start) + '-' + format_milliseconds(end)) + item_name.setToolTip('%s@%s-%s' % (file_name, format_milliseconds(start), format_milliseconds(end))) elif not os.path.exists(track): # File doesn't exist, mark as error. file_name = os.path.split(str(track))[1] From 05f4f2d72e2fad9e63926d59762b97e9cc3f152e Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Mon, 30 Jun 2014 21:54:11 +0100 Subject: [PATCH 22/44] fixed tests --- tests/functional/openlp_core_lib/test_file_dialog.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_file_dialog.py b/tests/functional/openlp_core_lib/test_file_dialog.py index ab7663a83..875e422da 100644 --- a/tests/functional/openlp_core_lib/test_file_dialog.py +++ b/tests/functional/openlp_core_lib/test_file_dialog.py @@ -65,11 +65,11 @@ class TestFileDialog(TestCase): # THEN: os.path.exists should have been called with known args. QmessageBox.information should have been # called. The returned result should correlate with the input. - self.mocked_os.path.exists.assert_callde_with('/Valid File') - self.mocked_os.path.exists.assert_callde_with('/url%20encoded%20file%20%231') - self.mocked_os.path.exists.assert_callde_with('/url encoded file #1') - self.mocked_os.path.exists.assert_callde_with('/non-existing') - self.mocked_os.path.exists.assert_callde_with('/non-existing') + self.mocked_os.path.exists.assert_any_call('/Valid File') + self.mocked_os.path.exists.assert_any_call('/url%20encoded%20file%20%231') + self.mocked_os.path.exists.assert_any_call('/url encoded file #1') + self.mocked_os.path.exists.assert_any_call('/non-existing') + self.mocked_os.path.exists.assert_any_call('/non-existing') self.mocked_qt_gui.QmessageBox.information.called_with(self.mocked_parent, UiStrings().FileNotFound, UiStrings().FileNotFoundMessage % '/non-existing') self.assertEqual(result, ['/Valid File', '/url encoded file #1'], 'The returned file list is incorrect') From 9b6979b840f393a3f31f30213260147a68397c60 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Mon, 30 Jun 2014 21:59:22 +0100 Subject: [PATCH 23/44] Changed log.warn to log.warning --- openlp/core/lib/toolbar.py | 2 +- openlp/core/lib/ui.py | 6 +++--- openlp/core/ui/media/mediacontroller.py | 2 +- openlp/core/utils/actions.py | 4 ++-- .../plugins/bibles/forms/bibleupgradeform.py | 12 ++++++------ openlp/plugins/bibles/lib/http.py | 4 ++-- openlp/plugins/bibles/lib/opensong.py | 2 +- .../presentations/lib/impresscontroller.py | 18 +++++++++--------- .../presentations/lib/messagelistener.py | 4 ++-- .../presentations/presentationplugin.py | 4 ++-- openlp/plugins/songs/lib/songshowplusimport.py | 2 +- .../songs/lib/worshipcenterproimport.py | 2 +- 12 files changed, 31 insertions(+), 31 deletions(-) diff --git a/openlp/core/lib/toolbar.py b/openlp/core/lib/toolbar.py index b1cc7b249..b24be89a8 100644 --- a/openlp/core/lib/toolbar.py +++ b/openlp/core/lib/toolbar.py @@ -81,4 +81,4 @@ class OpenLPToolbar(QtGui.QToolBar): if handle in self.actions: self.actions[handle].setVisible(visible) else: - log.warn('No handle "%s" in actions list.', str(handle)) + log.warning('No handle "%s" in actions list.', str(handle)) diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index a1e37abcf..cbc35e28d 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -172,7 +172,7 @@ def create_button(parent, name, **kwargs): kwargs.setdefault('icon', ':/services/service_down.png') kwargs.setdefault('tooltip', translate('OpenLP.Ui', 'Move selection down one position.')) else: - log.warn('The role "%s" is not defined in create_push_button().', role) + log.warning('The role "%s" is not defined in create_push_button().', role) if kwargs.pop('btn_class', '') == 'toolbutton': button = QtGui.QToolButton(parent) else: @@ -190,7 +190,7 @@ def create_button(parent, name, **kwargs): button.clicked.connect(kwargs.pop('click')) for key in list(kwargs.keys()): if key not in ['text', 'icon', 'tooltip', 'click']: - log.warn('Parameter %s was not consumed in create_button().', key) + log.warning('Parameter %s was not consumed in create_button().', key) return button @@ -275,7 +275,7 @@ def create_action(parent, name, **kwargs): action.triggered.connect(kwargs.pop('triggers')) for key in list(kwargs.keys()): if key not in ['text', 'icon', 'tooltip', 'statustip', 'checked', 'can_shortcuts', 'category', 'triggers']: - log.warn('Parameter %s was not consumed in create_action().' % key) + log.warning('Parameter %s was not consumed in create_action().' % key) return action diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 596b618cb..f086b80b2 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -175,7 +175,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): # On some platforms importing vlc.py might cause # also OSError exceptions. (e.g. Mac OS X) except (ImportError, OSError): - log.warn('Failed to import %s on path %s', module_name, path) + log.warning('Failed to import %s on path %s', module_name, path) player_classes = MediaPlayer.__subclasses__() for player_class in player_classes: player = player_class(self) diff --git a/openlp/core/utils/actions.py b/openlp/core/utils/actions.py index d81e16b2e..fb794866b 100644 --- a/openlp/core/utils/actions.py +++ b/openlp/core/utils/actions.py @@ -279,7 +279,7 @@ class ActionList(object): actions.append(action) ActionList.shortcut_map[shortcuts[1]] = actions else: - log.warn('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' % + log.warning('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' % (shortcuts[1], action.objectName())) shortcuts.remove(shortcuts[1]) # Check the primary shortcut. @@ -290,7 +290,7 @@ class ActionList(object): actions.append(action) ActionList.shortcut_map[shortcuts[0]] = actions else: - log.warn('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' % + log.warning('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' % (shortcuts[0], action.objectName())) shortcuts.remove(shortcuts[0]) action.setShortcuts([QtGui.QKeySequence(shortcut) for shortcut in shortcuts]) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 09c0942b7..2b0b57695 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -423,7 +423,7 @@ class BibleUpgradeForm(OpenLPWizard): else: language_id = self.new_bibles[number].get_language(name) if not language_id: - log.warn('Upgrading from "%s" failed' % filename[0]) + log.warning('Upgrading from "%s" failed' % filename[0]) self.new_bibles[number].session.close() del self.new_bibles[number] self.increment_progress_bar( @@ -444,7 +444,7 @@ class BibleUpgradeForm(OpenLPWizard): book_ref_id = self.new_bibles[number].\ get_book_ref_id_by_name(book, len(books), language_id) if not book_ref_id: - log.warn('Upgrading books from %s - download name: "%s" aborted by user' % ( + log.warning('Upgrading books from %s - download name: "%s" aborted by user' % ( meta_data['download_source'], meta_data['download_name'])) self.new_bibles[number].session.close() del self.new_bibles[number] @@ -457,7 +457,7 @@ class BibleUpgradeForm(OpenLPWizard): if oldbook: verses = old_bible.get_verses(oldbook['id']) if not verses: - log.warn('No verses found to import for book "%s"', book) + log.warning('No verses found to import for book "%s"', book) continue for verse in verses: if self.stop_import_flag: @@ -472,7 +472,7 @@ class BibleUpgradeForm(OpenLPWizard): if not language_id: language_id = self.new_bibles[number].get_language(name) if not language_id: - log.warn('Upgrading books from "%s" failed' % name) + log.warning('Upgrading books from "%s" failed' % name) self.new_bibles[number].session.close() del self.new_bibles[number] self.increment_progress_bar( @@ -493,7 +493,7 @@ class BibleUpgradeForm(OpenLPWizard): (number + 1, max_bibles, name, book['name'])) book_ref_id = self.new_bibles[number].get_book_ref_id_by_name(book['name'], len(books), language_id) if not book_ref_id: - log.warn('Upgrading books from %s " failed - aborted by user' % name) + log.warning('Upgrading books from %s " failed - aborted by user' % name) self.new_bibles[number].session.close() del self.new_bibles[number] self.success[number] = False @@ -503,7 +503,7 @@ class BibleUpgradeForm(OpenLPWizard): book_details['testament_id']) verses = old_bible.get_verses(book['id']) if not verses: - log.warn('No verses found to import for book "%s"', book['name']) + log.warning('No verses found to import for book "%s"', book['name']) self.new_bibles[number].delete_book(db_book) continue for verse in verses: diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 64b024639..8be0dbb5f 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -165,7 +165,7 @@ class BGExtract(RegistryProperties): if len(verse_parts) > 1: verse = int(verse_parts[0]) except TypeError: - log.warn('Illegal verse number: %s', str(verse)) + log.warning('Illegal verse number: %s', str(verse)) verses.append((verse, text)) verse_list = {} for verse, text in verses[::-1]: @@ -198,7 +198,7 @@ class BGExtract(RegistryProperties): if len(verse_parts) > 1: clean_verse_num = int(verse_parts[0]) except TypeError: - log.warn('Illegal verse number: %s', str(raw_verse_num)) + log.warning('Illegal verse number: %s', str(raw_verse_num)) if clean_verse_num: verse_text = raw_verse_num.next_element part = raw_verse_num.next_element.next_element diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index fa8323d7f..ecd1f718e 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -123,7 +123,7 @@ class OpenSongBible(BibleDB): if len(verse_parts) > 1: number = int(verse_parts[0]) except TypeError: - log.warn('Illegal verse number: %s', str(verse.attrib['n'])) + log.warning('Illegal verse number: %s', str(verse.attrib['n'])) verse_number = number else: verse_number += 1 diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 584c1401f..1d5e111c9 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -129,7 +129,7 @@ class ImpressController(PresentationController): try: uno_instance = get_uno_instance(resolver) except: - log.warn('Unable to find running instance ') + log.warning('Unable to find running instance ') self.start_process() loop += 1 try: @@ -138,7 +138,7 @@ class ImpressController(PresentationController): desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance) return desktop except: - log.warn('Failed to get UNO desktop') + log.warning('Failed to get UNO desktop') return None def get_com_desktop(self): @@ -152,7 +152,7 @@ class ImpressController(PresentationController): try: desktop = self.manager.createInstance('com.sun.star.frame.Desktop') except (AttributeError, pywintypes.com_error): - log.warn('Failure to find desktop - Impress may have closed') + log.warning('Failure to find desktop - Impress may have closed') return desktop if desktop else None def get_com_servicemanager(self): @@ -163,7 +163,7 @@ class ImpressController(PresentationController): try: return Dispatch('com.sun.star.ServiceManager') except pywintypes.com_error: - log.warn('Failed to get COM service manager. Impress Controller has been disabled') + log.warning('Failed to get COM service manager. Impress Controller has been disabled') return None def kill(self): @@ -180,7 +180,7 @@ class ImpressController(PresentationController): else: desktop = self.get_com_desktop() except: - log.warn('Failed to find an OpenOffice desktop to terminate') + log.warning('Failed to find an OpenOffice desktop to terminate') if not desktop: return docs = desktop.getComponents() @@ -198,7 +198,7 @@ class ImpressController(PresentationController): desktop.terminate() log.debug('OpenOffice killed') except: - log.warn('Failed to terminate OpenOffice') + log.warning('Failed to terminate OpenOffice') class ImpressDocument(PresentationDocument): @@ -244,7 +244,7 @@ class ImpressDocument(PresentationDocument): try: self.document = desktop.loadComponentFromURL(url, '_blank', 0, properties) except: - log.warn('Failed to load presentation %s' % url) + log.warning('Failed to load presentation %s' % url) return False if os.name == 'nt': # As we can't start minimized the Impress window gets in the way. @@ -318,7 +318,7 @@ class ImpressDocument(PresentationDocument): self.presentation = None self.document.dispose() except: - log.warn("Closing presentation failed") + log.warning("Closing presentation failed") self.document = None self.controller.remove_doc(self) @@ -335,7 +335,7 @@ class ImpressDocument(PresentationDocument): log.debug("getPresentation failed to find a presentation") return False except: - log.warn("getPresentation failed to find a presentation") + log.warning("getPresentation failed to find a presentation") return False return True diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 724282eb4..ac115228a 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -98,7 +98,7 @@ class Controller(object): return True if not self.doc.is_loaded(): if not self.doc.load_presentation(): - log.warn('Failed to activate %s' % self.doc.filepath) + log.warning('Failed to activate %s' % self.doc.filepath) return False if self.is_live: self.doc.start_presentation() @@ -109,7 +109,7 @@ class Controller(object): if self.doc.is_active(): return True else: - log.warn('Failed to activate %s' % self.doc.filepath) + log.warning('Failed to activate %s' % self.doc.filepath) return False def slide(self, slide): diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index 5e0d7395d..7f080df22 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -90,7 +90,7 @@ class PresentationPlugin(Plugin): try: self.controllers[controller].start_process() except Exception: - log.warn('Failed to start controller process') + log.warning('Failed to start controller process') self.controllers[controller].available = False self.media_item.build_file_mask_string() @@ -134,7 +134,7 @@ class PresentationPlugin(Plugin): try: __import__(module_name, globals(), locals(), []) except ImportError: - log.warn('Failed to import %s on path %s', module_name, path) + log.warning('Failed to import %s on path %s', module_name, path) controller_classes = PresentationController.__subclasses__() for controller_class in controller_classes: controller = controller_class(self) diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py index aebded029..b57a9bac1 100644 --- a/openlp/plugins/songs/lib/songshowplusimport.py +++ b/openlp/plugins/songs/lib/songshowplusimport.py @@ -152,7 +152,7 @@ class SongShowPlusImport(SongImport): if match: self.ccli_number = int(match.group()) else: - log.warn("Can't parse CCLI Number from string: %s" % self.decode(data)) + log.warning("Can't parse CCLI Number from string: %s" % self.decode(data)) elif block_key == VERSE: self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Verse], verse_no)) elif block_key == CHORUS: diff --git a/openlp/plugins/songs/lib/worshipcenterproimport.py b/openlp/plugins/songs/lib/worshipcenterproimport.py index b24d2ae83..8c32870a1 100644 --- a/openlp/plugins/songs/lib/worshipcenterproimport.py +++ b/openlp/plugins/songs/lib/worshipcenterproimport.py @@ -58,7 +58,7 @@ class WorshipCenterProImport(SongImport): try: conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s' % self.import_source) except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e: - log.warn('Unable to connect the WorshipCenter Pro database %s. %s', self.import_source, str(e)) + log.warning('Unable to connect the WorshipCenter Pro database %s. %s', self.import_source, str(e)) # Unfortunately no specific exception type self.log_error(self.import_source, translate('SongsPlugin.WorshipCenterProImport', 'Unable to connect the WorshipCenter Pro database.')) From 154334a33259a68784c8bd011d85e556a6f59f44 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 1 Jul 2014 19:48:36 +0200 Subject: [PATCH 24/44] Fix for dvd loading --- openlp/plugins/media/forms/mediaclipselectorform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 045fb390d..c27a60f64 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -207,7 +207,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): 'Given path does not exists')) self.toggle_disable_load_media(False) return - self.vlc_media = self.vlc_instance.media_new_location(path) + self.vlc_media = self.vlc_instance.media_new_location('file://' + path) if not self.vlc_media: log.debug('vlc media player is none') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', From 3c91a6bbfd45714ebe617a5446e2063112c21291 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 1 Jul 2014 22:06:55 +0200 Subject: [PATCH 25/44] Fixed seeking when playing mediaclip --- openlp/core/ui/media/vlcplayer.py | 18 ++++++++++++++---- .../media/forms/mediaclipselectordialog.py | 1 - 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 0c6d91078..8c957ea1d 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -246,10 +246,12 @@ class VlcPlayer(MediaPlayer): if controller.media_info.start_time > 0: log.debug('vlc play, starttime set: ' + str(controller.media_info.start_time)) start_time = controller.media_info.start_time + controller.media_info.length = controller.media_info.end_time - controller.media_info.start_time + else: + controller.media_info.length = int(display.vlc_media_player.get_media().get_duration() / 1000) self.volume(display, controller.media_info.volume) - if start_time > 0: - self.seek(display, int(start_time * 1000)) - controller.media_info.length = int(display.vlc_media_player.get_media().get_duration() / 1000) + if start_time > 0 and display.vlc_media_player.is_seekable(): + display.vlc_media_player.set_time(int(start_time * 1000)) controller.seek_slider.setMaximum(controller.media_info.length * 1000) self.state = MediaState.Playing display.vlc_widget.raise_() @@ -283,6 +285,9 @@ class VlcPlayer(MediaPlayer): """ Go to a particular position """ + if display.controller.media_info.media_type == MediaType.CD \ + or display.controller.media_info.media_type == MediaType.DVD: + seek_value += int(display.controller.media_info.start_time * 1000) if display.vlc_media_player.is_seekable(): display.vlc_media_player.set_time(seek_value) @@ -315,7 +320,12 @@ class VlcPlayer(MediaPlayer): self.set_visible(display, False) if not controller.seek_slider.isSliderDown(): controller.seek_slider.blockSignals(True) - controller.seek_slider.setSliderPosition(display.vlc_media_player.get_time()) + if display.controller.media_info.media_type == MediaType.CD \ + or display.controller.media_info.media_type == MediaType.DVD: + controller.seek_slider.setSliderPosition(display.vlc_media_player.get_time() - + int(display.controller.media_info.start_time * 1000)) + else: + controller.seek_slider.setSliderPosition(display.vlc_media_player.get_time()) controller.seek_slider.blockSignals(False) def get_info(self): diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index ad23aa83e..225be5cb0 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -166,7 +166,6 @@ class Ui_MediaClipSelector(object): self.position_horizontalslider.setInvertedAppearance(False) self.position_horizontalslider.setObjectName("position_horizontalslider") self.gridLayout.addWidget(self.position_horizontalslider, 6, 1, 1, 3) - self.retranslateUi(MediaClipSelector) QtCore.QMetaObject.connectSlotsByName(MediaClipSelector) MediaClipSelector.setTabOrder(self.media_path_combobox, self.load_disc_pushbutton) From 6f7f3be3ffa2c158742a6420a6010a86c49085de Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 3 Jul 2014 09:09:55 +0200 Subject: [PATCH 26/44] Fix optical drive detection on windows --- .../media/forms/mediaclipselectorform.py | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index c27a60f64..7216891a8 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -29,7 +29,7 @@ import os if os.name == 'nt': - from ctypes import windll + from win32com.client import Dispatch import string import sys if sys.platform.startswith('linux'): @@ -581,18 +581,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # insert empty string as first item self.media_path_combobox.addItem('') if os.name == 'nt': - # use win api to fine optical drives - bitmask = windll.kernel32.GetLogicalDrives() - for letter in string.uppercase: - if bitmask & 1: - try: - type = windll.kernel32.GetDriveTypeW('%s:\\' % letter) - # if type is 5, it is a cd-rom drive - if type == 5: - self.media_path_combobox.addItem('%s:\\' % letter) - except Exception as e: - log.debug('Exception while looking for optical drives: ', e) - bitmask >>= 1 + # use win api to find optical drives + fso = Dispatch('scripting.filesystemobject') + for drive in fso.Drives : + log.debug('Drive %s has type %d' % (drive.DriveLetter, drive.DriveType)) + # if type is 4, it is a cd-rom drive + if drive.DriveType == 4: + self.media_path_combobox.addItem('%s:\\' % drive.DriveLetter) elif sys.platform.startswith('linux'): # Get disc devices from dbus and find the ones that are optical bus = dbus.SystemBus() From d19e7bf3aa50015d4a2408e5690f87f9e50d692b Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 3 Jul 2014 11:27:54 +0200 Subject: [PATCH 27/44] Fix disc loading for windows --- openlp/plugins/media/forms/mediaclipselectordialog.py | 2 ++ openlp/plugins/media/forms/mediaclipselectorform.py | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index 225be5cb0..a25c0badb 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -204,3 +204,5 @@ class Ui_MediaClipSelector(object): self.subtitle_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Subtitle track", None)) self.jump_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to end point", None)) self.media_path_label.setText(translate("MediaPlugin.MediaClipSelector", "Media path", None)) + self.media_path_combobox.lineEdit().setPlaceholderText(translate("MediaPlugin.MediaClipSelector", + "Select drive from list", None)) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 7216891a8..8620ab9a9 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -35,6 +35,7 @@ import sys if sys.platform.startswith('linux'): import dbus import logging +import re from datetime import datetime @@ -207,7 +208,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): 'Given path does not exists')) self.toggle_disable_load_media(False) return - self.vlc_media = self.vlc_instance.media_new_location('file://' + path) + # If on windows fix path for VLC use + if os.name == 'nt': + # If the given path is in the format "D:\" or "D:", prefix it with "/" to make VLC happy + pattern = re.compile('^\w:\\\\*$') + if pattern.match(path): + path = '/' + path + self.vlc_media = self.vlc_instance.media_new_location('dvd://' + path) if not self.vlc_media: log.debug('vlc media player is none') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', @@ -583,7 +590,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if os.name == 'nt': # use win api to find optical drives fso = Dispatch('scripting.filesystemobject') - for drive in fso.Drives : + for drive in fso.Drives: log.debug('Drive %s has type %d' % (drive.DriveLetter, drive.DriveType)) # if type is 4, it is a cd-rom drive if drive.DriveType == 4: From 8a545ceaf77c01b4f8d72f5a7518186c9c0f4f06 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 3 Jul 2014 16:19:11 +0200 Subject: [PATCH 28/44] Try to fix some timing issues --- .../media/forms/mediaclipselectorform.py | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 8620ab9a9..b35f5ad1b 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -32,10 +32,12 @@ if os.name == 'nt': from win32com.client import Dispatch import string import sys + if sys.platform.startswith('linux'): import dbus import logging import re +from time import sleep from datetime import datetime @@ -239,6 +241,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): 'VLC player failed playing the media')) self.toggle_disable_load_media(False) return + # Sleep 1 second to make sure VLC has the needed metadata + self.vlc_media_player.audio_set_mute(True) + sleep(1) self.vlc_media_player.set_pause(1) self.vlc_media_player.set_time(0) if not self.audio_cd: @@ -257,6 +262,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.title_combo_box.setDisabled(False) self.vlc_media_player.set_pause(1) self.toggle_disable_load_media(False) + log.debug('leaving on_load_disc_pushbutton_clicked, vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(bool) def on_play_pushbutton_clicked(self, clicked): @@ -366,30 +372,37 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ log.debug('in on_title_combo_box_changed, index: %d', index) if not self.vlc_media_player: + log.error('vlc_media_player was None') return if self.audio_cd: self.vlc_media = self.audio_cd_tracks.item_at_index(index) self.vlc_media_player.set_media(self.vlc_media) self.vlc_media_player.set_time(0) self.vlc_media_player.play() - self.vlc_media_player.audio_set_mute(True) if not self.media_state_wait(vlc.State.Playing): + log.error('Could not start playing audio cd, needed to get track info') return + self.vlc_media_player.audio_set_mute(True) + # Sleep 1 second to make sure VLC has the needed metadata + sleep(1) # pause - self.vlc_media_player.set_pause(1) self.vlc_media_player.set_time(0) + self.vlc_media_player.set_pause(1) self.vlc_media_player.audio_set_mute(False) self.toggle_disable_player(False) else: self.vlc_media_player.set_title(index) self.vlc_media_player.set_time(0) self.vlc_media_player.play() - self.vlc_media_player.audio_set_mute(True) if not self.media_state_wait(vlc.State.Playing): + log.error('Could not start playing dvd, needed to get track info') return + self.vlc_media_player.audio_set_mute(True) + # Sleep 1 second to make sure VLC has the needed metadata + sleep(1) # pause - self.vlc_media_player.set_pause(1) self.vlc_media_player.set_time(0) + self.vlc_media_player.set_pause(1) # Get audio tracks, insert in combobox audio_tracks = self.vlc_media_player.audio_get_track_description() self.audio_tracks_combobox.clear() @@ -415,6 +428,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.toggle_disable_player(False) # Set media length info self.playback_length = self.vlc_media_player.get_length() + log.debug('playback_length: %d ms' % self.playback_length) self.position_horizontalslider.setMaximum(self.playback_length) # setup start and end time rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0) @@ -423,6 +437,10 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.start_timeedit.setMaximumTime(playback_length_time) self.end_timeedit.setMaximumTime(playback_length_time) self.end_timeedit.setTime(playback_length_time) + # Pause once again, just to make sure + self.vlc_media_player.set_time(0) + self.vlc_media_player.set_pause(1) + log.debug('leaving on_title_combo_box_currentIndexChanged, vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(int) def on_audio_tracks_combobox_currentIndexChanged(self, index): @@ -574,7 +592,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): while media_state != self.vlc_media_player.get_state(): if self.vlc_media_player.get_state() == vlc.State.Error: return False - if (datetime.now() - start).seconds > 15: + if (datetime.now() - start).seconds > 30: return False return True @@ -585,8 +603,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ # Clear list first self.media_path_combobox.clear() - # insert empty string as first item - self.media_path_combobox.addItem('') if os.name == 'nt': # use win api to find optical drives fso = Dispatch('scripting.filesystemobject') From 9d87fa46ca3791b181fc50d0f379126ba59e15cb Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 3 Jul 2014 20:43:35 +0200 Subject: [PATCH 29/44] Try to fix playing-when-loading --- openlp/plugins/media/forms/mediaclipselectorform.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index b35f5ad1b..77cd72c25 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -260,9 +260,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # Enable audio track combobox if anything is in it if len(titles) > 0: self.title_combo_box.setDisabled(False) - self.vlc_media_player.set_pause(1) self.toggle_disable_load_media(False) - log.debug('leaving on_load_disc_pushbutton_clicked, vlc_media_player state: %s' % self.vlc_media_player.get_state()) + log.debug('load_disc_pushbutton end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(bool) def on_play_pushbutton_clicked(self, clicked): @@ -438,9 +437,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.end_timeedit.setMaximumTime(playback_length_time) self.end_timeedit.setTime(playback_length_time) # Pause once again, just to make sure - self.vlc_media_player.set_time(0) - self.vlc_media_player.set_pause(1) - log.debug('leaving on_title_combo_box_currentIndexChanged, vlc_media_player state: %s' % self.vlc_media_player.get_state()) + loop_count = 0 + while self.vlc_media_player.get_state() == vlc.State.Playing and loop_count < 20: + sleep(0.1) + self.vlc_media_player.set_pause(1) + log.debug('title_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(int) def on_audio_tracks_combobox_currentIndexChanged(self, index): From 33e104d57d7fc82512ae91b0c8e2d712d0910519 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 4 Jul 2014 10:45:17 +0200 Subject: [PATCH 30/44] Tried to fix some linux vs windows issues. Also added a test. --- openlp/core/ui/media/__init__.py | 2 +- .../media/forms/mediaclipselectorform.py | 7 ++- tests/functional/openlp_core_ui/test_media.py | 58 ++++++++++++++++++- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 2c422dbd0..a44604d2f 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -129,7 +129,7 @@ def parse_optical_path(input): filename = clip_info[7] # Windows path usually contains a colon after the drive letter if len(clip_info) > 8: - filename += clip_info[8] + filename += ':' + clip_info[8] return filename, title, audio_track, subtitle_track, start, end, clip_name diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 77cd72c25..11a92d9d2 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -210,13 +210,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): 'Given path does not exists')) self.toggle_disable_load_media(False) return - # If on windows fix path for VLC use + # VLC behaves a bit differently on windows and linux when loading, which creates problems when trying to + # detect if we're dealing with a DVD or CD, so we use different loading approaches depending on the OS. if os.name == 'nt': # If the given path is in the format "D:\" or "D:", prefix it with "/" to make VLC happy pattern = re.compile('^\w:\\\\*$') if pattern.match(path): path = '/' + path - self.vlc_media = self.vlc_instance.media_new_location('dvd://' + path) + self.vlc_media = self.vlc_instance.media_new_location('dvd://' + path) + else: + self.vlc_media = self.vlc_instance.media_new_path(path) if not self.vlc_media: log.debug('vlc media player is none') critical_error_message_box(message=translate('MediaPlugin.MediaClipSelectorForm', diff --git a/tests/functional/openlp_core_ui/test_media.py b/tests/functional/openlp_core_ui/test_media.py index 4c6fa7f86..fbb5787c0 100644 --- a/tests/functional/openlp_core_ui/test_media.py +++ b/tests/functional/openlp_core_ui/test_media.py @@ -32,7 +32,7 @@ Package to test the openlp.core.ui package. from PyQt4 import QtCore from unittest import TestCase -from openlp.core.ui.media import get_media_players +from openlp.core.ui.media import get_media_players, parse_optical_path from tests.functional import MagicMock, patch from tests.helpers.testmixin import TestMixin @@ -126,3 +126,59 @@ class TestMedia(TestCase, TestMixin): # THEN: the used_players should be an empty list, and the overridden player should be an empty string self.assertEqual(['vlc', 'webkit', 'phonon'], used_players, 'Used players should be correct') self.assertEqual('vlc,webkit,phonon', overridden_player, 'Overridden player should be a string of players') + + def test_parse_optical_path_linux(self): + """ + Test that test_parse_optical_path() parses a optical path with linux device path correctly + """ + + # GIVEN: An optical formatted path + org_title_track = 1 + org_audio_track = 2 + org_subtitle_track = -1 + org_start = 1234 + org_end = 4321 + org_name = 'test name' + org_device_path = '/dev/dvd' + path = 'optical:%d:%d:%d:%d:%d:%s:%s' % (org_title_track, org_audio_track, org_subtitle_track, + org_start, org_end, org_name, org_device_path) + + # WHEN: parsing the path + (device_path, title_track, audio_track, subtitle_track, start, end, name) = parse_optical_path(path) + + # THEN: The return values should match the original values + self.assertEqual(org_title_track, title_track, 'Returned title_track should match the original') + self.assertEqual(org_audio_track, audio_track, 'Returned audio_track should match the original') + self.assertEqual(org_subtitle_track, subtitle_track, 'Returned subtitle_track should match the original') + self.assertEqual(org_start, start, 'Returned start should match the original') + self.assertEqual(org_end, end, 'Returned end should match the original') + self.assertEqual(org_name, name, 'Returned end should match the original') + self.assertEqual(org_device_path, device_path, 'Returned device_path should match the original') + + def test_parse_optical_path_win(self): + """ + Test that test_parse_optical_path() parses a optical path with windows device path correctly + """ + + # GIVEN: An optical formatted path + org_title_track = 1 + org_audio_track = 2 + org_subtitle_track = -1 + org_start = 1234 + org_end = 4321 + org_name = 'test name' + org_device_path = 'D:' + path = 'optical:%d:%d:%d:%d:%d:%s:%s' % (org_title_track, org_audio_track, org_subtitle_track, + org_start, org_end, org_name, org_device_path) + + # WHEN: parsing the path + (device_path, title_track, audio_track, subtitle_track, start, end, name) = parse_optical_path(path) + + # THEN: The return values should match the original values + self.assertEqual(org_title_track, title_track, 'Returned title_track should match the original') + self.assertEqual(org_audio_track, audio_track, 'Returned audio_track should match the original') + self.assertEqual(org_subtitle_track, subtitle_track, 'Returned subtitle_track should match the original') + self.assertEqual(org_start, start, 'Returned start should match the original') + self.assertEqual(org_end, end, 'Returned end should match the original') + self.assertEqual(org_name, name, 'Returned end should match the original') + self.assertEqual(org_device_path, device_path, 'Returned device_path should match the original') From 32ff9cdeb736724caaac2e95ae79d81bdc4a3b29 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 6 Jul 2014 21:48:23 +0200 Subject: [PATCH 31/44] Patch by Samuel --- openlp/plugins/media/forms/mediaclipselectorform.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 11a92d9d2..13bad606c 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -246,9 +246,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): return # Sleep 1 second to make sure VLC has the needed metadata self.vlc_media_player.audio_set_mute(True) - sleep(1) - self.vlc_media_player.set_pause(1) - self.vlc_media_player.set_time(0) + #sleep(1) + #self.vlc_media_player.set_pause(1) + #self.vlc_media_player.set_time(0) if not self.audio_cd: # Get titles, insert in combobox titles = self.vlc_media_player.video_get_title_description() @@ -401,10 +401,10 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): return self.vlc_media_player.audio_set_mute(True) # Sleep 1 second to make sure VLC has the needed metadata - sleep(1) + #sleep(1) # pause self.vlc_media_player.set_time(0) - self.vlc_media_player.set_pause(1) + #self.vlc_media_player.set_pause(1) # Get audio tracks, insert in combobox audio_tracks = self.vlc_media_player.audio_get_track_description() self.audio_tracks_combobox.clear() @@ -444,6 +444,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): while self.vlc_media_player.get_state() == vlc.State.Playing and loop_count < 20: sleep(0.1) self.vlc_media_player.set_pause(1) + loop_count += 1 log.debug('title_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(int) From bec0071e7c22694fbf737cc734289e8a64db091d Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 7 Jul 2014 13:30:03 +0200 Subject: [PATCH 32/44] Small adjustments --- openlp/plugins/media/forms/mediaclipselectorform.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 13bad606c..51063ffbd 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -244,11 +244,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): 'VLC player failed playing the media')) self.toggle_disable_load_media(False) return - # Sleep 1 second to make sure VLC has the needed metadata self.vlc_media_player.audio_set_mute(True) - #sleep(1) - #self.vlc_media_player.set_pause(1) - #self.vlc_media_player.set_time(0) if not self.audio_cd: # Get titles, insert in combobox titles = self.vlc_media_player.video_get_title_description() @@ -401,10 +397,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): return self.vlc_media_player.audio_set_mute(True) # Sleep 1 second to make sure VLC has the needed metadata - #sleep(1) - # pause + sleep(1) self.vlc_media_player.set_time(0) - #self.vlc_media_player.set_pause(1) # Get audio tracks, insert in combobox audio_tracks = self.vlc_media_player.audio_get_track_description() self.audio_tracks_combobox.clear() @@ -425,6 +419,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if len(subtitles_tracks) > 0: self.subtitle_tracks_combobox.setDisabled(False) self.vlc_media_player.audio_set_mute(False) + self.vlc_media_player.set_pause(1) # If a title or audio track is available the player is enabled if self.title_combo_box.count() > 0 or len(audio_tracks) > 0: self.toggle_disable_player(False) From 67ab5082862cda6f248f0c0f7cf3078e760bd679 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Sun, 20 Jul 2014 21:00:06 +0100 Subject: [PATCH 33/44] Tweeked test to use a call list --- tests/functional/openlp_core_lib/test_file_dialog.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_file_dialog.py b/tests/functional/openlp_core_lib/test_file_dialog.py index 875e422da..1190810da 100644 --- a/tests/functional/openlp_core_lib/test_file_dialog.py +++ b/tests/functional/openlp_core_lib/test_file_dialog.py @@ -5,7 +5,7 @@ from unittest import TestCase from openlp.core.common import UiStrings from openlp.core.lib.filedialog import FileDialog -from tests.functional import MagicMock, patch +from tests.functional import MagicMock, call, patch class TestFileDialog(TestCase): @@ -65,11 +65,9 @@ class TestFileDialog(TestCase): # THEN: os.path.exists should have been called with known args. QmessageBox.information should have been # called. The returned result should correlate with the input. - self.mocked_os.path.exists.assert_any_call('/Valid File') - self.mocked_os.path.exists.assert_any_call('/url%20encoded%20file%20%231') - self.mocked_os.path.exists.assert_any_call('/url encoded file #1') - self.mocked_os.path.exists.assert_any_call('/non-existing') - self.mocked_os.path.exists.assert_any_call('/non-existing') + call_list = [call('/Valid File'), call('/url%20encoded%20file%20%231'), call('/url encoded file #1'), + call('/non-existing'), call('/non-existing')] + self.mocked_os.path.exists.assert_has_calls(call_list) self.mocked_qt_gui.QmessageBox.information.called_with(self.mocked_parent, UiStrings().FileNotFound, UiStrings().FileNotFoundMessage % '/non-existing') self.assertEqual(result, ['/Valid File', '/url encoded file #1'], 'The returned file list is incorrect') From 4e6561b9c210fe56f403f678f6d2b5423aaeea6f Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 20 Aug 2014 22:09:07 +0200 Subject: [PATCH 35/44] Minor syntactic sugar --- openlp/plugins/media/forms/mediaclipselectordialog.py | 2 +- openlp/plugins/media/forms/mediaclipselectorform.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index a25c0badb..2721836fe 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -167,7 +167,7 @@ class Ui_MediaClipSelector(object): self.position_horizontalslider.setObjectName("position_horizontalslider") self.gridLayout.addWidget(self.position_horizontalslider, 6, 1, 1, 3) self.retranslateUi(MediaClipSelector) - QtCore.QMetaObject.connectSlotsByName(MediaClipSelector) + #QtCore.QMetaObject.connectSlotsByName(MediaClipSelector) MediaClipSelector.setTabOrder(self.media_path_combobox, self.load_disc_pushbutton) MediaClipSelector.setTabOrder(self.load_disc_pushbutton, self.title_combo_box) MediaClipSelector.setTabOrder(self.title_combo_box, self.audio_tracks_combobox) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 51063ffbd..5a520d992 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -72,6 +72,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): Constructor """ super(MediaClipSelectorForm, self).__init__(parent) + self.vlc_instance = None + self.vlc_media_player = None + self.vlc_media = None + self.timer = None + self.audio_cd_tracks = None + self.audio_cd = False + self.playback_length = 0 self.media_item = media_item self.setupUi(self) # most actions auto-connect due to the functions name, so only a few left to do From 4fc6025f1a936e65f71147901263946224ff4961 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 20 Aug 2014 23:33:30 +0200 Subject: [PATCH 36/44] Removed styled frame - looks ugly in KDE and is unnecessary --- openlp/plugins/media/forms/mediaclipselectordialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index 2721836fe..aa27b3d1c 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -138,7 +138,7 @@ class Ui_MediaClipSelector(object): self.media_view_frame = QtGui.QFrame(self.centralwidget) self.media_view_frame.setMinimumSize(QtCore.QSize(665, 375)) self.media_view_frame.setStyleSheet("background-color:black;") - self.media_view_frame.setFrameShape(QtGui.QFrame.StyledPanel) + self.media_view_frame.setFrameShape(QtGui.QFrame.NoFrame) self.media_view_frame.setFrameShadow(QtGui.QFrame.Raised) self.media_view_frame.setObjectName("media_view_frame") self.gridLayout.addWidget(self.media_view_frame, 5, 0, 1, 5) From 86291d0c412df1df9e1154f84922478d35fdc274 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 21 Aug 2014 01:35:24 +0200 Subject: [PATCH 37/44] Round 1 of media clip dialog refresh --- .../media/forms/mediaclipselectordialog.py | 343 +++++++++--------- .../media/forms/mediaclipselectorform.py | 98 ++--- openlp/plugins/media/lib/mediaitem.py | 12 +- openlp/plugins/songs/forms/songexportform.py | 2 +- .../media/forms/test_mediaclipselectorform.py | 12 +- 5 files changed, 237 insertions(+), 230 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index aa27b3d1c..fe62c99d3 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -30,179 +30,180 @@ from PyQt4 import QtCore, QtGui from openlp.core.common import translate +from openlp.core.lib import build_icon class Ui_MediaClipSelector(object): - def setupUi(self, MediaClipSelector): - MediaClipSelector.setObjectName("MediaClipSelector") - MediaClipSelector.resize(683, 739) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(MediaClipSelector.sizePolicy().hasHeightForWidth()) - MediaClipSelector.setSizePolicy(sizePolicy) - MediaClipSelector.setMinimumSize(QtCore.QSize(683, 686)) - MediaClipSelector.setFocusPolicy(QtCore.Qt.NoFocus) - MediaClipSelector.setAutoFillBackground(False) - MediaClipSelector.setInputMethodHints(QtCore.Qt.ImhNone) - self.centralwidget = QtGui.QWidget(MediaClipSelector) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) - self.centralwidget.setSizePolicy(sizePolicy) - self.centralwidget.setObjectName("centralwidget") - self.gridLayout = QtGui.QGridLayout(self.centralwidget) - self.gridLayout.setObjectName("gridLayout") - self.media_path_combobox = QtGui.QComboBox(self.centralwidget) - self.media_path_combobox.setEnabled(True) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.media_path_combobox.sizePolicy().hasHeightForWidth()) - self.media_path_combobox.setSizePolicy(sizePolicy) + def setupUi(self, media_clip_selector): + media_clip_selector.setObjectName('media_clip_selector') + media_clip_selector.resize(554, 654) + self.combobox_size_policy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) + media_clip_selector.setSizePolicy( + QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) + self.central_widget = QtGui.QWidget(media_clip_selector) + self.central_widget.setSizePolicy( + QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)) + self.central_widget.setObjectName('central_widget') + self.main_layout = QtGui.QVBoxLayout(self.central_widget) + self.main_layout.setObjectName('main_layout') + self.central_widget.setLayout(self.main_layout) + # Source groupbox + self.source_groupbox = QtGui.QGroupBox(self.central_widget) + self.source_groupbox.setObjectName('source_groupbox') + self.source_layout = QtGui.QHBoxLayout() + self.source_layout.setObjectName('source_layout') + self.source_groupbox.setLayout(self.source_layout) + # Media path label + self.media_path_label = QtGui.QLabel(self.source_groupbox) + self.media_path_label.setObjectName('media_path_label') + self.source_layout.addWidget(self.media_path_label) + # Media path combobox + self.media_path_combobox = QtGui.QComboBox(self.source_groupbox) + # Make the combobox expand + self.media_path_combobox.setSizePolicy(self.combobox_size_policy) self.media_path_combobox.setEditable(True) - self.media_path_combobox.setObjectName("media_path_combobox") - self.gridLayout.addWidget(self.media_path_combobox, 0, 2, 1, 2) - self.start_timeedit = QtGui.QTimeEdit(self.centralwidget) - self.start_timeedit.setEnabled(True) - self.start_timeedit.setObjectName("start_timeedit") - self.gridLayout.addWidget(self.start_timeedit, 7, 2, 1, 1) - self.end_timeedit = QtGui.QTimeEdit(self.centralwidget) - self.end_timeedit.setEnabled(True) - self.end_timeedit.setObjectName("end_timeedit") - self.gridLayout.addWidget(self.end_timeedit, 8, 2, 1, 1) - self.set_start_pushbutton = QtGui.QPushButton(self.centralwidget) - self.set_start_pushbutton.setEnabled(True) - self.set_start_pushbutton.setObjectName("set_start_pushbutton") - self.gridLayout.addWidget(self.set_start_pushbutton, 7, 3, 1, 1) - self.load_disc_pushbutton = QtGui.QPushButton(self.centralwidget) - self.load_disc_pushbutton.setEnabled(True) - self.load_disc_pushbutton.setObjectName("load_disc_pushbutton") - self.gridLayout.addWidget(self.load_disc_pushbutton, 0, 4, 1, 1) - spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) - self.gridLayout.addItem(spacerItem, 9, 3, 1, 1) - self.play_pushbutton = QtGui.QPushButton(self.centralwidget) - self.play_pushbutton.setEnabled(True) - self.play_pushbutton.setText("") - icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.play_pushbutton.setIcon(icon) - self.play_pushbutton.setObjectName("play_pushbutton") - self.gridLayout.addWidget(self.play_pushbutton, 6, 0, 1, 1) - self.end_point_label = QtGui.QLabel(self.centralwidget) - self.end_point_label.setEnabled(True) - self.end_point_label.setObjectName("end_point_label") - self.gridLayout.addWidget(self.end_point_label, 8, 0, 1, 1) - self.subtitle_tracks_combobox = QtGui.QComboBox(self.centralwidget) - self.subtitle_tracks_combobox.setEnabled(True) - self.subtitle_tracks_combobox.setObjectName("subtitle_tracks_combobox") - self.gridLayout.addWidget(self.subtitle_tracks_combobox, 4, 2, 1, 2) - self.title_label = QtGui.QLabel(self.centralwidget) - self.title_label.setEnabled(True) - self.title_label.setObjectName("title_label") - self.gridLayout.addWidget(self.title_label, 2, 0, 1, 1) - self.audio_tracks_combobox = QtGui.QComboBox(self.centralwidget) - self.audio_tracks_combobox.setEnabled(True) - self.audio_tracks_combobox.setObjectName("audio_tracks_combobox") - self.gridLayout.addWidget(self.audio_tracks_combobox, 3, 2, 1, 2) - self.set_end_pushbutton = QtGui.QPushButton(self.centralwidget) - self.set_end_pushbutton.setEnabled(True) - self.set_end_pushbutton.setObjectName("set_end_pushbutton") - self.gridLayout.addWidget(self.set_end_pushbutton, 8, 3, 1, 1) - self.save_pushbutton = QtGui.QPushButton(self.centralwidget) - self.save_pushbutton.setEnabled(True) - self.save_pushbutton.setObjectName("save_pushbutton") - self.gridLayout.addWidget(self.save_pushbutton, 10, 3, 1, 1) - self.close_pushbutton = QtGui.QPushButton(self.centralwidget) - self.close_pushbutton.setEnabled(True) - self.close_pushbutton.setObjectName("close_pushbutton") - self.gridLayout.addWidget(self.close_pushbutton, 10, 4, 1, 1) - self.start_point_label = QtGui.QLabel(self.centralwidget) - self.start_point_label.setEnabled(True) - self.start_point_label.setObjectName("start_point_label") - self.gridLayout.addWidget(self.start_point_label, 7, 0, 1, 2) - self.jump_start_pushbutton = QtGui.QPushButton(self.centralwidget) - self.jump_start_pushbutton.setEnabled(True) - self.jump_start_pushbutton.setObjectName("jump_start_pushbutton") - self.gridLayout.addWidget(self.jump_start_pushbutton, 7, 4, 1, 1) - self.audio_track_label = QtGui.QLabel(self.centralwidget) - self.audio_track_label.setEnabled(True) - self.audio_track_label.setObjectName("audio_track_label") - self.gridLayout.addWidget(self.audio_track_label, 3, 0, 1, 2) - self.media_position_timeedit = QtGui.QTimeEdit(self.centralwidget) - self.media_position_timeedit.setEnabled(True) - self.media_position_timeedit.setReadOnly(True) - self.media_position_timeedit.setObjectName("media_position_timeedit") - self.gridLayout.addWidget(self.media_position_timeedit, 6, 4, 1, 1) - self.media_view_frame = QtGui.QFrame(self.centralwidget) - self.media_view_frame.setMinimumSize(QtCore.QSize(665, 375)) - self.media_view_frame.setStyleSheet("background-color:black;") - self.media_view_frame.setFrameShape(QtGui.QFrame.NoFrame) - self.media_view_frame.setFrameShadow(QtGui.QFrame.Raised) - self.media_view_frame.setObjectName("media_view_frame") - self.gridLayout.addWidget(self.media_view_frame, 5, 0, 1, 5) - self.subtitle_track_label = QtGui.QLabel(self.centralwidget) - self.subtitle_track_label.setEnabled(True) - self.subtitle_track_label.setObjectName("subtitle_track_label") - self.gridLayout.addWidget(self.subtitle_track_label, 4, 0, 1, 2) - self.jump_end_pushbutton = QtGui.QPushButton(self.centralwidget) - self.jump_end_pushbutton.setEnabled(True) - self.jump_end_pushbutton.setObjectName("jump_end_pushbutton") - self.gridLayout.addWidget(self.jump_end_pushbutton, 8, 4, 1, 1) - self.media_path_label = QtGui.QLabel(self.centralwidget) - self.media_path_label.setEnabled(True) - self.media_path_label.setObjectName("media_path_label") - self.gridLayout.addWidget(self.media_path_label, 0, 0, 1, 2) - self.title_combo_box = QtGui.QComboBox(self.centralwidget) - self.title_combo_box.setEnabled(True) - self.title_combo_box.setProperty("currentText", "") - self.title_combo_box.setObjectName("title_combo_box") - self.gridLayout.addWidget(self.title_combo_box, 2, 2, 1, 2) - self.position_horizontalslider = QtGui.QSlider(self.centralwidget) - self.position_horizontalslider.setEnabled(True) - self.position_horizontalslider.setTracking(False) - self.position_horizontalslider.setOrientation(QtCore.Qt.Horizontal) - self.position_horizontalslider.setInvertedAppearance(False) - self.position_horizontalslider.setObjectName("position_horizontalslider") - self.gridLayout.addWidget(self.position_horizontalslider, 6, 1, 1, 3) - self.retranslateUi(MediaClipSelector) - #QtCore.QMetaObject.connectSlotsByName(MediaClipSelector) - MediaClipSelector.setTabOrder(self.media_path_combobox, self.load_disc_pushbutton) - MediaClipSelector.setTabOrder(self.load_disc_pushbutton, self.title_combo_box) - MediaClipSelector.setTabOrder(self.title_combo_box, self.audio_tracks_combobox) - MediaClipSelector.setTabOrder(self.audio_tracks_combobox, self.subtitle_tracks_combobox) - MediaClipSelector.setTabOrder(self.subtitle_tracks_combobox, self.play_pushbutton) - MediaClipSelector.setTabOrder(self.play_pushbutton, self.position_horizontalslider) - MediaClipSelector.setTabOrder(self.position_horizontalslider, self.media_position_timeedit) - MediaClipSelector.setTabOrder(self.media_position_timeedit, self.start_timeedit) - MediaClipSelector.setTabOrder(self.start_timeedit, self.set_start_pushbutton) - MediaClipSelector.setTabOrder(self.set_start_pushbutton, self.jump_start_pushbutton) - MediaClipSelector.setTabOrder(self.jump_start_pushbutton, self.end_timeedit) - MediaClipSelector.setTabOrder(self.end_timeedit, self.set_end_pushbutton) - MediaClipSelector.setTabOrder(self.set_end_pushbutton, self.jump_end_pushbutton) - MediaClipSelector.setTabOrder(self.jump_end_pushbutton, self.save_pushbutton) - MediaClipSelector.setTabOrder(self.save_pushbutton, self.close_pushbutton) + self.media_path_combobox.setObjectName('media_path_combobox') + self.source_layout.addWidget(self.media_path_combobox) + # Load disc button + self.load_disc_button = QtGui.QPushButton(self.central_widget) + self.load_disc_button.setEnabled(True) + self.load_disc_button.setObjectName('load_disc_button') + self.source_layout.addWidget(self.load_disc_button) + self.main_layout.addWidget(self.source_groupbox) + # Track details group box + self.track_groupbox = QtGui.QGroupBox(self.central_widget) + self.track_groupbox.setObjectName('track_groupbox') + self.track_layout = QtGui.QFormLayout() + self.track_layout.setObjectName('track_layout') + self.label_alignment = self.track_layout.labelAlignment() + self.track_groupbox.setLayout(self.track_layout) + # Title track + self.title_label = QtGui.QLabel(self.track_groupbox) + self.title_label.setObjectName('title_label') + self.titles_combo_box = QtGui.QComboBox(self.track_groupbox) + self.titles_combo_box.setSizePolicy(self.combobox_size_policy) + self.titles_combo_box.setEditText('') + self.titles_combo_box.setObjectName('titles_combo_box') + self.track_layout.addRow(self.title_label, self.titles_combo_box) + # Audio track + self.audio_track_label = QtGui.QLabel(self.track_groupbox) + self.audio_track_label.setObjectName('audio_track_label') + self.audio_tracks_combobox = QtGui.QComboBox(self.track_groupbox) + self.audio_tracks_combobox.setSizePolicy(self.combobox_size_policy) + self.audio_tracks_combobox.setObjectName('audio_tracks_combobox') + self.track_layout.addRow(self.audio_track_label, self.audio_tracks_combobox) + self.main_layout.addWidget(self.track_groupbox) + # Subtitle track + self.subtitle_track_label = QtGui.QLabel(self.track_groupbox) + self.subtitle_track_label.setObjectName('subtitle_track_label') + self.subtitle_tracks_combobox = QtGui.QComboBox(self.track_groupbox) + self.subtitle_tracks_combobox.setSizePolicy(self.combobox_size_policy) + self.subtitle_tracks_combobox.setObjectName('subtitle_tracks_combobox') + self.track_layout.addRow(self.subtitle_track_label, self.subtitle_tracks_combobox) + # Preview frame + self.preview_frame = QtGui.QFrame(self.central_widget) + self.preview_frame.setMinimumSize(QtCore.QSize(320, 240)) + self.preview_frame.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) + self.preview_frame.setStyleSheet('background-color:black;') + self.preview_frame.setFrameShape(QtGui.QFrame.NoFrame) + self.preview_frame.setObjectName('preview_frame') + self.main_layout.addWidget(self.preview_frame) + # player controls + self.controls_layout = QtGui.QHBoxLayout() + self.controls_layout.setObjectName('controls_layout') + self.play_button = QtGui.QToolButton(self.central_widget) + self.play_button.setIcon(build_icon(':/slides/media_playback_start.png')) + self.play_button.setObjectName('play_button') + self.controls_layout.addWidget(self.play_button) + self.position_slider = QtGui.QSlider(self.central_widget) + self.position_slider.setTracking(False) + self.position_slider.setOrientation(QtCore.Qt.Horizontal) + self.position_slider.setObjectName('position_slider') + self.controls_layout.addWidget(self.position_slider) + self.position_timeedit = QtGui.QTimeEdit(self.central_widget) + self.position_timeedit.setReadOnly(True) + self.position_timeedit.setObjectName('position_timeedit') + self.controls_layout.addWidget(self.position_timeedit) + self.main_layout.addLayout(self.controls_layout) + # Range + self.range_groupbox = QtGui.QGroupBox(self.central_widget) + self.range_groupbox.setObjectName('range_groupbox') + self.range_layout = QtGui.QGridLayout() + self.range_layout.setObjectName('range_layout') + self.range_groupbox.setLayout(self.range_layout) + # Start position + self.start_position_label = QtGui.QLabel(self.range_groupbox) + self.start_position_label.setObjectName('start_position_label') + self.range_layout.addWidget(self.start_position_label, 0, 0, self.label_alignment) + self.start_position_edit = QtGui.QTimeEdit(self.range_groupbox) + self.start_position_edit.setObjectName('start_position_edit') + self.range_layout.addWidget(self.start_position_edit, 0, 1) + self.set_start_button = QtGui.QPushButton(self.range_groupbox) + self.set_start_button.setObjectName('set_start_button') + self.range_layout.addWidget(self.set_start_button, 0, 2) + self.jump_start_button = QtGui.QPushButton(self.range_groupbox) + self.jump_start_button.setObjectName('jump_start_button') + self.range_layout.addWidget(self.jump_start_button, 0, 3) + # End position + self.end_position_label = QtGui.QLabel(self.range_groupbox) + self.end_position_label.setObjectName('end_position_label') + self.range_layout.addWidget(self.end_position_label, 1, 0, self.label_alignment) + self.end_timeedit = QtGui.QTimeEdit(self.range_groupbox) + self.end_timeedit.setObjectName('end_timeedit') + self.range_layout.addWidget(self.end_timeedit, 1, 1) + self.set_end_button = QtGui.QPushButton(self.range_groupbox) + self.set_end_button.setObjectName('set_end_button') + self.range_layout.addWidget(self.set_end_button, 1, 2) + self.jump_end_button = QtGui.QPushButton(self.range_groupbox) + self.jump_end_button.setObjectName('jump_end_button') + self.range_layout.addWidget(self.jump_end_button, 1, 3) + self.main_layout.addWidget(self.range_groupbox) + # Save and close buttons + self.button_box = QtGui.QDialogButtonBox(self.central_widget) + self.button_box.addButton(QtGui.QDialogButtonBox.Save) + self.button_box.addButton(QtGui.QDialogButtonBox.Cancel) + self.close_button = self.button_box.button(QtGui.QDialogButtonBox.Cancel) + self.save_button = self.button_box.button(QtGui.QDialogButtonBox.Save) + self.main_layout.addWidget(self.button_box) - def retranslateUi(self, MediaClipSelector): - MediaClipSelector.setWindowTitle(translate("MediaPlugin.MediaClipSelector", "Select media clip", None)) - self.start_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) - self.end_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) - self.set_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", - "Set current position as start point", None)) - self.load_disc_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Load disc", None)) - self.end_point_label.setText(translate("MediaPlugin.MediaClipSelector", "End point", None)) - self.title_label.setText(translate("MediaPlugin.MediaClipSelector", "Title", None)) - self.set_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", - "Set current position as end point", None)) - self.save_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Save current clip", None)) - self.close_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Close", None)) - self.start_point_label.setText(translate("MediaPlugin.MediaClipSelector", "Start point", None)) - self.jump_start_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to start point", None)) - self.audio_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Audio track", None)) - self.media_position_timeedit.setDisplayFormat(translate("MediaPlugin.MediaClipSelector", "HH:mm:ss.z", None)) - self.subtitle_track_label.setText(translate("MediaPlugin.MediaClipSelector", "Subtitle track", None)) - self.jump_end_pushbutton.setText(translate("MediaPlugin.MediaClipSelector", "Jump to end point", None)) - self.media_path_label.setText(translate("MediaPlugin.MediaClipSelector", "Media path", None)) - self.media_path_combobox.lineEdit().setPlaceholderText(translate("MediaPlugin.MediaClipSelector", - "Select drive from list", None)) + self.retranslateUi(media_clip_selector) + self.button_box.accepted.connect(media_clip_selector.accept) + self.button_box.rejected.connect(media_clip_selector.reject) + QtCore.QMetaObject.connectSlotsByName(media_clip_selector) + media_clip_selector.setTabOrder(self.media_path_combobox, self.load_disc_button) + media_clip_selector.setTabOrder(self.load_disc_button, self.titles_combo_box) + media_clip_selector.setTabOrder(self.titles_combo_box, self.audio_tracks_combobox) + media_clip_selector.setTabOrder(self.audio_tracks_combobox, self.subtitle_tracks_combobox) + media_clip_selector.setTabOrder(self.subtitle_tracks_combobox, self.play_button) + media_clip_selector.setTabOrder(self.play_button, self.position_slider) + media_clip_selector.setTabOrder(self.position_slider, self.position_timeedit) + media_clip_selector.setTabOrder(self.position_timeedit, self.start_position_edit) + media_clip_selector.setTabOrder(self.start_position_edit, self.set_start_button) + media_clip_selector.setTabOrder(self.set_start_button, self.jump_start_button) + media_clip_selector.setTabOrder(self.jump_start_button, self.end_timeedit) + media_clip_selector.setTabOrder(self.end_timeedit, self.set_end_button) + media_clip_selector.setTabOrder(self.set_end_button, self.jump_end_button) + media_clip_selector.setTabOrder(self.jump_end_button, self.save_button) + media_clip_selector.setTabOrder(self.save_button, self.close_button) + + def retranslateUi(self, media_clip_selector): + media_clip_selector.setWindowTitle(translate('MediaPlugin.MediaClipSelector', 'Select Media Clip')) + self.source_groupbox.setTitle(translate('MediaPlugin.MediaClipSelector', 'Source')) + self.media_path_label.setText(translate('MediaPlugin.MediaClipSelector', 'Media path:')) + self.media_path_combobox.lineEdit().setPlaceholderText(translate('MediaPlugin.MediaClipSelector', + 'Select drive from list')) + self.load_disc_button.setText(translate('MediaPlugin.MediaClipSelector', 'Load disc')) + self.track_groupbox.setTitle(translate('MediaPlugin.MediaClipSelector', 'Track Details')) + self.title_label.setText(translate('MediaPlugin.MediaClipSelector', 'Title:')) + self.audio_track_label.setText(translate('MediaPlugin.MediaClipSelector', 'Audio track:')) + self.subtitle_track_label.setText(translate('MediaPlugin.MediaClipSelector', 'Subtitle track:')) + self.position_timeedit.setDisplayFormat(translate('MediaPlugin.MediaClipSelector', 'HH:mm:ss.z')) + self.range_groupbox.setTitle(translate('MediaPlugin.MediaClipSelector', 'Clip Range')) + self.start_position_label.setText(translate('MediaPlugin.MediaClipSelector', 'Start point:')) + self.start_position_edit.setDisplayFormat(translate('MediaPlugin.MediaClipSelector', 'HH:mm:ss.z')) + self.set_start_button.setText(translate('MediaPlugin.MediaClipSelector', 'Set start point')) + self.jump_start_button.setText(translate('MediaPlugin.MediaClipSelector', 'Jump to start point')) + self.end_position_label.setText(translate('MediaPlugin.MediaClipSelector', 'End point:')) + self.end_timeedit.setDisplayFormat(translate('MediaPlugin.MediaClipSelector', 'HH:mm:ss.z')) + self.set_end_button.setText(translate('MediaPlugin.MediaClipSelector', 'Set end point')) + self.jump_end_button.setText(translate('MediaPlugin.MediaClipSelector', 'Jump to end point')) \ No newline at end of file diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 5a520d992..eec75d623 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -81,8 +81,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.playback_length = 0 self.media_item = media_item self.setupUi(self) - # most actions auto-connect due to the functions name, so only a few left to do - self.close_pushbutton.clicked.connect(self.reject) # setup play/pause icon self.play_icon = QtGui.QIcon() self.play_icon.addPixmap(QtGui.QPixmap(":/slides/media_playback_start.png"), QtGui.QIcon.Normal, @@ -96,6 +94,8 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): Exit Dialog and do not save """ log.debug('MediaClipSelectorForm.reject') + print(self.geometry().height()) + print(self.geometry().width()) # Tear down vlc if self.vlc_media_player: self.vlc_media_player.stop() @@ -107,7 +107,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if self.vlc_media: self.vlc_media.release() self.vlc_media = None - QtGui.QDialog.reject(self) + return QtGui.QDialog.reject(self) def exec_(self): """ @@ -122,16 +122,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): Reset the UI to default values """ self.playback_length = 0 - self.position_horizontalslider.setMinimum(0) + self.position_slider.setMinimum(0) self.disable_all() self.toggle_disable_load_media(False) self.subtitle_tracks_combobox.clear() self.audio_tracks_combobox.clear() - self.title_combo_box.clear() + self.titles_combo_box.clear() time = QtCore.QTime() - self.start_timeedit.setTime(time) + self.start_position_edit.setTime(time) self.end_timeedit.setTime(time) - self.media_position_timeedit.setTime(time) + self.position_timeedit.setTime(time) def setup_vlc(self): """ @@ -145,7 +145,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): # This is platform specific! # You have to give the id of the QFrame (or similar object) # to vlc, different platforms have different functions for this. - win_id = int(self.media_view_frame.winId()) + win_id = int(self.preview_frame.winId()) if sys.platform == "win32": self.vlc_media_player.set_hwnd(win_id) elif sys.platform == "darwin": @@ -182,16 +182,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.audio_cd_tracks = self.vlc_media.subitems() if not self.audio_cd_tracks or self.audio_cd_tracks.count() < 1: return False - # Insert into title_combo_box - self.title_combo_box.clear() + # Insert into titles_combo_box + self.titles_combo_box.clear() for i in range(self.audio_cd_tracks.count()): item = self.audio_cd_tracks.item_at_index(i) item_title = item.get_meta(vlc.Meta.Title) - self.title_combo_box.addItem(item_title, i) + self.titles_combo_box.addItem(item_title, i) self.vlc_media_player.set_media(self.audio_cd_tracks.item_at_index(0)) self.audio_cd = True - self.title_combo_box.setDisabled(False) - self.title_combo_box.setCurrentIndex(0) + self.titles_combo_box.setDisabled(False) + self.titles_combo_box.setCurrentIndex(0) self.on_title_combo_box_currentIndexChanged(0) return True @@ -255,19 +255,19 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if not self.audio_cd: # Get titles, insert in combobox titles = self.vlc_media_player.video_get_title_description() - self.title_combo_box.clear() + self.titles_combo_box.clear() for title in titles: - self.title_combo_box.addItem(title[1].decode(), title[0]) + self.titles_combo_box.addItem(title[1].decode(), title[0]) # Main title is usually title #1 if len(titles) > 1: - self.title_combo_box.setCurrentIndex(1) + self.titles_combo_box.setCurrentIndex(1) else: - self.title_combo_box.setCurrentIndex(0) + self.titles_combo_box.setCurrentIndex(0) # Enable audio track combobox if anything is in it if len(titles) > 0: - self.title_combo_box.setDisabled(False) + self.titles_combo_box.setDisabled(False) self.toggle_disable_load_media(False) - log.debug('load_disc_pushbutton end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) + log.debug('load_disc_button end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(bool) def on_play_pushbutton_clicked(self, clicked): @@ -278,23 +278,23 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): """ if self.vlc_media_player.get_state() == vlc.State.Playing: self.vlc_media_player.pause() - self.play_pushbutton.setIcon(self.play_icon) + self.play_button.setIcon(self.play_icon) else: self.vlc_media_player.play() self.media_state_wait(vlc.State.Playing) - self.play_pushbutton.setIcon(self.pause_icon) + self.play_button.setIcon(self.pause_icon) @QtCore.pyqtSlot(bool) def on_set_start_pushbutton_clicked(self, clicked): """ - Copy the current player position to start_timeedit + Copy the current player position to start_position_edit :param clicked: Given from signal, not used. """ vlc_ms_pos = self.vlc_media_player.get_time() time = QtCore.QTime() new_pos_time = time.addMSecs(vlc_ms_pos) - self.start_timeedit.setTime(new_pos_time) + self.start_position_edit.setTime(new_pos_time) # If start time is after end time, update end time. end_time = self.end_timeedit.time() if end_time < new_pos_time: @@ -312,14 +312,14 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): new_pos_time = time.addMSecs(vlc_ms_pos) self.end_timeedit.setTime(new_pos_time) # If start time is after end time, update start time. - start_time = self.start_timeedit.time() + start_time = self.start_position_edit.time() if start_time > new_pos_time: - self.start_timeedit.setTime(new_pos_time) + self.start_position_edit.setTime(new_pos_time) @QtCore.pyqtSlot(QtCore.QTime) def on_start_timeedit_timeChanged(self, new_time): """ - Called when start_timeedit is changed manually + Called when start_position_edit is changed manually :param new_time: The new time """ @@ -336,9 +336,9 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param new_time: The new time """ # If start time is after end time, update start time. - start_time = self.start_timeedit.time() + start_time = self.start_position_edit.time() if start_time > new_time: - self.start_timeedit.setTime(new_time) + self.start_position_edit.setTime(new_time) @QtCore.pyqtSlot(bool) def on_jump_end_pushbutton_clicked(self, clicked): @@ -357,11 +357,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): @QtCore.pyqtSlot(bool) def on_jump_start_pushbutton_clicked(self, clicked): """ - Set the player position to the position stored in start_timeedit + Set the player position to the position stored in start_position_edit :param clicked: Given from signal, not used. """ - start_time = self.start_timeedit.time() + start_time = self.start_position_edit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ start_time.minute() * 60 * 1000 + \ start_time.second() * 1000 + \ @@ -428,17 +428,17 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.audio_set_mute(False) self.vlc_media_player.set_pause(1) # If a title or audio track is available the player is enabled - if self.title_combo_box.count() > 0 or len(audio_tracks) > 0: + if self.titles_combo_box.count() > 0 or len(audio_tracks) > 0: self.toggle_disable_player(False) # Set media length info self.playback_length = self.vlc_media_player.get_length() log.debug('playback_length: %d ms' % self.playback_length) - self.position_horizontalslider.setMaximum(self.playback_length) + self.position_slider.setMaximum(self.playback_length) # setup start and end time rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0) time = QtCore.QTime() playback_length_time = time.addMSecs(rounded_vlc_ms_length) - self.start_timeedit.setMaximumTime(playback_length_time) + self.start_position_edit.setMaximumTime(playback_length_time) self.end_timeedit.setMaximumTime(playback_length_time) self.end_timeedit.setTime(playback_length_time) # Pause once again, just to make sure @@ -447,7 +447,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): sleep(0.1) self.vlc_media_player.set_pause(1) loop_count += 1 - log.debug('title_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) + log.debug('titles_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(int) def on_audio_tracks_combobox_currentIndexChanged(self, index): @@ -493,15 +493,15 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): rounded_vlc_ms_pos = int(round(vlc_ms_pos / 100.0) * 100.0) time = QtCore.QTime() new_pos_time = time.addMSecs(rounded_vlc_ms_pos) - self.media_position_timeedit.setTime(new_pos_time) - self.position_horizontalslider.setSliderPosition(vlc_ms_pos) + self.position_timeedit.setTime(new_pos_time) + self.position_slider.setSliderPosition(vlc_ms_pos) def disable_all(self): """ Disable all elements in the dialog """ self.toggle_disable_load_media(True) - self.title_combo_box.setDisabled(True) + self.titles_combo_box.setDisabled(True) self.audio_tracks_combobox.setDisabled(True) self.subtitle_tracks_combobox.setDisabled(True) self.toggle_disable_player(True) @@ -513,7 +513,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param action: If True elements are disabled, if False they are enabled. """ self.media_path_combobox.setDisabled(action) - self.load_disc_pushbutton.setDisabled(action) + self.load_disc_button.setDisabled(action) def toggle_disable_player(self, action): """ @@ -521,16 +521,16 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param action: If True elements are disabled, if False they are enabled. """ - self.play_pushbutton.setDisabled(action) - self.position_horizontalslider.setDisabled(action) - self.media_position_timeedit.setDisabled(action) - self.start_timeedit.setDisabled(action) - self.set_start_pushbutton.setDisabled(action) - self.jump_start_pushbutton.setDisabled(action) + self.play_button.setDisabled(action) + self.position_slider.setDisabled(action) + self.position_timeedit.setDisabled(action) + self.start_position_edit.setDisabled(action) + self.set_start_button.setDisabled(action) + self.jump_start_button.setDisabled(action) self.end_timeedit.setDisabled(action) - self.set_end_pushbutton.setDisabled(action) - self.jump_end_pushbutton.setDisabled(action) - self.save_pushbutton.setDisabled(action) + self.set_end_button.setDisabled(action) + self.jump_end_button.setDisabled(action) + self.save_button.setDisabled(action) @QtCore.pyqtSlot(bool) def on_save_pushbutton_clicked(self, clicked): @@ -540,7 +540,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): :param clicked: Given from signal, not used. """ log.debug('in on_save_pushbutton_clicked') - start_time = self.start_timeedit.time() + start_time = self.start_position_edit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ start_time.minute() * 60 * 1000 + \ start_time.second() * 1000 + \ @@ -550,7 +550,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): end_time.minute() * 60 * 1000 + \ end_time.second() * 1000 + \ end_time.msec() - title = self.title_combo_box.itemData(self.title_combo_box.currentIndex()) + title = self.titles_combo_box.itemData(self.titles_combo_box.currentIndex()) path = self.media_path_combobox.currentText() optical = '' if self.audio_cd: diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 5bdbe4d33..f0224aa88 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -287,8 +287,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): check_directory_exists(self.service_path) self.load_list(Settings().value(self.settings_section + '/media files')) self.rebuild_players() - if VLC_AVAILABLE: - self.media_clip_selector_form = MediaClipSelectorForm(self, self.main_window, None) + # if VLC_AVAILABLE: + # self.media_clip_selector_form = MediaClipSelectorForm(self, self.main_window, None) def rebuild_players(self): """ @@ -415,7 +415,13 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ When the load optical button is clicked, open the clip selector window. """ - self.media_clip_selector_form.exec_() + # self.media_clip_selector_form.exec_() + if VLC_AVAILABLE: + media_clip_selector_form = MediaClipSelectorForm(self, self.main_window, None) + media_clip_selector_form.exec_() + del media_clip_selector_form + else: + QtGui.QMessageBox.critical(self, 'VLC is not available', 'VLC is not available') def add_optical_clip(self, optical): """ diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 589da4d33..412ec0369 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -124,7 +124,7 @@ class SongExportForm(OpenLPWizard): self.export_song_layout = QtGui.QHBoxLayout(self.export_song_page) self.export_song_layout.setObjectName('export_song_layout') self.grid_layout = QtGui.QGridLayout() - self.grid_layout.setObjectName('grid_layout') + self.grid_layout.setObjectName('range_layout') self.selected_list_widget = QtGui.QListWidget(self.export_song_page) self.selected_list_widget.setObjectName('selected_list_widget') self.grid_layout.addWidget(self.selected_list_widget, 1, 0, 1, 1) diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index 241ef26c3..e97a06238 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -100,7 +100,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.exec_() # WHEN: The load button is clicked with no path set - QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) + QtTest.QTest.mouseClick(self.form.load_disc_button, QtCore.Qt.LeftButton) # THEN: we should get an error mocked_critical_error_message_box.assert_called_with(message='No path was given') @@ -109,7 +109,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): mocked_os_path_exists.return_value = False self.form.media_path_combobox.insertItem(0, '/non-existing/test-path.test') self.form.media_path_combobox.setCurrentIndex(0) - QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) + QtTest.QTest.mouseClick(self.form.load_disc_button, QtCore.Qt.LeftButton) # THEN: we should get an error assert self.form.media_path_combobox.currentText() == '/non-existing/test-path.test',\ @@ -122,7 +122,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.vlc_media_player.play.return_value = -1 self.form.media_path_combobox.insertItem(0, '/existing/test-path.test') self.form.media_path_combobox.setCurrentIndex(0) - QtTest.QTest.mouseClick(self.form.load_disc_pushbutton, QtCore.Qt.LeftButton) + QtTest.QTest.mouseClick(self.form.load_disc_button, QtCore.Qt.LeftButton) # THEN: we should get an error assert self.form.media_path_combobox.currentText() == '/existing/test-path.test',\ @@ -141,15 +141,15 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.subtitle_tracks_combobox.itemData = MagicMock() self.form.audio_tracks_combobox.itemData.return_value = None self.form.subtitle_tracks_combobox.itemData.return_value = None - self.form.title_combo_box.insertItem(0, 'Test Title 0') - self.form.title_combo_box.insertItem(1, 'Test Title 1') + self.form.titles_combo_box.insertItem(0, 'Test Title 0') + self.form.titles_combo_box.insertItem(1, 'Test Title 1') # WHEN: There exists audio and subtitle tracks and the index is updated. self.form.vlc_media_player.audio_get_track_description.return_value = [(-1, b'Disabled'), (0, b'Audio Track 1')] self.form.vlc_media_player.video_get_spu_description.return_value = [(-1, b'Disabled'), (0, b'Subtitle Track 1')] - self.form.title_combo_box.setCurrentIndex(1) + self.form.titles_combo_box.setCurrentIndex(1) # THEN: The subtitle and audio track comboboxes should be updated and get signals and call itemData. self.form.audio_tracks_combobox.itemData.assert_any_call(0) From 554ce81dd38122d97075ab54563ec748b0320a1c Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 21 Aug 2014 01:45:55 +0200 Subject: [PATCH 38/44] Added some padding and make the contents of the dialog expand out. --- .../media/forms/mediaclipselectordialog.py | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index fe62c99d3..88b4616eb 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -40,17 +40,14 @@ class Ui_MediaClipSelector(object): self.combobox_size_policy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) media_clip_selector.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) - self.central_widget = QtGui.QWidget(media_clip_selector) - self.central_widget.setSizePolicy( - QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)) - self.central_widget.setObjectName('central_widget') - self.main_layout = QtGui.QVBoxLayout(self.central_widget) + self.main_layout = QtGui.QVBoxLayout(media_clip_selector) + self.main_layout.setContentsMargins(8, 8, 8, 8) self.main_layout.setObjectName('main_layout') - self.central_widget.setLayout(self.main_layout) # Source groupbox - self.source_groupbox = QtGui.QGroupBox(self.central_widget) + self.source_groupbox = QtGui.QGroupBox(media_clip_selector) self.source_groupbox.setObjectName('source_groupbox') self.source_layout = QtGui.QHBoxLayout() + self.source_layout.setContentsMargins(8, 8, 8, 8) self.source_layout.setObjectName('source_layout') self.source_groupbox.setLayout(self.source_layout) # Media path label @@ -65,15 +62,16 @@ class Ui_MediaClipSelector(object): self.media_path_combobox.setObjectName('media_path_combobox') self.source_layout.addWidget(self.media_path_combobox) # Load disc button - self.load_disc_button = QtGui.QPushButton(self.central_widget) + self.load_disc_button = QtGui.QPushButton(media_clip_selector) self.load_disc_button.setEnabled(True) self.load_disc_button.setObjectName('load_disc_button') self.source_layout.addWidget(self.load_disc_button) self.main_layout.addWidget(self.source_groupbox) # Track details group box - self.track_groupbox = QtGui.QGroupBox(self.central_widget) + self.track_groupbox = QtGui.QGroupBox(media_clip_selector) self.track_groupbox.setObjectName('track_groupbox') self.track_layout = QtGui.QFormLayout() + self.track_layout.setContentsMargins(8, 8, 8, 8) self.track_layout.setObjectName('track_layout') self.label_alignment = self.track_layout.labelAlignment() self.track_groupbox.setLayout(self.track_layout) @@ -101,7 +99,7 @@ class Ui_MediaClipSelector(object): self.subtitle_tracks_combobox.setObjectName('subtitle_tracks_combobox') self.track_layout.addRow(self.subtitle_track_label, self.subtitle_tracks_combobox) # Preview frame - self.preview_frame = QtGui.QFrame(self.central_widget) + self.preview_frame = QtGui.QFrame(media_clip_selector) self.preview_frame.setMinimumSize(QtCore.QSize(320, 240)) self.preview_frame.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) self.preview_frame.setStyleSheet('background-color:black;') @@ -111,24 +109,25 @@ class Ui_MediaClipSelector(object): # player controls self.controls_layout = QtGui.QHBoxLayout() self.controls_layout.setObjectName('controls_layout') - self.play_button = QtGui.QToolButton(self.central_widget) + self.play_button = QtGui.QToolButton(media_clip_selector) self.play_button.setIcon(build_icon(':/slides/media_playback_start.png')) self.play_button.setObjectName('play_button') self.controls_layout.addWidget(self.play_button) - self.position_slider = QtGui.QSlider(self.central_widget) + self.position_slider = QtGui.QSlider(media_clip_selector) self.position_slider.setTracking(False) self.position_slider.setOrientation(QtCore.Qt.Horizontal) self.position_slider.setObjectName('position_slider') self.controls_layout.addWidget(self.position_slider) - self.position_timeedit = QtGui.QTimeEdit(self.central_widget) + self.position_timeedit = QtGui.QTimeEdit(media_clip_selector) self.position_timeedit.setReadOnly(True) self.position_timeedit.setObjectName('position_timeedit') self.controls_layout.addWidget(self.position_timeedit) self.main_layout.addLayout(self.controls_layout) # Range - self.range_groupbox = QtGui.QGroupBox(self.central_widget) + self.range_groupbox = QtGui.QGroupBox(media_clip_selector) self.range_groupbox.setObjectName('range_groupbox') self.range_layout = QtGui.QGridLayout() + self.range_layout.setContentsMargins(8, 8, 8, 8) self.range_layout.setObjectName('range_layout') self.range_groupbox.setLayout(self.range_layout) # Start position @@ -159,7 +158,7 @@ class Ui_MediaClipSelector(object): self.range_layout.addWidget(self.jump_end_button, 1, 3) self.main_layout.addWidget(self.range_groupbox) # Save and close buttons - self.button_box = QtGui.QDialogButtonBox(self.central_widget) + self.button_box = QtGui.QDialogButtonBox(media_clip_selector) self.button_box.addButton(QtGui.QDialogButtonBox.Save) self.button_box.addButton(QtGui.QDialogButtonBox.Cancel) self.close_button = self.button_box.button(QtGui.QDialogButtonBox.Cancel) @@ -206,4 +205,4 @@ class Ui_MediaClipSelector(object): self.end_position_label.setText(translate('MediaPlugin.MediaClipSelector', 'End point:')) self.end_timeedit.setDisplayFormat(translate('MediaPlugin.MediaClipSelector', 'HH:mm:ss.z')) self.set_end_button.setText(translate('MediaPlugin.MediaClipSelector', 'Set end point')) - self.jump_end_button.setText(translate('MediaPlugin.MediaClipSelector', 'Jump to end point')) \ No newline at end of file + self.jump_end_button.setText(translate('MediaPlugin.MediaClipSelector', 'Jump to end point')) From 7b25295c7fc014958125cc0ea535154c03a216c9 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 21 Aug 2014 01:49:22 +0200 Subject: [PATCH 39/44] Remove some debugging prints... oops --- openlp/plugins/media/forms/mediaclipselectorform.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index eec75d623..449b95d46 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -94,8 +94,6 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): Exit Dialog and do not save """ log.debug('MediaClipSelectorForm.reject') - print(self.geometry().height()) - print(self.geometry().width()) # Tear down vlc if self.vlc_media_player: self.vlc_media_player.stop() From 0b93faf7b9c877fef5714b8c9b228065278b906f Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Tue, 26 Aug 2014 18:38:07 +0100 Subject: [PATCH 40/44] PEP fixes --- openlp/core/utils/actions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/utils/actions.py b/openlp/core/utils/actions.py index fb794866b..9b5117233 100644 --- a/openlp/core/utils/actions.py +++ b/openlp/core/utils/actions.py @@ -280,7 +280,7 @@ class ActionList(object): ActionList.shortcut_map[shortcuts[1]] = actions else: log.warning('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' % - (shortcuts[1], action.objectName())) + (shortcuts[1], action.objectName())) shortcuts.remove(shortcuts[1]) # Check the primary shortcut. existing_actions = ActionList.shortcut_map.get(shortcuts[0], []) @@ -291,7 +291,7 @@ class ActionList(object): ActionList.shortcut_map[shortcuts[0]] = actions else: log.warning('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' % - (shortcuts[0], action.objectName())) + (shortcuts[0], action.objectName())) shortcuts.remove(shortcuts[0]) action.setShortcuts([QtGui.QKeySequence(shortcut) for shortcut in shortcuts]) From 62811d660fbbc005da735eb1649c2437c9719e92 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 27 Aug 2014 10:43:18 +0200 Subject: [PATCH 41/44] Implemented a workaround for bug1251437 Fixes: https://launchpad.net/bugs/1251437 --- openlp/core/utils/__init__.py | 19 +++++++++++++++++++ openlp/plugins/bibles/lib/http.py | 1 - .../openlp_plugins/bibles/test_lib_http.py | 13 +++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 9b024eb84..255384b2d 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -109,6 +109,22 @@ class VersionThread(QtCore.QThread): Registry().execute('openlp_version_check', '%s' % version) +class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler): + """ + Special HTTPRedirectHandler used to work around http://bugs.python.org/issue22248 + (Redirecting to urls with special chars) + """ + def redirect_request(self, req, fp, code, msg, headers, newurl): + # Test if the newurl can be decoded to ascii + try: + test_url = newurl.encode('latin1').decode('ascii') + fixed_url = newurl + except Exception: + # The url could not be decoded to ascii, so we do some url encoding + fixed_url = urllib.parse.quote(newurl.encode('latin1').decode('utf-8', 'replace'), safe='/:') + return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url) + + def get_application_version(): """ Returns the application version of the running instance of OpenLP:: @@ -341,6 +357,9 @@ def get_web_page(url, header=None, update_openlp=False): # http://docs.python.org/library/urllib2.html if not url: return None + # This is needed to work around http://bugs.python.org/issue22248 and https://bugs.launchpad.net/openlp/+bug/1251437 + opener = urllib.request.build_opener(HTTPRedirectHandlerFixed()) + urllib.request.install_opener(opener) req = urllib.request.Request(url) if not header or header[0].lower() != 'user-agent': user_agent = _get_user_agent() diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 6b26dfabe..9f60ecc33 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -32,7 +32,6 @@ The :mod:`http` module enables OpenLP to retrieve scripture from bible websites. import logging import re import socket -import urllib.request import urllib.parse import urllib.error from html.parser import HTMLParseError diff --git a/tests/interfaces/openlp_plugins/bibles/test_lib_http.py b/tests/interfaces/openlp_plugins/bibles/test_lib_http.py index 517732e4d..9d72677ce 100644 --- a/tests/interfaces/openlp_plugins/bibles/test_lib_http.py +++ b/tests/interfaces/openlp_plugins/bibles/test_lib_http.py @@ -59,6 +59,19 @@ class TestBibleHTTP(TestCase): # THEN: We should get back a valid service item assert len(books) == 66, 'The bible should not have had any books added or removed' + def bible_gateway_extract_books_support_redirect_test(self): + """ + Test the Bible Gateway retrieval of book list for DN1933 bible with redirect (bug 1251437) + """ + # GIVEN: A new Bible Gateway extraction class + handler = BGExtract() + + # WHEN: The Books list is called + books = handler.get_books_from_http('DN1933') + + # THEN: We should get back a valid service item + assert len(books) == 66, 'This bible should have 66 books' + def bible_gateway_extract_verse_test(self): """ Test the Bible Gateway retrieval of verse list for NIV bible John 3 From f3207dac8e2760c1f9fffaa0b836a35b42624997 Mon Sep 17 00:00:00 2001 From: Jonathan Springer Date: Wed, 27 Aug 2014 19:18:06 -0400 Subject: [PATCH 42/44] Consolidate platform specific checks into the common module --- openlp/core/__init__.py | 8 +-- openlp/core/common/__init__.py | 27 ++++++++++ openlp/core/common/applocation.py | 8 +-- openlp/core/common/registryproperties.py | 6 +-- openlp/core/common/settings.py | 6 +-- openlp/core/ui/exceptionform.py | 4 +- openlp/core/ui/maindisplay.py | 6 +-- openlp/core/ui/mainwindow.py | 13 ++--- openlp/core/ui/media/vlcplayer.py | 8 +-- openlp/core/utils/__init__.py | 4 +- openlp/core/utils/languagemanager.py | 4 +- .../presentations/lib/impresscontroller.py | 20 ++++---- .../presentations/lib/pdfcontroller.py | 4 +- .../presentations/lib/powerpointcontroller.py | 10 ++-- .../presentations/lib/pptviewcontroller.py | 8 +-- openlp/plugins/songs/forms/songselectform.py | 4 +- openlp/plugins/songs/lib/importer.py | 6 +-- .../plugins/songs/lib/importers/openoffice.py | 9 ++-- .../songs/lib/importers/songsoffellowship.py | 3 +- .../openlp_core_common/test_common.py | 51 ++++++++++++++++++- 20 files changed, 146 insertions(+), 63 deletions(-) diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py index 4ab94a250..32ef5c5a3 100644 --- a/openlp/core/__init__.py +++ b/openlp/core/__init__.py @@ -36,14 +36,14 @@ logging and a plugin framework are contained within the openlp.core module. import os import sys -import platform import logging from optparse import OptionParser from traceback import format_exception from PyQt4 import QtCore, QtGui -from openlp.core.common import Registry, OpenLPMixin, AppLocation, Settings, UiStrings, check_directory_exists +from openlp.core.common import Registry, OpenLPMixin, AppLocation, Settings, UiStrings, check_directory_exists, \ + is_macosx, is_win from openlp.core.lib import ScreenList from openlp.core.resources import qInitResources from openlp.core.ui.mainwindow import MainWindow @@ -126,7 +126,7 @@ class OpenLP(OpenLPMixin, QtGui.QApplication): alternate_rows_repair_stylesheet = \ 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' application_stylesheet += alternate_rows_repair_stylesheet - if os.name == 'nt': + if is_win(): application_stylesheet += NT_REPAIR_STYLESHEET if application_stylesheet: self.setStyleSheet(application_stylesheet) @@ -275,7 +275,7 @@ def main(args=None): # Throw the rest of the arguments at Qt, just in case. qt_args.extend(args) # Bug #1018855: Set the WM_CLASS property in X11 - if platform.system() not in ['Windows', 'Darwin']: + if not is_win() and not is_macosx(): qt_args.append('OpenLP') # Initialise the resources qInitResources() diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index 22207dec4..0776547ae 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -127,6 +127,33 @@ def de_hump(name): sub_name = FIRST_CAMEL_REGEX.sub(r'\1_\2', name) return SECOND_CAMEL_REGEX.sub(r'\1_\2', sub_name).lower() + +def is_win(): + """ + Returns true if running on a system with a nt kernel e.g. Windows, Wine + + :return: True if system is running a nt kernel false otherwise + """ + return os.name.startswith('nt') + + +def is_macosx(): + """ + Returns true if running on a system with a darwin kernel e.g. Mac OS X + + :return: True if system is running a darwin kernel false otherwise + """ + return sys.platform.startswith('darwin') + + +def is_linux(): + """ + Returns true if running on a system with a linux kernel e.g. Ubuntu, Debian, etc + + :return: True if system is running a linux kernel false otherwise + """ + return sys.platform.startswith('linux') + from .openlpmixin import OpenLPMixin from .registry import Registry from .registrymixin import RegistryMixin diff --git a/openlp/core/common/applocation.py b/openlp/core/common/applocation.py index 073d3c7f7..89f637e69 100644 --- a/openlp/core/common/applocation.py +++ b/openlp/core/common/applocation.py @@ -33,10 +33,10 @@ import logging import os import sys -from openlp.core.common import Settings +from openlp.core.common import Settings, is_win, is_macosx -if sys.platform != 'win32' and sys.platform != 'darwin': +if not is_win() and not is_macosx(): try: from xdg import BaseDirectory XDG_BASE_AVAILABLE = True @@ -145,13 +145,13 @@ def _get_os_dir_path(dir_type): directory = os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources')) if os.path.exists(directory): return directory - if sys.platform == 'win32': + if is_win(): if dir_type == AppLocation.DataDir: return os.path.join(str(os.getenv('APPDATA')), 'openlp', 'data') elif dir_type == AppLocation.LanguageDir: return os.path.dirname(openlp.__file__) return os.path.join(str(os.getenv('APPDATA')), 'openlp') - elif sys.platform == 'darwin': + elif is_macosx(): if dir_type == AppLocation.DataDir: return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp', 'Data') elif dir_type == AppLocation.LanguageDir: diff --git a/openlp/core/common/registryproperties.py b/openlp/core/common/registryproperties.py index 791fc33f7..e2cfffa09 100644 --- a/openlp/core/common/registryproperties.py +++ b/openlp/core/common/registryproperties.py @@ -29,9 +29,7 @@ """ Provide Registry values for adding to classes """ -import os - -from openlp.core.common import Registry +from openlp.core.common import Registry, is_win class RegistryProperties(object): @@ -45,7 +43,7 @@ class RegistryProperties(object): Adds the openlp to the class dynamically. Windows needs to access the application in a dynamic manner. """ - if os.name == 'nt': + if is_win(): return Registry().get('application') else: if not hasattr(self, '_application') or not self._application: diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 634bc5ced..f7202b590 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -36,7 +36,7 @@ import sys from PyQt4 import QtCore, QtGui -from openlp.core.common import ThemeLevel, SlideLimits, UiStrings +from openlp.core.common import ThemeLevel, SlideLimits, UiStrings, is_win, is_linux log = logging.getLogger(__name__) @@ -44,7 +44,7 @@ log = logging.getLogger(__name__) # Fix for bug #1014422. X11_BYPASS_DEFAULT = True -if sys.platform.startswith('linux'): +if is_linux(): # Default to False on Gnome. X11_BYPASS_DEFAULT = bool(not os.environ.get('GNOME_DESKTOP_SESSION_ID')) # Default to False on Xfce. @@ -86,7 +86,7 @@ class Settings(QtCore.QSettings): """ __default_settings__ = { 'advanced/add page break': False, - 'advanced/alternate rows': not sys.platform.startswith('win'), + 'advanced/alternate rows': not is_win(), 'advanced/current media plugin': -1, 'advanced/data path': '', 'advanced/default color': '#ffffff', diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index e0228a43b..65b858b75 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -38,7 +38,7 @@ import bs4 import sqlalchemy from lxml import etree -from openlp.core.common import RegistryProperties +from openlp.core.common import RegistryProperties, is_linux from PyQt4 import Qt, QtCore, QtGui, QtWebKit @@ -137,7 +137,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog, RegistryProperties): 'pyICU: %s\n' % ICU_VERSION + \ 'pyUNO bridge: %s\n' % self._pyuno_import() + \ 'VLC: %s\n' % VLC_VERSION - if platform.system() == 'Linux': + if is_linux(): if os.environ.get('KDE_FULL_SESSION') == 'true': system += 'Desktop: KDE SC\n' elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 5c905c972..f9f00a235 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -43,7 +43,7 @@ import sys from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL from PyQt4.phonon import Phonon -from openlp.core.common import Registry, RegistryProperties, OpenLPMixin, Settings, translate +from openlp.core.common import Registry, RegistryProperties, OpenLPMixin, Settings, translate, is_macosx from openlp.core.lib import ServiceItem, ImageSource, build_html, expand_tags, image_to_byte from openlp.core.lib.theme import BackgroundType @@ -74,7 +74,7 @@ class Display(QtGui.QGraphicsView): # OpenGL. Only white blank screen is shown on the 2nd monitor all the # time. We need to investigate more how to use OpenGL properly on Mac OS # X. - if sys.platform != 'darwin': + if not is_macosx(): self.setViewport(QtOpenGL.QGLWidget()) def setup(self): @@ -143,7 +143,7 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties): # on Mac OS X. For next OpenLP version we should test it on other # platforms. For OpenLP 2.0 keep it only for OS X to not cause any # regressions on other platforms. - if sys.platform == 'darwin': + if is_macosx(): window_flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Window # For primary screen ensure it stays above the OS X dock # and menu bar diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 6894293ce..1a6b688c7 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -41,7 +41,8 @@ from datetime import datetime from PyQt4 import QtCore, QtGui -from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, check_directory_exists, translate +from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, check_directory_exists, translate, \ + is_win, is_macosx from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, ImageManager, PluginStatus, ScreenList, \ build_icon from openlp.core.lib.ui import UiStrings, create_action @@ -289,7 +290,7 @@ class Ui_MainWindow(object): triggers=self.on_about_item_clicked) # Give QT Extra Hint that this is an About Menu Item self.about_item.setMenuRole(QtGui.QAction.AboutRole) - if os.name == 'nt': + if is_win(): self.local_help_file = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm') self.offline_help_item = create_action(main_window, 'offlineHelpItem', icon=':/system/system_help_contents.png', @@ -323,7 +324,7 @@ class Ui_MainWindow(object): # Qt on OS X looks for keywords in the menu items title to determine which menu items get added to the main # menu. If we are running on Mac OS X the menu items whose title contains those keywords but don't belong in the # main menu need to be marked as such with QAction.NoRole. - if sys.platform == 'darwin': + if is_macosx(): self.settings_shortcuts_item.setMenuRole(QtGui.QAction.NoRole) self.formatting_tag_item.setMenuRole(QtGui.QAction.NoRole) add_actions(self.settings_menu, (self.settings_plugin_list_item, self.settings_language_menu.menuAction(), @@ -332,7 +333,7 @@ class Ui_MainWindow(object): add_actions(self.tools_menu, (self.tools_open_data_folder, None)) add_actions(self.tools_menu, (self.tools_first_time_wizard, None)) add_actions(self.tools_menu, [self.update_theme_images]) - if os.name == 'nt': + if is_win(): add_actions(self.help_menu, (self.offline_help_item, self.on_line_help_item, None, self.web_site_item, self.about_item)) else: @@ -426,7 +427,7 @@ class Ui_MainWindow(object): self.settings_plugin_list_item.setStatusTip(translate('OpenLP.MainWindow', 'List the Plugins')) self.about_item.setText(translate('OpenLP.MainWindow', '&About')) self.about_item.setStatusTip(translate('OpenLP.MainWindow', 'More information about OpenLP')) - if os.name == 'nt': + if is_win(): self.offline_help_item.setText(translate('OpenLP.MainWindow', '&User Guide')) self.on_line_help_item.setText(translate('OpenLP.MainWindow', '&Online Help')) self.search_shortcut_action.setText(UiStrings().Search) @@ -1073,7 +1074,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties): if self.live_controller.display: self.live_controller.display.close() self.live_controller.display = None - if os.name == 'nt': + if is_win(): # Needed for Windows to stop crashes on exit Registry().remove('application') diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index d02526b0e..4394126c0 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -38,7 +38,7 @@ import threading from PyQt4 import QtGui -from openlp.core.common import Settings +from openlp.core.common import Settings, is_win, is_macosx from openlp.core.lib import translate from openlp.core.ui.media import MediaState from openlp.core.ui.media.mediaplayer import MediaPlayer @@ -52,7 +52,7 @@ try: except (ImportError, NameError, NotImplementedError): pass except OSError as e: - if sys.platform.startswith('win'): + if is_win(): if not isinstance(e, WindowsError) and e.winerror != 126: raise else: @@ -139,9 +139,9 @@ class VlcPlayer(MediaPlayer): # You have to give the id of the QFrame (or similar object) # to vlc, different platforms have different functions for this. win_id = int(display.vlc_widget.winId()) - if sys.platform == "win32": + if is_win(): display.vlc_media_player.set_hwnd(win_id) - elif sys.platform == "darwin": + elif is_macosx(): # We have to use 'set_nsobject' since Qt4 on OSX uses Cocoa # framework and not the old Carbon. display.vlc_media_player.set_nsobject(win_id) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 9b024eb84..bd72db1ac 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -44,10 +44,10 @@ from random import randint from PyQt4 import QtGui, QtCore -from openlp.core.common import Registry, AppLocation, Settings +from openlp.core.common import Registry, AppLocation, Settings, is_win, is_macosx -if sys.platform != 'win32' and sys.platform != 'darwin': +if not is_win() and not is_macosx(): try: from xdg import BaseDirectory XDG_BASE_AVAILABLE = True diff --git a/openlp/core/utils/languagemanager.py b/openlp/core/utils/languagemanager.py index dd048e04c..3c741e58f 100644 --- a/openlp/core/utils/languagemanager.py +++ b/openlp/core/utils/languagemanager.py @@ -35,7 +35,7 @@ import sys from PyQt4 import QtCore, QtGui -from openlp.core.common import AppLocation, Settings, translate +from openlp.core.common import AppLocation, Settings, translate, is_win, is_macosx log = logging.getLogger(__name__) @@ -60,7 +60,7 @@ class LanguageManager(object): app_translator = QtCore.QTranslator() app_translator.load(language, lang_path) # A translator for buttons and other default strings provided by Qt. - if sys.platform != 'win32' and sys.platform != 'darwin': + if not is_win() and not is_macosx(): lang_path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath) default_translator = QtCore.QTranslator() default_translator.load('qt_%s' % language, lang_path) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 1d5e111c9..d032b9161 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -42,7 +42,9 @@ import logging import os import time -if os.name == 'nt': +from openlp.core.common import is_win + +if is_win(): from win32com.client import Dispatch import pywintypes # Declare an empty exception to match the exception imported from UNO @@ -93,7 +95,7 @@ class ImpressController(PresentationController): Impress is able to run on this machine. """ log.debug('check_available') - if os.name == 'nt': + if is_win(): return self.get_com_servicemanager() is not None else: return uno_available @@ -104,7 +106,7 @@ class ImpressController(PresentationController): UNO interface when required. """ log.debug('start process Openoffice') - if os.name == 'nt': + if is_win(): self.manager = self.get_com_servicemanager() self.manager._FlagAsMethod('Bridge_GetStruct') self.manager._FlagAsMethod('Bridge_GetValueObject') @@ -175,7 +177,7 @@ class ImpressController(PresentationController): self.docs[0].close_presentation() desktop = None try: - if os.name != 'nt': + if not is_win(): desktop = self.get_uno_desktop() else: desktop = self.get_com_desktop() @@ -223,7 +225,7 @@ class ImpressDocument(PresentationDocument): is available the presentation is loaded and started. """ log.debug('Load Presentation OpenOffice') - if os.name == 'nt': + if is_win(): desktop = self.controller.get_com_desktop() if desktop is None: self.controller.start_process() @@ -236,7 +238,7 @@ class ImpressDocument(PresentationDocument): return False self.desktop = desktop properties = [] - if os.name != 'nt': + if not is_win(): # Recent versions of Impress on Windows won't start the presentation if it starts as minimized. It seems OK # on Linux though. properties.append(self.create_property('Minimized', True)) @@ -246,7 +248,7 @@ class ImpressDocument(PresentationDocument): except: log.warning('Failed to load presentation %s' % url) return False - if os.name == 'nt': + if is_win(): # As we can't start minimized the Impress window gets in the way. # Either window.setPosSize(0, 0, 200, 400, 12) or .setVisible(False) window = self.document.getCurrentController().getFrame().getContainerWindow() @@ -264,7 +266,7 @@ class ImpressDocument(PresentationDocument): log.debug('create thumbnails OpenOffice') if self.check_thumbnails(): return - if os.name == 'nt': + if is_win(): thumb_dir_url = 'file:///' + self.get_temp_folder().replace('\\', '/') \ .replace(':', '|').replace(' ', '%20') else: @@ -297,7 +299,7 @@ class ImpressDocument(PresentationDocument): Create an OOo style property object which are passed into some Uno methods. """ log.debug('create property OpenOffice') - if os.name == 'nt': + if is_win(): property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') else: property_object = PropertyValue() diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index b98ae131a..0283fefd4 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -34,7 +34,7 @@ import re from subprocess import check_output, CalledProcessError, STDOUT from openlp.core.utils import AppLocation -from openlp.core.common import Settings +from openlp.core.common import Settings, is_win from openlp.core.lib import ScreenList from .presentationcontroller import PresentationController, PresentationDocument @@ -123,7 +123,7 @@ class PdfController(PresentationController): else: # Fallback to autodetection application_path = AppLocation.get_directory(AppLocation.AppDir) - if os.name == 'nt': + if is_win(): # for windows we only accept mudraw.exe in the base folder application_path = AppLocation.get_directory(AppLocation.AppDir) if os.path.isfile(os.path.join(application_path, 'mudraw.exe')): diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 0f9c2ff35..f42e4f814 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -33,7 +33,9 @@ This modul is for controlling powerpiont. PPT API documentation: import os import logging -if os.name == 'nt': +from openlp.core.common import is_win + +if is_win(): from win32com.client import Dispatch import winreg import win32ui @@ -69,7 +71,7 @@ class PowerpointController(PresentationController): PowerPoint is able to run on this machine. """ log.debug('check_available') - if os.name == 'nt': + if is_win(): try: winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, 'PowerPoint.Application').Close() return True @@ -77,7 +79,7 @@ class PowerpointController(PresentationController): pass return False - if os.name == 'nt': + if is_win(): def start_process(self): """ Loads PowerPoint process. @@ -271,7 +273,7 @@ class PowerpointDocument(PresentationDocument): trace_error_handler(log) self.show_error_msg() - if os.name == 'nt': + if is_win(): def start_presentation(self): """ Starts a presentation from the beginning. diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index a9090dd1e..7e03e322f 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -30,7 +30,9 @@ import logging import os -if os.name == 'nt': +from openlp.core.common import is_win + +if is_win(): from ctypes import cdll from ctypes.wintypes import RECT @@ -63,11 +65,11 @@ class PptviewController(PresentationController): PPT Viewer is able to run on this machine. """ log.debug('check_available') - if os.name != 'nt': + if not is_win(): return False return self.check_installed() - if os.name == 'nt': + if is_win(): def check_installed(self): """ Check the viewer is installed. diff --git a/openlp/plugins/songs/forms/songselectform.py b/openlp/plugins/songs/forms/songselectform.py index f9f658c5b..aecdf9682 100755 --- a/openlp/plugins/songs/forms/songselectform.py +++ b/openlp/plugins/songs/forms/songselectform.py @@ -37,7 +37,7 @@ from time import sleep from PyQt4 import QtCore, QtGui from openlp.core import Settings -from openlp.core.common import Registry +from openlp.core.common import Registry, is_win from openlp.core.lib import translate from openlp.plugins.songs.forms.songselectdialog import Ui_SongSelectDialog from openlp.plugins.songs.lib.songselect import SongSelectImport @@ -377,7 +377,7 @@ class SongSelectForm(QtGui.QDialog, Ui_SongSelectDialog): Adds the openlp to the class dynamically. Windows needs to access the application in a dynamic manner. """ - if os.name == 'nt': + if is_win(): return Registry().get('application') else: if not hasattr(self, '_application'): diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index e9ee2c2f3..12c8887f7 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -32,7 +32,7 @@ The :mod:`importer` modules provides the general song import functionality. import os import logging -from openlp.core.common import translate, UiStrings +from openlp.core.common import translate, UiStrings, is_win from openlp.core.ui.wizard import WizardStrings from .importers.opensong import OpenSongImport from .importers.easyslides import EasySlidesImport @@ -70,14 +70,14 @@ except ImportError: log.exception('Error importing %s', 'OooImport') HAS_OOO = False HAS_MEDIASHOUT = False -if os.name == 'nt': +if is_win(): try: from .importers.mediashout import MediaShoutImport HAS_MEDIASHOUT = True except ImportError: log.exception('Error importing %s', 'MediaShoutImport') HAS_WORSHIPCENTERPRO = False -if os.name == 'nt': +if is_win(): try: from .importers.worshipcenterpro import WorshipCenterProImport HAS_WORSHIPCENTERPRO = True diff --git a/openlp/plugins/songs/lib/importers/openoffice.py b/openlp/plugins/songs/lib/importers/openoffice.py index 0e499f7ae..a0bb1df88 100644 --- a/openlp/plugins/songs/lib/importers/openoffice.py +++ b/openlp/plugins/songs/lib/importers/openoffice.py @@ -32,13 +32,14 @@ import time from PyQt4 import QtCore +from openlp.core.common import is_win from openlp.core.utils import get_uno_command, get_uno_instance from openlp.core.lib import translate from .songimport import SongImport log = logging.getLogger(__name__) -if os.name == 'nt': +if is_win(): from win32com.client import Dispatch NoConnectException = Exception else: @@ -106,7 +107,7 @@ class OpenOfficeImport(SongImport): Start OpenOffice.org process TODO: The presentation/Impress plugin may already have it running """ - if os.name == 'nt': + if is_win(): self.start_ooo_process() self.desktop = self.ooo_manager.createInstance('com.sun.star.frame.Desktop') else: @@ -133,7 +134,7 @@ class OpenOfficeImport(SongImport): Start the OO Process """ try: - if os.name == 'nt': + if is_win(): self.ooo_manager = Dispatch('com.sun.star.ServiceManager') self.ooo_manager._FlagAsMethod('Bridge_GetStruct') self.ooo_manager._FlagAsMethod('Bridge_GetValueObject') @@ -150,7 +151,7 @@ class OpenOfficeImport(SongImport): Open the passed file in OpenOffice.org Impress """ self.file_path = file_path - if os.name == 'nt': + if is_win(): url = file_path.replace('\\', '/') url = url.replace(':', '|').replace(' ', '%20') url = 'file:///' + url diff --git a/openlp/plugins/songs/lib/importers/songsoffellowship.py b/openlp/plugins/songs/lib/importers/songsoffellowship.py index c1ef8666f..2cc49caef 100644 --- a/openlp/plugins/songs/lib/importers/songsoffellowship.py +++ b/openlp/plugins/songs/lib/importers/songsoffellowship.py @@ -37,12 +37,13 @@ import logging import os import re +from openlp.core.common import is_win from .openoffice import OpenOfficeImport log = logging.getLogger(__name__) -if os.name == 'nt': +if is_win(): from .openoffice import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH RuntimeException = Exception else: diff --git a/tests/functional/openlp_core_common/test_common.py b/tests/functional/openlp_core_common/test_common.py index f52256c5c..0474bd404 100644 --- a/tests/functional/openlp_core_common/test_common.py +++ b/tests/functional/openlp_core_common/test_common.py @@ -32,7 +32,8 @@ Functional tests to test the AppLocation class and related methods. from unittest import TestCase -from openlp.core.common import check_directory_exists, de_hump, trace_error_handler, translate +from openlp.core.common import check_directory_exists, de_hump, trace_error_handler, translate, is_win, is_macosx, \ + is_linux from tests.functional import MagicMock, patch @@ -139,3 +140,51 @@ class TestCommonFunctions(TestCase): # THEN: the translated string should be returned, and the mocked function should have been called mocked_translate.assert_called_with(context, text, comment, encoding, n) self.assertEqual('Translated string', result, 'The translated string should have been returned') + + def is_win_test(self): + """ + Test the is_win() function + """ + # GIVEN: Mocked out objects + with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys: + + # WHEN: The mocked os.name and sys.platform are set to 'nt' and 'win32' repectivly + mocked_os.name = 'nt' + mocked_sys.platform = 'win32' + + # THEN: The three platform functions should perform properly + self.assertTrue(is_win(), 'is_win() should return True') + self.assertFalse(is_macosx(), 'is_macosx() should return False') + self.assertFalse(is_linux(), 'is_linux() should return False') + + def is_macosx_test(self): + """ + Test the is_macosx() function + """ + # GIVEN: Mocked out objects + with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys: + + # WHEN: The mocked os.name and sys.platform are set to 'posix' and 'darwin' repectivly + mocked_os.name = 'posix' + mocked_sys.platform = 'darwin' + + # THEN: The three platform functions should perform properly + self.assertTrue(is_macosx(), 'is_macosx() should return True') + self.assertFalse(is_win(), 'is_win() should return False') + self.assertFalse(is_linux(), 'is_linux() should return False') + + def is_linux_test(self): + """ + Test the is_linux() function + """ + # GIVEN: Mocked out objects + with patch('openlp.core.common.os') as mocked_os, patch('openlp.core.common.sys') as mocked_sys: + + # WHEN: The mocked os.name and sys.platform are set to 'posix' and 'linux3' repectivly + mocked_os.name = 'posix' + mocked_sys.platform = 'linux3' + + # THEN: The three platform functions should perform properly + self.assertTrue(is_linux(), 'is_linux() should return True') + self.assertFalse(is_win(), 'is_win() should return False') + self.assertFalse(is_macosx(), 'is_macosx() should return False') From 25608fd672a07413d39a9be8c14cc84f707dd34a Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 2 Sep 2014 21:15:18 +0100 Subject: [PATCH 43/44] Fixed signals. --- .../media/forms/mediaclipselectordialog.py | 4 +-- .../media/forms/mediaclipselectorform.py | 26 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index 88b4616eb..94d5ee05e 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -160,8 +160,8 @@ class Ui_MediaClipSelector(object): # Save and close buttons self.button_box = QtGui.QDialogButtonBox(media_clip_selector) self.button_box.addButton(QtGui.QDialogButtonBox.Save) - self.button_box.addButton(QtGui.QDialogButtonBox.Cancel) - self.close_button = self.button_box.button(QtGui.QDialogButtonBox.Cancel) + self.button_box.addButton(QtGui.QDialogButtonBox.Close) + self.close_button = self.button_box.button(QtGui.QDialogButtonBox.Close) self.save_button = self.button_box.button(QtGui.QDialogButtonBox.Save) self.main_layout.addWidget(self.button_box) diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 449b95d46..28d37f32e 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -195,12 +195,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): return True @QtCore.pyqtSlot(bool) - def on_load_disc_pushbutton_clicked(self, clicked): + def on_load_disc_button_clicked(self, clicked): """ Load the media when the load-button has been clicked :param clicked: Given from signal, not used. """ + log.debug('on_load_disc_button_clicked') self.disable_all() path = self.media_path_combobox.currentText() # Check if given path is non-empty and exists before starting VLC @@ -268,7 +269,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): log.debug('load_disc_button end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) @QtCore.pyqtSlot(bool) - def on_play_pushbutton_clicked(self, clicked): + def on_play_button_clicked(self, clicked): """ Toggle the playback @@ -283,7 +284,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.play_button.setIcon(self.pause_icon) @QtCore.pyqtSlot(bool) - def on_set_start_pushbutton_clicked(self, clicked): + def on_set_start_button_clicked(self, clicked): """ Copy the current player position to start_position_edit @@ -299,7 +300,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.end_timeedit.setTime(new_pos_time) @QtCore.pyqtSlot(bool) - def on_set_end_pushbutton_clicked(self, clicked): + def on_set_end_button_clicked(self, clicked): """ Copy the current player position to end_timeedit @@ -339,7 +340,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.start_position_edit.setTime(new_time) @QtCore.pyqtSlot(bool) - def on_jump_end_pushbutton_clicked(self, clicked): + def on_jump_end_button_clicked(self, clicked): """ Set the player position to the position stored in end_timeedit @@ -353,7 +354,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.set_time(end_time_ms) @QtCore.pyqtSlot(bool) - def on_jump_start_pushbutton_clicked(self, clicked): + def on_jump_start_button_clicked(self, clicked): """ Set the player position to the position stored in start_position_edit @@ -367,13 +368,13 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.vlc_media_player.set_time(start_time_ms) @QtCore.pyqtSlot(int) - def on_title_combo_box_currentIndexChanged(self, index): + def on_titles_combo_box_currentIndexChanged(self, index): """ When a new title is chosen, it is loaded by VLC and info about audio and subtitle tracks is reloaded :param index: The index of the newly chosen title track. """ - log.debug('in on_title_combo_box_changed, index: %d', index) + log.debug('in on_titles_combo_box_changed, index: %d', index) if not self.vlc_media_player: log.error('vlc_media_player was None') return @@ -474,7 +475,7 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): if subtitle_track: self.vlc_media_player.video_set_spu(int(subtitle_track)) - def on_position_horizontalslider_sliderMoved(self, position): + def on_position_slider_sliderMoved(self, position): """ Set player position according to new slider position. @@ -530,14 +531,11 @@ class MediaClipSelectorForm(QtGui.QDialog, Ui_MediaClipSelector): self.jump_end_button.setDisabled(action) self.save_button.setDisabled(action) - @QtCore.pyqtSlot(bool) - def on_save_pushbutton_clicked(self, clicked): + def accept(self): """ Saves the current media and trackinfo as a clip to the mediamanager - - :param clicked: Given from signal, not used. """ - log.debug('in on_save_pushbutton_clicked') + log.debug('in on_save_button_clicked') start_time = self.start_position_edit.time() start_time_ms = start_time.hour() * 60 * 60 * 1000 + \ start_time.minute() * 60 * 1000 + \ From 3b4ce374f2bffe476c0a828d094e3a955d8abcc6 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 2 Sep 2014 21:24:57 +0100 Subject: [PATCH 44/44] pep8 fix --- openlp/plugins/media/forms/mediaclipselectordialog.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/media/forms/mediaclipselectordialog.py b/openlp/plugins/media/forms/mediaclipselectordialog.py index 94d5ee05e..ca091693e 100644 --- a/openlp/plugins/media/forms/mediaclipselectordialog.py +++ b/openlp/plugins/media/forms/mediaclipselectordialog.py @@ -101,7 +101,8 @@ class Ui_MediaClipSelector(object): # Preview frame self.preview_frame = QtGui.QFrame(media_clip_selector) self.preview_frame.setMinimumSize(QtCore.QSize(320, 240)) - self.preview_frame.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) + self.preview_frame.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.MinimumExpanding)) self.preview_frame.setStyleSheet('background-color:black;') self.preview_frame.setFrameShape(QtGui.QFrame.NoFrame) self.preview_frame.setObjectName('preview_frame')