~tomasgroth/openlp/portable-path

« back to all changes in this revision

Viewing changes to openlp/core/projectors/manager.py

  • Committer: Tomas Groth
  • Date: 2019-04-30 19:02:42 UTC
  • mfrom: (2829.2.32 openlp)
  • Revision ID: tomasgroth@yahoo.dk-20190430190242-6zwjk8724tyux70m
trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
###############################################################################
5
5
# OpenLP - Open Source Lyrics Projection                                      #
6
6
# --------------------------------------------------------------------------- #
7
 
# Copyright (c) 2008-2018 OpenLP Developers                                   #
 
7
# Copyright (c) 2008-2019 OpenLP Developers                                   #
8
8
# --------------------------------------------------------------------------- #
9
9
# This program is free software; you can redistribute it and/or modify it     #
10
10
# under the terms of the GNU General Public License as published by the Free  #
30
30
from PyQt5 import QtCore, QtGui, QtWidgets
31
31
 
32
32
from openlp.core.common.i18n import translate
33
 
from openlp.core.ui.icons import UiIcons
34
33
from openlp.core.common.mixins import LogMixin, RegistryProperties
35
 
from openlp.core.common.registry import RegistryBase
 
34
from openlp.core.common.registry import Registry, RegistryBase
36
35
from openlp.core.common.settings import Settings
37
36
from openlp.core.lib.ui import create_widget_action
38
37
from openlp.core.projectors import DialogSourceStyle
39
 
from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, \
40
 
    E_SOCKET_TIMEOUT, E_UNKNOWN_SOCKET_ERROR, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, \
41
 
    S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP, PJLINK_PORT, STATUS_CODE, STATUS_MSG, QSOCKET_STATE
 
38
from openlp.core.projectors.constants import E_AUTHENTICATION, E_ERROR, E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT,\
 
39
    E_UNKNOWN_SOCKET_ERROR, QSOCKET_STATE, S_CONNECTED, S_CONNECTING, S_COOLDOWN, S_INITIALIZE, S_NOT_CONNECTED, S_OFF,\
 
40
    S_ON, S_STANDBY, S_WARMUP, STATUS_CODE, STATUS_MSG
42
41
 
43
42
from openlp.core.projectors.db import ProjectorDB
44
43
from openlp.core.projectors.editform import ProjectorEditForm
45
44
from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
46
 
from openlp.core.projectors.sourceselectform import SourceSelectTabs, SourceSelectSingle
 
45
from openlp.core.projectors.sourceselectform import SourceSelectSingle, SourceSelectTabs
 
46
from openlp.core.ui.icons import UiIcons
47
47
from openlp.core.widgets.toolbar import OpenLPToolbar
48
48
 
49
49
log = logging.getLogger(__name__)
50
50
log.debug('projectormanager loaded')
51
51
 
52
52
 
53
 
# Dict for matching projector status to display icon
54
 
STATUS_ICONS = {
55
 
    S_NOT_CONNECTED: ':/projector/projector_item_disconnect.png',
56
 
    S_CONNECTING: ':/projector/projector_item_connect.png',
57
 
    S_CONNECTED: ':/projector/projector_off.png',
58
 
    S_OFF: ':/projector/projector_off.png',
59
 
    S_INITIALIZE: ':/projector/projector_off.png',
60
 
    S_STANDBY: ':/projector/projector_off.png',
61
 
    S_WARMUP: ':/projector/projector_warmup.png',
62
 
    S_ON: ':/projector/projector_on.png',
63
 
    S_COOLDOWN: ':/projector/projector_cooldown.png',
64
 
    E_ERROR: ':/projector/projector_error.png',
65
 
    E_NETWORK: ':/projector/projector_not_connected_error.png',
66
 
    E_SOCKET_TIMEOUT: ':/projector/projector_not_connected_error.png',
67
 
    E_AUTHENTICATION: ':/projector/projector_not_connected_error.png',
68
 
    E_UNKNOWN_SOCKET_ERROR: ':/projector/projector_not_connected_error.png',
69
 
    E_NOT_CONNECTED: ':/projector/projector_not_connected_error.png'
70
 
}
71
 
 
72
 
 
73
53
class UiProjectorManager(object):
74
54
    """
75
55
    UI part of the Projector Manager
121
101
        self.one_toolbar.add_toolbar_action('connect_projector',
122
102
                                            text=translate('OpenLP.ProjectorManager',
123
103
                                                           'Connect to selected projector.'),
124
 
                                            icon=UiIcons().projector_connect,
 
104
                                            icon=UiIcons().projector_select_connect,
125
105
                                            tooltip=translate('OpenLP.ProjectorManager',
126
106
                                                              'Connect to selected projector.'),
127
107
                                            triggers=self.on_connect_projector)
135
115
        self.one_toolbar.add_toolbar_action('disconnect_projector',
136
116
                                            text=translate('OpenLP.ProjectorManager',
137
117
                                                           'Disconnect from selected projectors'),
138
 
                                            icon=UiIcons().projector_disconnect,
 
118
                                            icon=UiIcons().projector_select_disconnect,
139
119
                                            tooltip=translate('OpenLP.ProjectorManager',
140
120
                                                              'Disconnect from selected projector.'),
141
121
                                            triggers=self.on_disconnect_projector)
150
130
        self.one_toolbar.add_toolbar_action('poweron_projector',
151
131
                                            text=translate('OpenLP.ProjectorManager',
152
132
                                                           'Power on selected projector'),
153
 
                                            icon=UiIcons().projector_on,
 
133
                                            icon=UiIcons().projector_power_on,
154
134
                                            tooltip=translate('OpenLP.ProjectorManager',
155
135
                                                              'Power on selected projector.'),
156
136
                                            triggers=self.on_poweron_projector)
163
143
                                            triggers=self.on_poweron_projector)
164
144
        self.one_toolbar.add_toolbar_action('poweroff_projector',
165
145
                                            text=translate('OpenLP.ProjectorManager', 'Standby selected projector'),
166
 
                                            icon=UiIcons().projector_off,
 
146
                                            icon=UiIcons().projector_power_off,
167
147
                                            tooltip=translate('OpenLP.ProjectorManager',
168
148
                                                              'Put selected projector in standby.'),
169
149
                                            triggers=self.on_poweroff_projector)
297
277
        self.projector_list = []
298
278
        self.source_select_form = None
299
279
        # Dictionary of PJLinkUDP objects to listen for UDP broadcasts from PJLink 2+ projectors.
300
 
        # Key is port number that projectors use
 
280
        # Key is port number
301
281
        self.pjlink_udp = {}
302
282
        # Dict for matching projector status to display icon
303
283
        self.status_icons = {
308
288
            S_INITIALIZE: UiIcons().projector_on,
309
289
            S_STANDBY: UiIcons().projector_off,
310
290
            S_WARMUP: UiIcons().projector_warmup,
311
 
            S_ON: UiIcons().projector_off,
 
291
            S_ON: UiIcons().projector_on,
312
292
            S_COOLDOWN: UiIcons().projector_cooldown,
313
293
            E_ERROR: UiIcons().projector_error,
314
294
            E_NETWORK: UiIcons().error,
335
315
        """
336
316
        Post-initialize setups.
337
317
        """
338
 
        # Default PJLink port UDP socket
339
 
        log.debug('Creating PJLinkUDP listener for default port {port}'.format(port=PJLINK_PORT))
340
 
        self.pjlink_udp = {PJLINK_PORT: PJLinkUDP(port=PJLINK_PORT)}
341
 
        self.pjlink_udp[PJLINK_PORT].bind(PJLINK_PORT)
342
318
        # Set 1.5 second delay before loading all projectors
343
319
        if self.autostart:
344
320
            log.debug('Delaying 1.5 seconds before loading all projectors')
351
327
        self.projector_form.editProjector.connect(self.edit_projector_from_wizard)
352
328
        self.projector_list_widget.itemSelectionChanged.connect(self.update_icons)
353
329
 
 
330
    def udp_listen_add(self, port):
 
331
        """
 
332
        Add UDP broadcast listener
 
333
        """
 
334
        if port in self.pjlink_udp:
 
335
            log.warning('UDP Listener for port {port} already added - skipping'.format(port=port))
 
336
        else:
 
337
            log.debug('Adding UDP listener on port {port}'.format(port=port))
 
338
            self.pjlink_udp[port] = PJLinkUDP(port=port)
 
339
            Registry().execute('udp_broadcast_add', port=port, callback=self.pjlink_udp[port].check_settings)
 
340
 
 
341
    def udp_listen_delete(self, port):
 
342
        """
 
343
        Remove a UDP broadcast listener
 
344
        """
 
345
        log.debug('Checking for UDP port {port} listener deletion'.format(port=port))
 
346
        if port not in self.pjlink_udp:
 
347
            log.warn('UDP listener for port {port} not there - skipping delete'.format(port=port))
 
348
            return
 
349
        keep_port = False
 
350
        for item in self.projector_list:
 
351
            if port == item.link.port:
 
352
                keep_port = True
 
353
        if keep_port:
 
354
            log.warn('UDP listener for port {port} needed for other projectors - skipping delete'.format(port=port))
 
355
            return
 
356
        Registry().execute('udp_broadcast_remove', port=port)
 
357
        del self.pjlink_udp[port]
 
358
        log.debug('UDP listener for port {port} deleted'.format(port=port))
 
359
 
354
360
    def get_settings(self):
355
361
        """
356
362
        Retrieve the saved settings
444
450
                projector = list_item.data(QtCore.Qt.UserRole)
445
451
                try:
446
452
                    projector.link.set_shutter_closed()
447
 
                except:
 
453
                except Exception:
448
454
                    continue
449
455
 
450
456
    def on_doubleclick_item(self, item, opt=None):
459
465
            try:
460
466
                log.debug('ProjectorManager: Calling connect_to_host() on "{ip}"'.format(ip=projector.link.ip))
461
467
                projector.link.connect_to_host()
462
 
            except:
 
468
            except Exception:
463
469
                log.debug('ProjectorManager: "{ip}" already connected - skipping'.format(ip=projector.link.ip))
464
470
        return
465
471
 
478
484
                projector = list_item.data(QtCore.Qt.UserRole)
479
485
                try:
480
486
                    projector.link.connect_to_host()
481
 
                except:
 
487
                except Exception:
482
488
                    continue
483
489
 
484
490
    def on_delete_projector(self, opt=None):
518
524
        except (AttributeError, TypeError):
519
525
            pass
520
526
        try:
521
 
            projector.poll_timer.stop()
522
 
            projector.poll_timer.timeout.disconnect(projector.link.poll_loop)
523
 
        except (AttributeError, TypeError):
524
 
            pass
525
 
        try:
526
 
            projector.socket_timer.stop()
527
 
            projector.socket_timer.timeout.disconnect(projector.link.socket_abort)
528
 
        except (AttributeError, TypeError):
529
 
            pass
530
 
        # Disconnect signals from projector being deleted
531
 
        try:
532
 
            self.pjlink_udp[projector.link.port].data_received.disconnect(projector.link.get_buffer)
 
527
            projector.link.poll_timer.stop()
 
528
            projector.link.poll_timer.timeout.disconnect(projector.link.poll_loop)
 
529
        except (AttributeError, TypeError):
 
530
            pass
 
531
        try:
 
532
            projector.link.socket_timer.stop()
 
533
            projector.link.socket_timer.timeout.disconnect(projector.link.socket_abort)
533
534
        except (AttributeError, TypeError):
534
535
            pass
535
536
 
 
537
        old_port = projector.link.port
536
538
        # Rebuild projector list
537
539
        new_list = []
538
540
        for item in self.projector_list:
539
541
            if item.link.db_item.id == projector.link.db_item.id:
 
542
                log.debug('Removing projector "{item}"'.format(item=item.link.name))
540
543
                continue
541
544
            new_list.append(item)
542
545
        self.projector_list = new_list
546
549
            log.warning('Delete projector {item} failed'.format(item=projector.db_item))
547
550
        for item in self.projector_list:
548
551
            log.debug('New projector list - item: {ip} {name}'.format(ip=item.link.ip, name=item.link.name))
 
552
        self.udp_listen_delete(old_port)
549
553
 
550
554
    def on_disconnect_projector(self, opt=None):
551
555
        """
562
566
                projector = list_item.data(QtCore.Qt.UserRole)
563
567
                try:
564
568
                    projector.link.disconnect_from_host()
565
 
                except:
 
569
                except Exception:
566
570
                    continue
567
571
 
568
572
    def on_edit_projector(self, opt=None):
595
599
                projector = list_item.data(QtCore.Qt.UserRole)
596
600
                try:
597
601
                    projector.link.set_power_off()
598
 
                except:
 
602
                except Exception:
599
603
                    continue
600
604
 
601
605
    def on_poweron_projector(self, opt=None):
613
617
                projector = list_item.data(QtCore.Qt.UserRole)
614
618
                try:
615
619
                    projector.link.set_power_on()
616
 
                except:
 
620
                except Exception:
617
621
                    continue
618
622
 
619
623
    def on_show_projector(self, opt=None):
631
635
                projector = list_item.data(QtCore.Qt.UserRole)
632
636
                try:
633
637
                    projector.link.set_shutter_open()
634
 
                except:
 
638
                except Exception:
635
639
                    continue
636
640
 
637
641
    def on_status_projector(self, opt=None):
748
752
        item.link.projectorAuthentication.connect(self.authentication_error)
749
753
        item.link.projectorNoAuthentication.connect(self.no_authentication_error)
750
754
        item.link.projectorUpdateIcons.connect(self.update_icons)
751
 
        # Connect UDP signal to projector instances with same port
752
 
        if item.link.port not in self.pjlink_udp:
753
 
            log.debug('Adding new PJLinkUDP listener fo port {port}'.format(port=item.link.port))
754
 
            self.pjlink_udp[item.link.port] = PJLinkUDP(port=item.link.port)
755
 
            self.pjlink_udp[item.link.port].bind(item.link.port)
756
 
        log.debug('Connecting PJLinkUDP port {port} signal to "{item}"'.format(port=item.link.port,
757
 
                                                                               item=item.link.name))
758
 
        self.pjlink_udp[item.link.port].data_received.connect(item.link.get_buffer)
759
 
 
 
755
        # Add UDP listener for new projector port
 
756
        self.udp_listen_add(item.link.port)
760
757
        self.projector_list.append(item)
761
758
        if start:
762
759
            item.link.connect_to_host()
783
780
        :param projector: Projector() instance of projector with updated information
784
781
        """
785
782
        log.debug('edit_projector_from_wizard(ip={ip})'.format(ip=projector.ip))
 
783
        old_port = self.old_projector.link.port
 
784
        old_ip = self.old_projector.link.ip
786
785
        self.old_projector.link.name = projector.name
787
786
        self.old_projector.link.ip = projector.ip
788
787
        self.old_projector.link.pin = None if projector.pin == '' else projector.pin
789
 
        self.old_projector.link.port = projector.port
790
788
        self.old_projector.link.location = projector.location
791
789
        self.old_projector.link.notes = projector.notes
792
790
        self.old_projector.widget.setText(projector.name)
 
791
        self.old_projector.link.port = int(projector.port)
 
792
        # Update projector list items
 
793
        for item in self.projector_list:
 
794
            if item.link.ip == old_ip:
 
795
                item.link.port = int(projector.port)
 
796
                # NOTE: This assumes (!) we are using IP addresses as keys
 
797
                break
 
798
        # Update UDP listeners before setting old_projector.port
 
799
        if old_port != projector.port:
 
800
            self.udp_listen_delete(old_port)
 
801
            self.udp_listen_add(int(projector.port))
793
802
 
794
803
    def _load_projectors(self):
795
804
        """'
850
859
        """
851
860
        Update the icons when the selected projectors change
852
861
        """
 
862
        log.debug('update_icons(): Checking for selected projector items in list')
853
863
        count = len(self.projector_list_widget.selectedItems())
854
864
        projector = None
855
865
        if count == 0:
870
880
            self.get_toolbar_item('blank_projector_multiple', hidden=True)
871
881
            self.get_toolbar_item('show_projector_multiple', hidden=True)
872
882
        elif count == 1:
 
883
            log.debug('update_icons(): Found one item selected')
873
884
            projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole)
874
885
            connected = QSOCKET_STATE[projector.link.state()] == S_CONNECTED
875
886
            power = projector.link.power == S_ON
880
891
            self.get_toolbar_item('blank_projector_multiple', hidden=True)
881
892
            self.get_toolbar_item('show_projector_multiple', hidden=True)
882
893
            if connected:
 
894
                log.debug('update_icons(): Updating icons for connected state')
883
895
                self.get_toolbar_item('view_projector', enabled=True)
884
896
                self.get_toolbar_item('source_view_projector',
885
 
                                      enabled=connected and power and projector.link.source_available is not None)
 
897
                                      enabled=projector.link.source_available is not None and connected and power)
886
898
                self.get_toolbar_item('edit_projector', hidden=True)
887
899
                self.get_toolbar_item('delete_projector', hidden=True)
888
900
            else:
 
901
                log.debug('update_icons(): Updating for not connected state')
889
902
                self.get_toolbar_item('view_projector', hidden=True)
890
903
                self.get_toolbar_item('source_view_projector', hidden=True)
891
904
                self.get_toolbar_item('edit_projector', enabled=True)
901
914
                self.get_toolbar_item('blank_projector', enabled=False)
902
915
                self.get_toolbar_item('show_projector', enabled=False)
903
916
        else:
 
917
            log.debug('update_icons(): Updating for multiple items selected')
904
918
            self.get_toolbar_item('edit_projector', enabled=False)
905
919
            self.get_toolbar_item('delete_projector', enabled=False)
906
920
            self.get_toolbar_item('view_projector', hidden=True)