Add input source edit text option

This commit is contained in:
Ken Roberts 2014-10-22 19:21:26 -07:00
parent d08594ab55
commit 0264d57b61
4 changed files with 336 additions and 171 deletions

View File

@ -45,7 +45,7 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
log.debug('projector.lib.db module loaded') 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.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import backref, relationship from sqlalchemy.orm import backref, relationship
@ -165,6 +165,15 @@ class Projector(CommonBase, Base):
ProjectorSource relates 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)) ip = Column(String(100))
port = Column(String(8)) port = Column(String(8))
pin = Column(String(20)) pin = Column(String(20))
@ -197,6 +206,14 @@ class ProjectorSource(CommonBase, Base):
Projector table links here Projector table links here
""" """
def __repr__(self):
"""
Return basic representation of Source table entry.
"""
return '<ProjectorSource(id="%s", code="%s", text="%s", projector_id="%s")>' % (self.id,
self.code,
self.text,
self.projector_id)
code = Column(String(3)) code = Column(String(3))
text = Column(String(20)) text = Column(String(20))
projector_id = Column(Integer, ForeignKey('projector.id')) projector_id = Column(Integer, ForeignKey('projector.id'))
@ -363,29 +380,57 @@ class ProjectorDB(Manager):
key: (str) PJLink code for source key: (str) PJLink code for source
value: (str) From ProjectorSource, Sources tables or PJLink default code list 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 = {} source_dict = {}
for source in projector.source_available: # Get default list first
if source in local_list: for key in projector.source_available:
# User defined source text item = self.get_object_filtered(ProjectorSource,
source_dict[source] = local_list[source] and_(ProjectorSource.code == key,
elif source in model_list: ProjectorSource.projector_id == projector.dbid))
# Default manufacturer defined source text if item is None:
source_dict[source] = model_list[source] source_dict[key] = PJLINK_DEFAULT_CODES[key]
else: else:
# Default PJLink source text source_dict[key] = item.text
source_dict[source] = PJLINK_DEFAULT_CODES[source]
return source_dict 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)

View File

@ -105,30 +105,13 @@ class PJLink1(QTcpSocket):
self.dbid = None self.dbid = None
self.location = None self.location = None
self.notes = None self.notes = None
if 'dbid' in kwargs: self.dbid = None if 'dbid' not in kwargs else kwargs['dbid']
self.dbid = kwargs['dbid'] self.location = None if 'location' not in kwargs else kwargs['notes']
else: self.notes = None if 'notes' not in kwargs else kwargs['notes']
self.dbid = None # Poll time 20 seconds unless called with something else
if 'location' in kwargs: self.poll_time = 20000 if 'poll_time' not in kwargs else kwargs['poll_time'] * 1000
self.location = kwargs['location'] # Timeout 5 seconds unless called with something else
else: self.socket_timeout = 5000 if 'socket_timeout' not in kwargs else kwargs['socket_timeout'] * 1000
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
# In case we're called from somewhere that only wants information # In case we're called from somewhere that only wants information
self.no_poll = 'no_poll' in kwargs self.no_poll = 'no_poll' in kwargs
self.i_am_running = False 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)) 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) 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() @pyqtSlot()
def check_login(self, data=None): def check_login(self, data=None):
""" """
@ -401,11 +372,13 @@ class PJLink1(QTcpSocket):
log.debug('(%s) get_data(): Reading data' % self.ip) log.debug('(%s) get_data(): Reading data' % self.ip)
if self.state() != self.ConnectedState: if self.state() != self.ConnectedState:
log.debug('(%s) get_data(): Not connected - returning' % self.ip) log.debug('(%s) get_data(): Not connected - returning' % self.ip)
self.send_busy = False
return return
read = self.readLine(self.maxSize) read = self.readLine(self.maxSize)
if read == -1: if read == -1:
# No data available # No data available
log.debug('(%s) get_data(): No data available (-1)' % self.ip) log.debug('(%s) get_data(): No data available (-1)' % self.ip)
self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
self.socket_timer.stop() self.socket_timer.stop()
@ -415,16 +388,19 @@ class PJLink1(QTcpSocket):
if len(data) < 7: if len(data) < 7:
# Not enough data for a packet # Not enough data for a packet
log.debug('(%s) get_data(): Packet length < 7: "%s"' % (self.ip, data)) log.debug('(%s) get_data(): Packet length < 7: "%s"' % (self.ip, data))
self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
log.debug('(%s) get_data(): Checking new data "%s"' % (self.ip, data)) log.debug('(%s) get_data(): Checking new data "%s"' % (self.ip, data))
if data.upper().startswith('PJLINK'): if data.upper().startswith('PJLINK'):
# Reconnected from remote host disconnect ? # Reconnected from remote host disconnect ?
self.check_login(data) self.check_login(data)
self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
elif '=' not in data: elif '=' not in data:
log.warn('(%s) get_data(): Invalid packet received' % self.ip) log.warn('(%s) get_data(): Invalid packet received' % self.ip)
self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
data_split = data.split('=') 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(): Invalid packet - expected header + command + data' % self.ip)
log.warn('(%s) get_data(): Received data: "%s"' % (self.ip, read)) log.warn('(%s) get_data(): Received data: "%s"' % (self.ip, read))
self.change_status(E_INVALID_DATA) self.change_status(E_INVALID_DATA)
self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return 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)) log.warn('(%s) get_data(): Invalid packet - unknown command "%s"' % (self.ip, cmd))
self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
return self.process_command(cmd, data) return self.process_command(cmd, data)

View File

@ -104,7 +104,7 @@ class Ui_ProjectorManager(object):
tooltip=translate('OpenLP.ProjectorManager', 'Delete selected projector'), tooltip=translate('OpenLP.ProjectorManager', 'Delete selected projector'),
triggers=self.on_delete_projector) triggers=self.on_delete_projector)
# Show source/view when projector connected # 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'), text=translate('OpenLP.ProjectorManager', 'Select Input Source'),
icon=':/projector/projector_hdmi.png', icon=':/projector/projector_hdmi.png',
tooltip=translate('OpenLP.ProjectorManager', tooltip=translate('OpenLP.ProjectorManager',
@ -254,6 +254,11 @@ class Ui_ProjectorManager(object):
'Select &Input'), 'Select &Input'),
icon=':/projector/projector_hdmi.png', icon=':/projector/projector_hdmi.png',
triggers=self.on_select_input) 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, self.blank_action = create_widget_action(self.menu,
text=translate('OpenLP.ProjectorManager', text=translate('OpenLP.ProjectorManager',
'&Blank Projector Screen'), '&Blank Projector Screen'),
@ -348,6 +353,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager,
self.status_action.setVisible(visible) self.status_action.setVisible(visible)
if visible: if visible:
self.select_input_action.setVisible(real_projector.link.power == S_ON) 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.poweron_action.setVisible(real_projector.link.power == S_STANDBY)
self.poweroff_action.setVisible(real_projector.link.power == S_ON) self.poweroff_action.setVisible(real_projector.link.power == S_ON)
self.blank_action.setVisible(real_projector.link.power == S_ON and 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) real_projector.link.shutter)
else: else:
self.select_input_action.setVisible(False) self.select_input_action.setVisible(False)
self.edit_input_action.setVisible(False)
self.poweron_action.setVisible(False) self.poweron_action.setVisible(False)
self.poweroff_action.setVisible(False) self.poweroff_action.setVisible(False)
self.blank_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.projector = real_projector
self.menu.exec_(self.projector_list_widget.mapToGlobal(point)) 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 Builds menu for 'Select Input' option, then calls the selected projector
item to change input source. 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()) list_item = self.projector_list_widget.item(self.projector_list_widget.currentRow())
projector = list_item.data(QtCore.Qt.UserRole) projector = list_item.data(QtCore.Qt.UserRole)
# QTabwidget for source select # QTabwidget for source select
if self.source_select_dialog_type == DialogSourceStyle.Tabbed: source = 100
source_select_form = SourceSelectTabs(parent=self, while source > 99:
projectordb=self.projectordb) if self.source_select_dialog_type == DialogSourceStyle.Tabbed:
else: source_select_form = SourceSelectTabs(parent=self,
source_select_form = SourceSelectSingle(parent=self, projectordb=self.projectordb,
projectordb=self.projectordb) edit=edit)
source = source_select_form.exec_(projector.link) 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)) log.debug('(%s) source_select_form() returned %s' % (projector.link.ip, source))
if source is not None and source > 0: if source is not None and source > 0:
projector.link.set_input_source(str(source)) projector.link.set_input_source(str(source))
@ -682,29 +696,14 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager,
socket_timeout=self.socket_timeout 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. 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, :param projector: Projector instance to add
just the projector item :param start: Start projector if True
:param opt1: See above
:param opt2: See above
""" """
if opt1 is None:
return
if opt2 is None:
projector = opt1
else:
projector = opt2
item = ProjectorItem(link=self._add_projector(projector)) item = ProjectorItem(link=self._add_projector(projector))
item.db_item = projector item.db_item = projector
icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[S_NOT_CONNECTED])) 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 self.projector_list_widget
) )
widget.setData(QtCore.Qt.UserRole, item) widget.setData(QtCore.Qt.UserRole, item)
item.link.db_item = item.db_item
item.widget = widget item.widget = widget
thread = QThread(parent=self) thread = QThread(parent=self)
thread.my_parent = self thread.my_parent = self
@ -730,8 +730,9 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager,
timer.setInterval(self.poll_time) timer.setInterval(self.poll_time)
timer.timeout.connect(item.link.poll_loop) timer.timeout.connect(item.link.poll_loop)
item.timer = timer item.timer = timer
# Timeout in case of brain-dead projectors or cable disconnected
socket_timer = QtCore.QTimer(self) 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) socket_timer.timeout.connect(item.link.socket_abort)
item.socket_timer = socket_timer item.socket_timer = socket_timer
thread.start() thread.start()
@ -740,10 +741,10 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager,
item.link.socket_timer = socket_timer item.link.socket_timer = socket_timer
item.link.widget = item.widget item.link.widget = item.widget
self.projector_list.append(item) self.projector_list.append(item)
if self.autostart: if start:
item.link.connect_to_host() item.link.connect_to_host()
for i in self.projector_list: for item in self.projector_list:
log.debug('New projector list - item: (%s) %s' % (i.link.ip, i.link.name)) log.debug('New projector list - item: (%s) %s' % (item.link.ip, item.link.name))
@pyqtSlot(str) @pyqtSlot(str)
def add_projector_from_wizard(self, ip, opts=None): 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 ip: IP address of new record item to find
:param opts: Needed by PyQt4 :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) item = self.projectordb.get_projector_by_ip(ip)
self.add_projector(item) self.add_projector(item)
@pyqtSlot(object) @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 Update projector from the wizard edit page
:param projector: Projector() instance of projector with updated information :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.name = projector.name
self.old_projector.link.ip = projector.ip self.old_projector.link.ip = projector.ip
self.old_projector.link.pin = None if projector.pin == '' else projector.pin 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 Load projectors - only call when initializing
""" """
log.debug('load_projectors()') log.debug('_load_projectors()')
self.projector_list_widget.clear() self.projector_list_widget.clear()
for item in self.projectordb.get_projector_all(): 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): def get_projector_list(self):
""" """
@ -835,8 +835,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager,
item = self.one_toolbar.findChild(QtGui.QAction, name) item = self.one_toolbar.findChild(QtGui.QAction, name)
if item == 0: if item == 0:
log.debug('No item found with name "%s"' % name) log.debug('No item found with name "%s"' % name)
else: return
log.debug('item "%s" updating enabled=%s hidden=%s' % (name, enabled, hidden))
item.setVisible(False if hidden else True) item.setVisible(False if hidden else True)
item.setEnabled(True if enabled else False) 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('edit_projector')
self.get_toolbar_item('delete_projector') self.get_toolbar_item('delete_projector')
self.get_toolbar_item('view_projector', hidden=True) 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('connect_projector')
self.get_toolbar_item('disconnect_projector') self.get_toolbar_item('disconnect_projector')
self.get_toolbar_item('poweron_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) self.get_toolbar_item('show_projector_multiple', hidden=True)
if connected: if connected:
self.get_toolbar_item('view_projector', enabled=True) 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) enabled=connected and power and projector.link.source_available is not None)
self.get_toolbar_item('edit_projector', hidden=True) self.get_toolbar_item('edit_projector', hidden=True)
self.get_toolbar_item('delete_projector', hidden=True) self.get_toolbar_item('delete_projector', hidden=True)
else: else:
self.get_toolbar_item('view_projector', hidden=True) 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('edit_projector', enabled=True)
self.get_toolbar_item('delete_projector', enabled=True) self.get_toolbar_item('delete_projector', enabled=True)
self.get_toolbar_item('connect_projector', enabled=not connected) 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('edit_projector', enabled=False)
self.get_toolbar_item('delete_projector', enabled=False) self.get_toolbar_item('delete_projector', enabled=False)
self.get_toolbar_item('view_projector', hidden=True) 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('connect_projector', hidden=True)
self.get_toolbar_item('disconnect_projector', hidden=True) self.get_toolbar_item('disconnect_projector', hidden=True)
self.get_toolbar_item('poweron_projector', hidden=True) self.get_toolbar_item('poweron_projector', hidden=True)

View File

@ -37,12 +37,13 @@ log.debug('editform loaded')
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import pyqtSlot, QSize 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 QStyle, QStylePainter, QStyleOptionTab, QTabBar, QTabWidget, QVBoxLayout, QWidget
from openlp.core.common import translate, is_macosx from openlp.core.common import translate, is_macosx
from openlp.core.lib import build_icon 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): def source_group(inputs, source_text):
@ -53,7 +54,7 @@ def source_group(inputs, source_text):
source_text = dict{"key1": "key1-text", source_text = dict{"key1": "key1-text",
"key2": "key2-text", "key2": "key2-text",
...} ...}
ex: return:
dict{ key1[0]: { "key11": "key11-text", dict{ key1[0]: { "key11": "key11-text",
"key12": "key12-text", "key12": "key12-text",
"key13": "key13-text", "key13": "key13-text",
@ -82,7 +83,7 @@ def source_group(inputs, source_text):
return keydict 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. Create the radio button page for a tab.
Dictionary will be a 1-key entry where key=tab to setup, val=list of inputs. 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 group: Button group widget to add buttons to
:param source_key: Dictionary of sources for radio buttons :param source_key: Dictionary of sources for radio buttons
:param default: Default radio button to check :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 buttonchecked = False
widget = QWidget() widget = QWidget()
layout = QVBoxLayout() layout = QFormLayout() if edit else QVBoxLayout()
layout.setSpacing(10) layout.setSpacing(10)
widget.setLayout(layout) widget.setLayout(layout)
tempkey = list(source_key.keys())[0] # Should only be 1 key tempkey = list(source_key.keys())[0] # Should only be 1 key
sourcelist = list(source_key[tempkey]) sourcelist = list(source_key[tempkey])
sourcelist.sort() sourcelist.sort()
button_count = len(sourcelist) button_count = len(sourcelist)
for key in sourcelist: if edit:
itemwidget = QRadioButton(source_key[tempkey][key]) for key in sourcelist:
itemwidget.setAutoExclusive(True) item = QLineEdit()
if default == key: item.setObjectName('source_key_%s' % key)
itemwidget.setChecked(True) source_item = projectordb.get_source_by_code(code=key, projector_id=projector.db_item.id)
buttonchecked = itemwidget.isChecked() or buttonchecked if source_item is None:
group.addButton(itemwidget, int(key)) item.setText(PJLINK_DEFAULT_CODES[key])
layout.addWidget(itemwidget) else:
layout.addStretch() 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 return widget, button_count, buttonchecked
@ -188,16 +209,21 @@ class SourceSelectTabs(QDialog):
Class for handling selecting the source for the projector to use. Class for handling selecting the source for the projector to use.
Uses tabbed interface. Uses tabbed interface.
""" """
def __init__(self, parent, projectordb): def __init__(self, parent, projectordb, edit=False):
""" """
Build the source select dialog using tabbed interface. Build the source select dialog using tabbed interface.
:param projectordb: ProjectorDB session to use :param projectordb: ProjectorDB session to use
""" """
log.debug('Initializing SourceSelectTabs()') log.debug('Initializing SourceSelectTabs()')
self.projectordb = projectordb
super(SourceSelectTabs, self).__init__(parent) 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.setObjectName('source_select_tabs')
self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png')) self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
self.setModal(True) self.setModal(True)
@ -226,48 +252,106 @@ class SourceSelectTabs(QDialog):
self.source_text = self.projectordb.get_source_list(projector=projector) self.source_text = self.projectordb.get_source_list(projector=projector)
self.source_group = source_group(projector.source_available, self.source_text) self.source_group = source_group(projector.source_available, self.source_text)
# self.source_group = {'4': {'41': 'Storage 1'}, '5': {"51": 'Network 1'}} # 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 = list(self.source_group.keys())
keys.sort() keys.sort()
for key in keys: if self.edit:
(tab, button_count, buttonchecked) = Build_Tab(group=self.button_group, for key in keys:
source_key={key: self.source_group[key]}, (tab, button_count, buttonchecked) = Build_Tab(group=self.button_group,
default=self.projector.source) source_key={key: self.source_group[key]},
thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key]) default=self.projector.source,
if buttonchecked: projector=self.projector,
self.tabwidget.setCurrentIndex(thistab) projectordb=self.projectordb,
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok | 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) QtGui.QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept_me) self.button_box.clicked.connect(self.button_clicked)
self.button_box.rejected.connect(self.reject_me)
self.layout.addWidget(self.button_box) self.layout.addWidget(self.button_box)
selected = super(SourceSelectTabs, self).exec_() selected = super(SourceSelectTabs, self).exec_()
return selected 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): def accept_me(self):
""" """
Slot to accept 'OK' button Slot to accept 'OK' button
""" """
selected = self.button_group.checkedId() projector = self.projector.db_item
log.debug('SourceSelectTabs().accepted() Setting source to %s' % selected) 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) self.done(selected)
@pyqtSlot()
def reject_me(self):
"""
Slot to accept 'Cancel' button
"""
log.debug('SourceSelectTabs() - Rejected')
self.done(0)
class SourceSelectSingle(QDialog): class SourceSelectSingle(QDialog):
""" """
Class for handling selecting the source for the projector to use. Class for handling selecting the source for the projector to use.
Uses single dialog interface. Uses single dialog interface.
""" """
def __init__(self, parent, projectordb): def __init__(self, parent, projectordb, edit=False):
""" """
Build the source select dialog. Build the source select dialog.
@ -280,54 +364,113 @@ class SourceSelectSingle(QDialog):
self.setObjectName('source_select_single') self.setObjectName('source_select_single')
self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png')) self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
self.setModal(True) self.setModal(True)
self.layout = QVBoxLayout() self.edit = edit
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')
def exec_(self, projector): def exec_(self, projector, edit=False):
""" """
Override initial method so we can build the tabs. Override initial method so we can build the tabs.
:param projector: Projector instance to build source list from :param projector: Projector instance to build source list from
""" """
self.projector = projector 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) self.source_text = self.projectordb.get_source_list(projector=projector)
keys = list(self.source_text.keys()) keys = list(self.source_text.keys())
keys.sort() keys.sort()
key_count = len(keys) key_count = len(keys)
button_list = [] button_list = []
for key in keys: if self.edit:
button = QtGui.QRadioButton(self.source_text[key]) for key in keys:
button.setChecked(True if key == projector.source else False) item = QLineEdit()
self.layout.addWidget(button) item.setObjectName('source_key_%s' % key)
self.button_group.addButton(button, int(key)) source_item = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id)
button_list.append(key) if source_item is None:
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok | 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) QtGui.QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept_me) self.button_box.clicked.connect(self.button_clicked)
self.button_box.rejected.connect(self.reject_me)
self.layout.addWidget(self.button_box) self.layout.addWidget(self.button_box)
self.setMinimumHeight(key_count*25) self.setMinimumHeight(key_count*25)
selected = super(SourceSelectSingle, self).exec_() selected = super(SourceSelectSingle, self).exec_()
return selected 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() @pyqtSlot()
def accept_me(self): def accept_me(self):
""" """
Slot to accept 'OK' button Slot to accept 'OK' button
""" """
selected = self.button_group.checkedId() projector = self.projector.db_item
log.debug('SourceSelectDialog().accepted() Setting source to %s' % selected) 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) self.done(selected)
@pyqtSlot()
def reject_me(self):
"""
Slot to accept 'Cancel' button
"""
log.debug('SourceSelectDialog() - Rejected')
self.done(0)