Example #1
0
 def setUp(self):
     """
     Set up anything necessary for all tests
     """
     if not hasattr(self, 'projector'):
         with patch('openlp.core.lib.projector.db.init_url'
                    ) as mocked_init_url:
             mocked_init_url.start()
             mocked_init_url.return_value = 'sqlite:///%s' % tmpfile
             self.projector = ProjectorDB()
Example #2
0
 def bootstrap_initialise(self):
     """
     Pre-initialize setups.
     """
     self.setup_ui(self)
     if self.projectordb is None:
         # Work around for testing creating a ~/.openlp.data.projector.projector.sql file
         log.debug('Creating new ProjectorDB() instance')
         self.projectordb = ProjectorDB()
     else:
         log.debug('Using existing ProjectorDB() instance')
     self.get_settings()
Example #3
0
 def setUp(self):
     """
     Set up anything necessary for all tests
     """
     if not hasattr(self, "projector"):
         with patch("openlp.core.lib.projector.db.init_url") as mocked_init_url:
             mocked_init_url.start()
             mocked_init_url.return_value = "sqlite:///%s" % tmpfile
             self.projector = ProjectorDB()
Example #4
0
 def setUp(self, mocked_init_url):
     """
     Set up anything necessary for all tests
     """
     mocked_init_url.return_value = 'sqlite:///{}'.format(TEST_DB)
     self.build_settings()
     self.setup_application()
     Registry.create()
     # Do not try to recreate if we've already been created from a previous test
     if not hasattr(self, 'projectordb'):
         self.projectordb = ProjectorDB()
     # Retrieve/create a database record
     self.projector = self.projectordb.get_projector_by_ip(TEST1_DATA['ip'])
     if not self.projector:
         self.projectordb.add_projector(projector=Projector(**TEST1_DATA))
         self.projector = self.projectordb.get_projector_by_ip(
             TEST1_DATA['ip'])
     self.projector.dbid = self.projector.id
     self.projector.db_item = self.projector
Example #5
0
 def bootstrap_initialise(self):
     """
     Pre-initialize setups.
     """
     self.setup_ui(self)
     if self.projectordb is None:
         # Work around for testing creating a ~/.openlp.data.projector.projector.sql file
         log.debug('Creating new ProjectorDB() instance')
         self.projectordb = ProjectorDB()
     else:
         log.debug('Using existing ProjectorDB() instance')
     self.get_settings()
Example #6
0
    def setUp(self):
        """
        Create the UI and setup necessary options

        :return: None
        """
        self.build_settings()
        self.setup_application()
        Registry.create()
        with patch('openlp.core.lib.projector.db.init_url') as mocked_init_url:
            mocked_init_url.return_value = 'sqlite://'
            self.projectordb = ProjectorDB()
            self.projector_form = ProjectorEditForm(
                projectordb=self.projectordb)
 def setUp(self):
     """
     Create the UI and setup necessary options
     """
     self.build_settings()
     self.setup_application()
     Registry.create()
     with patch('openlp.core.lib.projector.db.init_url') as mocked_init_url:
         if os.path.exists(TEST_DB):
             os.unlink(TEST_DB)
         mocked_init_url.return_value = 'sqlite:///%s' % TEST_DB
         self.projectordb = ProjectorDB()
         if not hasattr(self, 'projector_manager'):
             self.projector_manager = ProjectorManager(
                 projectordb=self.projectordb)
Example #8
0
 def setUp(self):
     """
     Create the UI and setup necessary options
     """
     self.build_settings()
     self.setup_application()
     Registry.create()
     if not hasattr(self, 'projector_manager'):
         with patch('openlp.core.lib.projector.db.init_url'
                    ) as mocked_init_url:
             mocked_init_url.start()
             mocked_init_url.return_value = 'sqlite:///%s' % tmpfile
             self.projectordb = ProjectorDB()
             if not hasattr(self, 'projector_manager'):
                 self.projector_manager = ProjectorManager(
                     projectordb=self.projectordb)
 def setUp(self, mocked_init_url):
     """
     Set up anything necessary for all tests
     """
     mocked_init_url.return_value = 'sqlite:///{}'.format(TEST_DB)
     self.build_settings()
     self.setup_application()
     Registry.create()
     # Do not try to recreate if we've already been created from a previous test
     if not hasattr(self, 'projectordb'):
         self.projectordb = ProjectorDB()
     # Retrieve/create a database record
     self.projector = self.projectordb.get_projector_by_ip(TEST1_DATA['ip'])
     if not self.projector:
         self.projectordb.add_projector(projector=Projector(**TEST1_DATA))
         self.projector = self.projectordb.get_projector_by_ip(TEST1_DATA['ip'])
     self.projector.dbid = self.projector.id
     self.projector.db_item = self.projector
Example #10
0
class TestProjectorDB(TestCase):
    """
    Test case for ProjectorDB
    """
    @patch('openlp.core.lib.projector.db.init_url')
    def setUp(self, mocked_init_url):
        """
        Set up anything necessary for all tests
        """
        mocked_init_url.return_value = 'sqlite:///{db}'.format(db=TEST_DB)
        self.projector = ProjectorDB()

    def tearDown(self):
        """
        Clean up
        """
        self.projector.session.close()
        self.projector = None
        retries = 0
        while retries < 5:
            try:
                if os.path.exists(TEST_DB):
                    os.unlink(TEST_DB)
                break
            except:
                time.sleep(1)
                retries += 1

    def test_find_record_by_ip(self):
        """
        Test find record by IP
        """
        # GIVEN: Record entries in database
        add_records(self.projector, [Projector(**TEST1_DATA), Projector(**TEST2_DATA)])

        # WHEN: Search for record using IP
        record = self.projector.get_projector_by_ip(TEST2_DATA['ip'])

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(Projector(**TEST2_DATA), record),
                        'Record found should have been test_2 data')

    def test_find_record_by_name(self):
        """
        Test find record by name
        """
        # GIVEN: Record entries in database
        add_records(self.projector, [Projector(**TEST1_DATA), Projector(**TEST2_DATA)])

        # WHEN: Search for record using name
        record = self.projector.get_projector_by_name(TEST2_DATA['name'])

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(Projector(**TEST2_DATA), record),
                        'Record found should have been test_2 data')

    def test_record_delete(self):
        """
        Test record can be deleted
        """
        # GIVEN: Record in database
        add_records(self.projector, [Projector(**TEST3_DATA), ])
        record = self.projector.get_projector_by_ip(TEST3_DATA['ip'])

        # WHEN: Record deleted
        self.projector.delete_projector(record)

        # THEN: Verify record not retrievable
        found = self.projector.get_projector_by_ip(TEST3_DATA['ip'])
        self.assertFalse(found, 'test_3 record should have been deleted')

    def test_record_edit(self):
        """
        Test edited record returns the same record ID with different data
        """
        # GIVEN: Record entries in database
        add_records(self.projector, [Projector(**TEST1_DATA), Projector(**TEST2_DATA)])

        # WHEN: We retrieve a specific record
        record = self.projector.get_projector_by_ip(TEST1_DATA['ip'])
        record_id = record.id

        # WHEN: Data is changed
        record.ip = TEST3_DATA['ip']
        record.port = TEST3_DATA['port']
        record.pin = TEST3_DATA['pin']
        record.name = TEST3_DATA['name']
        record.location = TEST3_DATA['location']
        record.notes = TEST3_DATA['notes']
        updated = self.projector.update_projector(record)
        self.assertTrue(updated, 'Save updated record should have returned True')
        record = self.projector.get_projector_by_ip(TEST3_DATA['ip'])

        # THEN: Record ID should remain the same, but data should be changed
        self.assertEqual(record_id, record.id, 'Edited record should have the same ID')
        self.assertTrue(compare_data(Projector(**TEST3_DATA), record), 'Edited record should have new data')

    def test_source_add(self):
        """
        Test source entry for projector item
        """
        # GIVEN: Record entries in database
        projector1 = Projector(**TEST1_DATA)
        self.projector.add_projector(projector1)
        item = self.projector.get_projector_by_id(projector1.id)
        item_id = item.id

        # WHEN: A source entry is saved for item
        source = ProjectorSource(projector_id=item_id, code='11', text='First RGB source')
        self.projector.add_source(source)

        # THEN: Projector should have the same source entry
        item = self.projector.get_projector_by_id(item_id)
        self.assertTrue(compare_source(item.source_list[0], source))

    def test_manufacturer_repr(self):
        """
        Test Manufacturer.__repr__() text
        """
        # GIVEN: Test object
        manufacturer = Manufacturer()

        # WHEN: Name is set
        manufacturer.name = 'OpenLP Test'

        # THEN: __repr__ should return a proper string
        self.assertEqual(str(manufacturer), '<Manufacturer(name="OpenLP Test")>',
                         'Manufacturer.__repr__() should have returned a proper representation string')

    def test_model_repr(self):
        """
        Test Model.__repr__() text
        """
        # GIVEN: Test object
        model = Model()

        # WHEN: Name is set
        model.name = 'OpenLP Test'

        # THEN: __repr__ should return a proper string
        self.assertEqual(str(model), '<Model(name='"OpenLP Test"')>',
                         'Model.__repr__() should have returned a proper representation string')

    def test_source_repr(self):
        """
        Test Source.__repr__() text
        """
        # GIVEN: Test object
        source = Source()

        # WHEN: Source() information is set
        source.pjlink_name = 'Test object'
        source.pjlink_code = '11'
        source.text = 'Input text'

        # THEN: __repr__ should return a proper string
        self.assertEqual(str(source), '<Source(pjlink_name="Test object", pjlink_code="11", text="Input text")>',
                         'Source.__repr__() should have returned a proper representation string')

    def test_projector_repr(self):
        """
        Test Projector.__repr__() text
        """
        # GIVEN: Test object
        projector = Projector()

        # WHEN: projector() is populated
        # NOTE: projector.pin, projector.other, projector.sources should all return None
        #       projector.source_list should return an empty list
        projector.id = 0
        projector.ip = '127.0.0.1'
        projector.port = PJLINK_PORT
        projector.name = 'Test One'
        projector.location = 'Somewhere over the rainbow'
        projector.notes = 'Not again'
        projector.pjlink_name = 'TEST'
        projector.manufacturer = 'IN YOUR DREAMS'
        projector.model = 'OpenLP'

        # THEN: __repr__ should return a proper string
        self.assertEqual(str(projector),
                         '< Projector(id="0", ip="127.0.0.1", port="4352", pin="None", name="Test One", '
                         'location="Somewhere over the rainbow", notes="Not again", pjlink_name="TEST", '
                         'manufacturer="IN YOUR DREAMS", model="OpenLP", other="None", sources="None", '
                         'source_list="[]") >',
                         'Projector.__repr__() should have returned a proper representation string')

    def test_projectorsource_repr(self):
        """
        Test ProjectorSource.__repr__() text
        """
        # GIVEN: test setup
        projector1 = Projector(**TEST1_DATA)
        self.projector.add_projector(projector1)
        item = self.projector.get_projector_by_id(projector1.id)
        item_id = item.id

        # WHEN: A source entry is saved for item
        source = ProjectorSource(projector_id=item_id, code='11', text='First RGB source')
        self.projector.add_source(source)

        # THEN: __repr__ should return a proper string
        self.assertEqual(str(source),
                         '<ProjectorSource(id="1", code="11", text="First RGB source", projector_id="1")>',
                         'ProjectorSource.__repr__)_ should have returned a proper representation string')

    def test_get_projector_by_id_none(self):
        """
        Test get_projector_by_id() returns None if no db entry
        """
        # GIVEN: Test object and data
        projector = self.projector

        # WHEN: DB search for entry not saved
        results = projector.get_projector_by_id(dbid=123134556409824506)

        # THEN: Verify return was None
        self.assertEqual(results, None, 'Returned results should have equaled None')

    def test_get_projector_all_none(self):
        """
        Test get_projector_all() with no projectors in db
        """
        # GIVEN: Test object with no data
        projector = self.projector

        # WHEN: We retrieve the database entries
        results = projector.get_projector_all()

        # THEN: Verify results is None
        self.assertEqual(results, [], 'Returned results should have returned an empty list')

    def test_get_projector_all_one(self):
        """
        Test get_projector_all() with one entry in db
        """
        # GIVEN: One entry in database
        projector = Projector(**TEST1_DATA)
        self.projector.add_projector(projector)

        # WHEN: We retrieve the database entries
        results = self.projector.get_projector_all()

        # THEN: We should have a list with one entry
        self.assertEqual(len(results), 1, 'Returned results should have returned a list with one entry')
        self.assertTrue((projector in results), 'Result should have been equal to TEST1_DATA')

    def test_get_projector_all_many(self):
        """
        Test get_projector_all() with multiple entries in db
        """
        # GIVEN: multiple entries in database
        projector_list = []
        projector_list.append(Projector(**TEST1_DATA))
        projector_list.append(Projector(**TEST2_DATA))
        projector_list.append(Projector(**TEST3_DATA))
        for projector in projector_list:
            self.projector.add_projector(projector)

        # WHEN: We retrieve the database entries
        results = self.projector.get_projector_all()

        # THEN: We should have a list with three entries
        self.assertEqual(len(results), len(projector_list),
                         'Returned results should have returned a list with three entries')
        for projector in results:
            self.assertTrue((projector in projector_list),
                            'Projector DB entry should have been in expected list')

    def test_get_projector_by_name_fail(self):
        """
        Test get_projector_by_name() fail
        """
        # GIVEN: Test entry in database
        self.projector.add_projector(Projector(**TEST1_DATA))

        # WHEN: We attempt to get a projector that's not in database
        results = self.projector.get_projector_by_name(name=TEST2_DATA['name'])

        # THEN: We should have None
        self.assertEqual(results, None, 'projector.get_projector_by_name() should have returned None')

    def test_add_projector_fail(self):
        """
        Test add_projector() fail
        """
        # GIVEN: Test entry in the database
        ignore_result = self.projector.add_projector(Projector(**TEST1_DATA))

        # WHEN: Attempt to add same projector entry
        results = self.projector.add_projector(Projector(**TEST1_DATA))

        # THEN: We should have failed to add new entry
        self.assertFalse(results, 'add_projector() should have failed')

    def test_update_projector_default_fail(self):
        """
        Test update_projector() with no options fails
        """
        # GIVEN: projector instance
        projector = self.projector

        # WHEN: attempt to update a projector entry with no options
        results = projector.update_projector()

        # THEN: We should have failed
        self.assertFalse(results, 'update_projector(projector=None) should have returned False')

    def test_update_projector_not_in_db_fail(self):
        """
        Test update_projector() when entry not in database
        """
        # GIVEN: Projector entry in database
        ignore_result = self.projector.add_projector(Projector(**TEST1_DATA))
        projector = Projector(**TEST2_DATA)

        # WHEN: Attempt to update data with a different ID
        results = self.projector.update_projector(projector)

        # THEN: Results should be False
        self.assertFalse(results, 'update_projector(projector=projector) should have returned False')

    def test_delete_projector_fail(self):
        """
        Test delete_projector(projector) fails to delete record
        """
        # GIVEN: Test entry in db
        self.projector.add_projector(Projector(**TEST1_DATA))

        # wHEN: Attempting to delete an entry not in the databae
        results = self.projector.delete_projector(Projector(**TEST2_DATA))

        # THEN: Results should be False
        self.assertFalse(results, 'delete_projector() should have returned False')
Example #11
0
class ProjectorSourceFormTest(TestCase, TestMixin):
    """
    Test class for the Projector Source Select form module
    """
    @patch('openlp.core.lib.projector.db.init_url')
    def setUp(self, mocked_init_url):
        """
        Set up anything necessary for all tests
        """
        mocked_init_url.return_value = 'sqlite:///{}'.format(TEST_DB)
        self.build_settings()
        self.setup_application()
        Registry.create()
        # Do not try to recreate if we've already been created from a previous test
        if not hasattr(self, 'projectordb'):
            self.projectordb = ProjectorDB()
        # Retrieve/create a database record
        self.projector = self.projectordb.get_projector_by_ip(TEST1_DATA['ip'])
        if not self.projector:
            self.projectordb.add_projector(projector=Projector(**TEST1_DATA))
            self.projector = self.projectordb.get_projector_by_ip(
                TEST1_DATA['ip'])
        self.projector.dbid = self.projector.id
        self.projector.db_item = self.projector

    def tearDown(self):
        """
        Close database session.
        Delete all C++ objects at end so we don't segfault.
        """
        self.projectordb.session.close()
        del (self.projectordb)
        del (self.projector)
        retries = 0
        while retries < 5:
            try:
                if os.path.exists(TEST_DB):
                    os.unlink(TEST_DB)
                break
            except:
                time.sleep(1)
                retries += 1
        self.destroy_settings()

    def test_source_dict(self):
        """
        Test that source list dict returned from sourceselectform module is a valid dict with proper entries
        """
        # GIVEN: A list of inputs
        codes = []
        for item in PJLINK_DEFAULT_CODES.keys():
            codes.append(item)
        codes.sort()

        # WHEN: projector.sourceselectform.source_select() is called
        check = source_group(codes, PJLINK_DEFAULT_CODES)

        # THEN: return dictionary should match test dictionary
        self.assertEquals(
            check, build_source_dict(),
            "Source group dictionary should match test dictionary")

    @patch.object(QDialog, 'exec')
    def test_source_select_edit_button(self, mocked_qdialog):
        """
        Test source select form edit has Ok, Cancel, Reset, and Revert buttons
        """
        # GIVEN: Initial setup and mocks
        self.projector.source_available = [
            '11',
        ]
        self.projector.source = '11'

        # WHEN we create a source select widget and set edit=True
        select_form = SourceSelectSingle(parent=None,
                                         projectordb=self.projectordb)
        select_form.edit = True
        select_form.exec(projector=self.projector)
        projector = select_form.projector

        # THEN: Verify all 4 buttons are available
        self.assertEquals(
            len(select_form.button_box.buttons()), 4,
            'SourceSelect dialog box should have "OK", "Cancel" '
            '"Rest", and "Revert" buttons available')

    @patch.object(QDialog, 'exec')
    def test_source_select_noedit_button(self, mocked_qdialog):
        """
        Test source select form view has OK and Cancel buttons only
        """
        # GIVEN: Initial setup and mocks
        self.projector.source_available = [
            '11',
        ]
        self.projector.source = '11'

        # WHEN we create a source select widget and set edit=False
        select_form = SourceSelectSingle(parent=None,
                                         projectordb=self.projectordb)
        select_form.edit = False
        select_form.exec(projector=self.projector)
        projector = select_form.projector

        # THEN: Verify only 2 buttons are available
        self.assertEquals(
            len(select_form.button_box.buttons()), 2,
            'SourceSelect dialog box should only have "OK" '
            'and "Cancel" buttons available')
Example #12
0
 def setUp(self, mocked_init_url):
     """
     Set up anything necessary for all tests
     """
     mocked_init_url.return_value = 'sqlite:///{db}'.format(db=TEST_DB)
     self.projector = ProjectorDB()
Example #13
0
class TestProjectorDB(TestCase):
    """
    Test case for ProjectorDB
    """
    @patch('openlp.core.lib.projector.db.init_url')
    def setUp(self, mocked_init_url):
        """
        Set up anything necessary for all tests
        """
        mocked_init_url.return_value = 'sqlite:///{db}'.format(db=TEST_DB)
        self.projector = ProjectorDB()

    def tearDown(self):
        """
        Clean up
        """
        self.projector.session.close()
        self.projector = None
        retries = 0
        while retries < 5:
            try:
                if os.path.exists(TEST_DB):
                    os.unlink(TEST_DB)
                break
            except:
                time.sleep(1)
                retries += 1

    def test_find_record_by_ip(self):
        """
        Test find record by IP
        """
        # GIVEN: Record entries in database
        add_records(self.projector,
                    [Projector(**TEST1_DATA),
                     Projector(**TEST2_DATA)])

        # WHEN: Search for record using IP
        record = self.projector.get_projector_by_ip(TEST2_DATA['ip'])

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(Projector(**TEST2_DATA), record),
                        'Record found should have been test_2 data')

    def test_find_record_by_name(self):
        """
        Test find record by name
        """
        # GIVEN: Record entries in database
        add_records(self.projector,
                    [Projector(**TEST1_DATA),
                     Projector(**TEST2_DATA)])

        # WHEN: Search for record using name
        record = self.projector.get_projector_by_name(TEST2_DATA['name'])

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(Projector(**TEST2_DATA), record),
                        'Record found should have been test_2 data')

    def test_record_delete(self):
        """
        Test record can be deleted
        """
        # GIVEN: Record in database
        add_records(self.projector, [
            Projector(**TEST3_DATA),
        ])
        record = self.projector.get_projector_by_ip(TEST3_DATA['ip'])

        # WHEN: Record deleted
        self.projector.delete_projector(record)

        # THEN: Verify record not retrievable
        found = self.projector.get_projector_by_ip(TEST3_DATA['ip'])
        self.assertFalse(found, 'test_3 record should have been deleted')

    def test_record_edit(self):
        """
        Test edited record returns the same record ID with different data
        """
        # GIVEN: Record entries in database
        add_records(self.projector,
                    [Projector(**TEST1_DATA),
                     Projector(**TEST2_DATA)])

        # WHEN: We retrieve a specific record
        record = self.projector.get_projector_by_ip(TEST1_DATA['ip'])
        record_id = record.id

        # WHEN: Data is changed
        record.ip = TEST3_DATA['ip']
        record.port = TEST3_DATA['port']
        record.pin = TEST3_DATA['pin']
        record.name = TEST3_DATA['name']
        record.location = TEST3_DATA['location']
        record.notes = TEST3_DATA['notes']
        updated = self.projector.update_projector(record)
        self.assertTrue(updated,
                        'Save updated record should have returned True')
        record = self.projector.get_projector_by_ip(TEST3_DATA['ip'])

        # THEN: Record ID should remain the same, but data should be changed
        self.assertEqual(record_id, record.id,
                         'Edited record should have the same ID')
        self.assertTrue(compare_data(Projector(**TEST3_DATA), record),
                        'Edited record should have new data')

    def test_source_add(self):
        """
        Test source entry for projector item
        """
        # GIVEN: Record entries in database
        projector1 = Projector(**TEST1_DATA)
        self.projector.add_projector(projector1)
        item = self.projector.get_projector_by_id(projector1.id)
        item_id = item.id

        # WHEN: A source entry is saved for item
        source = ProjectorSource(projector_id=item_id,
                                 code='11',
                                 text='First RGB source')
        self.projector.add_source(source)

        # THEN: Projector should have the same source entry
        item = self.projector.get_projector_by_id(item_id)
        self.assertTrue(compare_source(item.source_list[0], source))

    def test_manufacturer_repr(self):
        """
        Test Manufacturer.__repr__ text
        """
        # GIVEN: Test object
        manufacturer = Manufacturer()

        # WHEN: Name is set
        manufacturer.name = 'OpenLP Test'

        # THEN: __repr__ should return a proper string
        self.assertEqual(
            str(manufacturer), '<Manufacturer(name="OpenLP Test")>',
            'Manufacturer.__repr__() should have returned a proper representation string'
        )

    def test_model_repr(self):
        """
        Test Model.__repr__ text
        """
        # GIVEN: Test object
        model = Model()

        # WHEN: Name is set
        model.name = 'OpenLP Test'

        # THEN: __repr__ should return a proper string
        self.assertEqual(
            str(model), '<Model(name='
            "OpenLP Test"
            ')>',
            'Model.__repr__() should have returned a proper representation string'
        )

    def test_source_repr(self):
        """
        Test Source.__repr__ text
        """
        # GIVEN: Test object
        source = Source()

        # WHEN: Source() information is set
        source.pjlink_name = 'Test object'
        source.pjlink_code = '11'
        source.text = 'Input text'

        # THEN: __repr__ should return a proper string
        self.assertEqual(
            str(source),
            '<Source(pjlink_name="Test object", pjlink_code="11", text="Input text")>',
            'Source.__repr__() should have returned a proper representation string'
        )

    def test_projector_repr(self):
        """
        Test Projector.__repr__() text
        """
        # GIVEN: Test object
        projector = Projector()

        # WHEN: projector() is populated
        # NOTE: projector.pin, projector.other, projector.sources should all return None
        #       projector.source_list should return an empty list
        projector.id = 0
        projector.ip = '127.0.0.1'
        projector.port = PJLINK_PORT
        projector.name = 'Test One'
        projector.location = 'Somewhere over the rainbow'
        projector.notes = 'Not again'
        projector.pjlink_name = 'TEST'
        projector.manufacturer = 'IN YOUR DREAMS'
        projector.model = 'OpenLP'

        # THEN: __repr__ should return a proper string
        self.assertEqual(
            str(projector),
            '< Projector(id="0", ip="127.0.0.1", port="4352", pin="None", name="Test One", '
            'location="Somewhere over the rainbow", notes="Not again", pjlink_name="TEST", '
            'manufacturer="IN YOUR DREAMS", model="OpenLP", other="None", sources="None", '
            'source_list="[]") >',
            'Projector.__repr__() should have returned a proper representation string'
        )

    def test_projectorsource_repr(self):
        """
        Test ProjectorSource.__repr__() text
        """
        # GIVEN: test setup
        projector1 = Projector(**TEST1_DATA)
        self.projector.add_projector(projector1)
        item = self.projector.get_projector_by_id(projector1.id)
        item_id = item.id

        # WHEN: A source entry is saved for item
        source = ProjectorSource(projector_id=item_id,
                                 code='11',
                                 text='First RGB source')
        self.projector.add_source(source)

        # THEN: __repr__ should return a proper string
        self.assertEqual(
            str(source),
            '<ProjectorSource(id="1", code="11", text="First RGB source", projector_id="1")>',
            'ProjectorSource.__repr__)_ should have returned a proper representation string'
        )

    def test_get_projector_by_id_none(self):
        """
        Test get_projector_by_id returns None if no db entry
        """
        # GIVEN: Test object and data
        projector = self.projector

        # WHEN: DB search for entry not saved
        results = projector.get_projector_by_id(dbid=123134556409824506)

        # THEN: Verify return was None
        self.assertEqual(results, None,
                         'Returned results should have equaled None')
Example #14
0
class TestProjectorDB(TestCase):
    """
    Test case for ProjectorDB
    """

    def setUp(self):
        """
        Set up anything necessary for all tests
        """
        if not hasattr(self, "projector"):
            with patch("openlp.core.lib.projector.db.init_url") as mocked_init_url:
                mocked_init_url.start()
                mocked_init_url.return_value = "sqlite:///%s" % tmpfile
                self.projector = ProjectorDB()

    def find_record_by_ip_test(self):
        """
        Test find record by IP
        """
        # GIVEN: Record entries in database
        add_records(self, [TEST1_DATA, TEST2_DATA])

        # WHEN: Search for record using IP
        record = self.projector.get_projector_by_ip(TEST2_DATA.ip)

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(TEST2_DATA, record), "Record found should have been test_2 data")

    def find_record_by_name_test(self):
        """
        Test find record by name
        """
        # GIVEN: Record entries in database
        add_records(self, [TEST1_DATA, TEST2_DATA])

        # WHEN: Search for record using name
        record = self.projector.get_projector_by_name(TEST2_DATA.name)

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(TEST2_DATA, record), "Record found should have been test_2 data")

    def record_delete_test(self):
        """
        Test record can be deleted
        """
        # GIVEN: Record in database
        add_records(self, [TEST3_DATA])
        record = self.projector.get_projector_by_ip(TEST3_DATA.ip)

        # WHEN: Record deleted
        self.projector.delete_projector(record)

        # THEN: Verify record not retrievable
        found = self.projector.get_projector_by_ip(TEST3_DATA.ip)
        self.assertFalse(found, "test_3 record should have been deleted")

    def record_edit_test(self):
        """
        Test edited record returns the same record ID with different data
        """
        # GIVEN: Record entries in database
        add_records(self, [TEST1_DATA, TEST2_DATA])

        # WHEN: We retrieve a specific record
        record = self.projector.get_projector_by_ip(TEST1_DATA.ip)
        record_id = record.id

        # WHEN: Data is changed
        record.ip = TEST3_DATA.ip
        record.port = TEST3_DATA.port
        record.pin = TEST3_DATA.pin
        record.name = TEST3_DATA.name
        record.location = TEST3_DATA.location
        record.notes = TEST3_DATA.notes
        updated = self.projector.update_projector(record)
        self.assertTrue(updated, "Save updated record should have returned True")
        record = self.projector.get_projector_by_ip(TEST3_DATA.ip)

        # THEN: Record ID should remain the same, but data should be changed
        self.assertEqual(record_id, record.id, "Edited record should have the same ID")
        self.assertTrue(compare_data(TEST3_DATA, record), "Edited record should have new data")

    def source_add_test(self):
        """
        Test source entry for projector item
        """
        # GIVEN: Record entries in database
        self.projector.add_projector(TEST1_DATA)
        item = self.projector.get_projector_by_id(TEST1_DATA.id)
        item_id = item.id

        # WHEN: A source entry is saved for item
        source = ProjectorSource(projector_id=item_id, code="11", text="First RGB source")
        self.projector.add_source(source)

        # THEN: Projector should have the same source entry
        item = self.projector.get_projector_by_id(item_id)
        self.assertTrue(compare_source(item.source_list[0], source))
class ProjectorSourceFormTest(TestCase, TestMixin):
    """
    Test class for the Projector Source Select form module
    """
    @patch('openlp.core.lib.projector.db.init_url')
    def setUp(self, mocked_init_url):
        """
        Set up anything necessary for all tests
        """
        mocked_init_url.return_value = 'sqlite:///{}'.format(TEST_DB)
        self.build_settings()
        self.setup_application()
        Registry.create()
        # Do not try to recreate if we've already been created from a previous test
        if not hasattr(self, 'projectordb'):
            self.projectordb = ProjectorDB()
        # Retrieve/create a database record
        self.projector = self.projectordb.get_projector_by_ip(TEST1_DATA['ip'])
        if not self.projector:
            self.projectordb.add_projector(projector=Projector(**TEST1_DATA))
            self.projector = self.projectordb.get_projector_by_ip(TEST1_DATA['ip'])
        self.projector.dbid = self.projector.id
        self.projector.db_item = self.projector

    def tearDown(self):
        """
        Close database session.
        Delete all C++ objects at end so we don't segfault.
        """
        self.projectordb.session.close()
        del(self.projectordb)
        del(self.projector)
        retries = 0
        while retries < 5:
            try:
                if os.path.exists(TEST_DB):
                    os.unlink(TEST_DB)
                break
            except:
                time.sleep(1)
                retries += 1
        self.destroy_settings()

    def test_source_dict(self):
        """
        Test that source list dict returned from sourceselectform module is a valid dict with proper entries
        """
        # GIVEN: A list of inputs
        codes = []
        for item in PJLINK_DEFAULT_CODES.keys():
            codes.append(item)
        codes.sort()

        # WHEN: projector.sourceselectform.source_select() is called
        check = source_group(codes, PJLINK_DEFAULT_CODES)

        # THEN: return dictionary should match test dictionary
        self.assertEquals(check, build_source_dict(),
                          "Source group dictionary should match test dictionary")

    @patch.object(QDialog, 'exec')
    def test_source_select_edit_button(self, mocked_qdialog):
        """
        Test source select form edit has Ok, Cancel, Reset, and Revert buttons
        """
        # GIVEN: Initial setup and mocks
        self.projector.source_available = ['11', ]
        self.projector.source = '11'

        # WHEN we create a source select widget and set edit=True
        select_form = SourceSelectSingle(parent=None, projectordb=self.projectordb)
        select_form.edit = True
        select_form.exec(projector=self.projector)
        projector = select_form.projector

        # THEN: Verify all 4 buttons are available
        self.assertEquals(len(select_form.button_box.buttons()), 4,
                          'SourceSelect dialog box should have "OK", "Cancel" '
                          '"Rest", and "Revert" buttons available')

    @patch.object(QDialog, 'exec')
    def test_source_select_noedit_button(self, mocked_qdialog):
        """
        Test source select form view has OK and Cancel buttons only
        """
        # GIVEN: Initial setup and mocks
        self.projector.source_available = ['11', ]
        self.projector.source = '11'

        # WHEN we create a source select widget and set edit=False
        select_form = SourceSelectSingle(parent=None, projectordb=self.projectordb)
        select_form.edit = False
        select_form.exec(projector=self.projector)
        projector = select_form.projector

        # THEN: Verify only 2 buttons are available
        self.assertEquals(len(select_form.button_box.buttons()), 2,
                          'SourceSelect dialog box should only have "OK" '
                          'and "Cancel" buttons available')
Example #16
0
class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget,
                       Ui_ProjectorManager, RegistryProperties):
    """
    Manage the projectors.
    """
    def __init__(self, parent=None, projectordb=None):
        """
        Basic initialization.

        :param parent: Who I belong to.
        :param projectordb: Database session inherited from superclass.
        """
        log.debug('__init__()')
        super().__init__(parent)
        self.settings_section = 'projector'
        self.projectordb = projectordb
        self.projector_list = []
        self.source_select_form = None

    def bootstrap_initialise(self):
        """
        Pre-initialize setups.
        """
        self.setup_ui(self)
        if self.projectordb is None:
            # Work around for testing creating a ~/.openlp.data.projector.projector.sql file
            log.debug('Creating new ProjectorDB() instance')
            self.projectordb = ProjectorDB()
        else:
            log.debug('Using existing ProjectorDB() instance')
        self.get_settings()

    def bootstrap_post_set_up(self):
        """
        Post-initialize setups.
        """
        # Set 1.5 second delay before loading all projectors
        if self.autostart:
            log.debug('Delaying 1.5 seconds before loading all projectors')
            QtCore.QTimer().singleShot(1500, self._load_projectors)
        else:
            log.debug('Loading all projectors')
            self._load_projectors()
        self.projector_form = ProjectorEditForm(self,
                                                projectordb=self.projectordb)
        self.projector_form.newProjector.connect(
            self.add_projector_from_wizard)
        self.projector_form.editProjector.connect(
            self.edit_projector_from_wizard)
        self.projector_list_widget.itemSelectionChanged.connect(
            self.update_icons)

    def get_settings(self):
        """
        Retrieve the saved settings
        """
        settings = Settings()
        settings.beginGroup(self.settings_section)
        self.autostart = settings.value('connect on start')
        self.poll_time = settings.value('poll time')
        self.socket_timeout = settings.value('socket timeout')
        self.source_select_dialog_type = settings.value('source dialog type')
        settings.endGroup()
        del settings

    def context_menu(self, point):
        """
        Build the Right Click Context menu and set state.

        :param point: The position of the mouse so the correct item can be found.
        """
        # QListWidgetItem to build menu for.
        item = self.projector_list_widget.itemAt(point)
        if item is None:
            return
        real_projector = item.data(QtCore.Qt.UserRole)
        projector_name = str(item.text())
        visible = real_projector.link.status_connect >= S_CONNECTED
        log.debug('(%s) Building menu - visible = %s' %
                  (projector_name, visible))
        self.delete_action.setVisible(True)
        self.edit_action.setVisible(True)
        self.connect_action.setVisible(not visible)
        self.disconnect_action.setVisible(visible)
        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 not real_projector.link.shutter)
            self.show_action.setVisible(real_projector.link.power == S_ON
                                        and 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)
            self.show_action.setVisible(False)
        self.menu.projector = real_projector
        self.menu.exec_(self.projector_list_widget.mapToGlobal(point))

    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.

        :param opt: Needed by PyQt4
        """
        self.get_settings()  # In case the dialog interface setting was changed
        list_item = self.projector_list_widget.item(
            self.projector_list_widget.currentRow())
        projector = list_item.data(QtCore.Qt.UserRole)
        # QTabwidget for source select
        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))
        return

    def on_add_projector(self, opt=None):
        """
        Calls edit dialog to add a new projector to the database

        :param opt: Needed by PyQt4
        """
        self.projector_form.exec_()

    def on_blank_projector(self, opt=None):
        """
        Calls projector thread to send blank screen command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_shutter_closed()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_shutter_closed()
                except:
                    continue

    def on_doubleclick_item(self, item, opt=None):
        """
        When item is doubleclicked, will connect to projector.

        :param item: List widget item for connection.
        :param opt: Needed by PyQt4
        """
        projector = item.data(QtCore.Qt.UserRole)
        if projector.link.state() != projector.link.ConnectedState:
            try:
                projector.link.connect_to_host()
            except:
                pass
        return

    def on_connect_projector(self, opt=None):
        """
        Calls projector thread to connect to projector

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.connect_to_host()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.connect_to_host()
                except:
                    continue

    def on_delete_projector(self, opt=None):
        """
        Deletes a projector from the list and the database

        :param opt: Needed by PyQt4
        """
        list_item = self.projector_list_widget.item(
            self.projector_list_widget.currentRow())
        if list_item is None:
            return
        projector = list_item.data(QtCore.Qt.UserRole)
        msg = QtGui.QMessageBox()
        msg.setText('Delete projector (%s) %s?' %
                    (projector.link.ip, projector.link.name))
        msg.setInformativeText(
            'Are you sure you want to delete this projector?')
        msg.setStandardButtons(msg.Cancel | msg.Ok)
        msg.setDefaultButton(msg.Cancel)
        ans = msg.exec_()
        if ans == msg.Cancel:
            return
        try:
            projector.link.projectorNetwork.disconnect(self.update_status)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.changeStatus.disconnect(self.update_status)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.authentication_error.disconnect(
                self.authentication_error)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.no_authentication_error.disconnect(
                self.no_authentication_error)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.projectorUpdateIcons.disconnect(self.update_icons)
        except (AttributeError, TypeError):
            pass
        try:
            projector.timer.stop()
            projector.timer.timeout.disconnect(projector.link.poll_loop)
        except (AttributeError, TypeError):
            pass
        try:
            projector.socket_timer.stop()
            projector.socket_timer.timeout.disconnect(
                projector.link.socket_abort)
        except (AttributeError, TypeError):
            pass
        projector.thread.quit()
        new_list = []
        for item in self.projector_list:
            if item.link.dbid == projector.link.dbid:
                continue
            new_list.append(item)
        self.projector_list = new_list
        list_item = self.projector_list_widget.takeItem(
            self.projector_list_widget.currentRow())
        list_item = None
        deleted = self.projectordb.delete_projector(projector.db_item)
        for item in self.projector_list:
            log.debug('New projector list - item: %s %s' %
                      (item.link.ip, item.link.name))

    def on_disconnect_projector(self, opt=None):
        """
        Calls projector thread to disconnect from projector

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.disconnect_from_host()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.disconnect_from_host()
                except:
                    continue

    def on_edit_projector(self, opt=None):
        """
        Calls edit dialog with selected projector to edit information

        :param opt: Needed by PyQt4
        """
        list_item = self.projector_list_widget.item(
            self.projector_list_widget.currentRow())
        projector = list_item.data(QtCore.Qt.UserRole)
        if projector is None:
            return
        self.old_projector = projector
        projector.link.disconnect_from_host()
        self.projector_form.exec_(projector.db_item)
        projector.db_item = self.projectordb.get_projector_by_id(
            self.old_projector.db_item.id)

    def on_poweroff_projector(self, opt=None):
        """
        Calls projector link to send Power Off command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_power_off()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_power_off()
                except:
                    continue

    def on_poweron_projector(self, opt=None):
        """
        Calls projector link to send Power On command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_power_on()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_power_on()
                except:
                    continue

    def on_show_projector(self, opt=None):
        """
        Calls projector thread to send open shutter command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_shutter_open()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_shutter_open()
                except:
                    continue

    def on_status_projector(self, opt=None):
        """
        Builds message box with projector status information

        :param opt: Needed by PyQt4
        """
        lwi = self.projector_list_widget.item(
            self.projector_list_widget.currentRow())
        projector = lwi.data(QtCore.Qt.UserRole)
        message = '<b>%s</b>: %s<BR />' % (translate(
            'OpenLP.ProjectorManager', 'Name'), projector.link.name)
        message = '%s<b>%s</b>: %s<br />' % (
            message, translate('OpenLP.ProjectorManager',
                               'IP'), projector.link.ip)
        message = '%s<b>%s</b>: %s<br />' % (
            message, translate('OpenLP.ProjectorManager',
                               'Port'), projector.link.port)
        message = '%s<b>%s</b>: %s<br />' % (
            message, translate('OpenLP.ProjectorManager',
                               'Notes'), projector.link.notes)
        message = '%s<hr /><br >' % message
        if projector.link.manufacturer is None:
            message = '%s%s' % (
                message,
                translate('OpenLP.ProjectorManager',
                          'Projector information not available at this time.'))
        else:
            message = '%s<b>%s</b>: %s<BR />' % (
                message, translate(
                    'OpenLP.ProjectorManager',
                    'Projector Name'), projector.link.pjlink_name)
            message = '%s<b>%s</b>: %s<br />' % (
                message, translate('OpenLP.ProjectorManager', 'Manufacturer'),
                projector.link.manufacturer)
            message = '%s<b>%s</b>: %s<br />' % (
                message, translate('OpenLP.ProjectorManager',
                                   'Model'), projector.link.model)
            message = '%s<b>%s</b>: %s<br /><br />' % (
                message, translate('OpenLP.ProjectorManager',
                                   'Other info'), projector.link.other_info)
            message = '%s<b>%s</b>: %s<br />' % (
                message, translate('OpenLP.ProjectorManager', 'Power status'),
                ERROR_MSG[projector.link.power])
            message = '%s<b>%s</b>: %s<br />' % (
                message, translate('OpenLP.ProjectorManager', 'Shutter is'),
                translate('OpenLP.ProjectorManager', 'Closed')
                if projector.link.shutter else translate('OpenLP', 'Open'))
            message = '%s<b>%s</b>: %s<br />' % (
                message,
                translate('OpenLP.ProjectorManager',
                          'Current source input is'), projector.link.source)
            count = 1
            for item in projector.link.lamp:
                message = '%s <b>%s %s</b> (%s) %s: %s<br />' % (
                    message, translate('OpenLP.ProjectorManager',
                                       'Lamp'), count,
                    translate('OpenLP.ProjectorManager', 'On') if item['On']
                    else translate('OpenLP.ProjectorManager', 'Off'),
                    translate('OpenLP.ProjectorManager',
                              'Hours'), item['Hours'])
                count = count + 1
            message = '%s<hr /><br />' % message
            if projector.link.projector_errors is None:
                message = '%s%s' % (message,
                                    translate('OpenLP.ProjectorManager',
                                              'No current errors or warnings'))
            else:
                message = '%s<b>%s</b>' % (message,
                                           translate(
                                               'OpenLP.ProjectorManager',
                                               'Current errors/warnings'))
                for (key, val) in projector.link.projector_errors.items():
                    message = '%s<b>%s</b>: %s<br />' % (message, key,
                                                         ERROR_MSG[val])
        QtGui.QMessageBox.information(
            self, translate('OpenLP.ProjectorManager',
                            'Projector Information'), message)

    def _add_projector(self, projector):
        """
        Helper app to build a projector instance

        :param projector: Dict of projector database information
        :returns: PJLink1() instance
        """
        log.debug('_add_projector()')
        return PJLink1(dbid=projector.id,
                       ip=projector.ip,
                       port=int(projector.port),
                       name=projector.name,
                       location=projector.location,
                       notes=projector.notes,
                       pin=None if projector.pin == '' else projector.pin,
                       poll_time=self.poll_time,
                       socket_timeout=self.socket_timeout)

    def add_projector(self, projector, start=False):
        """
        Builds manager list item, projector thread, and timer for projector instance.


        :param projector: Projector instance to add
        :param start: Start projector if True
        """
        item = ProjectorItem(link=self._add_projector(projector))
        item.db_item = projector
        icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[S_NOT_CONNECTED]))
        item.icon = icon
        widget = QtGui.QListWidgetItem(icon, item.link.name,
                                       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
        item.moveToThread(thread)
        thread.started.connect(item.link.thread_started)
        thread.finished.connect(item.link.thread_stopped)
        thread.finished.connect(thread.deleteLater)
        item.link.projectorNetwork.connect(self.update_status)
        item.link.changeStatus.connect(self.update_status)
        item.link.projectorAuthentication.connect(self.authentication_error)
        item.link.projectorNoAuthentication.connect(
            self.no_authentication_error)
        item.link.projectorUpdateIcons.connect(self.update_icons)
        timer = QtCore.QTimer(self)
        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(11000)
        socket_timer.timeout.connect(item.link.socket_abort)
        item.socket_timer = socket_timer
        thread.start()
        item.thread = thread
        item.link.timer = timer
        item.link.socket_timer = socket_timer
        item.link.widget = item.widget
        self.projector_list.append(item)
        if start:
            item.link.connect_to_host()
        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):
        """
        Add a projector from the edit dialog

        :param ip: IP address of new record item to find
        :param opts: Needed by PyQt4
        """
        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):
        """
        Update projector from the wizard edit page

        :param projector: Projector() instance of projector with updated information
        """
        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
        self.old_projector.link.port = projector.port
        self.old_projector.link.location = projector.location
        self.old_projector.link.notes = projector.notes
        self.old_projector.widget.setText(projector.name)

    def _load_projectors(self):
        """'
        Load projectors - only call when initializing
        """
        log.debug('_load_projectors()')
        self.projector_list_widget.clear()
        for item in self.projectordb.get_projector_all():
            self.add_projector(projector=item, start=self.autostart)

    def get_projector_list(self):
        """
        Return the list of active projectors

        :returns: list
        """
        return self.projector_list

    @pyqtSlot(str, int, str)
    def update_status(self, ip, status=None, msg=None):
        """
        Update the status information/icon for selected list item

        :param ip: IP address of projector
        :param status: Optional status code
        :param msg: Optional status message
        """
        if status is None:
            return
        item = None
        for list_item in self.projector_list:
            if ip == list_item.link.ip:
                item = list_item
                break
        message = translate('OpenLP.ProjectorManager',
                            'No message') if msg is None else msg
        if status in STATUS_STRING:
            status_code = STATUS_STRING[status]
            message = ERROR_MSG[status] if msg is None else msg
        elif status in ERROR_STRING:
            status_code = ERROR_STRING[status]
            message = ERROR_MSG[status] if msg is None else msg
        else:
            status_code = status
            message = ERROR_MSG[status] if msg is None else msg
        log.debug('(%s) updateStatus(status=%s) message: "%s"' %
                  (item.link.name, status_code, message))
        if status in STATUS_ICONS:
            if item.status == status:
                return
            item.status = status
            item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
            if status in ERROR_STRING:
                status_code = ERROR_STRING[status]
            elif status in STATUS_STRING:
                status_code = STATUS_STRING[status]
            log.debug('(%s) Updating icon with %s' %
                      (item.link.name, status_code))
            item.widget.setIcon(item.icon)
            self.update_icons()

    def get_toolbar_item(self, name, enabled=False, hidden=False):
        item = self.one_toolbar.findChild(QtGui.QAction, name)
        if item == 0:
            log.debug('No item found with name "%s"' % name)
            return
        item.setVisible(False if hidden else True)
        item.setEnabled(True if enabled else False)

    @pyqtSlot()
    def update_icons(self):
        """
        Update the icons when the selected projectors change
        """
        count = len(self.projector_list_widget.selectedItems())
        projector = None
        if count == 0:
            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_view_projector', hidden=True)
            self.get_toolbar_item('connect_projector')
            self.get_toolbar_item('disconnect_projector')
            self.get_toolbar_item('poweron_projector')
            self.get_toolbar_item('poweroff_projector')
            self.get_toolbar_item('blank_projector')
            self.get_toolbar_item('show_projector')
            self.get_toolbar_item('connect_projector_multiple', hidden=True)
            self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
            self.get_toolbar_item('poweron_projector_multiple', hidden=True)
            self.get_toolbar_item('poweroff_projector_multiple', hidden=True)
            self.get_toolbar_item('blank_projector_multiple', hidden=True)
            self.get_toolbar_item('show_projector_multiple', hidden=True)
        elif count == 1:
            projector = self.projector_list_widget.selectedItems()[0].data(
                QtCore.Qt.UserRole)
            connected = projector.link.state() == projector.link.ConnectedState
            power = projector.link.power == S_ON
            self.get_toolbar_item('connect_projector_multiple', hidden=True)
            self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
            self.get_toolbar_item('poweron_projector_multiple', hidden=True)
            self.get_toolbar_item('poweroff_projector_multiple', hidden=True)
            self.get_toolbar_item('blank_projector_multiple', hidden=True)
            self.get_toolbar_item('show_projector_multiple', hidden=True)
            if connected:
                self.get_toolbar_item('view_projector', enabled=True)
                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_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)
            self.get_toolbar_item('disconnect_projector', enabled=connected)
            self.get_toolbar_item('poweron_projector',
                                  enabled=connected
                                  and (projector.link.power == S_STANDBY))
            self.get_toolbar_item('poweroff_projector',
                                  enabled=connected
                                  and (projector.link.power == S_ON))
            if projector.link.shutter is not None:
                self.get_toolbar_item('blank_projector',
                                      enabled=(connected and power
                                               and not projector.link.shutter))
                self.get_toolbar_item('show_projector',
                                      enabled=(connected and power
                                               and projector.link.shutter))
            else:
                self.get_toolbar_item('blank_projector', enabled=False)
                self.get_toolbar_item('show_projector', enabled=False)
        else:
            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_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)
            self.get_toolbar_item('poweroff_projector', hidden=True)
            self.get_toolbar_item('blank_projector', hidden=True)
            self.get_toolbar_item('show_projector', hidden=True)
            self.get_toolbar_item('connect_projector_multiple',
                                  hidden=False,
                                  enabled=True)
            self.get_toolbar_item('disconnect_projector_multiple',
                                  hidden=False,
                                  enabled=True)
            self.get_toolbar_item('poweron_projector_multiple',
                                  hidden=False,
                                  enabled=True)
            self.get_toolbar_item('poweroff_projector_multiple',
                                  hidden=False,
                                  enabled=True)
            self.get_toolbar_item('blank_projector_multiple',
                                  hidden=False,
                                  enabled=True)
            self.get_toolbar_item('show_projector_multiple',
                                  hidden=False,
                                  enabled=True)

    @pyqtSlot(str)
    def authentication_error(self, name):
        """
        Display warning dialog when attempting to connect with invalid pin

        :param name: Name from QListWidgetItem
        """
        QtGui.QMessageBox.warning(
            self,
            translate('OpenLP.ProjectorManager',
                      '"%s" Authentication Error' % name),
            '<br />There was an authentication error while trying to connect.'
            '<br /><br />Please verify your PIN setting '
            'for projector item "%s"' % name)

    @pyqtSlot(str)
    def no_authentication_error(self, name):
        """
        Display warning dialog when pin saved for item but projector does not
        require pin.

        :param name: Name from QListWidgetItem
        """
        QtGui.QMessageBox.warning(
            self,
            translate('OpenLP.ProjectorManager',
                      '"%s" No Authentication Error' % name),
            '<br />PIN is set and projector does not require authentication.'
            '<br /><br />Please verify your PIN setting '
            'for projector item "%s"' % name)
Example #17
0
 def setUp(self, mocked_init_url):
     """
     Set up anything necessary for all tests
     """
     mocked_init_url.return_value = 'sqlite:///{db}'.format(db=TEST_DB)
     self.projector = ProjectorDB()
Example #18
0
class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, RegistryProperties):
    """
    Manage the projectors.
    """
    def __init__(self, parent=None, projectordb=None):
        """
        Basic initialization.

        :param parent: Who I belong to.
        :param projectordb: Database session inherited from superclass.
        """
        log.debug('__init__()')
        super().__init__(parent)
        self.settings_section = 'projector'
        self.projectordb = projectordb
        self.projector_list = []
        self.source_select_form = None

    def bootstrap_initialise(self):
        """
        Pre-initialize setups.
        """
        self.setup_ui(self)
        if self.projectordb is None:
            # Work around for testing creating a ~/.openlp.data.projector.projector.sql file
            log.debug('Creating new ProjectorDB() instance')
            self.projectordb = ProjectorDB()
        else:
            log.debug('Using existing ProjectorDB() instance')
        self.get_settings()

    def bootstrap_post_set_up(self):
        """
        Post-initialize setups.
        """
        # Set 1.5 second delay before loading all projectors
        if self.autostart:
            log.debug('Delaying 1.5 seconds before loading all projectors')
            QtCore.QTimer().singleShot(1500, self._load_projectors)
        else:
            log.debug('Loading all projectors')
            self._load_projectors()
        self.projector_form = ProjectorEditForm(self, projectordb=self.projectordb)
        self.projector_form.newProjector.connect(self.add_projector_from_wizard)
        self.projector_form.editProjector.connect(self.edit_projector_from_wizard)
        self.projector_list_widget.itemSelectionChanged.connect(self.update_icons)

    def get_settings(self):
        """
        Retrieve the saved settings
        """
        settings = Settings()
        settings.beginGroup(self.settings_section)
        self.autostart = settings.value('connect on start')
        self.poll_time = settings.value('poll time')
        self.socket_timeout = settings.value('socket timeout')
        self.source_select_dialog_type = settings.value('source dialog type')
        settings.endGroup()
        del settings

    def context_menu(self, point):
        """
        Build the Right Click Context menu and set state.

        :param point: The position of the mouse so the correct item can be found.
        """
        # QListWidgetItem to build menu for.
        item = self.projector_list_widget.itemAt(point)
        if item is None:
            return
        real_projector = item.data(QtCore.Qt.UserRole)
        projector_name = str(item.text())
        visible = real_projector.link.status_connect >= S_CONNECTED
        log.debug('(%s) Building menu - visible = %s' % (projector_name, visible))
        self.delete_action.setVisible(True)
        self.edit_action.setVisible(True)
        self.connect_action.setVisible(not visible)
        self.disconnect_action.setVisible(visible)
        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
                                         not real_projector.link.shutter)
            self.show_action.setVisible(real_projector.link.power == S_ON and
                                        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)
            self.show_action.setVisible(False)
        self.menu.projector = real_projector
        self.menu.exec_(self.projector_list_widget.mapToGlobal(point))

    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.

        :param opt: Needed by PyQt4
        """
        self.get_settings()  # In case the dialog interface setting was changed
        list_item = self.projector_list_widget.item(self.projector_list_widget.currentRow())
        projector = list_item.data(QtCore.Qt.UserRole)
        # QTabwidget for source select
        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))
        return

    def on_add_projector(self, opt=None):
        """
        Calls edit dialog to add a new projector to the database

        :param opt: Needed by PyQt4
        """
        self.projector_form.exec_()

    def on_blank_projector(self, opt=None):
        """
        Calls projector thread to send blank screen command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_shutter_closed()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_shutter_closed()
                except:
                    continue

    def on_doubleclick_item(self, item, opt=None):
        """
        When item is doubleclicked, will connect to projector.

        :param item: List widget item for connection.
        :param opt: Needed by PyQt4
        """
        projector = item.data(QtCore.Qt.UserRole)
        if projector.link.state() != projector.link.ConnectedState:
            try:
                projector.link.connect_to_host()
            except:
                pass
        return

    def on_connect_projector(self, opt=None):
        """
        Calls projector thread to connect to projector

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.connect_to_host()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.connect_to_host()
                except:
                    continue

    def on_delete_projector(self, opt=None):
        """
        Deletes a projector from the list and the database

        :param opt: Needed by PyQt4
        """
        list_item = self.projector_list_widget.item(self.projector_list_widget.currentRow())
        if list_item is None:
            return
        projector = list_item.data(QtCore.Qt.UserRole)
        msg = QtGui.QMessageBox()
        msg.setText('Delete projector (%s) %s?' % (projector.link.ip, projector.link.name))
        msg.setInformativeText('Are you sure you want to delete this projector?')
        msg.setStandardButtons(msg.Cancel | msg.Ok)
        msg.setDefaultButton(msg.Cancel)
        ans = msg.exec_()
        if ans == msg.Cancel:
            return
        try:
            projector.link.projectorNetwork.disconnect(self.update_status)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.changeStatus.disconnect(self.update_status)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.authentication_error.disconnect(self.authentication_error)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.no_authentication_error.disconnect(self.no_authentication_error)
        except (AttributeError, TypeError):
            pass
        try:
            projector.link.projectorUpdateIcons.disconnect(self.update_icons)
        except (AttributeError, TypeError):
            pass
        try:
            projector.timer.stop()
            projector.timer.timeout.disconnect(projector.link.poll_loop)
        except (AttributeError, TypeError):
            pass
        try:
            projector.socket_timer.stop()
            projector.socket_timer.timeout.disconnect(projector.link.socket_abort)
        except (AttributeError, TypeError):
            pass
        projector.thread.quit()
        new_list = []
        for item in self.projector_list:
            if item.link.dbid == projector.link.dbid:
                continue
            new_list.append(item)
        self.projector_list = new_list
        list_item = self.projector_list_widget.takeItem(self.projector_list_widget.currentRow())
        list_item = None
        deleted = self.projectordb.delete_projector(projector.db_item)
        for item in self.projector_list:
            log.debug('New projector list - item: %s %s' % (item.link.ip, item.link.name))

    def on_disconnect_projector(self, opt=None):
        """
        Calls projector thread to disconnect from projector

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.disconnect_from_host()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.disconnect_from_host()
                except:
                    continue

    def on_edit_projector(self, opt=None):
        """
        Calls edit dialog with selected projector to edit information

        :param opt: Needed by PyQt4
        """
        list_item = self.projector_list_widget.item(self.projector_list_widget.currentRow())
        projector = list_item.data(QtCore.Qt.UserRole)
        if projector is None:
            return
        self.old_projector = projector
        projector.link.disconnect_from_host()
        self.projector_form.exec_(projector.db_item)
        projector.db_item = self.projectordb.get_projector_by_id(self.old_projector.db_item.id)

    def on_poweroff_projector(self, opt=None):
        """
        Calls projector link to send Power Off command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_power_off()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_power_off()
                except:
                    continue

    def on_poweron_projector(self, opt=None):
        """
        Calls projector link to send Power On command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_power_on()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_power_on()
                except:
                    continue

    def on_show_projector(self, opt=None):
        """
        Calls projector thread to send open shutter command

        :param opt: Needed by PyQt4
        """
        try:
            ip = opt.link.ip
            projector = opt
            projector.link.set_shutter_open()
        except AttributeError:
            for list_item in self.projector_list_widget.selectedItems():
                if list_item is None:
                    return
                projector = list_item.data(QtCore.Qt.UserRole)
                try:
                    projector.link.set_shutter_open()
                except:
                    continue

    def on_status_projector(self, opt=None):
        """
        Builds message box with projector status information

        :param opt: Needed by PyQt4
        """
        lwi = self.projector_list_widget.item(self.projector_list_widget.currentRow())
        projector = lwi.data(QtCore.Qt.UserRole)
        message = '<b>%s</b>: %s<BR />' % (translate('OpenLP.ProjectorManager', 'Name'),
                                           projector.link.name)
        message = '%s<b>%s</b>: %s<br />' % (message, translate('OpenLP.ProjectorManager', 'IP'),
                                             projector.link.ip)
        message = '%s<b>%s</b>: %s<br />' % (message, translate('OpenLP.ProjectorManager', 'Port'),
                                             projector.link.port)
        message = '%s<b>%s</b>: %s<br />' % (message, translate('OpenLP.ProjectorManager', 'Notes'),
                                             projector.link.notes)
        message = '%s<hr /><br >' % message
        if projector.link.manufacturer is None:
            message = '%s%s' % (message, translate('OpenLP.ProjectorManager',
                                                   'Projector information not available at this time.'))
        else:
            message = '%s<b>%s</b>: %s<BR />' % (message, translate('OpenLP.ProjectorManager', 'Projector Name'),
                                                 projector.link.pjlink_name)
            message = '%s<b>%s</b>: %s<br />' % (message, translate('OpenLP.ProjectorManager', 'Manufacturer'),
                                                 projector.link.manufacturer)
            message = '%s<b>%s</b>: %s<br />' % (message, translate('OpenLP.ProjectorManager', 'Model'),
                                                 projector.link.model)
            message = '%s<b>%s</b>: %s<br /><br />' % (message, translate('OpenLP.ProjectorManager', 'Other info'),
                                                       projector.link.other_info)
            message = '%s<b>%s</b>: %s<br />' % (message, translate('OpenLP.ProjectorManager', 'Power status'),
                                                 ERROR_MSG[projector.link.power])
            message = '%s<b>%s</b>: %s<br />' % (message, translate('OpenLP.ProjectorManager', 'Shutter is'),
                                                 translate('OpenLP.ProjectorManager', 'Closed')
                                                 if projector.link.shutter else translate('OpenLP', 'Open'))
            message = '%s<b>%s</b>: %s<br />' % (message,
                                                 translate('OpenLP.ProjectorManager', 'Current source input is'),
                                                 projector.link.source)
            count = 1
            for item in projector.link.lamp:
                message = '%s <b>%s %s</b> (%s) %s: %s<br />' % (message,
                                                                 translate('OpenLP.ProjectorManager', 'Lamp'),
                                                                 count,
                                                                 translate('OpenLP.ProjectorManager', 'On')
                                                                 if item['On']
                                                                 else translate('OpenLP.ProjectorManager', 'Off'),
                                                                 translate('OpenLP.ProjectorManager', 'Hours'),
                                                                 item['Hours'])
                count = count + 1
            message = '%s<hr /><br />' % message
            if projector.link.projector_errors is None:
                message = '%s%s' % (message, translate('OpenLP.ProjectorManager', 'No current errors or warnings'))
            else:
                message = '%s<b>%s</b>' % (message, translate('OpenLP.ProjectorManager', 'Current errors/warnings'))
                for (key, val) in projector.link.projector_errors.items():
                    message = '%s<b>%s</b>: %s<br />' % (message, key, ERROR_MSG[val])
        QtGui.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message)

    def _add_projector(self, projector):
        """
        Helper app to build a projector instance

        :param projector: Dict of projector database information
        :returns: PJLink1() instance
        """
        log.debug('_add_projector()')
        return PJLink1(dbid=projector.id,
                       ip=projector.ip,
                       port=int(projector.port),
                       name=projector.name,
                       location=projector.location,
                       notes=projector.notes,
                       pin=None if projector.pin == '' else projector.pin,
                       poll_time=self.poll_time,
                       socket_timeout=self.socket_timeout
                       )

    def add_projector(self, projector, start=False):
        """
        Builds manager list item, projector thread, and timer for projector instance.


        :param projector: Projector instance to add
        :param start: Start projector if True
        """
        item = ProjectorItem(link=self._add_projector(projector))
        item.db_item = projector
        icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[S_NOT_CONNECTED]))
        item.icon = icon
        widget = QtGui.QListWidgetItem(icon,
                                       item.link.name,
                                       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
        item.moveToThread(thread)
        thread.started.connect(item.link.thread_started)
        thread.finished.connect(item.link.thread_stopped)
        thread.finished.connect(thread.deleteLater)
        item.link.projectorNetwork.connect(self.update_status)
        item.link.changeStatus.connect(self.update_status)
        item.link.projectorAuthentication.connect(self.authentication_error)
        item.link.projectorNoAuthentication.connect(self.no_authentication_error)
        item.link.projectorUpdateIcons.connect(self.update_icons)
        timer = QtCore.QTimer(self)
        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(11000)
        socket_timer.timeout.connect(item.link.socket_abort)
        item.socket_timer = socket_timer
        thread.start()
        item.thread = thread
        item.link.timer = timer
        item.link.socket_timer = socket_timer
        item.link.widget = item.widget
        self.projector_list.append(item)
        if start:
            item.link.connect_to_host()
        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):
        """
        Add a projector from the edit dialog

        :param ip: IP address of new record item to find
        :param opts: Needed by PyQt4
        """
        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):
        """
        Update projector from the wizard edit page

        :param projector: Projector() instance of projector with updated information
        """
        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
        self.old_projector.link.port = projector.port
        self.old_projector.link.location = projector.location
        self.old_projector.link.notes = projector.notes
        self.old_projector.widget.setText(projector.name)

    def _load_projectors(self):
        """'
        Load projectors - only call when initializing
        """
        log.debug('_load_projectors()')
        self.projector_list_widget.clear()
        for item in self.projectordb.get_projector_all():
            self.add_projector(projector=item, start=self.autostart)

    def get_projector_list(self):
        """
        Return the list of active projectors

        :returns: list
        """
        return self.projector_list

    @pyqtSlot(str, int, str)
    def update_status(self, ip, status=None, msg=None):
        """
        Update the status information/icon for selected list item

        :param ip: IP address of projector
        :param status: Optional status code
        :param msg: Optional status message
        """
        if status is None:
            return
        item = None
        for list_item in self.projector_list:
            if ip == list_item.link.ip:
                item = list_item
                break
        message = translate('OpenLP.ProjectorManager', 'No message') if msg is None else msg
        if status in STATUS_STRING:
            status_code = STATUS_STRING[status]
            message = ERROR_MSG[status] if msg is None else msg
        elif status in ERROR_STRING:
            status_code = ERROR_STRING[status]
            message = ERROR_MSG[status] if msg is None else msg
        else:
            status_code = status
            message = ERROR_MSG[status] if msg is None else msg
        log.debug('(%s) updateStatus(status=%s) message: "%s"' % (item.link.name, status_code, message))
        if status in STATUS_ICONS:
            if item.status == status:
                return
            item.status = status
            item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
            if status in ERROR_STRING:
                status_code = ERROR_STRING[status]
            elif status in STATUS_STRING:
                status_code = STATUS_STRING[status]
            log.debug('(%s) Updating icon with %s' % (item.link.name, status_code))
            item.widget.setIcon(item.icon)
            self.update_icons()

    def get_toolbar_item(self, name, enabled=False, hidden=False):
        item = self.one_toolbar.findChild(QtGui.QAction, name)
        if item == 0:
            log.debug('No item found with name "%s"' % name)
            return
        item.setVisible(False if hidden else True)
        item.setEnabled(True if enabled else False)

    @pyqtSlot()
    def update_icons(self):
        """
        Update the icons when the selected projectors change
        """
        count = len(self.projector_list_widget.selectedItems())
        projector = None
        if count == 0:
            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_view_projector', hidden=True)
            self.get_toolbar_item('connect_projector')
            self.get_toolbar_item('disconnect_projector')
            self.get_toolbar_item('poweron_projector')
            self.get_toolbar_item('poweroff_projector')
            self.get_toolbar_item('blank_projector')
            self.get_toolbar_item('show_projector')
            self.get_toolbar_item('connect_projector_multiple', hidden=True)
            self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
            self.get_toolbar_item('poweron_projector_multiple', hidden=True)
            self.get_toolbar_item('poweroff_projector_multiple', hidden=True)
            self.get_toolbar_item('blank_projector_multiple', hidden=True)
            self.get_toolbar_item('show_projector_multiple', hidden=True)
        elif count == 1:
            projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole)
            connected = projector.link.state() == projector.link.ConnectedState
            power = projector.link.power == S_ON
            self.get_toolbar_item('connect_projector_multiple', hidden=True)
            self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
            self.get_toolbar_item('poweron_projector_multiple', hidden=True)
            self.get_toolbar_item('poweroff_projector_multiple', hidden=True)
            self.get_toolbar_item('blank_projector_multiple', hidden=True)
            self.get_toolbar_item('show_projector_multiple', hidden=True)
            if connected:
                self.get_toolbar_item('view_projector', enabled=True)
                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_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)
            self.get_toolbar_item('disconnect_projector', enabled=connected)
            self.get_toolbar_item('poweron_projector', enabled=connected and (projector.link.power == S_STANDBY))
            self.get_toolbar_item('poweroff_projector', enabled=connected and (projector.link.power == S_ON))
            if projector.link.shutter is not None:
                self.get_toolbar_item('blank_projector', enabled=(connected and power and not projector.link.shutter))
                self.get_toolbar_item('show_projector', enabled=(connected and power and projector.link.shutter))
            else:
                self.get_toolbar_item('blank_projector', enabled=False)
                self.get_toolbar_item('show_projector', enabled=False)
        else:
            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_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)
            self.get_toolbar_item('poweroff_projector', hidden=True)
            self.get_toolbar_item('blank_projector', hidden=True)
            self.get_toolbar_item('show_projector', hidden=True)
            self.get_toolbar_item('connect_projector_multiple', hidden=False, enabled=True)
            self.get_toolbar_item('disconnect_projector_multiple', hidden=False, enabled=True)
            self.get_toolbar_item('poweron_projector_multiple', hidden=False, enabled=True)
            self.get_toolbar_item('poweroff_projector_multiple', hidden=False, enabled=True)
            self.get_toolbar_item('blank_projector_multiple', hidden=False, enabled=True)
            self.get_toolbar_item('show_projector_multiple', hidden=False, enabled=True)

    @pyqtSlot(str)
    def authentication_error(self, name):
        """
        Display warning dialog when attempting to connect with invalid pin

        :param name: Name from QListWidgetItem
        """
        QtGui.QMessageBox.warning(self, translate('OpenLP.ProjectorManager',
                                                  '"%s" Authentication Error' % name),
                                  '<br />There was an authentication error while trying to connect.'
                                  '<br /><br />Please verify your PIN setting '
                                  'for projector item "%s"' % name)

    @pyqtSlot(str)
    def no_authentication_error(self, name):
        """
        Display warning dialog when pin saved for item but projector does not
        require pin.

        :param name: Name from QListWidgetItem
        """
        QtGui.QMessageBox.warning(self, translate('OpenLP.ProjectorManager',
                                                  '"%s" No Authentication Error' % name),
                                  '<br />PIN is set and projector does not require authentication.'
                                  '<br /><br />Please verify your PIN setting '
                                  'for projector item "%s"' % name)
Example #19
0
class TestProjectorDB(TestCase):
    """
    Test case for ProjectorDB
    """
    def setUp(self):
        """
        Set up anything necessary for all tests
        """
        if not hasattr(self, 'projector'):
            with patch('openlp.core.lib.projector.db.init_url'
                       ) as mocked_init_url:
                mocked_init_url.start()
                mocked_init_url.return_value = 'sqlite:///%s' % tmpfile
                self.projector = ProjectorDB()

    def find_record_by_ip_test(self):
        """
        Test find record by IP
        """
        # GIVEN: Record entries in database
        add_records(self, [TEST1_DATA, TEST2_DATA])

        # WHEN: Search for record using IP
        record = self.projector.get_projector_by_ip(TEST2_DATA.ip)

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(TEST2_DATA, record),
                        'Record found should have been test_2 data')

    def find_record_by_name_test(self):
        """
        Test find record by name
        """
        # GIVEN: Record entries in database
        add_records(self, [TEST1_DATA, TEST2_DATA])

        # WHEN: Search for record using name
        record = self.projector.get_projector_by_name(TEST2_DATA.name)

        # THEN: Verify proper record returned
        self.assertTrue(compare_data(TEST2_DATA, record),
                        'Record found should have been test_2 data')

    def record_delete_test(self):
        """
        Test record can be deleted
        """
        # GIVEN: Record in database
        add_records(self, [
            TEST3_DATA,
        ])
        record = self.projector.get_projector_by_ip(TEST3_DATA.ip)

        # WHEN: Record deleted
        self.projector.delete_projector(record)

        # THEN: Verify record not retrievable
        found = self.projector.get_projector_by_ip(TEST3_DATA.ip)
        self.assertFalse(found, 'test_3 record should have been deleted')

    def record_edit_test(self):
        """
        Test edited record returns the same record ID with different data
        """
        # GIVEN: Record entries in database
        add_records(self, [TEST1_DATA, TEST2_DATA])

        # WHEN: We retrieve a specific record
        record = self.projector.get_projector_by_ip(TEST1_DATA.ip)
        record_id = record.id

        # WHEN: Data is changed
        record.ip = TEST3_DATA.ip
        record.port = TEST3_DATA.port
        record.pin = TEST3_DATA.pin
        record.name = TEST3_DATA.name
        record.location = TEST3_DATA.location
        record.notes = TEST3_DATA.notes
        updated = self.projector.update_projector(record)
        self.assertTrue(updated,
                        'Save updated record should have returned True')
        record = self.projector.get_projector_by_ip(TEST3_DATA.ip)

        # THEN: Record ID should remain the same, but data should be changed
        self.assertEqual(record_id, record.id,
                         'Edited record should have the same ID')
        self.assertTrue(compare_data(TEST3_DATA, record),
                        'Edited record should have new data')

    def source_add_test(self):
        """
        Test source entry for projector item
        """
        # GIVEN: Record entries in database
        self.projector.add_projector(TEST1_DATA)
        item = self.projector.get_projector_by_id(TEST1_DATA.id)
        item_id = item.id

        # WHEN: A source entry is saved for item
        source = ProjectorSource(projector_id=item_id,
                                 code='11',
                                 text='First RGB source')
        self.projector.add_source(source)

        # THEN: Projector should have the same source entry
        item = self.projector.get_projector_by_id(item_id)
        self.assertTrue(compare_source(item.source_list[0], source))