class Application(metaclass=Singleton):
    def __init__(self):
        self._mainWindow = MainWindow()
        self._app_conf = {}
        self._layout = None
        self._memento_model = None
        self._cue_model = CueModel()

        # Connect mainWindow actions
        self._mainWindow.new_session.connect(self.new_session_dialog)
        self._mainWindow.save_session.connect(self._save_to_file)
        self._mainWindow.open_session.connect(self._load_from_file)

        # Register general settings widget
        AppSettings.register_settings_widget(AppGeneral)
        AppSettings.register_settings_widget(CueAppSettings)

        # Show the mainWindow maximized
        self._mainWindow.showMaximized()

    @property
    def layout(self):
        """:rtype: lisp.layouts.cue_layout.CueLayout"""
        return self._layout

    @property
    def cue_model(self):
        """:rtype: lisp.cues.cue_model.CueModel"""
        return self._cue_model

    def start(self, session_file=''):
        if exists(session_file):
            self._load_from_file(session_file)
        elif cfg.config['Layout']['Default'].lower() != 'nodefault':
            layout = layouts.get_layout(cfg.config['Layout']['Default'])
            self._new_session(layout)
        else:
            self.new_session_dialog()

    def new_session_dialog(self):
        """Show the layout-selection dialog"""
        try:
            # Prompt the user for a new layout
            dialog = LayoutSelect()
            if dialog.exec_() != QDialog.Accepted:
                if self._layout is None:
                    # If the user close the dialog, and no layout exists
                    # the application is closed
                    self.finalize()
                    qApp.quit()
                    exit()
                else:
                    return

            # If a valid file is selected load it, otherwise load the layout
            if exists(dialog.filepath):
                self._load_from_file(dialog.filepath)
            else:
                self._new_session(dialog.selected())

        except Exception as e:
            elogging.exception('Startup error', e)
            qApp.quit()
            exit(-1)

    def _new_session(self, layout):
        self._delete_session()

        self._layout = layout(self._cue_model)
        self._memento_model = AdapterMementoModel(self.layout.model_adapter)
        self._mainWindow.set_layout(self._layout)
        self._app_conf['layout'] = layout.NAME

        plugins.init_plugins()

    def _delete_session(self):
        if self._layout is not None:
            MainActionsHandler.clear()
            plugins.reset_plugins()

            self._app_conf.clear()
            self._cue_model.reset()

            self._layout.finalize()
            self._layout = None
            self._memento_model = None
            self._cue_model.reset()

    def finalize(self):
        modules.terminate_modules()

        self._delete_session()
        self._mainWindow.deleteLater()

    def _save_to_file(self, session_file):
        """Save the current session into a file."""
        session = {"cues": [], "plugins": {}, "application": []}

        # Add the cues
        for cue in self._cue_model:
            session['cues'].append(cue.properties(only_changed=True))
        # Sort cues by index, allow sorted-models to load properly
        session['cues'].sort(key=lambda cue: cue['index'])

        session['plugins'] = plugins.get_plugin_settings()
        session['application'] = self._app_conf

        # Write to a file the json-encoded dictionary
        with open(session_file, mode='w', encoding='utf-8') as file:
            file.write(json.dumps(session, sort_keys=True, indent=4))

        MainActionsHandler.set_saved()
        self._mainWindow.update_window_title()

    def _load_from_file(self, session_file):
        """ Load a saved session from file """
        try:
            with open(session_file, mode='r', encoding='utf-8') as file:
                session = json.load(file)

            # New session
            self._new_session(
                layouts.get_layout(session['application']['layout']))
            # Get the application settings
            self._app_conf = session['application']

            # Load cues
            for cue_conf in session['cues']:
                cue_type = cue_conf.pop('_type_', 'Undefined')
                cue_id = cue_conf.pop('id')
                try:
                    cue = CueFactory.create_cue(cue_type, cue_id=cue_id)
                    cue.update_properties(cue_conf)
                    self._cue_model.add(cue)
                except Exception as e:
                    elogging.exception('Unable to create the cue', e)

            MainActionsHandler.set_saved()
            self._mainWindow.update_window_title()

            # Load plugins settings
            plugins.set_plugins_settings(session['plugins'])

            # Update the main-window
            self._mainWindow.filename = session_file
            self._mainWindow.update()
        except Exception as e:
            elogging.exception('Error during file reading', e)
            self.new_session_dialog()
class Application(metaclass=Singleton):

    def __init__(self):
        # Create the mainWindow
        self.mainWindow = MainWindow()
        # Create a layout 'reference' and set to None
        self.layout = None
        # Create an empty configuration
        self.app_conf = {}

        # Initialize modules
        failed = modules.init_modules()
        for err in failed:
            msg = 'Module "' + err[0] + '" loading failed'
            QDetailedMessageBox.dcritical('Module error', msg, str(err[1]))

        # Connect mainWindow actions
        self.mainWindow.new_session.connect(self._startup)
        self.mainWindow.save_session.connect(self._save_to_file)
        self.mainWindow.open_session.connect(self._load_from_file)

        # Register general settings widget
        AppSettings.register_settings_widget(General)

        # Show the mainWindow maximized
        self.mainWindow.showMaximized()

    def start(self, filepath=''):
        if exists(filepath):
            # Load the file
            self.mainWindow.file = filepath
            self._load_from_file(filepath)
        else:
            # Create the layout
            self._startup(first=True)

    def finalize(self):
        self.layout.destroy_layout()

        # Terminate the loaded modules
        modules.terminate_modules()

    def _create_layout(self, layout):
        '''
            Clear ActionHandler session;
            Reset plugins;
            Creates a new layout;
            Init plugins.
        '''

        ActionsHandler().clear()
        plugins.reset_plugins()

        if self.layout is not None:
            self.layout.destroy_layout()
            self.layout = None

        try:
            self.layout = layout(self)
            self.mainWindow.set_layout(self.layout)
            self.app_conf['layout'] = layout.NAME
            self._init_plugins()
        except Exception:
            QMessageBox.critical(None, 'Error', 'Layout init failed')
            print(traceback.format_exc(), file=sys.stderr)

    def _layout_dialog(self):
        ''' Show the layout-selection dialog '''
        try:
            select = LayoutSelect()
            select.exec_()
        except Exception as e:
            QMessageBox.critical(None, 'Fatal error', str(e))
            qApp.quit()
            exit(-1)

        if select.result() != QDialog.Accepted:
            qApp.quit()
            exit()

        if exists(select.filepath):
            self._load_from_file(select.filepath)
        else:
            self._create_layout(select.slected())

    def _startup(self, first=False):
        ''' Initializes the basic components '''
        self.mainWindow.file = ''
        self.app_conf = {}

        if first and cfg.config['Layout']['Default'].lower() != 'nodefault':
            layout = layouts.get_layout(cfg.config['Layout']['Default'])
            self._create_layout(layout)
        else:
            self._layout_dialog()

    def _save_to_file(self, filepath):
        ''' Save the current program into "filepath" '''

        # Empty structure
        program = {"cues": [], "plugins": {}, "application": []}

        # Add the cues
        for cue in self.layout.get_cues():
            if cue is not None:
                program['cues'].append(cue.properties())

        # Add the plugins
        failed = program['plugins'] = plugins.get_plugin_settings()
        for err in failed:
            msg = 'Plugin "' + err[0] + '" saving failed'
            QDetailedMessageBox.dcritical('Plugin error', msg, str(err[1]))

        # Add the app settings
        program['application'] = self.app_conf

        # Write to a file the json-encoded dictionary
        with open(filepath, mode='w', encoding='utf-8') as file:
            file.write(json.dumps(program, sort_keys=True, indent=4))

        ActionsHandler().set_saved()
        self.mainWindow.update_window_title()

    def _load_from_file(self, filepath):
        ''' Loads a saved program from "filepath" '''
        try:
            # Read the file
            with open(filepath, mode='r', encoding='utf-8') as file:
                program = json.load(file)

            # Get the application settings
            self.app_conf = program['application']

            # Create the layout
            self._create_layout(layouts.get_layout(self.app_conf['layout']))

            # Load cues
            for cue_conf in program['cues']:
                cue = CueFactory.create_cue(cue_conf)
                if cue is not None:
                    self.layout.add_cue(cue, cue['index'])

            ActionsHandler().set_saved()
            self.mainWindow.update_window_title()

            # Load plugins settings
            self._load_plugins_settings(program['plugins'])

            # Update the main-window
            self.mainWindow.file = filepath
            self.mainWindow.update()
        except Exception:
            QMessageBox.critical(None, 'Error', 'Error during file reading')
            print(traceback.format_exc(), file=sys.stderr)

            self._startup()

    def _init_plugins(self):
        ''' Initialize all the plugins '''
        failed = plugins.init_plugins()

        for err in failed:
            msg = 'Plugin "' + err[0] + '" initialization failed'
            QDetailedMessageBox.dcritical('Plugin error', msg, str(err[1]))

    def _load_plugins_settings(self, settings):
        ''' Loads all the plugins settings '''

        failed = plugins.set_plugins_settings(settings)

        for err in failed:
            msg = 'Plugin "' + err[0] + '" loading failed'
            QDetailedMessageBox.dcritical('Plugin error', msg, str(err[1]))
Beispiel #3
0
class Main:

    def __init__(self):
        QtGui.QIcon.setThemeSearchPaths(styles.QLiSPIconsThemePaths)
        QtGui.QIcon.setThemeName(styles.QLiSPIconsThemeName)

        self.mainWindow = MainWindow()
        self.collector = Collector()
        self.collectorUi = None
        self.programConf = {}
        try:
            midi.initialize()
            self.midiHandler = midi.MidiEventHandler(int(cfg.config['MIDI']['DeviceID']))
            self.midiHandler.start()
        except:
            self.midiHandler = None
            QtGui.QMessageBox.critical(self.mainWindow, 'Error', 'MIDI event handler cannot be started!')

        self.mainWindow.newProgramAction.connect(self.newProgram)
        self.mainWindow.saveProgramAction.connect(self.saveProgram)
        self.mainWindow.openProgramAction.connect(self.openProgram)
        self.mainWindow.addMediaAction.connect(self.addMedia, QtCore.Qt.QueuedConnection)

        if(cfg.config['Layout']['UseDefault'] == 'True'):
            self.createLayout(cfg.config['Layout']['Default'])
        else:
            self.mainWindow.setEnabled(False)
            while(not self.layoutDialog()):
                pass
            self.mainWindow.setEnabled(True)

        try:
            self.plugins = plugin.initPlugins(self)
        except Exception as e:
            QtGui.QMessageBox.critical(None, 'Error Message', ' '.join([str(i) for i in e.args]))

    def layoutDialog(self):
        select = LayoutSelect()
        select.exec_()
        if(select.result() == QtGui.QDialog.Accepted):
            self.createLayout(select.getSlected())
            return True
        else:
            return False

    def createLayout(self, lay):
        self.mainWindow.menuLayout.clear()

        if(self.collectorUi is not None):
            self.collectorUi.destroyLayout()
            self.mainWindow.multiEditAction.disconnect()
            self.mainWindow.selectAllAction.disconnect()
            self.mainWindow.deselectAllAction.disconnect()
            self.mainWindow.invertSelectionAction.disconnect()

        self.collectorUi = layout.buildLayout(lay, self, parent=self.mainWindow.centralwidget)

        self.mainWindow.multiEditAction.connect(self.collectorUi.editSelectedMedia)
        self.mainWindow.selectAllAction.connect(self.collectorUi.selectAll)
        self.mainWindow.deselectAllAction.connect(self.collectorUi.deselectAll)
        self.mainWindow.invertSelectionAction.connect(self.collectorUi.invertSelection)

        self.mainWindow.setProgramLayout(self.collectorUi)
        self.programConf['layout'] = lay

    def addMedia(self, files):
        try:
            for file in files:

                conf = {}
                conf['location'] = file
                conf['name'] = file.split('/')[len(file.split('/')) - 1]

                media = self.collectorUi.getMediaClass()(conf)

                self.collectorUi.addMedia(media)
        except Exception as e:
            QtGui.QMessageBox.critical(None, 'Error Message', ' '.join([str(i) for i in e.args]))

    def playByPos(self, pos):
        media = self.collectorUi.mediaAt(pos)
        if(media is not None):
            media.play()

    def stopByPos(self, pos):
        media = self.collectorUi.mediaAt(pos)
        if(media is not None):
            media.stop()

    def pauseByPos(self, pos):
        media = self.collectorUi.mediaAt(pos)
        if(media is not None):
            media.pause()

    def seekByPos(self, pos, time_ms):
        media = self.collectorUi.mediaAt(pos)
        if(media is not None):
            media.seek(time_ms)

    def newProgram(self):
        self.collectorUi.destroyLayout()
        self.collector.resetCollector()
        self.collectorUi = None
        self.mainWindow.file = ''
        while(not self.layoutDialog()):
            pass
        self.resetPlugin()

    def saveProgram(self, filepath):
        writer = xml_writer.XmlWriter(filepath)
        for media in self.collectorUi.mediaList():
            if(media is not None):
                if(media.state != Media.NONE):
                    writer.appendMedia(media.conf, media.uuid)

        writer.appendProgramSettings(self.programConf)

        for plug in self.plugins:
            data = self.getPluginData(plug)
            if(data is not None):
                writer.appendPluginSettings(plug.PLUGIN_NAME, data)

        writer.writeFile()

    def openProgram(self, filepath):
        progress = Progress(title='Loading ' + filepath)
        progress.show()
        try:
            progress.setLabelText('Reading file ...')
            reader = xml_reader.XmlReader(filepath)
            conf = reader.readMediaList()
            progress.setMaximum(len(conf) + 10)
            pluginsConf = reader.readPluginsSettings()
            self.programConf = reader.readProgramSettings()

            progress.setLabelText('Creating layout ...')
            self.createLayout(self.programConf['layout'])
            self.mainWindow.update()
            progress.setValue(progress.value() + 5)

            progress.setLabelText('Loading media ...')
            pfunc = lambda w: progress.setValue(progress.value() + 1)
            self.collector.onMediaAdded.connect(pfunc)
            self.collectorUi.readProgramConf(conf)
            self.collector.onMediaAdded.disconnect(pfunc)

            progress.setLabelText('Loading plugins ...')
            self.resetPlugin()
            self.reloadPlugins()
            self.setPluginsData(pluginsConf)
            progress.hide()
        except Exception as e:
            progress.hide()
            QtGui.QMessageBox.critical(None, 'Error Message', 'Error during file reading: ' + ' '.join([str(i) for i in e.args]))
            self.newProgram()

    def setPluginsData(self, conf, debug=False):
        for plug in self.plugins:
            if(plug.PLUGIN_NAME in conf):
                if(debug):
                    plug.setData(conf[plug.PLUGIN_NAME])
                else:
                    try:
                        plug.setData(conf[plug.PLUGIN_NAME])
                    except:
                        raise Exception('Plugin data read failed: ' + plug.PLUGIN_NAME)

    def reloadPlugins(self, debug=False):
        for plug in self.plugins:
            if(debug):
                plug.reload()
            else:
                try:
                    plug.reload()
                except:
                    raise Exception('Plugin load failed: ' + plug.PLUGIN_NAME)

    def resetPlugin(self, debug=False):
        for plug in self.plugins:
            if(debug):
                plug.reset()
            else:
                try:
                    plug.reset()
                except:
                    raise Exception('Plugin reset failed: ' + plug.PLUGIN_NAME)

    def getPluginData(self, plugin, debug=False):
        if(debug):
            return plugin.getData()
        else:
            try:
                return plugin.getData()
            except:
                raise Exception('Plugin data save failed: ' + plugin.PLUGIN_NAME)
class Application(metaclass=Singleton):
    def __init__(self):
        self._mainWindow = MainWindow()
        self._app_conf = {}
        self._layout = None
        self._memento_model = None
        self._cue_model = CueModel()

        # Connect mainWindow actions
        self._mainWindow.new_session.connect(self.new_session_dialog)
        self._mainWindow.save_session.connect(self._save_to_file)
        self._mainWindow.open_session.connect(self._load_from_file)

        # Register general settings widget
        AppSettings.register_settings_widget(General)

        # Show the mainWindow maximized
        self._mainWindow.showMaximized()

    @property
    def layout(self):
        """:rtype: lisp.layouts.cue_layout.CueLayout"""
        return self._layout

    @property
    def cue_model(self):
        """:rtype: lisp.model_view.cue_model.CueModel"""
        return self._cue_model

    def start(self, session_file=''):
        if exists(session_file):
            self._load_from_file(session_file)
        elif cfg.config['Layout']['Default'].lower() != 'nodefault':
            layout = layouts.get_layout(cfg.config['Layout']['Default'])
            self._new_session(layout)
        else:
            self.new_session_dialog()

    def new_session_dialog(self):
        """Show the layout-selection dialog"""
        try:
            # Prompt the user for a new layout
            dialog = LayoutSelect()
            if dialog.exec_() != QDialog.Accepted:
                if self._layout is None:
                    # If the user close the dialog, and no layout exists
                    # the application is closed
                    self.finalize()
                    qApp.quit()
                    exit()
                else:
                    return

            # If a valid file is selected load it, otherwise load the layout
            if exists(dialog.filepath):
                self._load_from_file(dialog.filepath)
            else:
                self._new_session(dialog.selected())

        except Exception as e:
            logging.exception('Startup error', e)
            qApp.quit()
            exit(-1)

    def _new_session(self, layout):
        self._delete_session()

        self._layout = layout(self._cue_model)
        self._memento_model = AdapterMementoModel(self.layout.model_adapter)
        self._mainWindow.set_layout(self._layout)
        self._app_conf['layout'] = layout.NAME

        plugins.init_plugins()

    def _delete_session(self):
        if self._layout is not None:
            MainActionsHandler().clear()
            plugins.reset_plugins()

            self._app_conf.clear()
            self._cue_model.reset()

            self._layout.finalize()
            self._layout = None
            self._memento_model = None

    def finalize(self):
        self._delete_session()
        modules.terminate_modules()

    def _save_to_file(self, session_file):
        """ Save the current session into a file """
        session = {"cues": [], "plugins": {}, "application": []}

        # Add the cues
        for cue in self._cue_model:
            session['cues'].append(cue.properties())
        # Sort cues by index, allow sorted-models to load properly
        session['cues'].sort(key=lambda cue: cue['index'])

        session['plugins'] = plugins.get_plugin_settings()
        session['application'] = self._app_conf

        # Write to a file the json-encoded dictionary
        with open(session_file, mode='w', encoding='utf-8') as file:
            file.write(json.dumps(session, sort_keys=True, indent=4))

        MainActionsHandler().set_saved()
        self._mainWindow.update_window_title()

    def _load_from_file(self, session_file):
        """ Load a saved session from file """
        try:
            with open(session_file, mode='r', encoding='utf-8') as file:
                session = json.load(file)

            # New session
            self._new_session(
                layouts.get_layout(session['application']['layout']))
            # Get the application settings
            self._app_conf = session['application']

            # Load cues
            for cue_conf in session['cues']:
                cue_type = cue_conf.pop('_type_', 'Undefined')
                try:
                    cue = CueFactory.create_cue(cue_type)
                    cue.update_properties(cue_conf)
                    self._cue_model.add(cue)
                except Exception as e:
                    logging.exception('Unable to create the cue', e)

            MainActionsHandler().set_saved()
            self._mainWindow.update_window_title()

            # Load plugins settings
            plugins.set_plugins_settings(session['plugins'])

            # Update the main-window
            self._mainWindow.filename = session_file
            self._mainWindow.update()
        except Exception as e:
            logging.exception('Error during file reading', e)
            self.new_session_dialog()