예제 #1
0
class TestProjectMethods(unittest.TestCase):
    def setUp(self):
        self.project = Project()
        self.create_test_presentation(self.project)

    def test_to_json(self):
        test_json_data = r'[["kek", ["a.jpg", "b.jpg"]], ["heck", ["b.jpg", "a.jpg"]]]'
        generated_json_data = self.project.dump_json()
        self.assertEqual(sorted(generated_json_data), sorted(test_json_data))

    def test_load_json(self):
        test_json_data = r'[["mad", ["c.jpg", "d.jpg"]], ["sad", ["d.png", "c.png"]]]'
        proj = Project()
        proj.load_json(test_json_data)

        project_json = proj.dump_json()
        self.assertEqual(sorted(project_json), sorted(test_json_data))

    def create_test_presentation(self, project):
        name1 = "kek"
        presentation1 = Presentation()
        presentation1.set_files(["a.jpg", "b.jpg"])

        name2 = "heck"
        presentation2 = Presentation()
        presentation2.set_files(["b.jpg", "a.jpg"])

        project.presentations.append((name1, presentation1))
        project.presentations.append((name2, presentation2))

    def test_removing_from_presentations(self):
        self.project.remove_from_presentations("kek")
        self.assertEqual(len(self.project.presentations), 1)
        self.assertEqual(self.project.presentations[0][0], "heck")
예제 #2
0
    def test_load_json(self):
        test_json_data = r'[["mad", ["c.jpg", "d.jpg"]], ["sad", ["d.png", "c.png"]]]'
        proj = Project()
        proj.load_json(test_json_data)

        project_json = proj.dump_json()
        self.assertEqual(sorted(project_json), sorted(test_json_data))
예제 #3
0
 def __init__(self, **kwargs):
     super(ProjectOverview, self).__init__(**kwargs)
     self.slave_buttons = {}
     self.slave_presentations = {}
     self.project = Project()
     self.effect_cls = ScrollEffect
     self.max = 1
     self.in_editor_mode = True
예제 #4
0
 def open_project(self, path, selection, savefilename=None):
     """
     A callback method to be called when the file to open has been selected
     by the user.
     :param path: the path to open the project file from
     :param selection: a list, the selected file will be in the first index
     :return: None
     """
     json_str = read_file(os.path.join(path, selection[0]))
     try:
         project = Project()
         project.load_json(json_str)
         self.master.setup_project(project)
         self.master.layout.clear_presentations()
         self.master.load_project_to_gui()
     except Exception as ex:
         ExceptionAlertPopUp("Error while opening project", ex).open()
예제 #5
0
 def setUp(self):
     self.project = Project()
     self.master = Master(None)
     self.master.project = self.project
     self.path = PathConstants.ABSOLUTE_TEST_MEDIA_FOLDER
     self.test_file = "project_test_file"
     self.test_file_with_extension = self.test_file + ".remu"
     self.test_file_with_path = os.path.join(self.path,
                                             self.test_file_with_extension)
     self.popup = ProjectSavePopUp(self.master, self.path, True)
예제 #6
0
    def test_setup_project_with_nonexistent_file(self):
        project = Project()
        name1 = "test1"
        presentation1 = Presentation()
        presentation1.set_files(["abadababababababbabababbababab.jpg", "b.jpg"])

        project.presentations.append((name1, presentation1))

        self.mock_master.setup_project(project, PathConstants.ABSOLUTE_TEST_MEDIA_FOLDER)
        self.mock_master.layout.setup_project.assert_not_called()
        self.assertNotEqual(self.mock_master.project, project)
예제 #7
0
    def test_setup_project_with_valid_project(self):
        project = Project()
        name1 = "test1"
        presentation1 = Presentation()
        presentation1.set_files(["a.jpg", "b.jpg"])

        name2 = "test2"
        presentation2 = Presentation()
        presentation2.set_files(["b.jpg", "a.jpg"])

        project.presentations.append((name1, presentation1))
        project.presentations.append((name2, presentation2))

        self.mock_master.setup_project(project, PathConstants.ABSOLUTE_TEST_MEDIA_FOLDER)
        self.mock_master.layout.setup_project.assert_called_once_with(project)
        self.assertEqual(self.mock_master.project, project)
예제 #8
0
파일: RemuApp.py 프로젝트: RemuTeam/Remu
    def create_servicemode(self, layout, is_master):
        """
        Creates a new service object and sets it in the self.servicemode

        layout: the layout to bind with self.servicemode
        """
        if is_master:
            new_master = Master(layout)
            self.set_servicemode(new_master, True)
            empty_project = Project()

            # Uncomment to test
            # empty_project.create_test_presentation()
            new_master.setup_project(empty_project)
            new_master.load_project_to_gui()
        else:
            new_slave = Slave(layout)
            tcp_port = self.config.getint('tcp port')
            new_slave.set_master_connection(RemuTCP(new_slave, port=tcp_port))
            self.set_servicemode(new_slave, False)
예제 #9
0
 def setUp(self):
     self.project = Project()
     self.create_test_presentation(self.project)
예제 #10
0
class ProjectOverview(BoxLayout):
    """
    ProjectOverview class is used in the master GUI, to keep track of the slaves in the presentation. It maintains two
    lists: slave_buttons and slave_presentations. For each slave, ProjectOverview has a button in slave_buttons and a
    SlavePresentation in slave_presentations.
    """
    def __init__(self, **kwargs):
        super(ProjectOverview, self).__init__(**kwargs)
        self.slave_buttons = {}
        self.slave_presentations = {}
        self.project = Project()
        self.effect_cls = ScrollEffect
        self.max = 1
        self.in_editor_mode = True

    def new_presentation_to_overview(self, name, given_presentation=None):
        """
        Creates a new GUI element for a single presentation. Is used when creating a new presentation and when loading
        a saved presentation
        :param name:
        :return: Nothing
        """
        master = App.get_running_app().servicemode
        if given_presentation is None:
            given_presentation = Presentation(name)
            self.project.presentations.append((name, given_presentation))
        new_slave_presentation = SlavePresentation(given_presentation)
        #button = Button(text=name, size_hint=(1, 0.2))
        #lf = lambda a: BindPresentationToSlavePopUp(master.slave_connections.keys(), new_presentation.get_presentation_from_widgets(), master, button).open()
        #button.on_press = lf
        self.slave_buttons[name] = SlavePresentationButton(text=name,
                                                           size_hint=(1, 0.2))
        self.slave_buttons[name].bind(
            on_press=lambda a: self.slave_button_action(
                new_slave_presentation.get_presentation_from_widgets(), self.
                slave_buttons[name]))
        self.slave_presentations[name] = new_slave_presentation
        #self.project.presentations.append((name, given_presentation))
        self.ids.slave_names.add_widget(self.slave_buttons[name])
        self.ids.slave_presentations.add_widget(self.slave_presentations[name])
        self.max = max(self.max, len(given_presentation))
        self.update_presentation_widths()

    def slave_button_action(self, presentation, button):
        master = App.get_running_app().servicemode
        if self.in_editor_mode:
            BindPresentationToSlavePopUp(master.slave_connections.keys(),
                                         presentation, master, button).open()
        else:
            button.slave_connection.show_next()

    def add_files_to_a_presentation(self, presentation_name, import_list):
        """
        Adds files to a single presentation based on the filenames given in the import list
        :param presentation_name: presentation to be added to
        :param import_list: filenames to be added to presentation
        :return:
        """
        self.slave_presentations[
            presentation_name].update_presentation_content(import_list)
        self.max = max(
            self.max, len(self.slave_presentations[presentation_name].visuals))
        self.ids.slave_presentations.width = self.width / 6 * self.max
        self.update_presentation_widths()

    def update_slave_to_overview(self, slave_connection):
        """
        Updates the ProjectOverview in the master's GUI. If a slave with an IP is already in the list, it is still deleted
        so that all changes in the slave's presentation will show.
        :param slave_connection: Slave's presentation data
        :return:
        """
        #slave_connection, "slave" + str(self.presentation_counter)
        self.remove_slave_from_overview(slave_connection.full_address)
        self.max = max(self.max, len(slave_connection.presentation))
        self.slave_buttons[slave_connection.full_address] = Button(
            text=slave_connection.full_address,
            size_hint=(1, 0.2),
            on_press=lambda a: slave_connection.show_next())
        self.slave_presentations[
            slave_connection.full_address] = SlavePresentation(
                slave_connection.presentation)
        self.ids.slave_presentations.width = len(
            slave_connection.presentation) * self.width / 6
        """if len(slave_connection.presentation) > self.ids.slave_presentations.width/150 else self.width --- was in the statement above, not sure if necessary :^)"""
        self.ids.slave_names.add_widget(
            self.slave_buttons[slave_connection.full_address])
        self.ids.slave_presentations.add_widget(
            self.slave_presentations[slave_connection.full_address])
        self.update_presentation_widths()

    def setup_presentation(self):
        self.in_editor_mode = False
        self.disable_rearrangement_of_buttons()

    def end_presentation(self):
        self.in_editor_mode = True
        self.reset_all_presentations()

    def update_presentation_widths(self):
        """
        Scales the SlaveVisualProperties in proportion to the longest presentation.
        :return:
        """
        for sp in self.slave_presentations.values():
            for budons in sp.children:
                budons.size_hint_x = 1 / self.max

    def remove_slave_from_overview(self, address):
        """
        Removes the slave's information from the slave_buttons and slave_presentations list, and removes the widgets
        associated with it.
        :param address: The key which is used for deleting
        :return: Nothing
        """
        if address in self.slave_buttons.keys(
        ) or address in self.slave_presentations.keys():
            self.ids.slave_names.remove_widget(self.slave_buttons[address])
            self.ids.slave_presentations.remove_widget(
                self.slave_presentations[address])
            del self.slave_buttons[address]
            del self.slave_presentations[address]

    def update_presentation_state(self):
        """
        Automatically progresses the scrollview forward based on where the presentation is at
        :return:
        """
        current = 9999
        for slave_presentation in self.slave_presentations.values():
            current = min(current, slave_presentation.update_status())
        self.ids.scrollview.scroll_x = (current +
                                        1) / self.max if current >= 1 else 0

    def reset_all_presentations(self):
        """
        Resets the presentations to their starting states and allows their
        elements to be rearranged.
        :return:
        """
        for presentation in self.slave_presentations.values():
            presentation.change_draggability(True)
            presentation.reset()

    def disable_rearrangement_of_buttons(self):
        """
        Called when Master starts the presentation so that the
        presentation elements won't be out of sync with what the
        slaves are showing.
        :return:
        """
        for presentation in self.slave_presentations.values():
            presentation.change_draggability(False)

    def notify_connection_lost(self, slave_connection):
        if slave_connection.presentation is not None:
            try:
                button = self.slave_buttons[slave_connection.presentation.name]
                button.background_color = (1, 0, 0, 0.8)
            except:
                pass

    def remove_presentation(self, name):
        """
        Masterlayout calls this method for all presentations that are to be removed from master_layout
        :param name:
        :return:
        """
        self.project.remove_from_presentations(name)
        self.ids.slave_presentations.remove_widget(
            self.slave_presentations[name])
        self.ids.slave_names.remove_widget(self.slave_buttons[name])
        del self.slave_buttons[name]
        del self.slave_presentations[name]

    def remove_presentations(self):
        """
        Clears all presentations in the ProjectOverview. Called when
        opening an existing project.
        :return:
        """
        self.ids.slave_presentations.clear_widgets()
        self.ids.slave_names.clear_widgets()
        self.slave_buttons = {}
        self.slave_presentations = {}