示例#1
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.__setupEvents()

    def __setupEvents(self):
        def on_cad_indicacoes():
            indicacoes = CadIndicacoes()
            indicacoes.show()

        def on_cad_alunos():
            alunos = CadAlunos()
            alunos.show()

        def on_cad_pacientes():
            pacientes = CadPacientes()
            pacientes.show()

        def on_cad_panoramicas():
            panoramicas = CadPanoramicas()
            panoramicas.show()

        def on_cad_tomografias():
            tomografias = CadTomografias()
            print("Teste")
            tomografias.show()

        self.ui.actionIndica_es.triggered.connect(on_cad_indicacoes)
        self.ui.actionAlunos.triggered.connect(on_cad_alunos)
        self.ui.actionPacientes.triggered.connect(on_cad_pacientes)
        self.ui.actionPanoramicas.triggered.connect(on_cad_panoramicas)
        self.ui.actionTomografias.triggered.connect(on_cad_tomografias)

    def keyPressEvent(self, event):
        if not event.isAutoRepeat():
            if event.key() == Qt.Key_Escape:
                self.close()
示例#2
0
class MainWindow(QMainWindow):
    def __init__(self, config):
        super(MainWindow, self).__init__()

        QFontDatabase.addApplicationFont(
            'resources/fonts/poppins/Poppins-Medium.ttf')
        QFontDatabase.addApplicationFont(
            'resources/fonts/source code pro/SourceCodePro-Regular.ttf')

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.splitter.setSizes([120, 800])
        self.setWindowTitle('Ryven')
        self.setWindowIcon(QIcon('resources/pics/program_icon2.png'))
        self.load_stylesheet('dark')
        self.ui.scripts_tab_widget.removeTab(0)

        # menu actions
        self.flow_design_actions = []
        self.setup_menu_actions()

        # shortcuts
        save_shortcut = QShortcut(QKeySequence.Save, self)
        save_shortcut.activated.connect(self.on_save_project_triggered)
        import_nodes_shortcut = QShortcut(QKeySequence('Ctrl+i'), self)
        import_nodes_shortcut.activated.connect(self.on_import_nodes_triggered)

        # clear temp folder
        if not os.path.exists('temp'):
            os.mkdir('temp')
        for f in os.listdir('temp'):
            os.remove('temp/' + f)

        # GENERAL ATTRIBUTES
        self.scripts = []
        self.custom_nodes = []
        self.all_nodes = [
            SetVariable_Node(),
            GetVariable_Node(),
            Val_Node(),
            Result_Node()
        ]
        self.package_names = []

        #   holds NI subCLASSES for imported nodes:
        self.all_node_instance_classes = {
            self.all_nodes[0]: SetVar_NodeInstance,
            self.all_nodes[1]: GetVar_NodeInstance,
            self.all_nodes[2]: Val_NodeInstance,
            self.all_nodes[3]: Result_NodeInstance
        }  # (key: node obj, val: NI subclass) (used in Flow)

        #   custom subclasses for input widgets
        #   {node : {str: PortInstanceWidget-subclass}} (used in PortInstance)
        self.custom_node_input_widget_classes = {}

        # UI
        self.scripts_list_widget = ScriptsListWidget(self, self.scripts)
        self.ui.scripts_scrollArea.setWidget(self.scripts_list_widget)
        self.ui.add_new_script_pushButton.clicked.connect(
            self.create_new_script_button_pressed)
        self.ui.new_script_name_lineEdit.returnPressed.connect(
            self.create_new_script_LE_return_pressed)

        if config['config'] == 'create plain new project':
            self.try_to_create_new_script()
        elif config['config'] == 'open project':
            print('importing packages...')
            self.import_packages(config['required packages'])
            print('loading project...')
            self.parse_project(config['content'])
            print('finished')

        print('''
        CONTROLS
            placing nodes: right mouse
            selecting components: left mouse
            panning: middle mouse
            saving: ctrl+s
        ''')

        Design.set_flow_theme()
        Design.set_flow_theme()  # temporary
        #   the double call is just a temporary fix for an issue I will address in a future release.
        #   Problem: because the signal emitted when setting a flow theme is directly connected to the according slots
        #   in NodeInstance as well as NodeInstance_TitleLabel, the NodeInstance's slot (which starts an animation which
        #   uses the title label's current and theme dependent color) could get called before the title
        #   label's slot has been called to reinitialize this color. This results in wrong color end points for the
        #   title label when activating animations.
        #   This is pretty nasty since I cannot think of a nice fix for this issue other that not letting the slot
        #   methods be called directly from the emitted signal but instead through a defined procedure like before.

        # maybe this will be necessary due to scheduling issues when loading flows
        # for s in self.scripts:
        #     s.flow.viewport().update()

        self.resize(1500, 800)

    def setup_menu_actions(self):
        # flow designs
        for d in Design.flow_themes:
            design_action = QAction(d, self)
            self.ui.menuFlow_Design_Style.addAction(design_action)
            design_action.triggered.connect(self.on_design_action_triggered)
            self.flow_design_actions.append(design_action)

        self.ui.actionImport_Nodes.triggered.connect(
            self.on_import_nodes_triggered)
        self.ui.actionSave_Project.triggered.connect(
            self.on_save_project_triggered)
        self.ui.actionEnableDebugging.triggered.connect(
            self.on_enable_debugging_triggered)
        self.ui.actionDisableDebugging.triggered.connect(
            self.on_disable_debugging_triggered)
        self.ui.actionSave_Pic_Viewport.triggered.connect(
            self.on_save_scene_pic_viewport_triggered)
        self.ui.actionSave_Pic_Whole_Scene_scaled.triggered.connect(
            self.on_save_scene_pic_whole_triggered)

        # performance mode
        self.action_set_performance_mode_fast = QAction('Fast', self)
        self.action_set_performance_mode_fast.setCheckable(True)

        self.action_set_performance_mode_pretty = QAction('Pretty', self)
        self.action_set_performance_mode_pretty.setCheckable(True)

        performance_mode_AG = QActionGroup(self)
        performance_mode_AG.addAction(self.action_set_performance_mode_fast)
        performance_mode_AG.addAction(self.action_set_performance_mode_pretty)
        self.action_set_performance_mode_fast.setChecked(True)
        performance_mode_AG.triggered.connect(self.on_performance_mode_changed)

        performance_menu = QMenu('Performance Mode', self)
        performance_menu.addAction(self.action_set_performance_mode_fast)
        performance_menu.addAction(self.action_set_performance_mode_pretty)

        self.ui.menuView.addMenu(performance_menu)

        # animations
        self.action_set_animation_active = QAction('Enabled', self)
        self.action_set_animation_active.setCheckable(True)

        self.action_set_animations_inactive = QAction('Disabled', self)
        self.action_set_animations_inactive.setCheckable(True)

        animation_enabled_AG = QActionGroup(self)
        animation_enabled_AG.addAction(self.action_set_animation_active)
        animation_enabled_AG.addAction(self.action_set_animations_inactive)
        self.action_set_animation_active.setChecked(True)
        animation_enabled_AG.triggered.connect(
            self.on_animation_enabling_changed)

        animations_menu = QMenu('Animations', self)
        animations_menu.addAction(self.action_set_animation_active)
        animations_menu.addAction(self.action_set_animations_inactive)

        self.ui.menuView.addMenu(animations_menu)

    def load_stylesheet(self, ss):
        ss_content = ''
        try:
            f = open('resources/stylesheets/' + ss + '.txt')
            ss_content = f.read()
            f.close()
        finally:
            Design.ryven_stylesheet = ss_content
            self.setStyleSheet(ss_content)

    def on_performance_mode_changed(self, action):
        if action == self.action_set_performance_mode_fast:
            Design.set_performance_mode('fast')
        else:
            Design.set_performance_mode('pretty')

    def on_animation_enabling_changed(self, action):
        if action == self.action_set_animation_active:
            Design.animations_enabled = True
        else:
            Design.animations_enabled = False

    def on_design_action_triggered(self):
        index = self.flow_design_actions.index(self.sender())
        Design.set_flow_theme(Design.flow_themes[index])

    def on_enable_debugging_triggered(self):
        Debugger.enable()

    def on_disable_debugging_triggered(self):
        Debugger.disable()

    def on_save_scene_pic_viewport_triggered(self):
        """Saves a picture of the currently visible viewport."""
        if len(self.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '',
                                                'PNG(*.png)')[0]
        img = self.scripts[
            self.ui.scripts_tab_widget.currentIndex()].flow.get_viewport_img()
        img.save(file_path)

    def on_save_scene_pic_whole_triggered(self):
        """Saves a picture of the whole currently visible scene."""
        if len(self.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '',
                                                'PNG(*.png)')[0]
        img = self.scripts[self.ui.scripts_tab_widget.currentIndex(
        )].flow.get_whole_scene_img()
        img.save(file_path)

    def create_new_script_button_pressed(self):
        self.try_to_create_new_script(
            name=self.ui.new_script_name_lineEdit.text())

    def create_new_script_LE_return_pressed(self):
        self.try_to_create_new_script(
            name=self.ui.new_script_name_lineEdit.text())

    def try_to_create_new_script(self, name='fancy script', config=None):
        """Tries to create a new script with a given name. If the name is already used or '', it fails."""
        if len(name) == 0:
            return
        for s in self.scripts:
            if s.name == name:
                return

        new_script = Script(self, name, config)
        new_script.name_changed.connect(self.rename_script)
        self.ui.scripts_tab_widget.addTab(new_script.widget, new_script.name)
        self.scripts.append(new_script)
        self.scripts_list_widget.recreate_ui()

    def rename_script(self, script, new_name):
        self.ui.scripts_tab_widget.setTabText(self.scripts.index(script),
                                              new_name)
        script.name = new_name

    def delete_script(self, script):
        index = self.scripts.index(script)
        self.ui.scripts_tab_widget.removeTab(index)
        del self.scripts[index]

    def on_import_nodes_triggered(self):
        file_path = QFileDialog.getOpenFileName(
            self,
            'select nodes file',
            '../packages',
            'Ryven Packages(*.rpc)',
        )[0]
        if file_path != '':
            self.import_nodes_package(file_path)

    def import_packages(self, packages_list):
        for p in packages_list:
            self.import_nodes_package(p)

    def import_nodes_package(self, file_path):
        j_str = ''
        try:
            f = open(file_path)
            j_str = f.read()
            f.close()
        except FileExistsError or FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return

        # don't import a package twice if it already has been imported
        filename = os.path.splitext(os.path.basename(file_path))
        if filename in self.package_names:
            return

        # Important: translate the package first (metacore files -> src code files)
        PackageTranslator = self.get_class_from_file(
            file_path='../Ryven_PackageTranslator',
            file_name='Ryven_PackageTranslator',
            class_name='PackageTranslator')
        package_translator = PackageTranslator(
            os.path.dirname(os.path.abspath(file_path)))

        self.parse_nodes(j_str,
                         package_path=os.path.dirname(file_path),
                         package_name=os.path.splitext(
                             os.path.basename(file_path))[0])  #

        self.package_names.append(filename)

    def parse_nodes(self, j_str, package_path, package_name):
        """Parses the nodes from a node package in JSON format.
        Here, all the classes get imported and for every node a Node object with specific attribute values gets
        created."""

        import json

        # strict=False is necessary to allow 'control characters' like '\n' for newline when loading the json
        j_obj = json.loads(j_str, strict=False)

        Debugger.debug(j_obj['type'])
        if j_obj['type'] != 'Ryven nodes package' and j_obj[
                'type'] != 'vyScriptFP nodes package':  # old syntax
            return

        # package_title = j_obj['title']
        # package_description = j_obj['description']
        j_nodes_list = j_obj['nodes']

        num_nodes = len(j_nodes_list)
        for ni in range(num_nodes):
            j_node = j_nodes_list[ni]
            self.parse_node(j_node, package_name, package_path)

        Debugger.debug(len(self.custom_nodes), 'nodes imported')

    def parse_node(self, j_node, package_name, package_path):
        new_node = Node()

        # loading the node's specifications which get finally set below after importing the classes
        node_title = j_node['title']
        node_class_name = j_node['class name']
        node_description = j_node['description']
        node_type = j_node['type']
        node_has_main_widget = j_node['has main widget']
        node_main_widget_pos = j_node[
            'widget position'] if node_has_main_widget else None
        node_design_style = j_node['design style']
        node_color = j_node['color']

        # Every node has a custom module name which differs from it's name to prevent import issues when using
        # multiple (different) Nodes with same titles. For further info: see node manager
        node_module_name = j_node['module name']
        module_name_separator = '___'

        # CUSTOM CLASS IMPORTS ----------------------------------------------------------------------------
        # creating all the necessary path variables here for all potentially imported classes

        #       IMPORT NODE INSTANCE SUBCLASS
        node_instance_class_file_path = package_path + '/nodes/' + node_module_name + '/'
        node_instance_widgets_file_path = node_instance_class_file_path + '/widgets'
        node_instance_filename = node_module_name  # the NI file's name is just the 'module name'
        new_node_instance_class = self.get_class_from_file(
            file_path=node_instance_class_file_path,
            file_name=node_instance_filename,
            class_name=node_class_name + '_NodeInstance')
        self.all_node_instance_classes[new_node] = new_node_instance_class

        #       IMPORT MAIN WIDGET
        if node_has_main_widget:
            main_widget_filename = node_module_name + module_name_separator + 'main_widget'
            new_node.main_widget_class = self.get_class_from_file(
                file_path=node_instance_widgets_file_path,
                file_name=main_widget_filename,
                class_name=node_class_name + '_NodeInstance_MainWidget')

        #       IMPORT CUSTOM INPUT WIDGETS
        #       I need to create the dict for the node's potential custom input widgets already here
        self.custom_node_input_widget_classes[new_node] = {}
        for w_name in j_node['custom input widgets']:
            input_widget_filename = node_module_name + module_name_separator + w_name
            custom_widget_class = self.get_class_from_file(
                file_path=node_instance_widgets_file_path,
                file_name=input_widget_filename,
                class_name=w_name + '_PortInstanceWidget')
            self.custom_node_input_widget_classes[new_node][
                w_name] = custom_widget_class

        # ---------------------------------------------------------------------------------------------------

        j_n_inputs = j_node['inputs']
        inputs = []
        num_inputs = len(j_n_inputs)
        for ii in range(num_inputs):
            # loading info
            j_input = j_n_inputs[ii]
            i_type = j_input['type']
            i_label = j_input['label']
            i_has_widget = None
            i_widget_name = ''
            i_widget_pos = None
            if i_type == 'data':
                i_has_widget = j_input['has widget']
                if i_has_widget:
                    i_widget_name = j_input['widget name']
                    i_widget_pos = j_input['widget position']

            # creating port
            new_input = NodePort()
            new_input.type_ = i_type
            new_input.label = i_label
            if i_has_widget:
                new_input.widget_name = i_widget_name
                new_input.widget_pos = i_widget_pos
            inputs.append(new_input)

        j_n_outputs = j_node['outputs']
        outputs = []
        num_outputs = len(j_n_outputs)
        for oi in range(num_outputs):
            # loading info
            j_output = j_n_outputs[oi]
            o_type = j_output['type']
            o_label = j_output['label']

            # creating port
            new_output = NodePort()
            new_output.type_ = o_type
            new_output.label = o_label
            outputs.append(new_output)

        # setting the Node's attributes
        new_node.title = node_title
        new_node.description = node_description
        new_node.type_ = node_type
        new_node.package = package_name
        new_node.has_main_widget = node_has_main_widget
        if node_has_main_widget:
            new_node.main_widget_pos = node_main_widget_pos
        new_node.design_style = node_design_style
        new_node.color = QColor(node_color)
        new_node.inputs = inputs
        new_node.outputs = outputs

        self.custom_nodes.append(new_node)
        self.all_nodes.append(new_node)

    def get_class_from_file(self, file_path, file_name, class_name):
        """Returns a class with a given name from a file for instantiation by importing the module.
        Used for all the dynamically imported classes:
            - NodeInstances
            - A NodeInstance's main widget
            - A NodeInstance's custom input widgets
        """
        # Debugger.debug(file_path)
        # Debugger.debug(file_name)
        # Debugger.debug(class_name)
        sys.path.append(file_path)
        try:
            new_module = __import__(file_name, fromlist=[class_name])
        except ModuleNotFoundError as e:
            QMessageBox.warning(self, 'Missing Python module', str(e))
            sys.exit()
        new_class = getattr(new_module, class_name)
        return new_class

    def parse_project(self, j_obj):
        if j_obj['general info']['type'] != 'Ryven project file':
            return

        for s in j_obj['scripts']:  # fill flows
            self.try_to_create_new_script(config=s)

    def on_save_project_triggered(self):
        file_name = QFileDialog.getSaveFileName(
            self, 'select location and give file name', '../saves',
            'Ryven Project(*.rpo)')[0]
        if file_name != '':
            self.save_project(file_name)

    def save_project(self, file_name):
        import json

        file = None
        try:
            if os.path.exists(file_name):
                os.remove(file_name)
            file = open(file_name, 'w')
        except FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return

        general_project_info_dict = {'type': 'Ryven project file'}

        scripts_data = []
        for script in self.scripts:
            scripts_data.append(script.get_json_data())

        whole_project_dict = {
            'general info': general_project_info_dict,
            'scripts': scripts_data
        }

        json_str = json.dumps(whole_project_dict)
        Debugger.debug(json_str)

        file.write(json_str)
        file.close()
示例#3
0
class ThermostatWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # setup UI
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        # setup thermostat
        self.thermostat = Thermostat()
        self.thermostat.tick_event.connect(self.update_from_arduino)
        self.thermostat.target_temperature_changed.connect(self.update_from_arduino)
        self.thermostat.start()
        self.on_termostat_status_changed()
        # setup clock
        self.clock_timer = QTimer()
        self.clock_timer.setSingleShot(False)
        self.clock_timer.setInterval(1000)
        self.update_clock()
        self.clock_timer.timeout.connect(self.update_clock)
        self.clock_timer.start()
        # setup web interface
        self.web = WebThermostat(self.thermostat)
        self.web.start()
        # connections
        self.ui.pb_up.pressed.connect(self.on_up_target_button_clicked)
        self.ui.pb_down.pressed.connect(self.on_down_target_button_clicked)
        self.ui.pb_ac.clicked.connect(self.on_ac_boutton_clicked)
        self.ui.pb_off.clicked.connect(self.on_off_button_clicked)
        self.ui.pb_heat.clicked.connect(self.on_heat_button_clicked)
        self.thermostat.mode_changed.connect(self.on_termostat_status_changed)

    @pyqtSlot(int)
    def update_temp_display(self, value: int):
        self.ui.lb_temp.setText("{}°C".format(value))

    @pyqtSlot(int)
    def update_humidity_display(self, value: int):
        self.ui.lb_humidity.setText("{:02d}% 💧️".format(value))

    @pyqtSlot(int)
    def update_target_temp_display(self, value: int):
        self.ui.lb_temp_target.setText("{}°C".format(value))

    def update_status_icons(self, fan_status: bool, ac_status: bool, heat_status: bool):
        self.ui.lb_status_ac.setVisible(ac_status)
        self.ui.lb_status_hot.setVisible(heat_status)
        self.ui.lb_status_vent.setVisible(fan_status)

    @pyqtSlot()
    def update_from_arduino(self):
        self.update_temp_display(int(self.thermostat.last_temperature))
        self.update_humidity_display(int(self.thermostat.last_humidity))
        self.update_target_temp_display(int(self.thermostat.temperature_target))
        self.update_status_icons(self.thermostat.last_fan_enabled,
                                 self.thermostat.last_ac_enabled,
                                 self.thermostat.last_heat_enabled)

    def on_up_target_button_clicked(self):
        t = self.thermostat.temperature_target
        self.thermostat.set_temperature_target(t + 1.0)

    def on_down_target_button_clicked(self):
        t = self.thermostat.temperature_target
        self.thermostat.set_temperature_target(t - 1.0)

    def on_ac_boutton_clicked(self):
        self.update_termostat_status("ac")

    def on_heat_button_clicked(self):
        self.update_termostat_status("heat")

    def on_off_button_clicked(self):
        self.update_termostat_status("off")

    def update_termostat_status(self, mode: str):
        assert mode in ["ac", "off", "heat"]
        self.thermostat.set_mode(mode)

    def on_termostat_status_changed(self):
        mode = self.thermostat.mode
        self.ui.pb_ac.setChecked(mode == "ac")
        self.ui.pb_off.setChecked(mode == "off")
        self.ui.pb_heat.setChecked(mode == "heat")

    @pyqtSlot()
    def update_clock(self):
        time_string = time.strftime("%A %d %B %H:%M:%S")
        # time_string = time.strftime("%c")
        self.ui.lb_time.setText(time_string)
示例#4
0
class MainWindow(QMainWindow):
    """MainWindow still lacks cleanup and documentation, sorry."""

    def __init__(self, config):
        super(MainWindow, self).__init__()

        QFontDatabase.addApplicationFont('fonts/poppins/Poppins-Medium.ttf')
        QFontDatabase.addApplicationFont('fonts/source code pro/SourceCodePro-Regular.ttf')

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.splitter.setSizes([120, 800])
        self.setWindowTitle('pyScript')
        self.setWindowIcon(QIcon('stuff/pics/program_icon.png'))
        self.load_stylesheet('dark')
        self.ui.scripts_tab_widget.removeTab(0)
        self.ui.actionImport_Nodes.triggered.connect(self.on_import_nodes_triggered)
        self.ui.actionSave_Project.triggered.connect(self.on_save_project_triggered)
        self.ui.actionDesignDark_Std.triggered.connect(self.on_dark_std_design_triggered)
        self.ui.actionDesignDark_Tron.triggered.connect(self.on_dark_tron_design_triggered)
        self.ui.actionEnableDebugging.triggered.connect(self.on_enable_debugging_triggered)
        self.ui.actionDisableDebugging.triggered.connect(self.on_disable_debugging_triggered)
        self.ui.actionSave_Pic_Viewport.triggered.connect(self.on_save_scene_pic_viewport_triggered)
        self.ui.actionSave_Pic_Whole_Scene_scaled.triggered.connect(self.on_save_scene_pic_whole_triggered)

        # Shortcuts
        save_shortcut = QShortcut(QKeySequence.Save, self)
        save_shortcut.activated.connect(self.on_save_project_triggered)

        self.custom_nodes = []
        self.all_nodes = [SetVariable_Node(), GetVariable_Node()]


        # holds NI subCLASSES for imported nodes:
        self.all_node_instance_classes = {
            self.all_nodes[0]: SetVar_NodeInstance,
            self.all_nodes[1]: GetVar_NodeInstance
        }  # (key: node obj, val: NI subclass) (used in Flow)

        # {node : {str: PortInstanceWidget-subclass}} (used in PortInstance)
        self.custom_node_input_widget_classes = {}

        # clear temp folder
        for f in os.listdir('temp'):
            os.remove('temp/'+f)

        self.scripts = []
        self.scripts_list_widget = ScriptsListWidget(self, self.scripts)
        self.ui.scripts_scrollArea.setWidget(self.scripts_list_widget)
        self.ui.add_new_script_pushButton.clicked.connect(self.create_new_script_button_pressed)
        self.ui.new_script_name_lineEdit.returnPressed.connect(self.create_new_script_le_return_pressed)

        self.design_style = 'dark std'


        if config['config'] == 'create plain new project':
            self.try_to_create_new_script()
        elif config['config'] == 'open project':
            self.import_required_packages(config['required packages'])
            self.parse_project(config['content'])

        self.resize(1500, 800)



    def load_stylesheet(self, ss):
        ss_content = ''
        try:
            f = open('stuff/stylesheets/'+ss+'.txt')
            ss_content = f.read()
            f.close()
        finally:
            self.setStyleSheet(ss_content)

    def on_dark_std_design_triggered(self):
        self.set_design('dark std')

    def on_dark_tron_design_triggered(self):
        self.set_design('dark tron')

    def set_design(self, new_design):
        Design.flow_style = new_design
        self.design_style = new_design
        for script in self.scripts:
            script.flow.design_style_changed()

    def on_enable_debugging_triggered(self):
        Debugger.enable()

    def on_disable_debugging_triggered(self):
        Debugger.disable()


    def on_save_scene_pic_viewport_triggered(self):
        if len(self.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '', 'PNG(*.png)')[0]
        img = self.scripts[self.ui.scripts_tab_widget.currentIndex()].flow.get_viewport_img()
        img.save(file_path)

    def on_save_scene_pic_whole_triggered(self):
        if len(self.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '', 'PNG(*.png)')[0]
        img = self.scripts[self.ui.scripts_tab_widget.currentIndex()].flow.get_whole_scene_img()
        img.save(file_path)


    def create_new_script_button_pressed(self):
        self.try_to_create_new_script(name=self.ui.new_script_name_lineEdit.text())

    def create_new_script_le_return_pressed(self):
        self.try_to_create_new_script(name=self.ui.new_script_name_lineEdit.text())


    def try_to_create_new_script(self, name='fancy script', config=None):
        if len(name) == 0:
            return
        for s in self.scripts:
            if s.name == name:
                return


        new_script = Script(self, name, config)
        new_script.name_changed.connect(self.rename_script)
        self.ui.scripts_tab_widget.addTab(new_script.widget, new_script.name)
        self.scripts.append(new_script)
        self.scripts_list_widget.recreate_ui()

    def rename_script(self, script, new_name):
        self.ui.scripts_tab_widget.setTabText(self.scripts.index(script), new_name)
        script.name = new_name

    def delete_script(self, script):
        index = self.scripts.index(script)
        self.ui.scripts_tab_widget.removeTab(index)
        del self.scripts[index]


    def on_import_nodes_triggered(self):
        file_path = QFileDialog.getOpenFileName(self, 'select nodes file', '../packages', 'PyScript Packages(*.pypac)',)[0]
        if file_path != '':
            self.import_nodes_package_from_file(file_path)

    def import_required_packages(self, packages_list):
        for p in packages_list:
            self.import_nodes_package_from_file(p)

    def import_nodes_package_from_file(self, file_path):
        j_str = ''
        try:
            f = open(file_path)
            j_str = f.read()
            f.close()
        except FileExistsError or FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return


        # Important: translate the package first (metacore files -> src code files)
        PackageTranslator = self.get_class_from_file(file_path='../pyScript_PackageTranslator',
                                                     file_name='pyScript_PackageTranslator',
                                                     class_name='PackageTranslator')
        package_translator = PackageTranslator(os.path.dirname(os.path.abspath(file_path)))


        self.parse_nodes(j_str, os.path.dirname(file_path), os.path.splitext(os.path.basename(file_path))[0])


    def parse_nodes(self, j_str, package_path, package_name):
        import json

        # strict=False is necessary to allow 'control characters' like '\n' for newline when loading the json
        j_obj = json.loads(j_str, strict=False)

        Debugger.debug(j_obj['type'])
        if j_obj['type'] != 'vyScriptFP nodes package':
            return

        # package_title = j_obj['title']
        # package_description = j_obj['description']
        j_nodes_list = j_obj['nodes']

        num_nodes = len(j_nodes_list)
        for ni in range(num_nodes):  # new node
            j_node = j_nodes_list[ni]

            new_node = Node()


            node_title = j_node['title']
            node_class_name = j_node['class name']
            node_description = j_node['description']
            node_type = j_node['type']
            node_has_main_widget = j_node['has main widget']
            node_main_widget_pos = j_node['widget position'] if node_has_main_widget else None
            node_design_style = j_node['design style']
            node_color = j_node['color']

            # every node has a custom module name which differs from it's name to prevent import issues when using
            # multiple (different) Nodes with same titles
            # FOR FURTHER EXPLANATION: see node manager
            node_module_name = j_node['module name']
            module_name_separator = '___'



            #   CUSTOM CLASS IMPORTS ----------------------------------------------------------------------------
            # creating all the necessary path variables here for all potentially imported classes


            #       IMPORT NODE INSTANCE SUBCLASS
            node_instance_class_file_path = package_path+'/nodes/'+node_module_name+'/'
            node_instance_widgets_file_path = node_instance_class_file_path+'/widgets'
            node_instance_filename = node_module_name  # the NI file's name is just the 'module name'
            new_node_instance_class = self.get_class_from_file(file_path=node_instance_class_file_path,
                                                               file_name=node_instance_filename,
                                                               class_name=node_class_name+'_NodeInstance')
            self.all_node_instance_classes[new_node] = new_node_instance_class

            #       IMPORT MAIN WIDGET
            if node_has_main_widget:
                main_widget_filename = node_module_name+module_name_separator+'main_widget'
                new_node.main_widget_class = self.get_class_from_file(file_path=node_instance_widgets_file_path,
                                                                      file_name=main_widget_filename,
                                                                      class_name=node_class_name+'_NodeInstance_MainWidget')

            #       I need to create the dict for the node's potential custom input widgets already here
            self.custom_node_input_widget_classes[new_node] = {}
            for w_name in j_node['custom input widgets']:
                input_widget_filename = node_module_name+module_name_separator+w_name
                custom_widget_class = self.get_class_from_file(file_path=node_instance_widgets_file_path,
                                                               file_name=input_widget_filename,
                                                               class_name=w_name+'_PortInstanceWidget')
                self.custom_node_input_widget_classes[new_node][w_name] = custom_widget_class


            #   note: the input widget classes get imported below in the loop
            # ---------------------------------------------------------------------------------------------------


            j_n_inputs = j_node['inputs']
            inputs = []
            num_inputs = len(j_n_inputs)
            for ii in range(num_inputs):
                j_input = j_n_inputs[ii]
                i_type = j_input['type']
                i_label = j_input['label']
                i_has_widget = None
                i_widget_type = ''
                i_widget_name = ''
                i_widget_pos = None
                if i_type == 'data':
                    i_has_widget = j_input['has widget']
                    if i_has_widget:
                        i_widget_type = j_input['widget type']
                        i_widget_pos = j_input['widget position']
                        if i_widget_type == 'custom widget':
                            i_widget_name = j_input['widget name']
                new_input = NodePort()
                new_input.type_ = i_type
                new_input.label = i_label
                if i_has_widget:
                    new_input.widget_type = i_widget_type
                    new_input.widget_name = i_widget_name
                    if i_widget_pos:
                        new_input.widget_pos = i_widget_pos
                else:
                    new_input.widget_type = 'None'
                inputs.append(new_input)

            j_n_outputs = j_node['outputs']
            outputs = []
            num_outputs = len(j_n_outputs)
            for oi in range(num_outputs):
                j_output = j_n_outputs[oi]
                o_type = j_output['type']
                o_label = j_output['label']
                new_output = NodePort()
                new_output.type_ = o_type
                new_output.label = o_label
                outputs.append(new_output)

            new_node.title = node_title
            new_node.description = node_description
            new_node.type_ = node_type
            new_node.package = package_name
            new_node.has_main_widget = node_has_main_widget
            if node_has_main_widget:
                new_node.main_widget_pos = node_main_widget_pos
            new_node.design_style = node_design_style
            new_node.color = QColor(node_color)
            new_node.inputs = inputs
            new_node.outputs = outputs

            
            self.custom_nodes.append(new_node)
            self.all_nodes.append(new_node)


        Debugger.debug(len(self.custom_nodes), 'nodes imported')


    def get_class_from_file(self, file_path, file_name, class_name):
        Debugger.debug(file_path)
        Debugger.debug(file_name)
        Debugger.debug(class_name)
        sys.path.append(file_path)
        new_module = __import__(file_name, fromlist=[class_name])
        new_class = getattr(new_module, class_name)
        return new_class



    def parse_project(self, j_obj):

        if j_obj['general info']['type'] != 'pyScriptFP project file':
            return

        for s in j_obj['scripts']:  # fill flows
            self.try_to_create_new_script(config=s)


    def on_save_project_triggered(self):
        file_name = ''
        file_name = QFileDialog.getSaveFileName(self, 'select location and give file name',
                                                '../saves', 'PyScript Project(*.pypro)')[0]
        if file_name != '':
            self.save_project(file_name)


    def save_project(self, file_name):
        import json

        file = None
        try:
            file = open(file_name, 'w')
        except FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return


        general_project_info_dict = {'type': 'pyScriptFP project file'}

        scripts_data = []
        for script in self.scripts:
            scripts_data.append(script.get_json_data())

        whole_project_dict = {'general info': general_project_info_dict,
                              'scripts': scripts_data}

        json_str = json.dumps(whole_project_dict)
        Debugger.debug(json_str)


        file.write(json_str)
        file.close()
示例#5
0
class MainWindow(QMainWindow):
    n = 8

    def __init__(self):
        super(MainWindow, self).__init__()

        # Set up the user interface from Designer.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Initial stuff
        self.chessboard = [['#' for _ in range(MainWindow.n)]
                           for _ in range(MainWindow.n)]
        self.chessboard_btns = []
        self.ui.centralwidget.setStyleSheet("background-color: #CBCBCB")
        self.ui.menubar.setStyleSheet("background-color: #A8A8A8")
        self.create_chessboard()
        self.reset_params_form()

        # Connect up the buttons.
        self.ui.resetButton.clicked.connect(self.reset_chessboard)
        self.ui.actionLoad.triggered.connect(self.load_file)
        self.ui.actionSave.triggered.connect(self.save_file)
        self.ui.solveButton.clicked.connect(self.solve)
        self.ui.algorithmComboBox.currentIndexChanged.connect(
            self.reset_params_form)
        # self.ui.paramComboBox.currentIndexChanged.connect(self.reset_params_comboBox)

        # Populate chessboard grid

    def create_chessboard(self):

        first_tile_in_row_light = True
        for i in range(MainWindow.n):
            tile_light = first_tile_in_row_light
            for j in range(MainWindow.n):
                btn = QPushButton()
                cbk = partial(self.chess_tile_clicked, btn)
                btn.clicked.connect(cbk)
                btn.setIconSize(QSize(50, 50))
                btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

                if tile_light:
                    btn.setStyleSheet(
                        "border-radius: 0px; background-color: #E8EBEF")
                else:
                    btn.setStyleSheet(
                        "border-radius: 0px; background-color: #7D8796")

                tile_light = not tile_light

                self.ui.gridLayout.addWidget(btn, i, j)
            first_tile_in_row_light = not first_tile_in_row_light

    def chess_tile_clicked(self, btn):
        index = self.ui.gridLayout.indexOf(btn)
        i = index // MainWindow.n
        j = index % MainWindow.n

        if self.chessboard[i][j] == '#':
            self.chessboard[i][j] = 'Q'
            btn.setIcon(QIcon('./ui/queen-tile.png'))
        elif self.chessboard[i][j] == 'Q':
            self.chessboard[i][j] = '#'
            btn.setIcon(QIcon())

    def reset_chessboard(self):
        s = ChessboardState(self.chessboard)
        self.chessboard = [['#' for _ in range(MainWindow.n)]
                           for _ in range(MainWindow.n)]
        for i in range(self.ui.gridLayout.count()):
            pass
            btn = self.ui.gridLayout.itemAt(i).widget()
            btn.setIcon(QIcon())

    def refresh_chessboard(self):
        for i in range(MainWindow.n):
            for j in range(MainWindow.n):
                index = i * MainWindow.n + j
                btn = self.ui.gridLayout.itemAt(index).widget()
                if self.chessboard[i][j] == '#':
                    btn.setIcon(QIcon())
                elif self.chessboard[i][j] == 'Q':
                    btn.setIcon(QIcon('./ui/queen-tile.png'))

    def reset_params_form(self):
        algorithm = self.ui.algorithmComboBox.currentText()

        if algorithm == "Hill Climbing":
            self.ui.paramLabel_1.setHidden(False)
            self.ui.paramLabel_1.setText("Restarts")
            self.ui.paramLabel_2.setHidden(True)
            self.ui.paramLineEdit_1.setHidden(False)
            self.ui.paramLineEdit_1.setText("10")
            self.ui.paramLineEdit_2.setHidden(True)
            self.ui.paramSelectLabel.setHidden(False)
            self.ui.paramComboBox.setHidden(False)
            self.ui.paramComboBox.setCurrentIndex(0)

        elif algorithm == "Beam Search":
            self.ui.paramLabel_1.setHidden(False)
            self.ui.paramLabel_1.setText("Beam Width K")
            self.ui.paramLabel_2.setHidden(True)
            self.ui.paramLineEdit_1.setHidden(False)
            self.ui.paramLineEdit_1.setText("8")
            self.ui.paramLineEdit_2.setHidden(True)
            self.ui.paramSelectLabel.setHidden(True)
            self.ui.paramComboBox.setHidden(True)

        elif algorithm == "Genetic Algorithm":
            self.ui.paramLabel_1.setHidden(False)
            self.ui.paramLabel_1.setText("Population Count")
            self.ui.paramLabel_2.setHidden(False)
            self.ui.paramLabel_2.setText("Generations")
            self.ui.paramLineEdit_1.setHidden(False)
            self.ui.paramLineEdit_1.setText("16")
            self.ui.paramLineEdit_2.setHidden(False)
            self.ui.paramLineEdit_2.setText("2500")
            self.ui.paramSelectLabel.setHidden(True)
            self.ui.paramComboBox.setHidden(True)

        elif algorithm == "CSP":
            self.ui.paramLabel_1.setHidden(True)
            self.ui.paramLabel_2.setHidden(True)
            self.ui.paramLineEdit_1.setHidden(True)
            self.ui.paramLineEdit_2.setHidden(True)
            self.ui.paramSelectLabel.setHidden(True)
            self.ui.paramComboBox.setHidden(True)

    def reset_params_comboBox(self):
        i = self.ui.paramComboBox.currentIndex()
        if i == 0:  # Random Restart
            self.ui.paramLabel_1.setHidden(False)
            self.ui.paramLineEdit_1.setHidden(False)
        else:
            self.ui.paramLabel_1.setHidden(True)
            self.ui.paramLineEdit_1.setHidden(True)

    def load_file(self):
        file, _ = QFileDialog.getOpenFileName(QFileDialog(), 'Open File')
        if file:
            self.chessboard = read_config(file)
            self.refresh_chessboard()

    def save_file(self):
        file, _ = QFileDialog.getSaveFileName(QFileDialog(), 'Save')
        if file:
            write_config(file, self.chessboard)

    def solve(self):
        algorithm = self.ui.algorithmComboBox.currentText()
        solver = None
        initial_state = ChessboardState(chessboard=self.chessboard)
        final_state = None

        if algorithm == "Hill Climbing":
            i = self.ui.paramComboBox.currentIndex()
            restarts_limit = int(self.ui.paramLineEdit_1.text())
            solver = HillClimbingSolver(['rr', 'sa'][i], restarts_limit)
            final_state = solver.solve(ChessboardStateNode(initial_state))
        elif algorithm == "Beam Search":
            k = int(self.ui.paramLineEdit_1.text())
            solver = BeamSearchSolver(k)
            final_state = solver.solve()
        elif algorithm == "Genetic Algorithm":
            pop = int(self.ui.paramLineEdit_1.text())
            gen = int(self.ui.paramLineEdit_2.text())
            solver = GASolver(n_population=pop, n_generations=gen)
            final_state = solver.solve()
        elif algorithm == "CSP":
            solver = CSPSolver()
            final_state = solver.solve(initial_state)

        self.chessboard = [['#' for _ in range(MainWindow.n)]
                           for _ in range(MainWindow.n)]
        for i, j in final_state.queen_positions:
            self.chessboard[i][j] = 'Q'
        self.refresh_chessboard()

        self.ui.runningTimeLineEdit.setText(str(solver.get_running_time()))
        self.ui.costLineEdit.setText(str(solver.get_cost()))
        self.ui.expandedNodesLineEdit.setText(str(solver.get_expanded_count()))
示例#6
0
class AppWindow(QMainWindow):
    change_data_signal = pyqtSignal(str)  # str - name of action
    scan_files_signal = pyqtSignal()

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        Shared['AppWindow'] = self

        self.old_size = None
        self.old_pos = None
        self.restore_setting()

        self.set_actions()

        self.set_menus()

        self.setup_context_menu()

        self.open_dialog = Shared['DB choice dialog']

    def set_actions(self):
        """
        Connect handlers to tool bar actions and widgets' events
        :return:
        """
        self.ui.actionOpenDB.triggered.connect(
            lambda: self.open_dialog.exec_())
        self.ui.actionScanFiles.triggered.connect(
            lambda: self.scan_files_signal.emit())
        self.ui.actionFileFilter.triggered.connect(
            lambda: self.change_data_signal.emit('Select files'))
        self.ui.actionFavorites.triggered.connect(
            lambda: self.change_data_signal.emit('Favorites'))

        self.ui.commentField.anchorClicked.connect(self.ref_clicked)
        self.ui.filesList.doubleClicked.connect(
            lambda: self.change_data_signal.emit('File_doubleClicked'))

        self.ui.dirTree.startDrag = self._start_drag
        self.ui.dirTree.dropEvent = self._drop_event
        self.ui.dirTree.dragMoveEvent = self._drag_move_event
        self.ui.filesList.startDrag = self._start_drag_files

        self.ui.filesList.resizeEvent = self.resize_event

    def _drag_move_event(self, event: QDragMoveEvent):
        index = self.ui.dirTree.indexAt(event.pos())
        mime_data = event.mimeData()
        if mime_data.hasFormat(MimeTypes[real_folder]):
            if not self.ui.dirTree.model().is_virtual(index):
                event.ignore()
            else:
                event.accept()
        else:
            event.accept()

    def _drop_event(self, event: QDropEvent):
        mime_data: QMimeData = event.mimeData()
        index = self.ui.dirTree.indexAt(event.pos())

        act = self._set_action(index, mime_data, event.pos())

        res = self.ui.dirTree.model().dropMimeData(mime_data, act, index)
        if res:
            event.accept()
        else:
            event.ignore()

    def _set_action(self, index, mime_data, pos):
        """
        index: in dirTree at drop position
        mime_data:
        pos: position where menu to be shown
        return: DropNoAction, DropCopyFolder, DropMoveFolder, DropCopyFile, DropMoveFile
        """
        if mime_data.hasFormat(MimeTypes[real_folder]):
            if self.ui.dirTree.model().is_virtual(index):
                return DropCopyFolder
            return DropNoAction
        if mime_data.hasFormat(MimeTypes[file_real]):
            if self.ui.dirTree.model().is_virtual(index):
                return DropCopyFile
            return self._ask_action_file(pos)
        if mime_data.hasFormat(MimeTypes[file_virtual]):
            return self._ask_action_file(pos)
        if mime_data.hasFormat(MimeTypes[virtual_folder]):
            return self._ask_action_folder(pos)
        return DropNoAction

    def _ask_action_file(self, pos):
        """
        Menu: drag-drop action chooser
        when drop file(s) to directory tree item(folder)
        Actions: Copy | Move | Cancel
        Returns: int (DropCopyFile=4, DropMoveFile=8, DropNoAction=0)
        """
        return self._ask_action_folder(pos) * 4

    def _ask_action_folder(self, pos):
        """
        Menu: drag-drop action chooser
        when drop folder(s) to directory tree item(folder)
        Actions: Copy | Move | Cancel
        Returns: int (DropCopyFolder=1, DropMoveFolder=2, DropNoAction=0)
        """
        menu = QMenu(self)
        menu.addAction('Copy')
        menu.addAction('Move')
        menu.addSeparator()
        menu.addAction('Cancel')
        action = menu.exec_(self.ui.dirTree.mapToGlobal(pos))
        if action:
            if action.text() == 'Copy':
                return DropCopyFolder
            elif action.text() == 'Move':
                return DropMoveFolder
        return DropNoAction

    def _start_drag_files(self, action):
        drag = QDrag(self)
        drag.setPixmap(QPixmap(":/image/List.png"))
        indexes = self.ui.filesList.selectionModel().selectedRows()
        mime_data = self.ui.filesList.model().mimeData(indexes)
        drag.setMimeData(mime_data)
        drag.exec_(Qt.CopyAction)

    def _start_drag(self, action):
        drag = QDrag(self)
        drag.setPixmap(QPixmap(":/image/Folder.png"))
        indexes = self.ui.dirTree.selectionModel().selectedRows()
        mime_data = self.ui.dirTree.model().mimeData(indexes)
        drag.setMimeData(mime_data)
        if mime_data.hasFormat(MimeTypes[real_folder]):
            drag.exec_(Qt.CopyAction)
        elif mime_data.hasFormat(MimeTypes[virtual_folder]):
            drag.exec_(Qt.MoveAction)

    def set_menus(self):
        """
        Set actions of main menu
        :return:
        """
        menu = QMenu(self)
        open_db = menu.addAction('Open DB')
        change_font = menu.addAction('Change Font')
        set_fields = menu.addAction('Set fields')
        self.ui.btnOption.setMenu(menu)
        open_db.triggered.connect(lambda: self.open_dialog.exec_())
        change_font.triggered.connect(
            lambda: self.change_data_signal.emit('change_font'))
        set_fields.triggered.connect(
            lambda: self.change_data_signal.emit('Set fields'))

        menu2 = QMenu(self)
        sel_opt = menu2.addAction('Selection options')
        self.ui.btnGetFiles.setMenu(menu2)
        sel_opt.triggered.connect(
            lambda: self.change_data_signal.emit('Selection options'))

    def setup_context_menu(self):
        """
        Set context menus for each widget
        :return:
        """
        self.ui.dirTree.customContextMenuRequested.connect(self._dir_menu)
        self.ui.filesList.customContextMenuRequested.connect(self._file_menu)
        self.ui.extList.customContextMenuRequested.connect(self._ext_menu)
        self.ui.tagsList.customContextMenuRequested.connect(self._tag_menu)
        self.ui.authorsList.customContextMenuRequested.connect(
            self._author_menu)

    def _file_menu(self, pos):
        idx = self.ui.filesList.indexAt(pos)
        if idx.isValid():
            menu = QMenu(self)
            menu.addAction('Open')
            menu.addAction('Open folder')
            menu.addAction('Add to favorites')
            menu.addAction('Delete row')
            menu.addSeparator()
            menu.addAction('Copy file name')
            menu.addAction('Copy path')
            menu.addSeparator()
            menu.addAction('Rename file')
            menu.addAction('Copy file(s)')
            if self.ui.filesList.model().in_real_folder(idx):
                menu.addAction('Move file(s)')
                menu.addAction('Delete file(s)')
            action = menu.exec_(self.ui.filesList.mapToGlobal(pos))
            if action:
                self.change_data_signal.emit('File {}'.format(action.text()))

    def _ext_menu(self, pos):
        menu = QMenu(self)
        menu.addAction('Remove unused')
        menu.addAction('Create group')
        menu.addAction('Delete all files with current extension')
        action = menu.exec_(self.ui.extList.mapToGlobal(pos))
        if action:
            self.change_data_signal.emit('Ext {}'.format(action.text()))

    def _tag_menu(self, pos):
        idx = self.ui.tagsList.indexAt(pos)
        menu = QMenu(self)
        menu.addAction('Remove unused')
        if idx.isValid():
            menu.addAction('Scan in names')
            menu.addAction('Rename')

        action = menu.exec_(self.ui.tagsList.mapToGlobal(pos))
        if action:
            self.change_data_signal.emit('Tag {}'.format(action.text()))

    def _author_menu(self, pos):
        menu = QMenu(self)
        menu.addAction('Remove unused')
        action = menu.exec_(self.ui.authorsList.mapToGlobal(pos))
        if action:
            self.change_data_signal.emit('Author {}'.format(action.text()))

    def _dir_menu(self, pos):
        idx = self.ui.dirTree.indexAt(pos)
        menu = QMenu(self)
        menu.addAction('Remove empty folders')
        if idx.isValid():
            if self.ui.dirTree.model().is_virtual(idx):
                if not self.ui.dirTree.model().is_favorites(idx):
                    menu.addSeparator()
                    menu.addAction('Rename folder')
                    menu.addAction('Delete folder')
            else:
                parent = self.ui.dirTree.model().parent(idx)
                if self.ui.dirTree.model().is_virtual(parent):
                    menu.addSeparator()
                    menu.addAction('Delete folder')
                menu.addAction('Rescan dir')
                menu.addSeparator()
                menu.addAction('Group')
            menu.addSeparator()
            menu.addAction('Create virtual folder')
            menu.addAction('Create virtual folder as child')
        else:
            menu.addAction('Create virtual folder')

        action = menu.exec_(self.ui.dirTree.mapToGlobal(pos))
        if action:
            self.change_data_signal.emit('Dirs {}'.format(action.text()))

    def ref_clicked(self, href):
        """
        Invoke methods to change file information: tags, authors, comment
        :param href:
        :return:
        """
        self.ui.commentField.setSource(QUrl())
        self.change_data_signal.emit(href.toString())

    def resizeEvent(self, event):
        """
        resizeEvent - when changed main window. To save size for next run
        :param event:
        :return:
        """
        super().resizeEvent(event)
        self.old_size = event.oldSize()
        settings = QSettings()
        settings.setValue("MainFlow/Size", QVariant(self.size()))

    def resize_event(self, event: QResizeEvent):
        """
        resizeEvent of filesList, to change width of columns
        :param event:
        :return:
        """
        old_w = event.oldSize().width()
        w = event.size().width()
        if not old_w == w:
            self.change_data_signal.emit('Resize columns')

    def changeEvent(self, event):
        """
        Save size and position of window before it maximized
        :param event:
        :return:
        """
        if event.type() == QEvent.WindowStateChange:
            settings = QSettings()
            if event.oldState() == Qt.WindowMaximized:
                settings.setValue("MainFlow/isFullScreen", QVariant(False))
            elif event.oldState() == Qt.WindowNoState and \
                    self.windowState() == Qt.WindowMaximized:
                settings.setValue("MainFlow/isFullScreen", QVariant(True))
                if self.old_size:
                    settings.setValue("MainFlow/Size", QVariant(self.old_size))
                if self.old_pos:
                    settings.setValue("MainFlow/Position",
                                      QVariant(self.old_pos))
        else:
            super().changeEvent(event)

    def moveEvent(self, event):
        """
        Save new position of window
        :param event:
        :return:
        """
        self.old_pos = event.oldPos()
        settings = QSettings()
        settings.setValue("MainFlow/Position", QVariant(self.pos()))
        super().moveEvent(event)

    def restore_setting(self):
        settings = QSettings()
        if settings.contains("MainFlow/Size"):
            size = settings.value("MainFlow/Size", QSize(640, 480))
            self.resize(size)
            position = settings.value("MainFlow/Position")
            self.move(position)
            self.restoreState(settings.value("MainFlow/State"))
            self.restoreState(settings.value("MainFlow/State"))
            self.ui.splitter_files.restoreState(
                settings.value("FilesSplitter"))
            self.ui.opt_splitter.restoreState(settings.value("OptSplitter"))
            self.ui.main_splitter.restoreState(settings.value("MainSplitter"))
            if settings.value("MainFlow/isFullScreen", False, type=bool):
                self.showMaximized()
        else:
            self.ui.main_splitter.setStretchFactor(0, 2)
            self.ui.main_splitter.setStretchFactor(1, 5)
            self.ui.main_splitter.setStretchFactor(2, 1)
            self.ui.splitter_files.setStretchFactor(0, 5)
            self.ui.splitter_files.setStretchFactor(1, 2)

    def first_open_data_base(self):
        """
        Open DB when application starts
        :return:
        """
        if not self.open_dialog.skip_open_dialog():
            self.open_dialog.exec_()
        else:
            self.open_dialog.emit_open_dialog()

    def closeEvent(self, event):
        self.open_dialog.save_init_data()
        settings = QSettings()
        settings.setValue("MainFlow/State", QVariant(self.saveState()))
        settings.setValue("FilesSplitter",
                          QVariant(self.ui.splitter_files.saveState()))
        settings.setValue("OptSplitter",
                          QVariant(self.ui.opt_splitter.saveState()))
        settings.setValue("MainSplitter",
                          QVariant(self.ui.main_splitter.saveState()))
        super(AppWindow, self).closeEvent(event)