def setUp(self): ''' Stardard init method: runs before each test_* method Initializes a QtGui.QApplication and ConfigToolApp object. ConfigToolApp.show() causes the UI to be rendered. ''' settings.configdir = tempfile.mkdtemp() self.app = QtGui.QApplication([]) self.config_tool = ConfigToolApp() self.config_tool.show()
def launch_configtool(): """Launch Freeseer Configuration GUI if no arguments are passed""" from PyQt4 import QtGui from freeseer.frontend.configtool.configtool import ConfigToolApp profile = settings.profile_manager.get() config = profile.get_config('freeseer.conf', settings.FreeseerConfig, storage_args=['Global'], read_only=False) app = QtGui.QApplication(sys.argv) main = ConfigToolApp(profile, config) main.show() sys.exit(app.exec_())
def setUp(self): ''' Stardard init method: runs before each test_* method Initializes a QtGui.QApplication and ConfigToolApp object. ConfigToolApp.show() causes the UI to be rendered. ''' self.profile_manager = ProfileManager(tempfile.mkdtemp()) profile = self.profile_manager.get('testing') config = profile.get_config('freeseer.conf', settings.FreeseerConfig, storage_args=['Global'], read_only=False) self.app = QtGui.QApplication([]) self.config_tool = ConfigToolApp(profile, config) self.config_tool.show()
def __init__(self, profile, config): FreeseerApp.__init__(self) self.db = profile.get_database() self.config = config self.controller = RecordingController(profile, self.db, self.config) self.recently_recorded_video = None self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.autoRecordWidget = AutoRecordWidget() self.configToolApp = ConfigToolApp(profile, config) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self.config, self.db) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # Initialize variables for auto-recording self.singleID = None self.timeUntilStart = None self.timeUntilEnd = None self.autoTalks = None self.recorded = False self.beforeStartTimer = QtCore.QTimer(self) self.beforeStartTimer.timeout.connect(self.start_single_record) self.beforeEndTimer = QtCore.QTimer(self) self.beforeEndTimer.timeout.connect(self.single_auto_record) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.actionAutoRecord = QtGui.QAction(self) leaveButtonShortcut = "Ctrl+R" self.actionAutoRecord.setShortcut(leaveButtonShortcut) self.actionAutoRecord.setCheckable(True) self.actionAutoRecord.setObjectName(_fromUtf8("actionAutoRecord")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) self.menuOptions.addAction(self.actionAutoRecord) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName( _fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL('triggered()'), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL('triggered()'), self.toggle_record_button) self.connect( self.systray, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self._icon_activated) # --- End Systray Setup # main tab connections self.connect(self.mainWidget.eventComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_rooms_from_event) self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_dates_from_event_room) self.connect(self.mainWidget.dateComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_date) self.connect(self.mainWidget.talkComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.set_talk_tooltip) self.connect(self.mainWidget.standbyButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.disengageButton, QtCore.SIGNAL("clicked()"), functools.partial(self.standby, state=False)) self.connect(self.mainWidget.recordButton, QtCore.SIGNAL('clicked()'), self.record) self.connect(self.mainWidget.pauseButton, QtCore.SIGNAL('toggled(bool)'), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL('toggled(bool)'), self.toggle_audio_feedback) self.connect(self.mainWidget.playButton, QtCore.SIGNAL('clicked()'), self.play_video) self.connect(self.autoRecordWidget.leaveButton, QtCore.SIGNAL('clicked()'), functools.partial(self.auto_record, state=False)) self.autoRecordWidget.leaveButton.setShortcut(leaveButtonShortcut) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL('triggered()'), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL('triggered()'), self.open_talkeditor) self.connect(self.actionAutoRecord, QtCore.SIGNAL('toggled(bool)'), self.auto_record) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL('triggered()'), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL('triggered()'), self.show_report_widget) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.pauseButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.pauseButton.setFocus() self.retranslate()
class RecordApp(FreeseerApp): """Freeseer's main GUI class.""" def __init__(self, profile, config): FreeseerApp.__init__(self) self.db = profile.get_database() self.config = config self.controller = RecordingController(profile, self.db, self.config) self.recently_recorded_video = None self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.autoRecordWidget = AutoRecordWidget() self.configToolApp = ConfigToolApp(profile, config) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self.config, self.db) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # Initialize variables for auto-recording self.singleID = None self.timeUntilStart = None self.timeUntilEnd = None self.autoTalks = None self.recorded = False self.beforeStartTimer = QtCore.QTimer(self) self.beforeStartTimer.timeout.connect(self.start_single_record) self.beforeEndTimer = QtCore.QTimer(self) self.beforeEndTimer.timeout.connect(self.single_auto_record) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.actionAutoRecord = QtGui.QAction(self) leaveButtonShortcut = "Ctrl+R" self.actionAutoRecord.setShortcut(leaveButtonShortcut) self.actionAutoRecord.setCheckable(True) self.actionAutoRecord.setObjectName(_fromUtf8("actionAutoRecord")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) self.menuOptions.addAction(self.actionAutoRecord) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName( _fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL('triggered()'), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL('triggered()'), self.toggle_record_button) self.connect( self.systray, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self._icon_activated) # --- End Systray Setup # main tab connections self.connect(self.mainWidget.eventComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_rooms_from_event) self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_dates_from_event_room) self.connect(self.mainWidget.dateComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_date) self.connect(self.mainWidget.talkComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.set_talk_tooltip) self.connect(self.mainWidget.standbyButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.disengageButton, QtCore.SIGNAL("clicked()"), functools.partial(self.standby, state=False)) self.connect(self.mainWidget.recordButton, QtCore.SIGNAL('clicked()'), self.record) self.connect(self.mainWidget.pauseButton, QtCore.SIGNAL('toggled(bool)'), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL('toggled(bool)'), self.toggle_audio_feedback) self.connect(self.mainWidget.playButton, QtCore.SIGNAL('clicked()'), self.play_video) self.connect(self.autoRecordWidget.leaveButton, QtCore.SIGNAL('clicked()'), functools.partial(self.auto_record, state=False)) self.autoRecordWidget.leaveButton.setShortcut(leaveButtonShortcut) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL('triggered()'), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL('triggered()'), self.open_talkeditor) self.connect(self.actionAutoRecord, QtCore.SIGNAL('toggled(bool)'), self.auto_record) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL('triggered()'), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL('triggered()'), self.show_report_widget) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.pauseButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.pauseButton.setFocus() self.retranslate() ### ### Translation Related ### def retranslate(self): self.setWindowTitle( self.app.translate( "RecordApp", "Freeseer - portable presentation recording station")) # # Reusable Strings # self.standbyString = self.app.translate("RecordApp", "Standby") self.disengageString = self.app.translate("RecordApp", "Leave record-mode") self.standbyTooltipString = self.app.translate( "RecordApp", "Sets up the system for recording") self.disengageTooltipString = self.app.translate( "RecordApp", "Go back to edit talk information or select a different talk") self.autoRecordString = self.app.translate("RecordApp", "Auto Record") self.recordString = self.app.translate("RecordApp", "Record") self.pauseString = self.app.translate("RecordApp", "Pause") self.resumeString = self.app.translate("RecordApp", "Resume") self.stopString = self.app.translate("RecordApp", "Stop") self.stopAutoString = self.app.translate("RecordApp", "Stop Auto Record") self.hideWindowString = self.app.translate("RecordApp", "Hide Main Window") self.showWindowString = self.app.translate("RecordApp", "Show Main Window") self.playVideoString = self.app.translate("RecordApp", "Play") # Status Bar messages self.idleString = self.app.translate("RecordApp", "Idle.") self.readyString = self.app.translate("RecordApp", "Ready.") self.recordingString = self.app.translate("RecordApp", "Recording") self.pausedString = self.app.translate("RecordApp", "Recording Paused.") self.freeSpaceString = self.app.translate("RecordApp", "Free Space:") self.elapsedTimeString = self.app.translate("RecordApp", "Elapsed Time:") # --- End Reusable Strings if self.mainWidget.is_recording and self.mainWidget.pauseButton.isChecked( ): self.mainWidget.statusLabel.setText(self.pausedString) elif self.mainWidget.is_recording and ( not self.mainWidget.pauseButton.isChecked()): self.mainWidget.statusLabel.setText(self.recordingString) elif self.mainWidget.standbyButton.isChecked(): self.mainWidget.statusLabel.setText(self.readyString) elif self.actionAutoRecord.isChecked(): self.mainWidget.statusLabel.setText(self.autoRecordString) else: self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format( self.freeSpaceString, get_free_space(self.config.videodir), self.idleString)) # # Menubar # self.menuOptions.setTitle(self.app.translate("RecordApp", "&Options")) self.actionConfigTool.setText( self.app.translate("RecordApp", "&Configuration")) self.actionTalkEditor.setText( self.app.translate("RecordApp", "&Edit Talks")) self.actionAutoRecord.setText(self.autoRecordString) self.actionOpenVideoFolder.setText( self.app.translate("RecordApp", "&Open Video Directory")) self.actionReport.setText(self.app.translate("RecordApp", "&Report")) # --- End Menubar # # Systray # self.visibilityAction.setText(self.hideWindowString) self.recordAction.setText(self.recordString) # --- End Systray # # RecordingWidget # self.mainWidget.disengageButton.setText(self.disengageString) self.mainWidget.standbyButton.setText(self.standbyString) self.mainWidget.standbyButton.setToolTip(self.standbyTooltipString) self.mainWidget.disengageButton.setToolTip(self.disengageTooltipString) if self.mainWidget.is_recording: self.mainWidget.recordButton.setToolTip(self.stopString) else: self.mainWidget.recordButton.setToolTip(self.recordString) self.mainWidget.pauseButton.setText(self.pauseString) self.mainWidget.pauseButton.setToolTip(self.pauseString) self.mainWidget.eventLabel.setText( self.app.translate("RecordApp", "Event")) self.mainWidget.roomLabel.setText( self.app.translate("RecordApp", "Room")) self.mainWidget.dateLabel.setText( self.app.translate("RecordApp", "Date")) self.mainWidget.talkLabel.setText( self.app.translate("RecordApp", "Talk")) # --- End RecordingWidget # # ReportWidget # self.reportWidget.setWindowTitle( self.app.translate("RecordApp", "Reporting Tool")) self.reportWidget.titleLabel.setText( self.app.translate("RecordApp", "Title:")) self.reportWidget.speakerLabel.setText( self.app.translate("RecordApp", "Speaker:")) self.reportWidget.eventLabel.setText( self.app.translate("RecordApp", "Event:")) self.reportWidget.roomLabel.setText( self.app.translate("RecordApp", "Room:")) self.reportWidget.startTimeLabel.setText( self.app.translate("RecordApp", "Start Time:")) self.reportWidget.endTimeLabel.setText( self.app.translate("RecordApp", "End Time:")) self.reportWidget.commentLabel.setText( self.app.translate("RecordApp", "Comment")) self.reportWidget.releaseCheckBox.setText( self.app.translate("RecordApp", "Release Received")) self.reportWidget.closeButton.setText( self.app.translate("RecordApp", "Close")) self.reportWidget.reportButton.setText( self.app.translate("RecordApp", "Report")) # Logic for translating the report options noissues = self.app.translate("RecordApp", "No Issues") noaudio = self.app.translate("RecordApp", "No Audio") novideo = self.app.translate("RecordApp", "No Video") noaudiovideo = self.app.translate("RecordApp", "No Audio/Video") self.reportWidget.options = [noissues, noaudio, novideo, noaudiovideo] self.reportWidget.reportCombo.clear() for i in self.reportWidget.options: self.reportWidget.reportCombo.addItem(i) # --- End ReportWidget ### ### UI Logic ### def load_settings(self): """Load settings for Freeseer""" log.info('Loading settings...') # Load default language. actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talks as a SQL Data Model. self.load_event_list() def current_presentation(self): """Creates a presentation object of the current presentation. Current presentation is the currently selected title on the GUI. """ #i = self.mainWidget.talkComboBox.currentIndex() #p_id = self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() return self.db.get_presentation(self.current_presentation_id()) def current_presentation_id(self): """Returns the current selected presentation ID.""" i = self.mainWidget.talkComboBox.currentIndex() return self.mainWidget.talkComboBox.model().index(i, 1).data( QtCore.Qt.DisplayRole).toString() def standby(self, state): """Prepares the GStreamer pipelines for recording Sets the pipeline to paused state so that initiating a recording does not have a delay due to GStreamer initialization. """ def toggle_gui(state): """Toggles GUI components when standby is pressed""" if state: self.mainWidget.standbyButton.setHidden(state) self.mainWidget.disengageButton.setVisible(state) else: self.mainWidget.disengageButton.setVisible(state) self.mainWidget.standbyButton.setHidden(state) self.mainWidget.recordButton.setEnabled(state) self.mainWidget.eventComboBox.setDisabled(state) self.mainWidget.roomComboBox.setDisabled(state) self.mainWidget.dateComboBox.setDisabled(state) self.mainWidget.talkComboBox.setDisabled(state) self.mainWidget.audioFeedbackCheckbox.setDisabled(state) if state: # Prepare the pipelines if self.load_backend(): toggle_gui(True) self.controller.pause() self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format( self.freeSpaceString, get_free_space(self.config.videodir), self.readyString)) else: toggle_gui(False) self.mainWidget.standbyButton.setChecked(False) else: toggle_gui(False) self.controller.stop() self.mainWidget.standbyButton.setChecked(False) self.mainWidget.playButton.setEnabled(False) def record(self): """The logic for recording and stopping recording.""" if self.mainWidget.is_recording: # Start Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo_rec.png") sysIcon2 = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon2) self.controller.record() self.mainWidget.recordButton.setToolTip(self.stopString) self.mainWidget.disengageButton.setEnabled(False) self.mainWidget.pauseButton.setEnabled(True) self.recordAction.setText(self.stopString) # Hide if auto-hide is set. if self.config.auto_hide: self.hide_window() self.visibilityAction.setText(self.showWindowString) log.debug( 'auto-hide is enabled, main window is now hidden in systray.' ) # Start timer. self.timer.start(1000) else: # Stop Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo.png") sysIcon = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon) self.controller.stop() self.mainWidget.pauseButton.setChecked(False) self.mainWidget.recordButton.setToolTip(self.recordString) self.mainWidget.disengageButton.setEnabled(True) self.mainWidget.pauseButton.setEnabled(False) self.recordAction.setText(self.recordString) self.mainWidget.audioSlider.setValue(0) self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format( self.freeSpaceString, get_free_space(self.config.videodir), self.idleString)) # Finally set the standby button back to unchecked position. self.standby(False) # Stop and reset timer. self.timer.stop() self.reset_timer() #Show playback button self.mainWidget.playButton.setVisible(True) self.mainWidget.playButton.setEnabled(True) # Select next talk if there is one within 15 minutes. if self.current_event and self.current_room: starttime = QtCore.QDateTime().currentDateTime() stoptime = starttime.addSecs(900) talkid = self.db.get_talk_between_time(self.current_event, self.current_room, starttime.toString(), stoptime.toString()) if talkid is not None: for i in range(self.mainWidget.talkComboBox.count()): if talkid == self.mainWidget.talkComboBox.model( ).index(i, 1).data(QtCore.Qt.DisplayRole).toString(): self.mainWidget.talkComboBox.setCurrentIndex(i) def _enable_disable_gui(self, state): """Disables GUI components when Auto Record is pressed, and enables them when Auto Record is released""" self.mainWidget.standbyButton.setDisabled(state) self.mainWidget.eventComboBox.setDisabled(state) self.mainWidget.roomComboBox.setDisabled(state) self.mainWidget.dateComboBox.setDisabled(state) self.mainWidget.talkComboBox.setDisabled(state) self.mainWidget.audioFeedbackCheckbox.setDisabled(state) def stop_auto_record_gui(self): """Sets the gui for stopping the auto record""" self.autoRecordWidget.stop_timer() self.autoRecordWidget.close() self._enable_disable_gui(False) self.recorded = False self.actionAutoRecord.setChecked(False) def auto_record(self, state): """Starts automated recording""" if state: # If there is a room selected, then it's possible to auto-record if self.current_room: self.autoTalks = self.db.get_talks_by_room_and_time( self.current_room) # Start recording if there are talks in database that can be auto-recorded if self.autoTalks.next(): # Set the cursor back to before the first record so that single_auto_record works properly self.autoTalks.previous() self._enable_disable_gui(True) self.single_auto_record() else: # Dialog for no talks to auto-record QtGui.QMessageBox.information( self, 'No Talks to Record', 'There are no upcoming talks to auto-record in this room', QtGui.QMessageBox.Ok) self.actionAutoRecord.setChecked(False) else: # Dialog that pops up when no room is selected QtGui.QMessageBox.information( self, 'No Room Selected', 'Please select a room to auto-record', QtGui.QMessageBox.Ok) self.actionAutoRecord.setChecked(False) else: self.beforeStartTimer.stop() self.beforeEndTimer.stop() self.controller.stop() self.stop_auto_record_gui() self.mainWidget.playButton.setEnabled(False) def single_auto_record(self): """Completes one display and record cycle of the auto-record feature. Stops the recording of the last talk if it exists, displays the countdown until the start of the next talk, and when the talk begins, records the talk while displaying the countdown until the end of the talk. """ if self.recorded: self.controller.stop() self.recorded = False log.debug("Auto-recording for the current talk stopped.") if self.autoTalks.next(): starttime = QtCore.QTime.fromString( self.autoTalks.value(8).toString()) endtime = QtCore.QTime.fromString( self.autoTalks.value(9).toString()) currenttime = QtCore.QTime.currentTime() if currenttime <= starttime: self.singleID = self.autoTalks.value(0).toString() title = self.autoTalks.value(1).toString() speaker = self.autoTalks.value(2).toString() # Time (in seconds) until recording for the talk starts self.timeUntilStart = currenttime.secsTo(starttime) # Time (in seconds) from the starttime to endtime of this talk self.timeUntilEnd = starttime.secsTo(endtime) # Display fullscreen countdown and talk info until talk starts self.autoRecordWidget.set_recording(False) self.autoRecordWidget.set_display_message(title, speaker) self.autoRecordWidget.start_timer(self.timeUntilStart) self.autoRecordWidget.showFullScreen() # Wait for talk to start, then change display and start recording self.beforeStartTimer.setInterval( (self.timeUntilStart + 1) * 1000) self.beforeStartTimer.setSingleShot(True) self.beforeStartTimer.start() else: # Start time has already passed, so move on to next talk self.single_auto_record() else: self.stop_auto_record_gui() def start_single_record(self): """Begins the auto-recording of a single talk while displaying the countdown on screen""" self.autoRecordWidget.set_recording(True) self.autoRecordWidget.set_display_message() self.autoRecordWidget.start_timer(self.timeUntilEnd) if self.controller.record_talk_id(self.singleID): log.debug("Auto-recording for the current talk started.") self.recorded = True self.beforeEndTimer.setInterval((self.timeUntilEnd + 1) * 1000) self.beforeEndTimer.setSingleShot(True) self.beforeEndTimer.start() def pause(self, state): """Pause the recording""" if state: # Pause Recording. self.controller.pause() log.info("Recording paused.") self.mainWidget.pauseButton.setToolTip(self.resumeString) self.mainWidget.statusLabel.setText(self.pausedString) self.timer.stop() elif self.mainWidget.is_recording: self.controller.record() log.info("Recording unpaused.") self.mainWidget.pauseButton.setToolTip(self.pauseString) self.timer.start(1000) def load_backend(self): """Prepares the backend for recording""" if self.current_presentation(): presentation = self.current_presentation() # If current presentation is no existant (empty talk database) # use a default recording name. else: presentation = Presentation(title=unicode("default")) initialized, self.recently_recorded_video = self.controller.load_backend( presentation) if initialized: return True else: return False # Error something failed while loading the backend def update_timer(self): """Updates the Elapsed Time displayed. Uses the statusLabel for the display. """ frmt_time = "%d:%02d" % (self.time_minutes, self.time_seconds) self.time_seconds += 1 if self.time_seconds == 60: self.time_seconds = 0 self.time_minutes += 1 self.mainWidget.statusLabel.setText(u"{} {} --- {} {} --- {}".format( self.elapsedTimeString, frmt_time, self.freeSpaceString, get_free_space(self.config.videodir), self.recordingString)) def reset_timer(self): """Resets the Elapsed Time.""" self.time_minutes = 0 self.time_seconds = 0 def toggle_audio_feedback(self, enabled): """Enables or disables audio feedback according to checkbox state""" self.config.audio_feedback = enabled ### ### Talk Related ### def set_talk_tooltip(self, talk): self.mainWidget.talkComboBox.setToolTip(talk) def load_event_list(self): model = self.db.get_events_model() self.mainWidget.eventComboBox.setModel(model) def load_rooms_from_event(self, event): #self.disconnect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) self.current_event = event model = self.db.get_rooms_model(self.current_event) self.mainWidget.roomComboBox.setModel(model) #self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) def load_dates_from_event_room(self, change): event = str(self.mainWidget.eventComboBox.currentText()) room = str(self.mainWidget.roomComboBox.currentText()) model = self.db.get_dates_from_event_room_model(event, room) self.mainWidget.dateComboBox.setModel(model) def load_talks_from_date(self, date): self.current_room = str(self.mainWidget.roomComboBox.currentText()) self.current_date = date model = self.db.get_talks_model(self.current_event, self.current_room, self.current_date) self.mainWidget.talkComboBox.setModel(model) ### ### Report Failure ### def show_report_widget(self): p = self.current_presentation() self.reportWidget.titleLabel2.setText(p.title) self.reportWidget.speakerLabel2.setText(p.speaker) self.reportWidget.eventLabel2.setText(p.event) self.reportWidget.roomLabel2.setText(p.room) self.reportWidget.startTimeLabel2.setText(p.startTime) self.reportWidget.endTimeLabel2.setText(p.endTime) # Get existing report if there is one. talk_id = self.current_presentation_id() f = self.db.get_report(talk_id) if f is not None: self.reportWidget.commentEdit.setText(f.comment) i = self.reportWidget.reportCombo.findText(f.indicator) self.reportWidget.reportCombo.setCurrentIndex(i) self.reportWidget.releaseCheckBox.setChecked(f.release) else: self.reportWidget.commentEdit.setText("") self.reportWidget.reportCombo.setCurrentIndex(0) self.reportWidget.releaseCheckBox.setChecked(False) self.reportWidget.show() def report(self): talk_id = self.current_presentation_id() i = self.reportWidget.reportCombo.currentIndex() failure = Failure(talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked()) log.info("Report Failure: %s, %s, %s, release form? %s" % (talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked())) self.db.insert_failure(failure) self.reportWidget.close() ### ### Misc. ### def _icon_activated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self.systray.menu.popup(QCursor.pos()) if reason == QtGui.QSystemTrayIcon.DoubleClick: self.toggle_record_button() def hide_window(self): self.geometry = self.saveGeometry() self.hide() def show_window(self): if (self.geometry is not None): self.restoreGeometry(self.geometry) self.show() def toggle_window_visibility(self): """Toggles the visibility of the Recording Main Window.""" if self.isHidden(): self.show_window() self.visibilityAction.setText(self.hideWindowString) else: self.hide_window() self.visibilityAction.setText(self.showWindowString) def toggle_record_button(self): self.mainWidget.standbyButton.toggle() self.mainWidget.recordButton.toggle() def audio_feedback(self, value): self.mainWidget.audioSlider.setValue(value) def open_video_directory(self): if sys.platform.startswith("linux"): os.system("xdg-open %s" % self.config.videodir) elif sys.platform.startswith("win32"): os.system("explorer %s" % self.config.videodir) else: log.info("Error: This command is not supported on the current OS.") def closeEvent(self, event): log.info('Exiting freeseer...') event.accept() ''' This function plays the most recently recorded video ''' def play_video(self): if sys.platform.startswith("linux"): subprocess.call([ "xdg-open", "{}/{}".format(self.config.videodir, self.recently_recorded_video) ]) if sys.platform.startswith("win32"): os.system("start {}".format( os.path.join(self.config.videodir, self.recently_recorded_video))) ''' Client functions ''' def show_client_widget(self): self.current_presentation() self.clientWidget.show() ''' This function is for handling commands sent from the server to the client ''' def getAction(self): message = self.clientWidget.socket.read( self.clientWidget.socket.bytesAvailable()) if message == 'Record': self.mainWidget.standbyButton.toggle() self.mainWidget.recordButton.toggle() self.clientWidget.sendMessage('Started recording') log.info("Started recording by server's request") elif message == 'Stop': self.mainWidget.recordButton.toggle() log.info("Stopping recording by server's request") elif message == 'Pause' or 'Resume': self.mainWidget.pauseButton.toggle() if message == 'Pause': log.info("Paused recording by server's request") elif message == 'Resume': log.info("Resumed recording by server's request") ### ### Utility ### def open_configtool(self): self.configToolApp.show() def open_talkeditor(self): self.talkEditorApp.show() self.load_event_list()
def __init__(self): FreeseerApp.__init__(self) self.controller = RecordingController() self.config = self.controller.config self.db = self.controller.db self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.clientWidget = ClientDialog(self.config.configdir, self.db) self.configToolApp = ConfigToolApp(self) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName(_fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) self.actionClient = QtGui.QAction(self) self.actionClient.setIcon(self.icon) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) # Hide the controller client configuration screen for Freeseer 3.0.0 # release. This feature's not ready for public use so lets keep it # hidden for now. # self.menuFile.insertAction(self.actionExit, self.actionClient) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL("triggered()"), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL("triggered()"), self.toggle_record_button) self.connect(self.systray, QtCore.SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self._icon_activated) # --- End Systray Setup # main tab connections self.connect( self.mainWidget.eventComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_rooms_from_event, ) self.connect( self.mainWidget.roomComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_dates_from_event_room, ) self.connect( self.mainWidget.dateComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_talks_from_date, ) self.connect( self.mainWidget.talkComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.set_talk_tooltip ) self.connect(self.mainWidget.standbyPushButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.recordPushButton, QtCore.SIGNAL("toggled(bool)"), self.record) self.connect(self.mainWidget.pauseToolButton, QtCore.SIGNAL("toggled(bool)"), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL("toggled(bool)"), self.toggle_audio_feedback) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL("triggered()"), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL("triggered()"), self.open_talkeditor) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL("triggered()"), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL("triggered()"), self.show_report_widget) self.connect(self.actionClient, QtCore.SIGNAL("triggered()"), self.show_client_widget) # GUI Disabling/Enabling Connections self.connect( self.mainWidget.recordPushButton, QtCore.SIGNAL("toggled(bool)"), self.mainWidget.pauseToolButton.setEnabled ) # Client Connections self.connect(self.clientWidget.socket, QtCore.SIGNAL("readyRead()"), self.getAction) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.recordPushButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.recordPushButton.setFocus() self.retranslate()
class RecordApp(FreeseerApp): """Freeseer's main GUI class.""" def __init__(self): FreeseerApp.__init__(self) self.controller = RecordingController() self.config = self.controller.config self.db = self.controller.db self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.clientWidget = ClientDialog(self.config.configdir, self.db) self.configToolApp = ConfigToolApp(self) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName(_fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) self.actionClient = QtGui.QAction(self) self.actionClient.setIcon(self.icon) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) # Hide the controller client configuration screen for Freeseer 3.0.0 # release. This feature's not ready for public use so lets keep it # hidden for now. # self.menuFile.insertAction(self.actionExit, self.actionClient) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL("triggered()"), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL("triggered()"), self.toggle_record_button) self.connect(self.systray, QtCore.SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self._icon_activated) # --- End Systray Setup # main tab connections self.connect( self.mainWidget.eventComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_rooms_from_event, ) self.connect( self.mainWidget.roomComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_dates_from_event_room, ) self.connect( self.mainWidget.dateComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_talks_from_date, ) self.connect( self.mainWidget.talkComboBox, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.set_talk_tooltip ) self.connect(self.mainWidget.standbyPushButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.recordPushButton, QtCore.SIGNAL("toggled(bool)"), self.record) self.connect(self.mainWidget.pauseToolButton, QtCore.SIGNAL("toggled(bool)"), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL("toggled(bool)"), self.toggle_audio_feedback) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL("triggered()"), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL("triggered()"), self.open_talkeditor) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL("triggered()"), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL("triggered()"), self.show_report_widget) self.connect(self.actionClient, QtCore.SIGNAL("triggered()"), self.show_client_widget) # GUI Disabling/Enabling Connections self.connect( self.mainWidget.recordPushButton, QtCore.SIGNAL("toggled(bool)"), self.mainWidget.pauseToolButton.setEnabled ) # Client Connections self.connect(self.clientWidget.socket, QtCore.SIGNAL("readyRead()"), self.getAction) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.recordPushButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.recordPushButton.setFocus() self.retranslate() ### ### Translation Related ### def retranslate(self): self.clientWidget.retranslate(self.current_language) self.setWindowTitle(self.app.translate("RecordApp", "Freeseer - portable presentation recording station")) # # Reusable Strings # self.standbyString = self.app.translate("RecordApp", "Standby") self.recordString = self.app.translate("RecordApp", "Record") self.pauseString = self.app.translate("RecordApp", "Pause") self.resumeString = self.app.translate("RecordApp", "Resume") self.stopString = self.app.translate("RecordApp", "Stop") self.hideWindowString = self.app.translate("RecordApp", "Hide Main Window") self.showWindowString = self.app.translate("RecordApp", "Show Main Window") # Status Bar messages self.idleString = self.app.translate("RecordApp", "Idle.") self.readyString = self.app.translate("RecordApp", "Ready.") self.recordingString = self.app.translate("RecordApp", "Recording...") self.pausedString = self.app.translate("RecordApp", "Recording Paused.") # --- End Reusable Strings if self.mainWidget.recordPushButton.isChecked() and self.mainWidget.pauseToolButton.isChecked(): self.mainWidget.statusLabel.setText(self.pausedString) elif self.mainWidget.recordPushButton.isChecked() and (not self.mainWidget.pauseToolButton.isChecked()): self.mainWidget.statusLabel.setText(self.recordingString) elif self.mainWidget.standbyPushButton.isChecked(): self.mainWidget.statusLabel.setText(self.readyString) else: self.mainWidget.statusLabel.setText(self.idleString) # # Menubar # self.menuOptions.setTitle(self.app.translate("RecordApp", "&Options")) self.actionConfigTool.setText(self.app.translate("RecordApp", "&ConfigTool")) self.actionTalkEditor.setText(self.app.translate("RecordApp", "Talk&Editor")) self.actionOpenVideoFolder.setText(self.app.translate("RecordApp", "&Open Video Directory")) self.actionClient.setText(self.app.translate("RecordApp", "&Connect to server")) self.actionReport.setText(self.app.translate("RecordApp", "&Report")) # --- End Menubar # # Systray # self.visibilityAction.setText(self.hideWindowString) self.recordAction.setText(self.recordString) # --- End Systray # # RecordingWidget # self.mainWidget.standbyPushButton.setText(self.standbyString) self.mainWidget.standbyPushButton.setToolTip(self.standbyString) if self.mainWidget.recordPushButton.isChecked(): self.mainWidget.recordPushButton.setText(self.stopString) self.mainWidget.recordPushButton.setToolTip(self.stopString) else: self.mainWidget.recordPushButton.setText(self.recordString) self.mainWidget.recordPushButton.setToolTip(self.recordString) self.mainWidget.pauseToolButton.setText(self.pauseString) self.mainWidget.pauseToolButton.setToolTip(self.pauseString) self.mainWidget.eventLabel.setText(self.app.translate("RecordApp", "Event")) self.mainWidget.roomLabel.setText(self.app.translate("RecordApp", "Room")) self.mainWidget.dateLabel.setText(self.app.translate("RecordApp", "Date")) self.mainWidget.talkLabel.setText(self.app.translate("RecordApp", "Talk")) # --- End RecordingWidget # # ReportWidget # self.reportWidget.setWindowTitle(self.app.translate("RecordApp", "Reporting Tool")) self.reportWidget.titleLabel.setText(self.app.translate("RecordApp", "Title:")) self.reportWidget.speakerLabel.setText(self.app.translate("RecordApp", "Speaker:")) self.reportWidget.eventLabel.setText(self.app.translate("RecordApp", "Event:")) self.reportWidget.roomLabel.setText(self.app.translate("RecordApp", "Room:")) self.reportWidget.timeLabel.setText(self.app.translate("RecordApp", "Time:")) self.reportWidget.commentLabel.setText(self.app.translate("RecordApp", "Comment")) self.reportWidget.releaseCheckBox.setText(self.app.translate("RecordApp", "Release Received")) self.reportWidget.closeButton.setText(self.app.translate("RecordApp", "Close")) self.reportWidget.reportButton.setText(self.app.translate("RecordApp", "Report")) # Logic for translating the report options noissues = self.app.translate("RecordApp", "No Issues") noaudio = self.app.translate("RecordApp", "No Audio") novideo = self.app.translate("RecordApp", "No Video") noaudiovideo = self.app.translate("RecordApp", "No Audio/Video") self.reportWidget.options = [noissues, noaudio, novideo, noaudiovideo] self.reportWidget.reportCombo.clear() for i in self.reportWidget.options: self.reportWidget.reportCombo.addItem(i) # --- End ReportWidget ### ### UI Logic ### def load_settings(self): """Load settings for Freeseer""" log.info("Loading settings...") # Load default language. actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talks as a SQL Data Model. self.load_event_list() def current_presentation(self): """Creates a presentation object of the current presentation. Current presentation is the currently selected title on the GUI. """ # i = self.mainWidget.talkComboBox.currentIndex() # p_id = self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() return self.db.get_presentation(self.current_presentation_id()) def current_presentation_id(self): """Returns the current selected presentation ID.""" i = self.mainWidget.talkComboBox.currentIndex() return self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() def standby(self, state): """Prepares the GStreamer pipelines for recording Sets the pipeline to paused state so that initiating a recording does not have a delay due to GStreamer initialization. """ def toggle_gui(state): """Toggles GUI components when standby is pressed""" self.mainWidget.standbyPushButton.setHidden(state) self.mainWidget.recordPushButton.setVisible(state) self.mainWidget.recordPushButton.setEnabled(state) self.mainWidget.pauseToolButton.setVisible(state) self.mainWidget.eventComboBox.setDisabled(state) self.mainWidget.roomComboBox.setDisabled(state) self.mainWidget.dateComboBox.setDisabled(state) self.mainWidget.talkComboBox.setDisabled(state) self.mainWidget.audioFeedbackCheckbox.setDisabled(state) if state: # Prepare the pipelines if self.load_backend(): toggle_gui(True) self.controller.pause() self.mainWidget.statusLabel.setText(self.readyString) else: toggle_gui(False) self.mainWidget.standbyPushButton.setChecked(False) else: toggle_gui(False) self.mainWidget.standbyPushButton.setChecked(False) def record(self, state): """The logic for recording and stopping recording.""" if state: # Start Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo_rec.png") sysIcon2 = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon2) self.systray.showMessage("Recording", "RECORDING") self.controller.record() self.mainWidget.recordPushButton.setText(self.stopString) self.recordAction.setText(self.stopString) # Hide if auto-hide is set. if self.config.auto_hide == True: self.hide_window() self.visibilityAction.setText(self.showWindowString) log.debug("auto-hide is enabled, main window is now hidden in systray.") self.mainWidget.statusLabel.setText(self.recordingString) # Start timer. self.timer.start(1000) else: # Stop Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo.png") sysIcon = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon) self.controller.stop() self.mainWidget.pauseToolButton.setChecked(False) self.mainWidget.recordPushButton.setText(self.recordString) self.recordAction.setText(self.recordString) self.mainWidget.audioSlider.setValue(0) # Finally set the standby button back to unchecked position. self.standby(False) # Stop and reset timer. self.timer.stop() self.reset_timer() # Select next talk if there is one within 15 minutes. if self.current_event and self.current_room: starttime = QtCore.QDateTime().currentDateTime() stoptime = starttime.addSecs(900) talkid = self.db.get_talk_between_time( self.current_event, self.current_room, starttime.toString(), stoptime.toString() ) if talkid is not None: for i in range(self.mainWidget.talkComboBox.count()): if ( talkid == self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() ): self.mainWidget.talkComboBox.setCurrentIndex(i) def pause(self, state): """Pause the recording""" if state: # Pause Recording. self.controller.pause() log.info("Recording paused.") self.mainWidget.pauseToolButton.setToolTip(self.resumeString) self.mainWidget.statusLabel.setText(self.pausedString) self.timer.stop() elif self.mainWidget.recordPushButton.isChecked(): self.controller.record() log.info("Recording unpaused.") self.mainWidget.pauseToolButton.setToolTip(self.pauseString) self.mainWidget.statusLabel.setText(self.recordingString) self.timer.start(1000) def load_backend(self): """Prepares the backend for recording""" if self.current_presentation(): presentation = self.current_presentation() # If current presentation is no existant (empty talk database) # use a default recording name. else: presentation = Presentation(title=unicode("default")) if self.controller.load_backend(presentation): return True else: return False # Error something failed while loading the backend def update_timer(self): """Updates the Elapsed Time displayed. Uses the statusLabel for the display. """ time = "%d:%02d" % (self.time_minutes, self.time_seconds) self.time_seconds += 1 if self.time_seconds == 60: self.time_seconds = 0 self.time_minutes += 1 self.mainWidget.statusLabel.setText( "Free Space: %s --- Elapsed Time: %s" % (get_free_space(self.config.videodir), time) ) def reset_timer(self): """Resets the Elapsed Time.""" self.time_minutes = 0 self.time_seconds = 0 def toggle_audio_feedback(self, enabled): """Enables or disables audio feedback according to checkbox state""" self.config.audio_feedback = enabled ### ### Talk Related ### def set_talk_tooltip(self, talk): self.mainWidget.talkComboBox.setToolTip(talk) def load_event_list(self): model = self.db.get_events_model() self.mainWidget.eventComboBox.setModel(model) def load_rooms_from_event(self, event): # self.disconnect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) self.current_event = event model = self.db.get_rooms_model(self.current_event) self.mainWidget.roomComboBox.setModel(model) # self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) def load_dates_from_event_room(self, change): event = str(self.mainWidget.eventComboBox.currentText()) room = str(self.mainWidget.roomComboBox.currentText()) model = self.db.get_dates_from_event_room_model(event, room) self.mainWidget.dateComboBox.setModel(model) def load_talks_from_date(self, date): self.current_room = str(self.mainWidget.roomComboBox.currentText()) self.current_date = date model = self.db.get_talks_model(self.current_event, self.current_room, self.current_date) self.mainWidget.talkComboBox.setModel(model) ### ### Report Failure ### def show_report_widget(self): p = self.current_presentation() self.reportWidget.titleLabel2.setText(p.title) self.reportWidget.speakerLabel2.setText(p.speaker) self.reportWidget.eventLabel2.setText(p.event) self.reportWidget.roomLabel2.setText(p.room) self.reportWidget.timeLabel2.setText(p.time) # Get existing report if there is one. talk_id = self.current_presentation_id() f = self.db.get_report(talk_id) if f is not None: self.reportWidget.commentEdit.setText(f.comment) i = self.reportWidget.reportCombo.findText(f.indicator) self.reportWidget.reportCombo.setCurrentIndex(i) self.reportWidget.releaseCheckBox.setChecked(f.release) else: self.reportWidget.commentEdit.setText("") self.reportWidget.reportCombo.setCurrentIndex(0) self.reportWidget.releaseCheckBox.setChecked(False) self.reportWidget.show() def report(self): talk_id = self.current_presentation_id() presentation = self.current_presentation() i = self.reportWidget.reportCombo.currentIndex() failure = Failure( talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked(), ) log.info( "Report Failure: %s, %s, %s, release form? %s" % ( talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked(), ) ) self.db.insert_failure(failure) self.reportWidget.close() ### ### Misc. ### def _icon_activated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self.systray.menu.popup(QCursor.pos()) if reason == QtGui.QSystemTrayIcon.DoubleClick: self.toggle_record_button() def hide_window(self): self.geometry = self.saveGeometry() self.hide() def show_window(self): if self.geometry is not None: self.restoreGeometry(self.geometry) self.show() def toggle_window_visibility(self): """Toggles the visibility of the Recording Main Window.""" if self.isHidden(): self.show_window() self.visibilityAction.setText(self.hideWindowString) else: self.hide_window() self.visibilityAction.setText(self.showWindowString) def toggle_record_button(self): self.mainWidget.standbyPushButton.toggle() self.mainWidget.recordPushButton.toggle() def audio_feedback(self, value): self.mainWidget.audioSlider.setValue(value) def open_video_directory(self): if sys.platform.startswith("linux"): os.system("xdg-open %s" % self.config.videodir) elif sys.platform.startswith("win32"): os.system("explorer %s" % self.config.videodir) else: log.info("Error: This command is not supported on the current OS.") def closeEvent(self, event): log.info("Exiting freeseer...") event.accept() """ Client functions """ def show_client_widget(self): self.current_presentation() self.clientWidget.show() """ This function is for handling commands sent from the server to the client """ def getAction(self): message = self.clientWidget.socket.read(self.clientWidget.socket.bytesAvailable()) if message == "Record": self.mainWidget.standbyPushButton.toggle() self.mainWidget.recordPushButton.toggle() self.clientWidget.sendMessage("Started recording") log.info("Started recording by server's request") elif message == "Stop": self.mainWidget.recordPushButton.toggle() log.info("Stopping recording by server's request") elif message == "Pause" or "Resume": self.mainWidget.pauseToolButton.toggle() if message == "Pause": log.info("Paused recording by server's request") elif message == "Resume": log.info("Resumed recording by server's request") ### ### Utility ### def open_configtool(self): self.configToolApp.show() def open_talkeditor(self): self.talkEditorApp.show()
def __init__(self, profile, config): super(RecordApp, self).__init__(config) self.db = profile.get_database() self.controller = RecordingController(profile, self.db, self.config) self.recently_recorded_video = None self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.autoRecordWidget = AutoRecordWidget() self.configToolApp = ConfigToolApp(profile, config) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self.config, self.db) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.logStatusWidget = LogStatusWidget(self.logDialog) self.statusBar().addPermanentWidget(self.logStatusWidget, 1) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # Initialize variables for auto-recording self.singleID = None self.timeUntilStart = None self.timeUntilEnd = None self.autoTalks = None self.recorded = False self.beforeStartTimer = QtCore.QTimer(self) self.beforeStartTimer.timeout.connect(self.start_single_record) self.beforeEndTimer = QtCore.QTimer(self) self.beforeEndTimer.timeout.connect(self.single_auto_record) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.actionAutoRecord = QtGui.QAction(self) leaveButtonShortcut = "Ctrl+R" self.actionAutoRecord.setShortcut(leaveButtonShortcut) self.actionAutoRecord.setCheckable(True) self.actionAutoRecord.setObjectName(_fromUtf8("actionAutoRecord")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) self.menuOptions.addAction(self.actionAutoRecord) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName(_fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL('triggered()'), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL('triggered()'), self.toggle_record_button) self.connect(self.systray, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self._icon_activated) # --- End Systray Setup # main tab connections self.connect(self.mainWidget.eventComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_rooms_from_event) self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_dates_from_event_room) self.connect(self.mainWidget.dateComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_date) self.connect(self.mainWidget.talkComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.set_talk_tooltip) self.connect(self.mainWidget.standbyButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.disengageButton, QtCore.SIGNAL("clicked()"), functools.partial(self.standby, state=False)) self.connect(self.mainWidget.recordButton, QtCore.SIGNAL('clicked()'), self.record) self.connect(self.mainWidget.pauseButton, QtCore.SIGNAL('toggled(bool)'), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL('toggled(bool)'), self.toggle_audio_feedback) self.connect(self.mainWidget.playButton, QtCore.SIGNAL('clicked()'), self.play_video) self.connect(self.autoRecordWidget.leaveButton, QtCore.SIGNAL('clicked()'), functools.partial(self.auto_record, state=False)) self.autoRecordWidget.leaveButton.setShortcut(leaveButtonShortcut) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL('triggered()'), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL('triggered()'), self.open_talkeditor) self.connect(self.actionAutoRecord, QtCore.SIGNAL('toggled(bool)'), self.auto_record) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL('triggered()'), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL('triggered()'), self.show_report_widget) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.pauseButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.pauseButton.setFocus() self.retranslate()
class RecordApp(FreeseerApp): """Freeseer's main GUI class.""" def __init__(self, profile, config): super(RecordApp, self).__init__(config) self.db = profile.get_database() self.controller = RecordingController(profile, self.db, self.config) self.recently_recorded_video = None self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.autoRecordWidget = AutoRecordWidget() self.configToolApp = ConfigToolApp(profile, config) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self.config, self.db) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.logStatusWidget = LogStatusWidget(self.logDialog) self.statusBar().addPermanentWidget(self.logStatusWidget, 1) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # Initialize variables for auto-recording self.singleID = None self.timeUntilStart = None self.timeUntilEnd = None self.autoTalks = None self.recorded = False self.beforeStartTimer = QtCore.QTimer(self) self.beforeStartTimer.timeout.connect(self.start_single_record) self.beforeEndTimer = QtCore.QTimer(self) self.beforeEndTimer.timeout.connect(self.single_auto_record) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.actionAutoRecord = QtGui.QAction(self) leaveButtonShortcut = "Ctrl+R" self.actionAutoRecord.setShortcut(leaveButtonShortcut) self.actionAutoRecord.setCheckable(True) self.actionAutoRecord.setObjectName(_fromUtf8("actionAutoRecord")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) self.menuOptions.addAction(self.actionAutoRecord) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName(_fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL('triggered()'), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL('triggered()'), self.toggle_record_button) self.connect(self.systray, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self._icon_activated) # --- End Systray Setup # main tab connections self.connect(self.mainWidget.eventComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_rooms_from_event) self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_dates_from_event_room) self.connect(self.mainWidget.dateComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_date) self.connect(self.mainWidget.talkComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.set_talk_tooltip) self.connect(self.mainWidget.standbyButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.disengageButton, QtCore.SIGNAL("clicked()"), functools.partial(self.standby, state=False)) self.connect(self.mainWidget.recordButton, QtCore.SIGNAL('clicked()'), self.record) self.connect(self.mainWidget.pauseButton, QtCore.SIGNAL('toggled(bool)'), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL('toggled(bool)'), self.toggle_audio_feedback) self.connect(self.mainWidget.playButton, QtCore.SIGNAL('clicked()'), self.play_video) self.connect(self.autoRecordWidget.leaveButton, QtCore.SIGNAL('clicked()'), functools.partial(self.auto_record, state=False)) self.autoRecordWidget.leaveButton.setShortcut(leaveButtonShortcut) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL('triggered()'), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL('triggered()'), self.open_talkeditor) self.connect(self.actionAutoRecord, QtCore.SIGNAL('toggled(bool)'), self.auto_record) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL('triggered()'), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL('triggered()'), self.show_report_widget) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.pauseButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.pauseButton.setFocus() self.retranslate() ### ### Translation Related ### def retranslate(self): self.setWindowTitle(self.app.translate("RecordApp", "Freeseer - portable presentation recording station")) # # Reusable Strings # self.standbyString = self.app.translate("RecordApp", "Standby") self.disengageString = self.app.translate("RecordApp", "Leave record-mode") self.standbyTooltipString = self.app.translate("RecordApp", "Sets up the system for recording") self.disengageTooltipString = self.app.translate("RecordApp", "Go back to edit talk information or select a different talk") self.autoRecordString = self.app.translate("RecordApp", "Auto Record") self.recordString = self.app.translate("RecordApp", "Record") self.pauseString = self.app.translate("RecordApp", "Pause") self.resumeString = self.app.translate("RecordApp", "Resume") self.stopString = self.app.translate("RecordApp", "Stop") self.stopAutoString = self.app.translate("RecordApp", "Stop Auto Record") self.hideWindowString = self.app.translate("RecordApp", "Hide Main Window") self.showWindowString = self.app.translate("RecordApp", "Show Main Window") self.playVideoString = self.app.translate("RecordApp", "Play") # Status Bar messages self.idleString = self.app.translate("RecordApp", "Idle.") self.readyString = self.app.translate("RecordApp", "Ready.") self.recordingString = self.app.translate("RecordApp", "Recording") self.pausedString = self.app.translate("RecordApp", "Recording Paused.") self.freeSpaceString = self.app.translate("RecordApp", "Free Space:") self.elapsedTimeString = self.app.translate("RecordApp", "Elapsed Time:") # --- End Reusable Strings if self.mainWidget.is_recording and self.mainWidget.pauseButton.isChecked(): self.mainWidget.statusLabel.setText(self.pausedString) elif self.mainWidget.is_recording and (not self.mainWidget.pauseButton.isChecked()): self.mainWidget.statusLabel.setText(self.recordingString) elif self.mainWidget.standbyButton.isChecked(): self.mainWidget.statusLabel.setText(self.readyString) elif self.actionAutoRecord.isChecked(): self.mainWidget.statusLabel.setText(self.autoRecordString) else: self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, get_free_space(self.config.videodir), self.idleString)) # # Menubar # self.menuOptions.setTitle(self.app.translate("RecordApp", "&Options")) self.actionConfigTool.setText(self.app.translate("RecordApp", "&Configuration")) self.actionTalkEditor.setText(self.app.translate("RecordApp", "&Edit Talks")) self.actionAutoRecord.setText(self.autoRecordString) self.actionOpenVideoFolder.setText(self.app.translate("RecordApp", "&Open Video Directory")) self.actionReport.setText(self.app.translate("RecordApp", "&Report")) # --- End Menubar # # Systray # self.visibilityAction.setText(self.hideWindowString) self.recordAction.setText(self.recordString) # --- End Systray # # RecordingWidget # self.mainWidget.disengageButton.setText(self.disengageString) self.mainWidget.standbyButton.setText(self.standbyString) self.mainWidget.standbyButton.setToolTip(self.standbyTooltipString) self.mainWidget.disengageButton.setToolTip(self.disengageTooltipString) if self.mainWidget.is_recording: self.mainWidget.recordButton.setToolTip(self.stopString) else: self.mainWidget.recordButton.setToolTip(self.recordString) self.mainWidget.pauseButton.setText(self.pauseString) self.mainWidget.pauseButton.setToolTip(self.pauseString) self.mainWidget.eventLabel.setText(self.app.translate("RecordApp", "Event")) self.mainWidget.roomLabel.setText(self.app.translate("RecordApp", "Room")) self.mainWidget.dateLabel.setText(self.app.translate("RecordApp", "Date")) self.mainWidget.talkLabel.setText(self.app.translate("RecordApp", "Talk")) # --- End RecordingWidget # # ReportWidget # self.reportWidget.setWindowTitle(self.app.translate("RecordApp", "Reporting Tool")) self.reportWidget.titleLabel.setText(self.app.translate("RecordApp", "Title:")) self.reportWidget.speakerLabel.setText(self.app.translate("RecordApp", "Speaker:")) self.reportWidget.eventLabel.setText(self.app.translate("RecordApp", "Event:")) self.reportWidget.roomLabel.setText(self.app.translate("RecordApp", "Room:")) self.reportWidget.startTimeLabel.setText(self.app.translate("RecordApp", "Start Time:")) self.reportWidget.endTimeLabel.setText(self.app.translate("RecordApp", "End Time:")) self.reportWidget.commentLabel.setText(self.app.translate("RecordApp", "Comment")) self.reportWidget.releaseCheckBox.setText(self.app.translate("RecordApp", "Release Received")) self.reportWidget.closeButton.setText(self.app.translate("RecordApp", "Close")) self.reportWidget.reportButton.setText(self.app.translate("RecordApp", "Report")) # Logic for translating the report options noissues = self.app.translate("RecordApp", "No Issues") noaudio = self.app.translate("RecordApp", "No Audio") novideo = self.app.translate("RecordApp", "No Video") noaudiovideo = self.app.translate("RecordApp", "No Audio/Video") self.reportWidget.options = [noissues, noaudio, novideo, noaudiovideo] self.reportWidget.reportCombo.clear() for i in self.reportWidget.options: self.reportWidget.reportCombo.addItem(i) # --- End ReportWidget self.logStatusWidget.retranslate() ### ### UI Logic ### def load_settings(self): """Load settings for Freeseer""" log.info('Loading settings...') # Load default language. actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talks as a SQL Data Model. self.load_event_list() def current_presentation(self): """Creates a presentation object of the current presentation. Current presentation is the currently selected title on the GUI. """ #i = self.mainWidget.talkComboBox.currentIndex() #p_id = self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() return self.db.get_presentation(self.current_presentation_id()) def current_presentation_id(self): """Returns the current selected presentation ID.""" i = self.mainWidget.talkComboBox.currentIndex() return self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() def standby(self, state): """Prepares the GStreamer pipelines for recording Sets the pipeline to paused state so that initiating a recording does not have a delay due to GStreamer initialization. """ def toggle_gui(state): """Toggles GUI components when standby is pressed""" if state: self.mainWidget.standbyButton.setHidden(state) self.mainWidget.disengageButton.setVisible(state) else: self.mainWidget.disengageButton.setVisible(state) self.mainWidget.standbyButton.setHidden(state) self.mainWidget.recordButton.setEnabled(state) self.mainWidget.eventComboBox.setDisabled(state) self.mainWidget.roomComboBox.setDisabled(state) self.mainWidget.dateComboBox.setDisabled(state) self.mainWidget.talkComboBox.setDisabled(state) self.mainWidget.audioFeedbackCheckbox.setDisabled(state) if state: # Prepare the pipelines if self.load_backend(): toggle_gui(True) self.controller.pause() self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, get_free_space(self.config.videodir), self.readyString)) else: toggle_gui(False) self.mainWidget.standbyButton.setChecked(False) else: toggle_gui(False) self.controller.stop() self.mainWidget.standbyButton.setChecked(False) self.mainWidget.playButton.setEnabled(False) def record(self): """The logic for recording and stopping recording.""" if self.mainWidget.is_recording: # Start Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo_rec.png") sysIcon2 = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon2) self.controller.record() self.mainWidget.recordButton.setToolTip(self.stopString) self.mainWidget.disengageButton.setEnabled(False) self.mainWidget.pauseButton.setEnabled(True) self.recordAction.setText(self.stopString) # Hide if auto-hide is set. if self.config.auto_hide: self.hide_window() self.visibilityAction.setText(self.showWindowString) log.debug('auto-hide is enabled, main window is now hidden in systray.') # Start timer. self.timer.start(1000) else: # Stop Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo.png") sysIcon = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon) self.controller.stop() self.mainWidget.pauseButton.setChecked(False) self.mainWidget.recordButton.setToolTip(self.recordString) self.mainWidget.disengageButton.setEnabled(True) self.mainWidget.pauseButton.setEnabled(False) self.recordAction.setText(self.recordString) self.mainWidget.audioSlider.setValue(0) self.mainWidget.statusLabel.setText(u"{} {} --- {} ".format(self.freeSpaceString, get_free_space(self.config.videodir), self.idleString)) # Finally set the standby button back to unchecked position. self.standby(False) # Stop and reset timer. self.timer.stop() self.reset_timer() #Show playback button self.mainWidget.playButton.setVisible(True) self.mainWidget.playButton.setEnabled(True) # Select next talk if there is one within 15 minutes. if self.current_event and self.current_room: starttime = QtCore.QDateTime().currentDateTime() stoptime = starttime.addSecs(900) talkid = self.db.get_talk_between_time(self.current_event, self.current_room, starttime.toString(), stoptime.toString()) if talkid is not None: for i in range(self.mainWidget.talkComboBox.count()): if talkid == self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString(): self.mainWidget.talkComboBox.setCurrentIndex(i) def _enable_disable_gui(self, state): """Disables GUI components when Auto Record is pressed, and enables them when Auto Record is released""" self.mainWidget.standbyButton.setDisabled(state) self.mainWidget.eventComboBox.setDisabled(state) self.mainWidget.roomComboBox.setDisabled(state) self.mainWidget.dateComboBox.setDisabled(state) self.mainWidget.talkComboBox.setDisabled(state) self.mainWidget.audioFeedbackCheckbox.setDisabled(state) def stop_auto_record_gui(self): """Sets the gui for stopping the auto record""" self.autoRecordWidget.stop_timer() self.autoRecordWidget.close() self._enable_disable_gui(False) self.recorded = False self.actionAutoRecord.setChecked(False) def auto_record(self, state): """Starts automated recording""" if state: # If there is a room selected, then it's possible to auto-record if self.current_room: self.autoTalks = self.db.get_talks_by_room_and_time(self.current_room) # Start recording if there are talks in database that can be auto-recorded if self.autoTalks.next(): # Set the cursor back to before the first record so that single_auto_record works properly self.autoTalks.previous() self._enable_disable_gui(True) self.single_auto_record() else: # Dialog for no talks to auto-record QtGui.QMessageBox.information(self, 'No Talks to Record', 'There are no upcoming talks to auto-record in this room', QtGui.QMessageBox.Ok) self.actionAutoRecord.setChecked(False) else: # Dialog that pops up when no room is selected QtGui.QMessageBox.information(self, 'No Room Selected', 'Please select a room to auto-record', QtGui.QMessageBox.Ok) self.actionAutoRecord.setChecked(False) else: self.beforeStartTimer.stop() self.beforeEndTimer.stop() self.controller.stop() self.stop_auto_record_gui() self.mainWidget.playButton.setEnabled(False) def single_auto_record(self): """Completes one display and record cycle of the auto-record feature. Stops the recording of the last talk if it exists, displays the countdown until the start of the next talk, and when the talk begins, records the talk while displaying the countdown until the end of the talk. """ if self.recorded: self.controller.stop() self.recorded = False log.debug("Auto-recording for the current talk stopped.") if self.autoTalks.next(): starttime = QtCore.QTime.fromString(self.autoTalks.value(8).toString()) endtime = QtCore.QTime.fromString(self.autoTalks.value(9).toString()) currenttime = QtCore.QTime.currentTime() if currenttime <= starttime: self.singleID = self.autoTalks.value(0).toString() title = self.autoTalks.value(1).toString() speaker = self.autoTalks.value(2).toString() # Time (in seconds) until recording for the talk starts self.timeUntilStart = currenttime.secsTo(starttime) # Time (in seconds) from the starttime to endtime of this talk self.timeUntilEnd = starttime.secsTo(endtime) # Display fullscreen countdown and talk info until talk starts self.autoRecordWidget.set_recording(False) self.autoRecordWidget.set_display_message(title, speaker) self.autoRecordWidget.start_timer(self.timeUntilStart) self.autoRecordWidget.showFullScreen() # Wait for talk to start, then change display and start recording self.beforeStartTimer.setInterval((self.timeUntilStart + 1) * 1000) self.beforeStartTimer.setSingleShot(True) self.beforeStartTimer.start() else: # Start time has already passed, so move on to next talk self.single_auto_record() else: self.stop_auto_record_gui() def start_single_record(self): """Begins the auto-recording of a single talk while displaying the countdown on screen""" self.autoRecordWidget.set_recording(True) self.autoRecordWidget.set_display_message() self.autoRecordWidget.start_timer(self.timeUntilEnd) if self.controller.record_talk_id(self.singleID): log.debug("Auto-recording for the current talk started.") self.recorded = True self.beforeEndTimer.setInterval((self.timeUntilEnd + 1) * 1000) self.beforeEndTimer.setSingleShot(True) self.beforeEndTimer.start() def pause(self, state): """Pause the recording""" if state: # Pause Recording. self.controller.pause() log.info("Recording paused.") self.mainWidget.pauseButton.setToolTip(self.resumeString) self.mainWidget.statusLabel.setText(self.pausedString) self.timer.stop() elif self.mainWidget.is_recording: self.controller.record() log.info("Recording unpaused.") self.mainWidget.pauseButton.setToolTip(self.pauseString) self.timer.start(1000) def load_backend(self): """Prepares the backend for recording""" if self.current_presentation(): presentation = self.current_presentation() # If current presentation is no existant (empty talk database) # use a default recording name. else: presentation = Presentation(title=unicode("default")) initialized, self.recently_recorded_video = self.controller.load_backend(presentation) if initialized: return True else: return False # Error something failed while loading the backend def update_timer(self): """Updates the Elapsed Time displayed. Uses the statusLabel for the display. """ frmt_time = "%d:%02d" % (self.time_minutes, self.time_seconds) self.time_seconds += 1 if self.time_seconds == 60: self.time_seconds = 0 self.time_minutes += 1 self.mainWidget.statusLabel.setText(u"{} {} --- {} {} --- {}".format(self.elapsedTimeString, frmt_time, self.freeSpaceString, get_free_space(self.config.videodir), self.recordingString)) def reset_timer(self): """Resets the Elapsed Time.""" self.time_minutes = 0 self.time_seconds = 0 def toggle_audio_feedback(self, enabled): """Enables or disables audio feedback according to checkbox state""" self.config.audio_feedback = enabled ### ### Talk Related ### def set_talk_tooltip(self, talk): self.mainWidget.talkComboBox.setToolTip(talk) def load_event_list(self): model = self.db.get_events_model() self.mainWidget.eventComboBox.setModel(model) def load_rooms_from_event(self, event): #self.disconnect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) self.current_event = event model = self.db.get_rooms_model(self.current_event) self.mainWidget.roomComboBox.setModel(model) #self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) def load_dates_from_event_room(self, change): event = str(self.mainWidget.eventComboBox.currentText()) room = str(self.mainWidget.roomComboBox.currentText()) model = self.db.get_dates_from_event_room_model(event, room) self.mainWidget.dateComboBox.setModel(model) def load_talks_from_date(self, date): self.current_room = str(self.mainWidget.roomComboBox.currentText()) self.current_date = date model = self.db.get_talks_model(self.current_event, self.current_room, self.current_date) self.mainWidget.talkComboBox.setModel(model) ### ### Report Failure ### def show_report_widget(self): p = self.current_presentation() self.reportWidget.titleLabel2.setText(p.title) self.reportWidget.speakerLabel2.setText(p.speaker) self.reportWidget.eventLabel2.setText(p.event) self.reportWidget.roomLabel2.setText(p.room) self.reportWidget.startTimeLabel2.setText(p.startTime) self.reportWidget.endTimeLabel2.setText(p.endTime) # Get existing report if there is one. talk_id = self.current_presentation_id() f = self.db.get_report(talk_id) if f is not None: self.reportWidget.commentEdit.setText(f.comment) i = self.reportWidget.reportCombo.findText(f.indicator) self.reportWidget.reportCombo.setCurrentIndex(i) self.reportWidget.releaseCheckBox.setChecked(f.release) else: self.reportWidget.commentEdit.setText("") self.reportWidget.reportCombo.setCurrentIndex(0) self.reportWidget.releaseCheckBox.setChecked(False) self.reportWidget.show() def report(self): talk_id = self.current_presentation_id() i = self.reportWidget.reportCombo.currentIndex() failure = Failure(talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked()) log.info("Report Failure: %s, %s, %s, release form? %s" % (talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked())) self.db.insert_failure(failure) self.reportWidget.close() ### ### Misc. ### def _icon_activated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self.systray.menu.popup(QCursor.pos()) if reason == QtGui.QSystemTrayIcon.DoubleClick: self.toggle_record_button() def hide_window(self): self.geometry = self.saveGeometry() self.hide() def show_window(self): if (self.geometry is not None): self.restoreGeometry(self.geometry) self.show() def toggle_window_visibility(self): """Toggles the visibility of the Recording Main Window.""" if self.isHidden(): self.show_window() self.visibilityAction.setText(self.hideWindowString) else: self.hide_window() self.visibilityAction.setText(self.showWindowString) def toggle_record_button(self): self.mainWidget.standbyButton.toggle() self.mainWidget.recordButton.toggle() def audio_feedback(self, value): self.mainWidget.audioSlider.setValue(value) def open_video_directory(self): if sys.platform.startswith("linux"): os.system("xdg-open %s" % self.config.videodir) elif sys.platform.startswith("win32"): os.system("explorer %s" % self.config.videodir) else: log.info("Error: This command is not supported on the current OS.") def closeEvent(self, event): log.info('Exiting freeseer...') event.accept() ''' This function plays the most recently recorded video ''' def play_video(self): if sys.platform.startswith("linux"): subprocess.call(["xdg-open", "{}/{}".format(self.config.videodir, self.recently_recorded_video)]) if sys.platform.startswith("win32"): os.system("start {}".format(os.path.join(self.config.videodir, self.recently_recorded_video))) ''' Client functions ''' def show_client_widget(self): self.current_presentation() self.clientWidget.show() ''' This function is for handling commands sent from the server to the client ''' def getAction(self): message = self.clientWidget.socket.read(self.clientWidget.socket.bytesAvailable()) if message == 'Record': self.mainWidget.standbyButton.toggle() self.mainWidget.recordButton.toggle() self.clientWidget.sendMessage('Started recording') log.info("Started recording by server's request") elif message == 'Stop': self.mainWidget.recordButton.toggle() log.info("Stopping recording by server's request") elif message == 'Pause' or 'Resume': self.mainWidget.pauseButton.toggle() if message == 'Pause': log.info("Paused recording by server's request") elif message == 'Resume': log.info("Resumed recording by server's request") ### ### Utility ### def open_configtool(self): self.configToolApp.show() def open_talkeditor(self): self.talkEditorApp.show() self.load_event_list()
class TestConfigToolApp(unittest.TestCase): ''' Test suite to verify the functionality of the ConfigToolApp class. Tests interact like an end user (using QtTest). Expect the app to be rendered. NOTE: most tests will follow this format: 1. Get current config setting 2. Make UI change (config change happens immediately) 3. Reparse config file 4. Test that has changed (using the previous and new) ''' def setUp(self): ''' Stardard init method: runs before each test_* method Initializes a QtGui.QApplication and ConfigToolApp object. ConfigToolApp.show() causes the UI to be rendered. ''' self.profile_manager = ProfileManager(tempfile.mkdtemp()) profile = self.profile_manager.get('testing') config = profile.get_config('freeseer.conf', settings.FreeseerConfig, storage_args=['Global'], read_only=False) self.app = QtGui.QApplication([]) self.config_tool = ConfigToolApp(profile, config) self.config_tool.show() def tearDown(self): ''' Standard tear down method. Runs after each test_* method. This method closes the ConfigToolApp by clicking the "close" button ''' QtTest.QTest.mouseClick(self.config_tool.mainWidget.closePushButton, Qt.Qt.LeftButton) shutil.rmtree(self.profile_manager._base_folder) del self.config_tool.app self.app.deleteLater() def test_default_widget(self): self.assertTrue(self.config_tool.currentWidget == self.config_tool.generalWidget) def test_general_settings(self): ''' Tests for the config tool's General Tab ''' # Select "General" tab item = self.config_tool.mainWidget.optionsTreeWidget.findItems(self.config_tool.generalString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) # Language drop-down # TODO # Record directory # TODO # AutoHide Checkbox for i in range(2): state = self.config_tool.currentWidget.autoHideCheckBox.checkState() expected_state = QtCore.Qt.Unchecked if state == QtCore.Qt.Unchecked: expected_state = QtCore.Qt.Checked self.config_tool.currentWidget.autoHideCheckBox.click() self.assertEquals( self.config_tool.currentWidget.autoHideCheckBox.checkState(), expected_state) self.assertEquals(self.config_tool.config.auto_hide, expected_state == QtCore.Qt.Checked) def test_recording_settings(self): ''' Tests for config tool's Recording tab ''' # Select "Recording" tab item = self.config_tool.mainWidget.optionsTreeWidget.findItems(self.config_tool.avString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) # Recording tab self.assertTrue(self.config_tool.currentWidget == self.config_tool.avWidget) # Audio Input # Checkbox for i in range(2): #self.config_tool.config.readConfig() if self.config_tool.currentWidget.audioGroupBox.isChecked(): self.assertTrue(self.config_tool.config.enable_audio_recording) self.assertTrue(self.config_tool.config.audiomixer == "Audio Passthrough" or self.config_tool.config.audiomixer == "Multiple Audio Inputs") self.config_tool.currentWidget.audioGroupBox.setChecked(False) else: self.assertFalse(self.config_tool.config.enable_audio_recording) self.config_tool.currentWidget.audioGroupBox.setChecked(True) # Dropdown # TODO # Video Input # Checkbox for i in range(2): #self.config_tool.config.readConfig() if self.config_tool.currentWidget.videoGroupBox.isChecked(): self.assertTrue(self.config_tool.config.enable_video_recording) # TODO: Write better test case for this self.assertTrue(self.config_tool.config.videomixer == "Video Passthrough" or self.config_tool.config.videomixer == "Picture-In-Picture") self.config_tool.currentWidget.videoGroupBox.setChecked(False) else: self.assertFalse(self.config_tool.config.enable_video_recording) self.config_tool.currentWidget.videoGroupBox.setChecked(True) # Dropdown # TODO # Record to File # Checkbox for i in range(2): #self.config_tool.config.readConfig() if self.config_tool.currentWidget.fileGroupBox.isChecked(): self.assertTrue(self.config_tool.config.record_to_file) # TODO: Write better test case for this self.assertTrue(self.config_tool.config.record_to_file_plugin == "Ogg Output" or self.config_tool.config.record_to_file_plugin == "WebM Output") self.config_tool.currentWidget.fileGroupBox.setChecked(False) else: self.assertFalse(self.config_tool.config.record_to_file) self.config_tool.currentWidget.fileGroupBox.setChecked(True) # Dropdown # TODO # Record to Stream # Checkbox for i in range(2): #self.config_tool.config.readConfig() if self.config_tool.currentWidget.streamGroupBox.isChecked(): self.assertTrue(self.config_tool.config.record_to_stream) # TODO: Write better test case for this #self.assertTrue(self.config_tool.config.record_to_stream_plugin == None) self.config_tool.currentWidget.streamGroupBox.setChecked(False) else: self.assertFalse(self.config_tool.config.record_to_stream) self.config_tool.currentWidget.streamGroupBox.setChecked(True) # Dropdown # TODO def test_plugin_audio_input_settings(self): ''' Tests for config tool's Plugins->Audio Input tab ''' # TODO pass def test_plugin_audio_mixer_settings(self): ''' Tests for config tool's Plugins->Audio Mixer tab ''' # TODO pass def test_plugin_video_input_settings(self): ''' Tests for config tool's Plugins->Video Input tab ''' # TODO pass def test_plugin_video_mixer_settings(self): ''' Tests for config tool's Plugins->Video Mixer tab ''' # TODO pass def test_plugin_output_settings(self): ''' Tests for config tool's Plugins->Output tab ''' # TODO pass def test_logger_settings(self): ''' Tests for config tool's Logger tab Needs to be tested differently since the Config instance isn't affected by changes in this tab. ''' # TODO pass def test_close_configtool(self): ''' Tests for config tool's close button ''' self.assertTrue(self.config_tool.mainWidget.isVisible()) QtTest.QTest.mouseClick(self.config_tool.mainWidget.closePushButton, Qt.Qt.LeftButton) self.assertFalse(self.config_tool.mainWidget.isVisible()) def test_file_menu_quit(self): ''' Tests for config tool's File->Quit ''' self.assertTrue(self.config_tool.isVisible()) # File->Quit self.config_tool.actionExit.trigger() self.assertFalse(self.config_tool.isVisible()) def test_help_menu_about(self): ''' Tests for config tool's Help->About ''' self.assertTrue(self.config_tool.isVisible()) # Help->About self.config_tool.actionAbout.trigger() self.assertFalse(self.config_tool.hasFocus()) self.assertTrue(self.config_tool.aboutDialog.isVisible()) # Click "Close" QtTest.QTest.mouseClick(self.config_tool.aboutDialog.closeButton, Qt.Qt.LeftButton) self.assertFalse(self.config_tool.aboutDialog.isVisible())
def __init__(self): FreeseerApp.__init__(self) self.controller = RecordingController() self.config = self.controller.config self.db = self.controller.db self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.clientWidget = ClientDialog(self.config.configdir, self.db) self.configToolApp = ConfigToolApp(self) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName(_fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) self.actionClient = QtGui.QAction(self) self.actionClient.setIcon(self.icon) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) # Hide the controller client configuration screen for Freeseer 3.0.0 # release. This feature's not ready for public use so lets keep it # hidden for now. #self.menuFile.insertAction(self.actionExit, self.actionClient) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL('triggered()'), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL('triggered()'), self.toggle_record_button) self.connect(self.systray, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self._icon_activated) # --- End Systray Setup # main tab connections self.connect(self.mainWidget.eventComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_rooms_from_event) self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_dates_from_event_room) self.connect(self.mainWidget.dateComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_date) self.connect(self.mainWidget.talkComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.set_talk_tooltip) self.connect(self.mainWidget.standbyPushButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.recordPushButton, QtCore.SIGNAL('toggled(bool)'), self.record) self.connect(self.mainWidget.pauseToolButton, QtCore.SIGNAL('toggled(bool)'), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL('toggled(bool)'), self.toggle_audio_feedback) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL('triggered()'), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL('triggered()'), self.open_talkeditor) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL('triggered()'), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL('triggered()'), self.show_report_widget) self.connect(self.actionClient, QtCore.SIGNAL('triggered()'), self.show_client_widget) # GUI Disabling/Enabling Connections self.connect(self.mainWidget.recordPushButton, QtCore.SIGNAL("toggled(bool)"), self.mainWidget.pauseToolButton.setEnabled) #Client Connections self.connect(self.clientWidget.socket, QtCore.SIGNAL('readyRead()'), self.getAction) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.recordPushButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.recordPushButton.setFocus() self.retranslate()
class RecordApp(FreeseerApp): """Freeseer's main GUI class.""" def __init__(self): FreeseerApp.__init__(self) self.controller = RecordingController() self.config = self.controller.config self.db = self.controller.db self.resize(550, 450) # Setup custom widgets self.mainWidget = RecordingWidget() self.setCentralWidget(self.mainWidget) self.reportWidget = ReportDialog() self.reportWidget.setModal(True) self.clientWidget = ClientDialog(self.config.configdir, self.db) self.configToolApp = ConfigToolApp(self) self.configToolApp.setWindowModality(QtCore.Qt.ApplicationModal) self.configToolApp.setWindowFlags(QtCore.Qt.Dialog) self.talkEditorApp = TalkEditorApp(self) self.talkEditorApp.setWindowModality(QtCore.Qt.ApplicationModal) self.talkEditorApp.setWindowFlags(QtCore.Qt.Dialog) self.statusBar().addPermanentWidget(self.mainWidget.statusLabel) # Initialize geometry, to be used for restoring window positioning. self.geometry = None self.current_event = None self.current_room = None self.controller.set_window_id(self.mainWidget.previewWidget.winId()) self.controller.set_audio_feedback_handler(self.audio_feedback) # Set timer for recording how much time elapsed during a recording self.reset_timer() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_timer) # # Setup Menubar # # Build the options Menu, TalkEditor and ConfigTool self.menuOptions = QtGui.QMenu(self.menubar) self.menuOptions.setObjectName(_fromUtf8("menuOptions")) self.menubar.insertMenu(self.menuHelp.menuAction(), self.menuOptions) self.actionConfigTool = QtGui.QAction(self) self.actionConfigTool.setShortcut("Ctrl+C") self.actionConfigTool.setObjectName(_fromUtf8("actionConfigTool")) self.actionTalkEditor = QtGui.QAction(self) self.actionTalkEditor.setShortcut("Ctrl+E") self.actionTalkEditor.setObjectName(_fromUtf8("actionTalkEditor")) self.menuOptions.addAction(self.actionConfigTool) self.menuOptions.addAction(self.actionTalkEditor) folderIcon = QtGui.QIcon.fromTheme("folder") self.actionOpenVideoFolder = QtGui.QAction(self) self.actionOpenVideoFolder.setShortcut("Ctrl+O") self.actionOpenVideoFolder.setObjectName(_fromUtf8("actionOpenVideoFolder")) self.actionOpenVideoFolder.setIcon(folderIcon) self.actionReport = QtGui.QAction(self) self.actionReport.setObjectName(_fromUtf8("actionReport")) self.actionClient = QtGui.QAction(self) self.actionClient.setIcon(self.icon) # Actions self.menuFile.insertAction(self.actionExit, self.actionOpenVideoFolder) # Hide the controller client configuration screen for Freeseer 3.0.0 # release. This feature's not ready for public use so lets keep it # hidden for now. #self.menuFile.insertAction(self.actionExit, self.actionClient) self.menuHelp.addAction(self.actionReport) # --- End Menubar # # Systray Setup # self.systray = QtGui.QSystemTrayIcon(self.icon) self.systray.show() self.systray.menu = QtGui.QMenu() self.systray.setContextMenu(self.systray.menu) self.visibilityAction = QtGui.QAction(self) self.recordAction = QtGui.QAction(self) self.systray.menu.addAction(self.visibilityAction) self.systray.menu.addAction(self.recordAction) self.connect(self.visibilityAction, QtCore.SIGNAL('triggered()'), self.toggle_window_visibility) self.connect(self.recordAction, QtCore.SIGNAL('triggered()'), self.toggle_record_button) self.connect(self.systray, QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self._icon_activated) # --- End Systray Setup # main tab connections self.connect(self.mainWidget.eventComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_rooms_from_event) self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_dates_from_event_room) self.connect(self.mainWidget.dateComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_date) self.connect(self.mainWidget.talkComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.set_talk_tooltip) self.connect(self.mainWidget.standbyPushButton, QtCore.SIGNAL("toggled(bool)"), self.standby) self.connect(self.mainWidget.recordPushButton, QtCore.SIGNAL('toggled(bool)'), self.record) self.connect(self.mainWidget.pauseToolButton, QtCore.SIGNAL('toggled(bool)'), self.pause) self.connect(self.mainWidget.audioFeedbackCheckbox, QtCore.SIGNAL('toggled(bool)'), self.toggle_audio_feedback) # Main Window Connections self.connect(self.actionConfigTool, QtCore.SIGNAL('triggered()'), self.open_configtool) self.connect(self.actionTalkEditor, QtCore.SIGNAL('triggered()'), self.open_talkeditor) self.connect(self.actionOpenVideoFolder, QtCore.SIGNAL('triggered()'), self.open_video_directory) self.connect(self.actionReport, QtCore.SIGNAL('triggered()'), self.show_report_widget) self.connect(self.actionClient, QtCore.SIGNAL('triggered()'), self.show_client_widget) # GUI Disabling/Enabling Connections self.connect(self.mainWidget.recordPushButton, QtCore.SIGNAL("toggled(bool)"), self.mainWidget.pauseToolButton.setEnabled) #Client Connections self.connect(self.clientWidget.socket, QtCore.SIGNAL('readyRead()'), self.getAction) # # ReportWidget Connections # self.connect(self.reportWidget.reportButton, QtCore.SIGNAL("clicked()"), self.report) self.load_settings() # Setup spacebar key. self.mainWidget.recordPushButton.setShortcut(QtCore.Qt.Key_Space) self.mainWidget.recordPushButton.setFocus() self.retranslate() ### ### Translation Related ### def retranslate(self): self.clientWidget.retranslate(self.current_language) self.setWindowTitle(self.app.translate("RecordApp", "Freeseer - portable presentation recording station")) # # Reusable Strings # self.standbyString = self.app.translate("RecordApp", "Standby") self.recordString = self.app.translate("RecordApp", "Record") self.pauseString = self.app.translate("RecordApp", "Pause") self.resumeString = self.app.translate("RecordApp", "Resume") self.stopString = self.app.translate("RecordApp", "Stop") self.hideWindowString = self.app.translate("RecordApp", "Hide Main Window") self.showWindowString = self.app.translate("RecordApp", "Show Main Window") # Status Bar messages self.idleString = self.app.translate("RecordApp", "Idle.") self.readyString = self.app.translate("RecordApp", "Ready.") self.recordingString = self.app.translate("RecordApp", "Recording...") self.pausedString = self.app.translate("RecordApp", "Recording Paused.") # --- End Reusable Strings if self.mainWidget.recordPushButton.isChecked() and self.mainWidget.pauseToolButton.isChecked(): self.mainWidget.statusLabel.setText(self.pausedString) elif self.mainWidget.recordPushButton.isChecked() and (not self.mainWidget.pauseToolButton.isChecked()): self.mainWidget.statusLabel.setText(self.recordingString) elif self.mainWidget.standbyPushButton.isChecked(): self.mainWidget.statusLabel.setText(self.readyString) else: self.mainWidget.statusLabel.setText(self.idleString) # # Menubar # self.menuOptions.setTitle(self.app.translate("RecordApp", "&Options")) self.actionConfigTool.setText(self.app.translate("RecordApp", "&Configuration")) self.actionTalkEditor.setText(self.app.translate("RecordApp", "&Edit Talks")) self.actionOpenVideoFolder.setText(self.app.translate("RecordApp", "&Open Video Directory")) self.actionClient.setText(self.app.translate("RecordApp", "&Connect to server")) self.actionReport.setText(self.app.translate("RecordApp", "&Report")) # --- End Menubar # # Systray # self.visibilityAction.setText(self.hideWindowString) self.recordAction.setText(self.recordString) # --- End Systray # # RecordingWidget # self.mainWidget.standbyPushButton.setText(self.standbyString) self.mainWidget.standbyPushButton.setToolTip(self.standbyString) if self.mainWidget.recordPushButton.isChecked(): self.mainWidget.recordPushButton.setText(self.stopString) self.mainWidget.recordPushButton.setToolTip(self.stopString) else: self.mainWidget.recordPushButton.setText(self.recordString) self.mainWidget.recordPushButton.setToolTip(self.recordString) self.mainWidget.pauseToolButton.setText(self.pauseString) self.mainWidget.pauseToolButton.setToolTip(self.pauseString) self.mainWidget.eventLabel.setText(self.app.translate("RecordApp", "Event")) self.mainWidget.roomLabel.setText(self.app.translate("RecordApp", "Room")) self.mainWidget.dateLabel.setText(self.app.translate("RecordApp", "Date")) self.mainWidget.talkLabel.setText(self.app.translate("RecordApp", "Talk")) # --- End RecordingWidget # # ReportWidget # self.reportWidget.setWindowTitle(self.app.translate("RecordApp", "Reporting Tool")) self.reportWidget.titleLabel.setText(self.app.translate("RecordApp", "Title:")) self.reportWidget.speakerLabel.setText(self.app.translate("RecordApp", "Speaker:")) self.reportWidget.eventLabel.setText(self.app.translate("RecordApp", "Event:")) self.reportWidget.roomLabel.setText(self.app.translate("RecordApp", "Room:")) self.reportWidget.timeLabel.setText(self.app.translate("RecordApp", "Time:")) self.reportWidget.commentLabel.setText(self.app.translate("RecordApp", "Comment")) self.reportWidget.releaseCheckBox.setText(self.app.translate("RecordApp", "Release Received")) self.reportWidget.closeButton.setText(self.app.translate("RecordApp", "Close")) self.reportWidget.reportButton.setText(self.app.translate("RecordApp", "Report")) # Logic for translating the report options noissues = self.app.translate("RecordApp", "No Issues") noaudio = self.app.translate("RecordApp", "No Audio") novideo = self.app.translate("RecordApp", "No Video") noaudiovideo = self.app.translate("RecordApp", "No Audio/Video") self.reportWidget.options = [noissues, noaudio, novideo, noaudiovideo] self.reportWidget.reportCombo.clear() for i in self.reportWidget.options: self.reportWidget.reportCombo.addItem(i) # --- End ReportWidget ### ### UI Logic ### def load_settings(self): """Load settings for Freeseer""" log.info('Loading settings...') # Load default language. actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talks as a SQL Data Model. self.load_event_list() def current_presentation(self): """Creates a presentation object of the current presentation. Current presentation is the currently selected title on the GUI. """ #i = self.mainWidget.talkComboBox.currentIndex() #p_id = self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() return self.db.get_presentation(self.current_presentation_id()) def current_presentation_id(self): """Returns the current selected presentation ID.""" i = self.mainWidget.talkComboBox.currentIndex() return self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString() def standby(self, state): """Prepares the GStreamer pipelines for recording Sets the pipeline to paused state so that initiating a recording does not have a delay due to GStreamer initialization. """ def toggle_gui(state): """Toggles GUI components when standby is pressed""" self.mainWidget.standbyPushButton.setHidden(state) self.mainWidget.recordPushButton.setVisible(state) self.mainWidget.recordPushButton.setEnabled(state) self.mainWidget.pauseToolButton.setVisible(state) self.mainWidget.eventComboBox.setDisabled(state) self.mainWidget.roomComboBox.setDisabled(state) self.mainWidget.dateComboBox.setDisabled(state) self.mainWidget.talkComboBox.setDisabled(state) self.mainWidget.audioFeedbackCheckbox.setDisabled(state) if (state): # Prepare the pipelines if self.load_backend(): toggle_gui(True) self.controller.pause() self.mainWidget.statusLabel.setText(self.readyString) else: toggle_gui(False) self.mainWidget.standbyPushButton.setChecked(False) else: toggle_gui(False) self.mainWidget.standbyPushButton.setChecked(False) def record(self, state): """The logic for recording and stopping recording.""" if state: # Start Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo_rec.png") sysIcon2 = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon2) self.systray.showMessage("Recording", "RECORDING") self.controller.record() self.mainWidget.recordPushButton.setText(self.stopString) self.recordAction.setText(self.stopString) # Hide if auto-hide is set. if self.config.auto_hide: self.hide_window() self.visibilityAction.setText(self.showWindowString) log.debug('auto-hide is enabled, main window is now hidden in systray.') self.mainWidget.statusLabel.setText(self.recordingString) # Start timer. self.timer.start(1000) else: # Stop Recording. logo_rec = QtGui.QPixmap(":/freeseer/logo.png") sysIcon = QtGui.QIcon(logo_rec) self.systray.setIcon(sysIcon) self.controller.stop() self.mainWidget.pauseToolButton.setChecked(False) self.mainWidget.recordPushButton.setText(self.recordString) self.recordAction.setText(self.recordString) self.mainWidget.audioSlider.setValue(0) # Finally set the standby button back to unchecked position. self.standby(False) # Stop and reset timer. self.timer.stop() self.reset_timer() # Select next talk if there is one within 15 minutes. if self.current_event and self.current_room: starttime = QtCore.QDateTime().currentDateTime() stoptime = starttime.addSecs(900) talkid = self.db.get_talk_between_time(self.current_event, self.current_room, starttime.toString(), stoptime.toString()) if talkid is not None: for i in range(self.mainWidget.talkComboBox.count()): if talkid == self.mainWidget.talkComboBox.model().index(i, 1).data(QtCore.Qt.DisplayRole).toString(): self.mainWidget.talkComboBox.setCurrentIndex(i) def pause(self, state): """Pause the recording""" if (state): # Pause Recording. self.controller.pause() log.info("Recording paused.") self.mainWidget.pauseToolButton.setToolTip(self.resumeString) self.mainWidget.statusLabel.setText(self.pausedString) self.timer.stop() elif self.mainWidget.recordPushButton.isChecked(): self.controller.record() log.info("Recording unpaused.") self.mainWidget.pauseToolButton.setToolTip(self.pauseString) self.mainWidget.statusLabel.setText(self.recordingString) self.timer.start(1000) def load_backend(self): """Prepares the backend for recording""" if self.current_presentation(): presentation = self.current_presentation() # If current presentation is no existant (empty talk database) # use a default recording name. else: presentation = Presentation(title=unicode("default")) if self.controller.load_backend(presentation): return True else: return False # Error something failed while loading the backend def update_timer(self): """Updates the Elapsed Time displayed. Uses the statusLabel for the display. """ time = "%d:%02d" % (self.time_minutes, self.time_seconds) self.time_seconds += 1 if self.time_seconds == 60: self.time_seconds = 0 self.time_minutes += 1 self.mainWidget.statusLabel.setText("Free Space: %s --- Elapsed Time: %s" % (get_free_space(self.config.videodir), time)) def reset_timer(self): """Resets the Elapsed Time.""" self.time_minutes = 0 self.time_seconds = 0 def toggle_audio_feedback(self, enabled): """Enables or disables audio feedback according to checkbox state""" self.config.audio_feedback = enabled ### ### Talk Related ### def set_talk_tooltip(self, talk): self.mainWidget.talkComboBox.setToolTip(talk) def load_event_list(self): model = self.db.get_events_model() self.mainWidget.eventComboBox.setModel(model) def load_rooms_from_event(self, event): #self.disconnect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) self.current_event = event model = self.db.get_rooms_model(self.current_event) self.mainWidget.roomComboBox.setModel(model) #self.connect(self.mainWidget.roomComboBox, QtCore.SIGNAL('currentIndexChanged(const QString&)'), self.load_talks_from_room) def load_dates_from_event_room(self, change): event = str(self.mainWidget.eventComboBox.currentText()) room = str(self.mainWidget.roomComboBox.currentText()) model = self.db.get_dates_from_event_room_model(event, room) self.mainWidget.dateComboBox.setModel(model) def load_talks_from_date(self, date): self.current_room = str(self.mainWidget.roomComboBox.currentText()) self.current_date = date model = self.db.get_talks_model(self.current_event, self.current_room, self.current_date) self.mainWidget.talkComboBox.setModel(model) ### ### Report Failure ### def show_report_widget(self): p = self.current_presentation() self.reportWidget.titleLabel2.setText(p.title) self.reportWidget.speakerLabel2.setText(p.speaker) self.reportWidget.eventLabel2.setText(p.event) self.reportWidget.roomLabel2.setText(p.room) self.reportWidget.timeLabel2.setText(p.time) # Get existing report if there is one. talk_id = self.current_presentation_id() f = self.db.get_report(talk_id) if f is not None: self.reportWidget.commentEdit.setText(f.comment) i = self.reportWidget.reportCombo.findText(f.indicator) self.reportWidget.reportCombo.setCurrentIndex(i) self.reportWidget.releaseCheckBox.setChecked(f.release) else: self.reportWidget.commentEdit.setText("") self.reportWidget.reportCombo.setCurrentIndex(0) self.reportWidget.releaseCheckBox.setChecked(False) self.reportWidget.show() def report(self): talk_id = self.current_presentation_id() presentation = self.current_presentation() i = self.reportWidget.reportCombo.currentIndex() failure = Failure(talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked()) log.info("Report Failure: %s, %s, %s, release form? %s" % (talk_id, self.reportWidget.commentEdit.text(), self.reportWidget.options[i], self.reportWidget.releaseCheckBox.isChecked())) self.db.insert_failure(failure) self.reportWidget.close() ### ### Misc. ### def _icon_activated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self.systray.menu.popup(QCursor.pos()) if reason == QtGui.QSystemTrayIcon.DoubleClick: self.toggle_record_button() def hide_window(self): self.geometry = self.saveGeometry() self.hide() def show_window(self): if (self.geometry is not None): self.restoreGeometry(self.geometry) self.show() def toggle_window_visibility(self): """Toggles the visibility of the Recording Main Window.""" if self.isHidden(): self.show_window() self.visibilityAction.setText(self.hideWindowString) else: self.hide_window() self.visibilityAction.setText(self.showWindowString) def toggle_record_button(self): self.mainWidget.standbyPushButton.toggle() self.mainWidget.recordPushButton.toggle() def audio_feedback(self, value): self.mainWidget.audioSlider.setValue(value) def open_video_directory(self): if sys.platform.startswith("linux"): os.system("xdg-open %s" % self.config.videodir) elif sys.platform.startswith("win32"): os.system("explorer %s" % self.config.videodir) else: log.info("Error: This command is not supported on the current OS.") def closeEvent(self, event): log.info('Exiting freeseer...') event.accept() ''' Client functions ''' def show_client_widget(self): self.current_presentation() self.clientWidget.show() ''' This function is for handling commands sent from the server to the client ''' def getAction(self): message = self.clientWidget.socket.read(self.clientWidget.socket.bytesAvailable()) if message == 'Record': self.mainWidget.standbyPushButton.toggle() self.mainWidget.recordPushButton.toggle() self.clientWidget.sendMessage('Started recording') log.info("Started recording by server's request") elif message == 'Stop': self.mainWidget.recordPushButton.toggle() log.info("Stopping recording by server's request") elif message == 'Pause' or 'Resume': self.mainWidget.pauseToolButton.toggle() if message == 'Pause': log.info("Paused recording by server's request") elif message == 'Resume': log.info("Resumed recording by server's request") ### ### Utility ### def open_configtool(self): self.configToolApp.show() def open_talkeditor(self): self.talkEditorApp.show()
class TestConfigToolApp(unittest.TestCase): """ Test suite to verify the functionality of the ConfigToolApp class. Tests interact like an end user (using QtTest). Expect the app to be rendered. NOTE: most tests will follow this format: 1. Get current config setting 2. Make UI change (config change happens immediately) 3. Reparse config file 4. Test that has changed (using the previous and new) """ def setUp(self): """ Stardard init method: runs before each test_* method Initializes a QtGui.QApplication and ConfigToolApp object. ConfigToolApp.show() causes the UI to be rendered. """ self.profile_manager = ProfileManager(tempfile.mkdtemp()) profile = self.profile_manager.get('testing') config = profile.get_config('freeseer.conf', settings.FreeseerConfig, storage_args=['Global'], read_only=False) self.app = QtGui.QApplication([]) self.config_tool = ConfigToolApp(profile, config) self.config_tool.show() def tearDown(self): """ Standard tear down method. Runs after each test_* method. This method closes the ConfigToolApp by clicking the "close" button """ QtTest.QTest.mouseClick(self.config_tool.mainWidget.closePushButton, Qt.Qt.LeftButton) shutil.rmtree(self.profile_manager._base_folder) del self.config_tool.app self.app.deleteLater() def test_default_widget(self): self.assertEqual(self.config_tool.currentWidget, self.config_tool.generalWidget) def check_combobox_corner_cases_frontend(self, combobox_widget): """ Tests that a given QtComboBox has: - a default selected item - does not blow up on the minimum and maximum index item in the combobox list """ index = combobox_widget.currentIndex() combobox_widget.setCurrentIndex(0) self.assertEquals(combobox_widget.currentIndex(), 0) self.assertIsNot(combobox_widget.currentText(), None) combobox_widget.setCurrentIndex(combobox_widget.count() - 1) self.assertEquals(combobox_widget.currentIndex(), (combobox_widget.count() - 1)) self.assertIsNot(combobox_widget.currentText(), None) combobox_widget.setCurrentIndex(index) self.assertEquals(combobox_widget.currentIndex(), index) self.assertIsNot(combobox_widget.currentText(), None) def select_general_settings_tab(self): # Select "General" tab item = self.config_tool.mainWidget.optionsTreeWidget.findItems( self.config_tool.generalString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) def test_general_settings_checkbox(self): """ Test the config tool's General Tab auto-hide system tray icon checkbox with simulated user input """ self.select_general_settings_tab() # Test disabled checkbox self.config_tool.currentWidget.autoHideCheckBox.setChecked(False) self.assertEqual( self.config_tool.currentWidget.autoHideCheckBox.checkState(), QtCore.Qt.Unchecked) self.assertFalse(self.config_tool.config.auto_hide) # Test enabled checkbox self.config_tool.currentWidget.autoHideCheckBox.setChecked(True) self.assertEqual( self.config_tool.currentWidget.autoHideCheckBox.checkState(), QtCore.Qt.Checked) self.assertTrue(self.config_tool.config.auto_hide) def test_general_settings_dropdown_menu(self): """ Test the config tool's General Tab language selection drop down menu with simulated user input """ self.select_general_settings_tab() # Test dropdown menu language_combo_box = self.config_tool.generalWidget.languageComboBox self.check_combobox_corner_cases_frontend(language_combo_box) QtTest.QTest.keyClick( language_combo_box, QtCore.Qt.Key_PageUp ) # Test simulated user interaction with drop down list for i in range(language_combo_box.count() - 2): last_language = self.config_tool.config.default_language QtTest.QTest.keyClick(language_combo_box, QtCore.Qt.Key_Down) current_language = self.config_tool.config.default_language self.assertNotEqual(last_language, current_language) # Test frontend constants self.assertNotEqual( language_combo_box.findText('Deutsch'), -1) # Assert there are multiple languages in the menu self.assertNotEqual(language_combo_box.findText('English'), -1) self.assertNotEqual(language_combo_box.findText('Nederlands'), -1) def test_general_settings_help_reset(self): """ Test the config tool's General Tab help link and reset button with simulated user input """ self.select_general_settings_tab() # Test that Help us translate tries to open a web url. QtGui.QDesktopServices.openUrl = MagicMock(return_value=None) self.config_tool.open_translate_url() QtGui.QDesktopServices.openUrl.assert_called_with( QtCore.QUrl( "http://freeseer.readthedocs.org/en/latest/contribute/translation.html" )) # Reset # The reset test should set the backend config_tool values, simulate a user clicking through the reset popup and # verify that the backend config_tool values have been set to defaults. # TODO: FIXME. Related to gh#631. The buttons on the dialog cause segfaults in the test environment and prevent # the test from being implemented at the present time. # self.config_tool.confirm_reset() def select_recording_tab(self): """ Helper function used to open up the recording tab for recording tab related tests """ item = self.config_tool.mainWidget.optionsTreeWidget.findItems( self.config_tool.avString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) self.assertEqual(self.config_tool.currentWidget, self.config_tool.avWidget) def test_recording_settings_file(self): """ Simulates a user interacting with the config tool record to file settings. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.fileGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.record_to_file) # Test enabled checkbox self.config_tool.currentWidget.fileGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.record_to_file) self.assertIn(self.config_tool.config.record_to_file_plugin, ['Ogg Output', 'WebM Output', 'Raw Output']) # Test combo box file_combo_box = self.config_tool.avWidget.fileComboBox self.check_combobox_corner_cases_frontend(file_combo_box) QtTest.QTest.keyClick( file_combo_box, QtCore.Qt.Key_PageUp ) # Simulate user input to test backend and frontend for i in range(file_combo_box.count() - 2): last_plugin = self.config_tool.config.record_to_file_plugin QtTest.QTest.keyClick(file_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.config.record_to_file_plugin self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertNotEqual(file_combo_box.findText('Ogg Output'), -1) self.assertNotEqual(file_combo_box.findText('WebM Output'), -1) self.assertNotEqual(file_combo_box.findText('Raw Output'), -1) def test_recording_settings_stream(self): """ Simulates a user interacting with the config tool record to output stream settings. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.streamGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.record_to_stream) # Test enabled checkbox self.config_tool.currentWidget.streamGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.record_to_stream) # Test combo box stream_combo_box = self.config_tool.avWidget.streamComboBox self.check_combobox_corner_cases_frontend(stream_combo_box) QtTest.QTest.keyClick( stream_combo_box, QtCore.Qt.Key_PageUp ) # Simulate user input to test backend and frontend for i in range(stream_combo_box.count() - 2): last_plugin = self.config_tool.plugman.get_plugin_by_name( stream_combo_box.currentText(), 'Output') QtTest.QTest.keyClick(stream_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.plugman.get_plugin_by_name( stream_combo_box.currentText(), 'Output') self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertNotEqual(stream_combo_box.findText('RTMP Streaming'), -1) self.assertNotEqual(stream_combo_box.findText('Ogg Icecast'), -1) def test_recording_settings_video_input(self): """ Simulates a user interacting with the config tool record to video input setting. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.videoGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.enable_video_recording) # Test enabled checkbox self.config_tool.currentWidget.videoGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.enable_video_recording) self.assertIn(self.config_tool.config.videomixer, ['Video Passthrough', 'Picture-In-Picture']) # Test combo box video_mixer_combo_box = self.config_tool.avWidget.videoMixerComboBox self.check_combobox_corner_cases_frontend(video_mixer_combo_box) QtTest.QTest.keyClick( video_mixer_combo_box, QtCore.Qt.Key_PageUp) # Simulate user to test backend/frontend for i in range(video_mixer_combo_box.count() - 2): last_plugin = self.config_tool.videomixer QtTest.QTest.keyClick(video_mixer_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.videomixer self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertTrue( video_mixer_combo_box.findText('Video Passthrough') != -1) self.assertTrue( video_mixer_combo_box.findText('Picture-In-Picture') != -1) def test_recording_settings_audio_input(self): """ Simulates a user interacting with the config tool record to audio input settings. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.audioGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.enable_audio_recording) # Test enabled checkbox self.config_tool.currentWidget.audioGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.enable_audio_recording) self.assertIn(self.config_tool.config.audiomixer, ['Audio Passthrough', 'Multiple Audio Inputs']) # Test combo box audio_mixer_combo_box = self.config_tool.avWidget.audioMixerComboBox self.check_combobox_corner_cases_frontend(audio_mixer_combo_box) QtTest.QTest.keyClick( audio_mixer_combo_box, QtCore.Qt.Key_PageUp) # Simulate user to test backend/frontend for i in range(audio_mixer_combo_box.count() - 2): last_plugin = self.config_tool.audiomixer QtTest.QTest.keyClick(audio_mixer_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.audiomixer self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertNotEqual( audio_mixer_combo_box.findText('Audio Passthrough'), -1) self.assertNotEqual( audio_mixer_combo_box.findText('Multiple Audio Inputs'), -1) def test_plugin_settings(self): """ Simulate a user going through the list of plugins in the plugin settings page of the config tool. This test builds a dictionary value based on a traversal of the QTreeWidget that contains the plugins displayed in the GUI. The dictionary is then used to assert that plugins exist in the appropriate categories. This test also uses a map to relate the GUI's category names to the backend's category names since the two differ. """ item = self.config_tool.mainWidget.optionsTreeWidget.findItems( self.config_tool.pluginsString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) self.assertEqual(self.config_tool.currentWidget, self.config_tool.pluginWidget) # GUI names categories are different than the backend. Define a translation from GUI -> backend gui_category_to_backend_category = { 'Audio Input': 'AudioInput', 'Audio Mixer': 'AudioMixer', 'Video Input': 'VideoInput', 'Video Mixer': 'VideoMixer', 'Output': 'Output', 'Input': 'Importer' } QtTest.QTest.keyClick(self.config_tool.pluginWidget.list, QtCore.Qt.Key_PageUp) root = self.config_tool.pluginWidget.list.invisibleRootItem() plugin_category = {} # A dictionary of plugin -> category for category_index in range(root.childCount()): category = str( self.config_tool.pluginWidget.list.currentItem().text(0)) QtTest.QTest.keyClick(self.config_tool.pluginWidget.list, QtCore.Qt.Key_Down) for plugin_index in range(root.child(category_index).childCount()): plugin_name = str( self.config_tool.pluginWidget.list.currentItem().text(0)) plugin_category[ plugin_name] = gui_category_to_backend_category[category] QtTest.QTest.keyClick(self.config_tool.pluginWidget.list, QtCore.Qt.Key_Down) # Assert expected categories exist. self.assertIn('AudioInput', plugin_category.values()) self.assertIn('AudioMixer', plugin_category.values()) self.assertIn('VideoInput', plugin_category.values()) self.assertIn('VideoMixer', plugin_category.values()) self.assertIn('Output', plugin_category.values()) self.assertIn('Importer', plugin_category.values()) for category in [ 'AudioInput', 'AudioMixer', 'VideoInput', 'VideoMixer', 'Output', 'Importer' ]: for plugin in self.config_tool.get_plugins(category): self.assertIn(plugin.plugin_object.name, plugin_category) self.assertEqual(plugin_category[plugin.plugin_object.name], category) self.assertEqual(category, plugin.plugin_object.CATEGORY) def test_logger_settings(self): """ Tests for config tool's Logger tab Needs to be tested differently since the Config instance isn't affected by changes in this tab. """ # TODO pass def test_close_configtool(self): """ Tests for config tool's close button """ self.assertTrue(self.config_tool.mainWidget.isVisible()) QtTest.QTest.mouseClick(self.config_tool.mainWidget.closePushButton, Qt.Qt.LeftButton) self.assertFalse(self.config_tool.mainWidget.isVisible()) def test_file_menu_quit(self): """ Tests for config tool's File->Quit """ self.assertTrue(self.config_tool.isVisible()) # File->Quit self.config_tool.actionExit.trigger() self.assertFalse(self.config_tool.isVisible()) def test_help_menu_about(self): """ Tests for config tool's Help->About """ self.assertTrue(self.config_tool.isVisible()) # Help->About self.config_tool.actionAbout.trigger() self.assertFalse(self.config_tool.hasFocus()) self.assertTrue(self.config_tool.aboutDialog.isVisible()) # Click "Close" QtTest.QTest.mouseClick(self.config_tool.aboutDialog.closeButton, Qt.Qt.LeftButton) self.assertFalse(self.config_tool.aboutDialog.isVisible())
class TestConfigToolApp(unittest.TestCase): """ Test suite to verify the functionality of the ConfigToolApp class. Tests interact like an end user (using QtTest). Expect the app to be rendered. NOTE: most tests will follow this format: 1. Get current config setting 2. Make UI change (config change happens immediately) 3. Reparse config file 4. Test that has changed (using the previous and new) """ def setUp(self): """ Stardard init method: runs before each test_* method Initializes a QtGui.QApplication and ConfigToolApp object. ConfigToolApp.show() causes the UI to be rendered. """ self.profile_manager = ProfileManager(tempfile.mkdtemp()) profile = self.profile_manager.get('testing') config = profile.get_config('freeseer.conf', settings.FreeseerConfig, storage_args=['Global'], read_only=False) self.app = QtGui.QApplication([]) self.config_tool = ConfigToolApp(profile, config) self.config_tool.show() def tearDown(self): """ Standard tear down method. Runs after each test_* method. This method closes the ConfigToolApp by clicking the "close" button """ QtTest.QTest.mouseClick(self.config_tool.mainWidget.closePushButton, Qt.Qt.LeftButton) shutil.rmtree(self.profile_manager._base_folder) del self.config_tool.app self.app.deleteLater() def test_default_widget(self): self.assertEqual(self.config_tool.currentWidget, self.config_tool.generalWidget) def check_combobox_corner_cases_frontend(self, combobox_widget): """ Tests that a given QtComboBox has: - a default selected item - does not blow up on the minimum and maximum index item in the combobox list """ index = combobox_widget.currentIndex() combobox_widget.setCurrentIndex(0) self.assertEquals(combobox_widget.currentIndex(), 0) self.assertIsNot(combobox_widget.currentText(), None) combobox_widget.setCurrentIndex(combobox_widget.count() - 1) self.assertEquals(combobox_widget.currentIndex(), (combobox_widget.count() - 1)) self.assertIsNot(combobox_widget.currentText(), None) combobox_widget.setCurrentIndex(index) self.assertEquals(combobox_widget.currentIndex(), index) self.assertIsNot(combobox_widget.currentText(), None) def select_general_settings_tab(self): # Select "General" tab item = self.config_tool.mainWidget.optionsTreeWidget.findItems(self.config_tool.generalString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) def test_general_settings_checkbox(self): """ Test the config tool's General Tab auto-hide system tray icon checkbox with simulated user input """ self.select_general_settings_tab() # Test disabled checkbox self.config_tool.currentWidget.autoHideCheckBox.setChecked(False) self.assertEqual(self.config_tool.currentWidget.autoHideCheckBox.checkState(), QtCore.Qt.Unchecked) self.assertFalse(self.config_tool.config.auto_hide) # Test enabled checkbox self.config_tool.currentWidget.autoHideCheckBox.setChecked(True) self.assertEqual(self.config_tool.currentWidget.autoHideCheckBox.checkState(), QtCore.Qt.Checked) self.assertTrue(self.config_tool.config.auto_hide) def test_general_settings_dropdown_menu(self): """ Test the config tool's General Tab language selection drop down menu with simulated user input """ self.select_general_settings_tab() # Test dropdown menu language_combo_box = self.config_tool.generalWidget.languageComboBox self.check_combobox_corner_cases_frontend(language_combo_box) QtTest.QTest.keyClick(language_combo_box, QtCore.Qt.Key_PageUp) # Test simulated user interaction with drop down list for i in range(language_combo_box.count() - 2): last_language = self.config_tool.config.default_language QtTest.QTest.keyClick(language_combo_box, QtCore.Qt.Key_Down) current_language = self.config_tool.config.default_language self.assertNotEqual(last_language, current_language) # Test frontend constants self.assertNotEqual(language_combo_box.findText('Deutsch'), -1) # Assert there are multiple languages in the menu self.assertNotEqual(language_combo_box.findText('English'), -1) self.assertNotEqual(language_combo_box.findText('Nederlands'), -1) def test_general_settings_help_reset(self): """ Test the config tool's General Tab help link and reset button with simulated user input """ self.select_general_settings_tab() # Test that Help us translate tries to open a web url. QtGui.QDesktopServices.openUrl = MagicMock(return_value=None) self.config_tool.open_translate_url() QtGui.QDesktopServices.openUrl.assert_called_with( QtCore.QUrl("http://freeseer.readthedocs.org/en/latest/contribute/translation.html") ) # Reset # The reset test should set the backend config_tool values, simulate a user clicking through the reset popup and # verify that the backend config_tool values have been set to defaults. # TODO: FIXME. Related to gh#631. The buttons on the dialog cause segfaults in the test environment and prevent # the test from being implemented at the present time. # self.config_tool.confirm_reset() def select_recording_tab(self): """ Helper function used to open up the recording tab for recording tab related tests """ item = self.config_tool.mainWidget.optionsTreeWidget.findItems(self.config_tool.avString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) self.assertEqual(self.config_tool.currentWidget, self.config_tool.avWidget) def test_recording_settings_file(self): """ Simulates a user interacting with the config tool record to file settings. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.fileGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.record_to_file) # Test enabled checkbox self.config_tool.currentWidget.fileGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.record_to_file) self.assertIn(self.config_tool.config.record_to_file_plugin, ['Ogg Output', 'WebM Output', 'Raw Output']) # Test combo box file_combo_box = self.config_tool.avWidget.fileComboBox self.check_combobox_corner_cases_frontend(file_combo_box) QtTest.QTest.keyClick(file_combo_box, QtCore.Qt.Key_PageUp) # Simulate user input to test backend and frontend for i in range(file_combo_box.count() - 2): last_plugin = self.config_tool.config.record_to_file_plugin QtTest.QTest.keyClick(file_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.config.record_to_file_plugin self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertNotEqual(file_combo_box.findText('Ogg Output'), -1) self.assertNotEqual(file_combo_box.findText('WebM Output'), -1) self.assertNotEqual(file_combo_box.findText('Raw Output'), -1) def test_recording_settings_stream(self): """ Simulates a user interacting with the config tool record to output stream settings. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.streamGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.record_to_stream) # Test enabled checkbox self.config_tool.currentWidget.streamGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.record_to_stream) # Test combo box stream_combo_box = self.config_tool.avWidget.streamComboBox self.check_combobox_corner_cases_frontend(stream_combo_box) QtTest.QTest.keyClick(stream_combo_box, QtCore.Qt.Key_PageUp) # Simulate user input to test backend and frontend for i in range(stream_combo_box.count() - 2): last_plugin = self.config_tool.plugman.get_plugin_by_name(stream_combo_box.currentText(), 'Output') QtTest.QTest.keyClick(stream_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.plugman.get_plugin_by_name(stream_combo_box.currentText(), 'Output') self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertNotEqual(stream_combo_box.findText('RTMP Streaming'), -1) self.assertNotEqual(stream_combo_box.findText('Ogg Icecast'), -1) def test_recording_settings_video_input(self): """ Simulates a user interacting with the config tool record to video input setting. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.videoGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.enable_video_recording) # Test enabled checkbox self.config_tool.currentWidget.videoGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.enable_video_recording) self.assertIn(self.config_tool.config.videomixer, ['Video Passthrough', 'Picture-In-Picture']) # Test combo box video_mixer_combo_box = self.config_tool.avWidget.videoMixerComboBox self.check_combobox_corner_cases_frontend(video_mixer_combo_box) QtTest.QTest.keyClick(video_mixer_combo_box, QtCore.Qt.Key_PageUp) # Simulate user to test backend/frontend for i in range(video_mixer_combo_box.count() - 2): last_plugin = self.config_tool.videomixer QtTest.QTest.keyClick(video_mixer_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.videomixer self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertTrue(video_mixer_combo_box.findText('Video Passthrough') != -1) self.assertTrue(video_mixer_combo_box.findText('Picture-In-Picture') != -1) def test_recording_settings_audio_input(self): """ Simulates a user interacting with the config tool record to audio input settings. """ self.select_recording_tab() # Test disabled checkbox self.config_tool.currentWidget.audioGroupBox.setChecked(False) self.assertFalse(self.config_tool.config.enable_audio_recording) # Test enabled checkbox self.config_tool.currentWidget.audioGroupBox.setChecked(True) self.assertTrue(self.config_tool.config.enable_audio_recording) self.assertIn(self.config_tool.config.audiomixer, ['Audio Passthrough', 'Multiple Audio Inputs']) # Test combo box audio_mixer_combo_box = self.config_tool.avWidget.audioMixerComboBox self.check_combobox_corner_cases_frontend(audio_mixer_combo_box) QtTest.QTest.keyClick(audio_mixer_combo_box, QtCore.Qt.Key_PageUp) # Simulate user to test backend/frontend for i in range(audio_mixer_combo_box.count() - 2): last_plugin = self.config_tool.audiomixer QtTest.QTest.keyClick(audio_mixer_combo_box, QtCore.Qt.Key_Down) current_plugin = self.config_tool.audiomixer self.assertNotEqual(last_plugin, current_plugin) # Test frontend text values self.assertNotEqual(audio_mixer_combo_box.findText('Audio Passthrough'), -1) self.assertNotEqual(audio_mixer_combo_box.findText('Multiple Audio Inputs'), -1) def test_plugin_settings(self): """ Simulate a user going through the list of plugins in the plugin settings page of the config tool. This test builds a dictionary value based on a traversal of the QTreeWidget that contains the plugins displayed in the GUI. The dictionary is then used to assert that plugins exist in the appropriate categories. This test also uses a map to relate the GUI's category names to the backend's category names since the two differ. """ item = self.config_tool.mainWidget.optionsTreeWidget.findItems(self.config_tool.pluginsString, QtCore.Qt.MatchExactly) self.assertFalse(not item or item[0] is None) self.config_tool.mainWidget.optionsTreeWidget.setCurrentItem(item[0]) QtTest.QTest.mouseClick(self.config_tool.mainWidget.optionsTreeWidget, Qt.Qt.LeftButton) self.assertEqual(self.config_tool.currentWidget, self.config_tool.pluginWidget) # GUI names categories are different than the backend. Define a translation from GUI -> backend gui_category_to_backend_category = { 'Audio Input': 'AudioInput', 'Audio Mixer': 'AudioMixer', 'Video Input': 'VideoInput', 'Video Mixer': 'VideoMixer', 'Output': 'Output', 'Input': 'Importer' } QtTest.QTest.keyClick(self.config_tool.pluginWidget.list, QtCore.Qt.Key_PageUp) root = self.config_tool.pluginWidget.list.invisibleRootItem() plugin_category = {} # A dictionary of plugin -> category for category_index in range(root.childCount()): category = str(self.config_tool.pluginWidget.list.currentItem().text(0)) QtTest.QTest.keyClick(self.config_tool.pluginWidget.list, QtCore.Qt.Key_Down) for plugin_index in range(root.child(category_index).childCount()): plugin_name = str(self.config_tool.pluginWidget.list.currentItem().text(0)) plugin_category[plugin_name] = gui_category_to_backend_category[category] QtTest.QTest.keyClick(self.config_tool.pluginWidget.list, QtCore.Qt.Key_Down) # Assert expected categories exist. self.assertIn('AudioInput', plugin_category.values()) self.assertIn('AudioMixer', plugin_category.values()) self.assertIn('VideoInput', plugin_category.values()) self.assertIn('VideoMixer', plugin_category.values()) self.assertIn('Output', plugin_category.values()) self.assertIn('Importer', plugin_category.values()) for category in ['AudioInput', 'AudioMixer', 'VideoInput', 'VideoMixer', 'Output', 'Importer']: for plugin in self.config_tool.get_plugins(category): self.assertIn(plugin.plugin_object.name, plugin_category) self.assertEqual(plugin_category[plugin.plugin_object.name], category) self.assertEqual(category, plugin.plugin_object.CATEGORY) def test_logger_settings(self): """ Tests for config tool's Logger tab Needs to be tested differently since the Config instance isn't affected by changes in this tab. """ # TODO pass def test_close_configtool(self): """ Tests for config tool's close button """ self.assertTrue(self.config_tool.mainWidget.isVisible()) QtTest.QTest.mouseClick(self.config_tool.mainWidget.closePushButton, Qt.Qt.LeftButton) self.assertFalse(self.config_tool.mainWidget.isVisible()) def test_file_menu_quit(self): """ Tests for config tool's File->Quit """ self.assertTrue(self.config_tool.isVisible()) # File->Quit self.config_tool.actionExit.trigger() self.assertFalse(self.config_tool.isVisible()) def test_help_menu_about(self): """ Tests for config tool's Help->About """ self.assertTrue(self.config_tool.isVisible()) # Help->About self.config_tool.actionAbout.trigger() self.assertFalse(self.config_tool.hasFocus()) self.assertTrue(self.config_tool.aboutDialog.isVisible()) # Click "Close" QtTest.QTest.mouseClick(self.config_tool.aboutDialog.closeButton, Qt.Qt.LeftButton) self.assertFalse(self.config_tool.aboutDialog.isVisible())