diff --git a/openlp/core/lib/projector/db.py b/openlp/core/lib/projector/db.py index 527507a64..347e93052 100644 --- a/openlp/core/lib/projector/db.py +++ b/openlp/core/lib/projector/db.py @@ -45,7 +45,7 @@ import logging log = logging.getLogger(__name__) log.debug('projector.lib.db module loaded') -from sqlalchemy import Column, ForeignKey, Integer, MetaData, String +from sqlalchemy import Column, ForeignKey, Integer, MetaData, String, and_ from sqlalchemy.ext.declarative import declarative_base, declared_attr from sqlalchemy.orm import backref, relationship @@ -165,6 +165,15 @@ class Projector(CommonBase, Base): ProjectorSource relates """ + def __repr__(self): + """ + Return basic representation of Source table entry. + """ + return '< Projector(id="%s", ip="%s", port="%s", pin="%s", name="%s", location="%s",' \ + 'notes="%s", pjlink_name="%s", manufacturer="%s", model="%s", other="%s",' \ + 'sources="%s", source_list="%s") >' % (self.id, self.ip, self.port, self.pin, self.name, self.location, + self.notes, self.pjlink_name, self.manufacturer, self.model, + self.other, self.sources, self.source_list) ip = Column(String(100)) port = Column(String(8)) pin = Column(String(20)) @@ -197,6 +206,14 @@ class ProjectorSource(CommonBase, Base): Projector table links here """ + def __repr__(self): + """ + Return basic representation of Source table entry. + """ + return '' % (self.id, + self.code, + self.text, + self.projector_id) code = Column(String(3)) text = Column(String(20)) projector_id = Column(Integer, ForeignKey('projector.id')) @@ -363,29 +380,57 @@ class ProjectorDB(Manager): key: (str) PJLink code for source value: (str) From ProjectorSource, Sources tables or PJLink default code list """ - # Get manufacturer-defined source text - model_list = self.get_all_objects(Model, Model.name == projector.model) - if model_list is None or len(model_list) < 1: - # No entry for model, so see if there's a default entry - default_list = self.get_object_filtered(Manufacturer, Manufacturer.name == projector.manufacturer) - if default_list is None or len(default_list) < 1: - # No entry for manufacturer, so can't check for default text - model_list = {} - else: - model_list = default_list.models['DEFAULT'] - # Get user-defined source text - local_list = self.get_all_objects(ProjectorSource, ProjectorSource.projector_id == projector.dbid) - if local_list is None or len(local_list) < 1: - local_list = {} source_dict = {} - for source in projector.source_available: - if source in local_list: - # User defined source text - source_dict[source] = local_list[source] - elif source in model_list: - # Default manufacturer defined source text - source_dict[source] = model_list[source] + # Get default list first + for key in projector.source_available: + item = self.get_object_filtered(ProjectorSource, + and_(ProjectorSource.code == key, + ProjectorSource.projector_id == projector.dbid)) + if item is None: + source_dict[key] = PJLINK_DEFAULT_CODES[key] else: - # Default PJLink source text - source_dict[source] = PJLINK_DEFAULT_CODES[source] + source_dict[key] = item.text return source_dict + + def get_source_by_id(self, source): + """ + Retrieves the ProjectorSource by ProjectorSource.id + + :param source: ProjectorSource id + :returns: ProjetorSource instance or None + """ + source_entry = self.get_object_filtered(ProjetorSource, ProjectorSource.id == source) + if source_entry is None: + # Not found + log.warn('get_source_by_id() did not find "%s"' % source) + return None + log.debug('get_source_by_id() returning one entry for "%s""' % (source)) + return source_entry + + def get_source_by_code(self, code, projector_id): + """ + Retrieves the ProjectorSource by ProjectorSource.id + + :param source: PJLink ID + :param projector_id: Projector.id + :returns: ProjetorSource instance or None + """ + source_entry = self.get_object_filtered(ProjectorSource, + and_(ProjectorSource.code == code, + ProjectorSource.projector_id == projector_id)) + if source_entry is None: + # Not found + log.warn('get_source_by_id() did not find code="%s" projector_id="%s"' % (code, projector_id)) + return None + log.debug('get_source_by_id() returning one entry for code="%s" projector_id="%s"' % (code, projector_id)) + return source_entry + + def add_source(self, source): + """ + Add a new ProjectorSource record + + :param source: ProjectorSource() instance to add + """ + log.debug('Saving ProjectorSource(projector_id="%s" code="%s" text="%s")' % (source.projector_id, + source.code, source.text)) + return self.save_object(source) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index c0e13efd0..132de0dca 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -105,30 +105,13 @@ class PJLink1(QTcpSocket): self.dbid = None self.location = None self.notes = None - if 'dbid' in kwargs: - self.dbid = kwargs['dbid'] - else: - self.dbid = None - if 'location' in kwargs: - self.location = kwargs['location'] - else: - self.location = None - if 'notes' in kwargs: - self.notes = kwargs['notes'] - else: - self.notes = None - if 'poll_time' in kwargs: - # Convert seconds to milliseconds - self.poll_time = kwargs['poll_time'] * 1000 - else: - # Default 20 seconds - self.poll_time = 20000 - if 'socket_timeout' in kwargs: - # Convert seconds to milliseconds - self.socket_timeout = kwargs['socket_timeout'] * 1000 - else: - # Default is 5 seconds - self.socket_timeout = 5000 + self.dbid = None if 'dbid' not in kwargs else kwargs['dbid'] + self.location = None if 'location' not in kwargs else kwargs['notes'] + self.notes = None if 'notes' not in kwargs else kwargs['notes'] + # Poll time 20 seconds unless called with something else + self.poll_time = 20000 if 'poll_time' not in kwargs else kwargs['poll_time'] * 1000 + # Timeout 5 seconds unless called with something else + self.socket_timeout = 5000 if 'socket_timeout' not in kwargs else kwargs['socket_timeout'] * 1000 # In case we're called from somewhere that only wants information self.no_poll = 'no_poll' in kwargs self.i_am_running = False @@ -305,18 +288,6 @@ class PJLink1(QTcpSocket): log.debug('(%s) error_status: %s: %s' % (self.ip, status_code, status_message if msg is None else msg)) self.changeStatus.emit(self.ip, status, message) - def check_command(self, cmd): - """ - Verifies command is valid based on PJLink class. - - :param cmd: PJLink command to validate. - :returns: bool - True if command is valid PJLink command - False if command is not a valid PJLink command - """ - return self.pjlink_class in PJLINK_VALID_CMD and \ - cmd in PJLINK_VALID_CMD[self.pjlink_class] - @pyqtSlot() def check_login(self, data=None): """ @@ -401,11 +372,13 @@ class PJLink1(QTcpSocket): log.debug('(%s) get_data(): Reading data' % self.ip) if self.state() != self.ConnectedState: log.debug('(%s) get_data(): Not connected - returning' % self.ip) + self.send_busy = False return read = self.readLine(self.maxSize) if read == -1: # No data available log.debug('(%s) get_data(): No data available (-1)' % self.ip) + self.send_busy = False self.projectorReceivedData.emit() return self.socket_timer.stop() @@ -415,16 +388,19 @@ class PJLink1(QTcpSocket): if len(data) < 7: # Not enough data for a packet log.debug('(%s) get_data(): Packet length < 7: "%s"' % (self.ip, data)) + self.send_busy = False self.projectorReceivedData.emit() return log.debug('(%s) get_data(): Checking new data "%s"' % (self.ip, data)) if data.upper().startswith('PJLINK'): # Reconnected from remote host disconnect ? self.check_login(data) + self.send_busy = False self.projectorReceivedData.emit() return elif '=' not in data: log.warn('(%s) get_data(): Invalid packet received' % self.ip) + self.send_busy = False self.projectorReceivedData.emit() return data_split = data.split('=') @@ -434,11 +410,13 @@ class PJLink1(QTcpSocket): log.warn('(%s) get_data(): Invalid packet - expected header + command + data' % self.ip) log.warn('(%s) get_data(): Received data: "%s"' % (self.ip, read)) self.change_status(E_INVALID_DATA) + self.send_busy = False self.projectorReceivedData.emit() return - if not self.check_command(cmd): + if not (self.pjlink_class in PJLINK_VALID_CMD and cmd in PJLINK_VALID_CMD[self.pjlink_class]): log.warn('(%s) get_data(): Invalid packet - unknown command "%s"' % (self.ip, cmd)) + self.send_busy = False self.projectorReceivedData.emit() return return self.process_command(cmd, data) diff --git a/openlp/core/ui/projector/manager.py b/openlp/core/ui/projector/manager.py index 99e5c6229..db69d7eb6 100644 --- a/openlp/core/ui/projector/manager.py +++ b/openlp/core/ui/projector/manager.py @@ -104,7 +104,7 @@ class Ui_ProjectorManager(object): tooltip=translate('OpenLP.ProjectorManager', 'Delete selected projector'), triggers=self.on_delete_projector) # Show source/view when projector connected - self.one_toolbar.add_toolbar_action('source_projector', + self.one_toolbar.add_toolbar_action('source_view_projector', text=translate('OpenLP.ProjectorManager', 'Select Input Source'), icon=':/projector/projector_hdmi.png', tooltip=translate('OpenLP.ProjectorManager', @@ -254,6 +254,11 @@ class Ui_ProjectorManager(object): 'Select &Input'), icon=':/projector/projector_hdmi.png', triggers=self.on_select_input) + self.edit_input_action = create_widget_action(self.menu, + text=translate('OpenLP.ProjectorManager', + 'Edit Input Source'), + icon=':/general/general_edit.png', + triggers=self.on_edit_input) self.blank_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', '&Blank Projector Screen'), @@ -348,6 +353,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, self.status_action.setVisible(visible) if visible: self.select_input_action.setVisible(real_projector.link.power == S_ON) + self.edit_input_action.setVisible(real_projector.link.power == S_ON) self.poweron_action.setVisible(real_projector.link.power == S_STANDBY) self.poweroff_action.setVisible(real_projector.link.power == S_ON) self.blank_action.setVisible(real_projector.link.power == S_ON and @@ -356,6 +362,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, real_projector.link.shutter) else: self.select_input_action.setVisible(False) + self.edit_input_action.setVisible(False) self.poweron_action.setVisible(False) self.poweroff_action.setVisible(False) self.blank_action.setVisible(False) @@ -363,7 +370,10 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, self.menu.projector = real_projector self.menu.exec_(self.projector_list_widget.mapToGlobal(point)) - def on_select_input(self, opt=None): + def on_edit_input(self, opt=None): + self.on_select_input(opt=opt, edit=True) + + def on_select_input(self, opt=None, edit=False): """ Builds menu for 'Select Input' option, then calls the selected projector item to change input source. @@ -374,13 +384,17 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, list_item = self.projector_list_widget.item(self.projector_list_widget.currentRow()) projector = list_item.data(QtCore.Qt.UserRole) # QTabwidget for source select - if self.source_select_dialog_type == DialogSourceStyle.Tabbed: - source_select_form = SourceSelectTabs(parent=self, - projectordb=self.projectordb) - else: - source_select_form = SourceSelectSingle(parent=self, - projectordb=self.projectordb) - source = source_select_form.exec_(projector.link) + source = 100 + while source > 99: + if self.source_select_dialog_type == DialogSourceStyle.Tabbed: + source_select_form = SourceSelectTabs(parent=self, + projectordb=self.projectordb, + edit=edit) + else: + source_select_form = SourceSelectSingle(parent=self, + projectordb=self.projectordb, + edit=edit) + source = source_select_form.exec_(projector.link) log.debug('(%s) source_select_form() returned %s' % (projector.link.ip, source)) if source is not None and source > 0: projector.link.set_input_source(str(source)) @@ -682,29 +696,14 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, socket_timeout=self.socket_timeout ) - def add_projector(self, opt1, opt2=None): + def add_projector(self, projector, start=False): """ Builds manager list item, projector thread, and timer for projector instance. - If called by add projector wizard: - opt1 = wizard instance - opt2 = item - Otherwise: - opt1 = item - opt2 = None - We are not concerned with the wizard instance, - just the projector item - - :param opt1: See above - :param opt2: See above + :param projector: Projector instance to add + :param start: Start projector if True """ - if opt1 is None: - return - if opt2 is None: - projector = opt1 - else: - projector = opt2 item = ProjectorItem(link=self._add_projector(projector)) item.db_item = projector icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[S_NOT_CONNECTED])) @@ -714,6 +713,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, self.projector_list_widget ) widget.setData(QtCore.Qt.UserRole, item) + item.link.db_item = item.db_item item.widget = widget thread = QThread(parent=self) thread.my_parent = self @@ -730,8 +730,9 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, timer.setInterval(self.poll_time) timer.timeout.connect(item.link.poll_loop) item.timer = timer + # Timeout in case of brain-dead projectors or cable disconnected socket_timer = QtCore.QTimer(self) - socket_timer.setInterval(5000) # % second timer in case of brain-dead projectors + socket_timer.setInterval(11000) socket_timer.timeout.connect(item.link.socket_abort) item.socket_timer = socket_timer thread.start() @@ -740,10 +741,10 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, item.link.socket_timer = socket_timer item.link.widget = item.widget self.projector_list.append(item) - if self.autostart: + if start: item.link.connect_to_host() - for i in self.projector_list: - log.debug('New projector list - item: (%s) %s' % (i.link.ip, i.link.name)) + for item in self.projector_list: + log.debug('New projector list - item: (%s) %s' % (item.link.ip, item.link.name)) @pyqtSlot(str) def add_projector_from_wizard(self, ip, opts=None): @@ -753,19 +754,18 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param ip: IP address of new record item to find :param opts: Needed by PyQt4 """ - log.debug('load_projector(ip=%s)' % ip) + log.debug('add_projector_from_wizard(ip=%s)' % ip) item = self.projectordb.get_projector_by_ip(ip) self.add_projector(item) @pyqtSlot(object) - def edit_projector_from_wizard(self, projector, opts=None): + def edit_projector_from_wizard(self, projector): """ Update projector from the wizard edit page :param projector: Projector() instance of projector with updated information - :param opts: Needed by PyQt4 """ - + log.debug('edit_projector_from_wizard(ip=%s)' % projector.ip) self.old_projector.link.name = projector.name self.old_projector.link.ip = projector.ip self.old_projector.link.pin = None if projector.pin == '' else projector.pin @@ -778,10 +778,10 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, """' Load projectors - only call when initializing """ - log.debug('load_projectors()') + log.debug('_load_projectors()') self.projector_list_widget.clear() for item in self.projectordb.get_projector_all(): - self.add_projector(item) + self.add_projector(projector=item, start=self.autostart) def get_projector_list(self): """ @@ -835,8 +835,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, item = self.one_toolbar.findChild(QtGui.QAction, name) if item == 0: log.debug('No item found with name "%s"' % name) - else: - log.debug('item "%s" updating enabled=%s hidden=%s' % (name, enabled, hidden)) + return item.setVisible(False if hidden else True) item.setEnabled(True if enabled else False) @@ -851,7 +850,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, self.get_toolbar_item('edit_projector') self.get_toolbar_item('delete_projector') self.get_toolbar_item('view_projector', hidden=True) - self.get_toolbar_item('source_projector', hidden=True) + self.get_toolbar_item('source_view_projector', hidden=True) self.get_toolbar_item('connect_projector') self.get_toolbar_item('disconnect_projector') self.get_toolbar_item('poweron_projector') @@ -876,13 +875,13 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, self.get_toolbar_item('show_projector_multiple', hidden=True) if connected: self.get_toolbar_item('view_projector', enabled=True) - self.get_toolbar_item('source_projector', + self.get_toolbar_item('source_view_projector', enabled=connected and power and projector.link.source_available is not None) self.get_toolbar_item('edit_projector', hidden=True) self.get_toolbar_item('delete_projector', hidden=True) else: self.get_toolbar_item('view_projector', hidden=True) - self.get_toolbar_item('source_projector', hidden=True) + self.get_toolbar_item('source_view_projector', hidden=True) self.get_toolbar_item('edit_projector', enabled=True) self.get_toolbar_item('delete_projector', enabled=True) self.get_toolbar_item('connect_projector', enabled=not connected) @@ -899,7 +898,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, self.get_toolbar_item('edit_projector', enabled=False) self.get_toolbar_item('delete_projector', enabled=False) self.get_toolbar_item('view_projector', hidden=True) - self.get_toolbar_item('source_projector', hidden=True) + self.get_toolbar_item('source_view_projector', hidden=True) self.get_toolbar_item('connect_projector', hidden=True) self.get_toolbar_item('disconnect_projector', hidden=True) self.get_toolbar_item('poweron_projector', hidden=True) diff --git a/openlp/core/ui/projector/sourceselectform.py b/openlp/core/ui/projector/sourceselectform.py index 8d04c95c1..a5040ba5a 100644 --- a/openlp/core/ui/projector/sourceselectform.py +++ b/openlp/core/ui/projector/sourceselectform.py @@ -37,12 +37,13 @@ log.debug('editform loaded') from PyQt4 import QtCore, QtGui from PyQt4.QtCore import pyqtSlot, QSize -from PyQt4.QtGui import QDialog, QButtonGroup, QDialogButtonBox, QRadioButton, \ +from PyQt4.QtGui import QDialog, QButtonGroup, QDialogButtonBox, QFormLayout, QLineEdit, QRadioButton, \ QStyle, QStylePainter, QStyleOptionTab, QTabBar, QTabWidget, QVBoxLayout, QWidget from openlp.core.common import translate, is_macosx from openlp.core.lib import build_icon -from openlp.core.lib.projector.constants import PJLINK_DEFAULT_SOURCES +from openlp.core.lib.projector.db import ProjectorSource +from openlp.core.lib.projector.constants import PJLINK_DEFAULT_SOURCES, PJLINK_DEFAULT_CODES def source_group(inputs, source_text): @@ -53,7 +54,7 @@ def source_group(inputs, source_text): source_text = dict{"key1": "key1-text", "key2": "key2-text", ...} - ex: + return: dict{ key1[0]: { "key11": "key11-text", "key12": "key12-text", "key13": "key13-text", @@ -82,7 +83,7 @@ def source_group(inputs, source_text): return keydict -def Build_Tab(group, source_key, default): +def Build_Tab(group, source_key, default, projector, projectordb, edit=False): """ Create the radio button page for a tab. Dictionary will be a 1-key entry where key=tab to setup, val=list of inputs. @@ -101,25 +102,45 @@ def Build_Tab(group, source_key, default): :param group: Button group widget to add buttons to :param source_key: Dictionary of sources for radio buttons :param default: Default radio button to check + :param projector: Projector instance + :param projectordb: ProjectorDB instance for session + :param edit: If we're editing the source text """ buttonchecked = False widget = QWidget() - layout = QVBoxLayout() + layout = QFormLayout() if edit else QVBoxLayout() layout.setSpacing(10) widget.setLayout(layout) tempkey = list(source_key.keys())[0] # Should only be 1 key sourcelist = list(source_key[tempkey]) sourcelist.sort() button_count = len(sourcelist) - for key in sourcelist: - itemwidget = QRadioButton(source_key[tempkey][key]) - itemwidget.setAutoExclusive(True) - if default == key: - itemwidget.setChecked(True) - buttonchecked = itemwidget.isChecked() or buttonchecked - group.addButton(itemwidget, int(key)) - layout.addWidget(itemwidget) - layout.addStretch() + if edit: + for key in sourcelist: + item = QLineEdit() + item.setObjectName('source_key_%s' % key) + source_item = projectordb.get_source_by_code(code=key, projector_id=projector.db_item.id) + if source_item is None: + item.setText(PJLINK_DEFAULT_CODES[key]) + else: + item.setText(source_item.text) + layout.addRow(PJLINK_DEFAULT_CODES[key], item) + group.append(item) + else: + for key in sourcelist: + source_item = projectordb.get_source_by_code(code=key, projector_id=projector.db_item.id) + if source_item is None: + text = source_key[tempkey][key] + else: + text = source_item.text + itemwidget = QRadioButton(text) + itemwidget.setAutoExclusive(True) + if default == key: + itemwidget.setChecked(True) + buttonchecked = itemwidget.isChecked() or buttonchecked + group.addButton(itemwidget, int(key)) + layout.addWidget(itemwidget) + layout.addStretch() return widget, button_count, buttonchecked @@ -188,16 +209,21 @@ class SourceSelectTabs(QDialog): Class for handling selecting the source for the projector to use. Uses tabbed interface. """ - def __init__(self, parent, projectordb): + def __init__(self, parent, projectordb, edit=False): """ Build the source select dialog using tabbed interface. :param projectordb: ProjectorDB session to use """ log.debug('Initializing SourceSelectTabs()') - self.projectordb = projectordb super(SourceSelectTabs, self).__init__(parent) - self.setWindowTitle(translate('OpenLP.SourceSelectForm', 'Select Projector Source')) + self.projectordb = projectordb + self.edit = edit + if self.edit: + title = translate('OpenLP.SourceSelectForm', 'Select Projector Source') + else: + title = translate('OpenLP.SourceSelectForm', 'Edit Projector Source Text') + self.setWindowTitle(title) self.setObjectName('source_select_tabs') self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png')) self.setModal(True) @@ -226,48 +252,106 @@ class SourceSelectTabs(QDialog): self.source_text = self.projectordb.get_source_list(projector=projector) self.source_group = source_group(projector.source_available, self.source_text) # self.source_group = {'4': {'41': 'Storage 1'}, '5': {"51": 'Network 1'}} - self.button_group = QButtonGroup() + self.button_group = [] if self.edit else QButtonGroup() keys = list(self.source_group.keys()) keys.sort() - for key in keys: - (tab, button_count, buttonchecked) = Build_Tab(group=self.button_group, - source_key={key: self.source_group[key]}, - default=self.projector.source) - thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key]) - if buttonchecked: - self.tabwidget.setCurrentIndex(thistab) - self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok | + if self.edit: + for key in keys: + (tab, button_count, buttonchecked) = Build_Tab(group=self.button_group, + source_key={key: self.source_group[key]}, + default=self.projector.source, + projector=self.projector, + projectordb=self.projectordb, + edit=self.edit) + thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key]) + if buttonchecked: + self.tabwidget.setCurrentIndex(thistab) + else: + for key in keys: + (tab, button_count, buttonchecked) = Build_Tab(group=self.button_group, + source_key={key: self.source_group[key]}, + default=self.projector.source, + projector=self.projector, + projectordb=self.projectordb, + edit=self.edit) + thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key]) + if buttonchecked: + self.tabwidget.setCurrentIndex(thistab) + self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset | + QtGui.QDialogButtonBox.Discard | + QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) - self.button_box.accepted.connect(self.accept_me) - self.button_box.rejected.connect(self.reject_me) + self.button_box.clicked.connect(self.button_clicked) self.layout.addWidget(self.button_box) selected = super(SourceSelectTabs, self).exec_() return selected - @pyqtSlot() + @pyqtSlot(object) + def button_clicked(self, button): + """ + Checks which button was clicked + + :param button: Button that was clicked + :returns: Ok: calls accept_me() + Reset: 100 + Cancel: self.done(0) + """ + if self.button_box.standardButton(button) == self.button_box.Cancel: + self.done(0) + elif self.button_box.standardButton(button) == self.button_box.Reset: + self.done(100) + elif self.button_box.standardButton(button) == self.button_box.Discard: + self.delete_sources() + elif self.button_box.standardButton(button) == self.button_box.Ok: + return self.accept_me() + else: + return 100 + + def delete_sources(self): + msg = QtGui.QMessageBox() + msg.setText('Delete entries for this projector') + msg.setInformativeText('Are you sure you want to delete ALL user-defined ' + 'source input text for this projector?') + msg.setStandardButtons(msg.Cancel | msg.Ok) + msg.setDefaultButton(msg.Cancel) + ans = msg.exec_() + if ans == msg.Cancel: + return + self.projectordb.delete_all_objects(ProjectorSource, ProjectorSource.projector_id == self.projector.db_item.id) + self.done(100) + def accept_me(self): """ Slot to accept 'OK' button """ - selected = self.button_group.checkedId() - log.debug('SourceSelectTabs().accepted() Setting source to %s' % selected) + projector = self.projector.db_item + if self.edit: + for key in self.button_group: + code = key.objectName().split("_")[-1] + text = key.text().strip() + if key.text().strip().lower() == PJLINK_DEFAULT_CODES[code].strip().lower(): + continue + item = self.projectordb.get_source_by_code(code=code, projector_id=projector.id) + if item is None: + log.debug("(%s) Adding new source text %s: %s" % (projector.ip, code, text)) + item = ProjectorSource(projector_id=projector.id, code=code, text=text) + else: + item.text = text + log.debug('(%s) Updating source code %s with text="%s"' % (projector.ip, item.code, item.text)) + self.projectordb.add_source(item) + selected = 0 + else: + selected = self.button_group.checkedId() + log.debug('SourceSelectTabs().accepted() Setting source to %s' % selected) self.done(selected) - @pyqtSlot() - def reject_me(self): - """ - Slot to accept 'Cancel' button - """ - log.debug('SourceSelectTabs() - Rejected') - self.done(0) - class SourceSelectSingle(QDialog): """ Class for handling selecting the source for the projector to use. Uses single dialog interface. """ - def __init__(self, parent, projectordb): + def __init__(self, parent, projectordb, edit=False): """ Build the source select dialog. @@ -280,54 +364,113 @@ class SourceSelectSingle(QDialog): self.setObjectName('source_select_single') self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png')) self.setModal(True) - self.layout = QVBoxLayout() - self.layout.setObjectName('source_select_tabs_layout') - self.layout.setSpacing(10) - self.setLayout(self.layout) - self.setMinimumWidth(350) - self.button_group = QButtonGroup() - self.button_group.setObjectName('source_select_single_buttongroup') + self.edit = edit - def exec_(self, projector): + def exec_(self, projector, edit=False): """ Override initial method so we can build the tabs. :param projector: Projector instance to build source list from """ self.projector = projector + self.layout = QFormLayout() if self.edit else QVBoxLayout() + self.layout.setObjectName('source_select_tabs_layout') + self.layout.setSpacing(10) + self.setLayout(self.layout) + self.setMinimumWidth(350) + self.button_group = [] if self.edit else QButtonGroup() self.source_text = self.projectordb.get_source_list(projector=projector) keys = list(self.source_text.keys()) keys.sort() key_count = len(keys) button_list = [] - for key in keys: - button = QtGui.QRadioButton(self.source_text[key]) - button.setChecked(True if key == projector.source else False) - self.layout.addWidget(button) - self.button_group.addButton(button, int(key)) - button_list.append(key) - self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok | + if self.edit: + for key in keys: + item = QLineEdit() + item.setObjectName('source_key_%s' % key) + source_item = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id) + if source_item is None: + item.setText(PJLINK_DEFAULT_CODES[key]) + else: + item.old_text = item.text() + item.setText(source_item.text) + self.layout.addRow(PJLINK_DEFAULT_CODES[key], item) + self.button_group.append(item) + else: + for key in keys: + source_text = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id) + text = self.source_text[key] if source_text is None else source_text.text + button = QtGui.QRadioButton(text) + button.setChecked(True if key == projector.source else False) + self.layout.addWidget(button) + self.button_group.addButton(button, int(key)) + button_list.append(key) + self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset | + QtGui.QDialogButtonBox.Discard | + QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) - self.button_box.accepted.connect(self.accept_me) - self.button_box.rejected.connect(self.reject_me) + self.button_box.clicked.connect(self.button_clicked) self.layout.addWidget(self.button_box) self.setMinimumHeight(key_count*25) selected = super(SourceSelectSingle, self).exec_() return selected + @pyqtSlot(object) + def button_clicked(self, button): + """ + Checks which button was clicked + + :param button: Button that was clicked + :returns: Ok: calls accept_me() + Reset: 100 + Cancel: self.done(0) + """ + if self.button_box.standardButton(button) == self.button_box.Cancel: + self.done(0) + elif self.button_box.standardButton(button) == self.button_box.Reset: + self.done(100) + elif self.button_box.standardButton(button) == self.button_box.Discard: + self.delete_sources() + elif self.button_box.standardButton(button) == self.button_box.Ok: + return self.accept_me() + else: + return 100 + + def delete_sources(self): + msg = QtGui.QMessageBox() + msg.setText('Delete entries for this projector') + msg.setInformativeText('Are you sure you want to delete ALL user-defined ' + 'source input text for this projector?') + msg.setStandardButtons(msg.Cancel | msg.Ok) + msg.setDefaultButton(msg.Cancel) + ans = msg.exec_() + if ans == msg.Cancel: + return + self.projectordb.delete_all_objects(ProjectorSource, ProjectorSource.projector_id == self.projector.db_item.id) + self.done(100) + @pyqtSlot() def accept_me(self): """ Slot to accept 'OK' button """ - selected = self.button_group.checkedId() - log.debug('SourceSelectDialog().accepted() Setting source to %s' % selected) + projector = self.projector.db_item + if self.edit: + for key in self.button_group: + code = key.objectName().split("_")[-1] + text = key.text().strip() + if key.text().strip().lower() == PJLINK_DEFAULT_CODES[code].strip().lower(): + continue + item = self.projectordb.get_source_by_code(code=code, projector_id=projector.id) + if item is None: + log.debug("(%s) Adding new source text %s: %s" % (projector.ip, code, text)) + item = ProjectorSource(projector_id=projector.id, code=code, text=text) + else: + item.text = text + log.debug('(%s) Updating source code %s with text="%s"' % (projector.ip, item.code, item.text)) + self.projectordb.add_source(item) + selected = 0 + else: + selected = self.button_group.checkedId() + log.debug('SourceSelectDialog().accepted() Setting source to %s' % selected) self.done(selected) - - @pyqtSlot() - def reject_me(self): - """ - Slot to accept 'Cancel' button - """ - log.debug('SourceSelectDialog() - Rejected') - self.done(0)