def _clearSettings(self):
     """
     Just clears all peacock settings.
     """
     settings = QSettings()
     settings.clear()
     settings.sync()
Example #2
0
    def testPrefs(self):
        settings = QSettings()
        settings.setValue("execute/maxRecentWorkingDirs", 2)
        settings.setValue("execute/maxRecentExes", 3)
        settings.setValue("execute/maxRecentArgs", 4)
        settings.setValue("execute/mpiEnabled", True)
        settings.setValue("execute/mpiArgs", "foo bar")
        settings.setValue("execute/threadsEnabled", True)
        settings.setValue("execute/threadsArgs", "threads args")
        settings.sync()

        main_win, w = self.newWidget()
        ops = w.ExecuteOptionsPlugin
        self.assertEqual(ops.mpi_checkbox.isChecked(), True)
        self.assertEqual(ops.threads_checkbox.isChecked(), True)
        self.assertEqual(ops.mpi_line.text(), "foo bar")
        self.assertEqual(ops.threads_line.text(), "threads args")

        settings.setValue("execute/mpiEnabled", False)
        settings.setValue("execute/mpiArgs", "some args")
        settings.setValue("execute/threadsEnabled", False)
        settings.setValue("execute/threadsArgs", "other args")
        settings.sync()

        main_win, w = self.newWidget()
        ops = w.ExecuteOptionsPlugin
        self.assertEqual(ops.mpi_checkbox.isChecked(), False)
        self.assertEqual(ops.threads_checkbox.isChecked(), False)
        self.assertEqual(ops.mpi_line.text(), "some args")
        self.assertEqual(ops.threads_line.text(), "other args")
 def SetLanguage(self):
     global actualLanguage
     settings = QSettings('Pandoc', 'PanConvert')
     settings.setValue('default_language', str(self.ui.comboBoxLanguageSelector.currentText()))
     actualLanguage = str(self.ui.comboBoxLanguageSelector.currentText())
     settings.sync()
     settings.status()
    def settings(self):

        settings = QSettings("Pandoc", "PanConvert")
        settings.setValue("path_pandoc", self.ui.Pandoc_Path.text())
        settings.setValue("path_multimarkdown", self.ui.Markdown_Path.text())
        settings.setValue("path_dialog", self.ui.Dialog_Path.text())

        settings.setValue("fromParameter", self.ui.FromParameter.text())
        settings.setValue("toParameter", self.ui.ToParameter.text())
        settings.setValue("xtraParameter", self.ui.XtraParameter.text())

        settings.setValue("Standard_Conversion", self.ui.StandardConversion.isChecked())
        settings.setValue("Batch_Conversion", self.ui.BatchConversion.isChecked())

        settings.setValue("From_Markdown", self.ui.ButtonFromMarkdown.isChecked())
        settings.setValue("From_Html", self.ui.ButtonFromHtml.isChecked())
        settings.setValue("From_Latex", self.ui.ButtonFromLatex.isChecked())
        settings.setValue("From_Opml", self.ui.ButtonFromOpml.isChecked())

        settings.setValue("To_Markdown", self.ui.ButtonToMarkdown.isChecked())
        settings.setValue("To_Html", self.ui.ButtonToHtml.isChecked())
        settings.setValue("To_Latex", self.ui.ButtonToLatex.isChecked())
        settings.setValue("To_Opml", self.ui.ButtonToOpml.isChecked())
        settings.setValue("To_Lyx", self.ui.ButtonToLyx.isChecked())

        settings.sync()
        settings.status()

        PreferenceDialog.close(self)
def test_init(init_patch, config_tmpdir):
    configfiles.init()

    # Make sure qsettings land in a subdir
    if utils.is_linux:
        settings = QSettings()
        settings.setValue("hello", "world")
        settings.sync()
        assert (config_tmpdir / 'qsettings').exists()
Example #6
0
 def _save(self):
     """
     Saves all the settings from the different widgets.
     """
     settings = QSettings()
     for i in range(self.tabs.count()):
         w = self.tabs.widget(i)
         w.save(settings)
     settings.sync()
     self.close()
Example #7
0
    def batch_settings(self):
        global batch_open_path, openfiles

        batch_settings = QSettings('Pandoc', 'PanConvert')
        batch_settings.setValue('batch_convert_directory', self.ui.ParameterBatchconvertDirectory.isChecked())
        batch_settings.setValue('batch_convert_files', self.ui.ParameterBatchconvertFiles.isChecked())
        batch_settings.setValue('batch_convert_recursive', self.ui.ParameterBatchconvertRecursive.isChecked())
        batch_settings.setValue('batch_open_path', self.ui.OpenPath.text())
        batch_settings.sync()
        batch_settings.status()

        BatchDialog.close(self)
Example #8
0
 def clearAll(settings_key):
     """
     Clear the cache files and the value in QSettings
     Input:
         settings_key[str]: The key in QSettings
     """
     settings = QSettings()
     val = settings.value(settings_key, type=dict)
     for key, val in val.items():
         FileCache.removeCacheFile(val["pickle_path"])
     settings.remove(settings_key)
     settings.sync()
Example #9
0
    def closeEvent(self, event):

        settings = QSettings('Pandoc', 'PanConvert')
        Dialog_Size = settings.value('Dialog_Size')
        if Dialog_Size is True or Dialog_Size == 'true':
            settings.setValue("Batch_size", self.size())
            settings.setValue("Batch_pos", self.pos())


        settings.sync()
        settings.status()
        BatchDialog.close(self)
Example #10
0
    def show_preferences(self):
        """shows the preferences dialog"""

        dialog = QDialog()
        my_preferences_dialog = PreferencesDialog(dialog)

        dialog_accepted = dialog.exec()

        if dialog_accepted:
            print('image quality set to ' + str(my_preferences_dialog.spinBox.value()))
            mySettings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'Sogeti', 'validate')
            mySettings.setValue('report/imageQuality', my_preferences_dialog.spinBox.value())
            mySettings.sync()
Example #11
0
    def resetPushButtonPressed(self, button):
        # create an object for PersepolisDB
        persepolis_db = PersepolisDB()

        # Reset data base
        persepolis_db.resetDataBase()

        # close connections
        persepolis_db.closeConnections()

        # Reset persepolis_setting
        persepolis_setting = QSettings('persepolis_download_manager', 'persepolis')
        persepolis_setting.clear()
        persepolis_setting.sync()
    def settings(self):

        settings = QSettings('Pandoc', 'PanConvert')

        settings.setValue('Window_Size', self.ui.Window_Size.isChecked())
        settings.setValue('Dock_Size', self.ui.Dock_Size.isChecked())
        settings.setValue('Dialog_Size', self.ui.Dialog_Size.isChecked())
        settings.setValue('Hide_Batch', self.ui.Hide_Batch.isChecked())

        settings.setValue('Button_OldGui', self.ui.Button_OldGui.isChecked())
        settings.setValue('Button_NewGui', self.ui.Button_NewGui.isChecked())
        settings.setValue('Tab_StandardConverter', self.ui.Tab_StandardConverter.isChecked())
        settings.setValue('Tab_ManualConverter', self.ui.Tab_ManualConverter.isChecked())

        settings.setValue('path_pandoc', self.ui.Pandoc_Path.text())
        settings.setValue('path_multimarkdown', self.ui.Markdown_Path.text())
        settings.setValue('path_dialog', self.ui.Dialog_Path.text())

        settings.setValue('BufferSaveSuffix', self.ui.BufferSaveSuffix.text())
        settings.setValue('BufferSaveName', self.ui.BufferSaveName.text())

        settings.setValue('fromParameter', self.ui.FromParameter.text())
        settings.setValue('toParameter', self.ui.ToParameter.text())
        settings.setValue('xtraParameter', self.ui.XtraParameter.text())

        settings.setValue('Standard_Conversion', self.ui.StandardConversion.isChecked())
        settings.setValue('Batch_Conversion', self.ui.BatchConversion.isChecked())


        settings.setValue('From_Markdown', self.ui.ButtonFromMarkdown.isChecked())
        settings.setValue('From_Html', self.ui.ButtonFromHtml.isChecked())
        settings.setValue('From_Latex', self.ui.ButtonFromLatex.isChecked())
        settings.setValue('From_Opml', self.ui.ButtonFromOpml.isChecked())

        settings.setValue('To_Markdown', self.ui.ButtonToMarkdown.isChecked())
        settings.setValue('To_Html', self.ui.ButtonToHtml.isChecked())
        settings.setValue('To_Latex', self.ui.ButtonToLatex.isChecked())
        settings.setValue('To_Opml', self.ui.ButtonToOpml.isChecked())
        settings.setValue('To_Lyx', self.ui.ButtonToLyx.isChecked())

        Dialog_Size = settings.value('Dialog_Size')
        if Dialog_Size is True or Dialog_Size == 'true':
            settings.setValue("Preference_size", self.size())
            settings.setValue("Preference_pos", self.pos())

        settings.sync()
        settings.status()

        PreferenceDialog.close(self)
Example #13
0
def get_path_pandoc():

    settings = QSettings('Pandoc', 'PanConvert')
    path_pandoc_tmp = settings.value('path_pandoc','')
    path_pandoc = str(path_pandoc_tmp)

    if not os.path.isfile(path_pandoc):

        if platform.system() == 'Darwin' or os.name == 'posix':
            path_pandoc = which("pandoc")
            settings.setValue('path_pandoc', path_pandoc)
            settings.sync()
        else:
            path_pandoc = where("pandoc.exe")
            settings.setValue('path_pandoc', path_pandoc)
            settings.sync()
Example #14
0
    def saveSettingsChanged(self):
        if self.txtAutoSave.text() in ["", "0"]:
            self.txtAutoSave.setText("1")
        if self.txtAutoSaveNoChanges.text() in ["", "0"]:
            self.txtAutoSaveNoChanges.setText("1")

        sttgs = QSettings()
        sttgs.setValue("autoLoad", True if self.chkAutoLoad.checkState() else False)
        sttgs.sync()

        settings.autoSave = True if self.chkAutoSave.checkState() else False
        settings.autoSaveNoChanges = True if self.chkAutoSaveNoChanges.checkState() else False
        settings.saveOnQuit = True if self.chkSaveOnQuit.checkState() else False
        settings.autoSaveDelay = int(self.txtAutoSave.text())
        settings.autoSaveNoChangesDelay = int(self.txtAutoSaveNoChanges.text())
        self.mw.saveTimer.setInterval(settings.autoSaveDelay * 60 * 1000)
        self.mw.saveTimerNoChanges.setInterval(settings.autoSaveNoChangesDelay * 1000)
        settings.defaultTextType = self.cmbDefaultTextType.currentData()
Example #15
0
def get_path_pandoc():

    settings = QSettings('Pandoc', 'PanConvert')
    path_pandoc = settings.value('path_pandoc','')

    if len(path_pandoc) == 0:

        if platform.system() == 'Darwin' or platform.system() == 'Linux':
            args = ['which', 'pandoc']
            p = subprocess.Popen(
                args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE)

            path_pandoc = str.rstrip(p.communicate(path_pandoc.encode('utf-8'))[0].decode('utf-8'))
            settings.setValue('path_pandoc', path_pandoc)
            settings.sync()
            return path_pandoc

        elif platform.system() == 'Windows':
            args = ['where', 'pandoc']
            p = subprocess.Popen(
                args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE)

            path_pandoc = str.rstrip(p.communicate(path_pandoc.encode('utf-8'))[0].decode('utf-8'))
            settings.setValue('path_pandoc', path_pandoc)
            settings.sync()
            return path_pandoc
        else:
            QtWidgets.QMessageBox.warning(None, 'Error-Message',
                                          'Could not detect the actual operating system. Please fill in the Path'
                                          ' to Pandoc manually via Preferences.')

    elif len(path_pandoc) != 0:
        return path_pandoc

    else:
       QtWidgets.QMessageBox.warning(None, 'Error-Message',
                                          'I tried automagically to detect pandoc. But it failed.'
                                          'Please input the path of pandoc manually via preferences')
Example #16
0
class Config:
    def __init__(self, organization, product):
        self.config = QSettings(organization, product)

    def setValue(self, option, value):
        self.config.setValue(option, QVariant(value))
        self.config.sync()

    def getBoolValue(self, option):
        default = self._initValue(option, False)
        return self.config.value(option, QVariant(default)).toBool()

    def getNumValue(self, option):
        default = self._initValue(option, 0)
        return self.config.value(option, QVariant(default)).toInt()[0]

    def _initValue(self, option, value):
        if defaults.has_key(option):
            return defaults[option]
        return value
Example #17
0
def gui_main():
    init()
    global config, root_folder, settings, main_window
    root_folder = os.path.expanduser(config.get("root_folder"))
    if root_folder[-1] != '/':
        root_folder += '/'
    settings = QSettings("org", "edocuments")

    app = QApplication(sys.argv)
    main_window = MainWindow()
    if settings.value("geometry") is not None:
        main_window.restoreGeometry(settings.value("geometry"))
    if settings.value("state") is not None:
        main_window.restoreState(settings.value("state"))

    main_window.show()
    app.exec()
    settings.setValue("geometry", main_window.saveGeometry())
    settings.setValue("state", main_window.saveState())
    settings.sync()
class L5RCMSettings(object):
    """A QSettings wrapper for easy access to application settings"""

    def __init__(self):
        self._qsettings = QSettings()

        # Application settings
        self._app = L5RCMSettings_App(self._qsettings)
        # UI settings
        self._ui = L5RCMSettings_UI(self._qsettings)
        # PC export PDF generation settings
        self._pc_export = L5RCMSettings_PcExport(self._qsettings)
        # NPC export PDF generation settings
        self._npc_export = L5RCMSettings_NpcExport(self._qsettings)

    @property
    def app(self):
        return self._app

    @property
    def ui(self):
        return self._ui

    @property
    def pc_export(self):
        return self._pc_export

    @property
    def npc_export(self):
        return self._npc_export

    def sync(self):
        self._qsettings.sync()

    def load_defaults(self):
        self._app.load_defaults()
        self._ui.load_defaults()
        self._pc_export.load_defaults()
        self._npc_export.load_defaults()
Example #19
0
def get_path_multimarkdown():
    settings = QSettings('Pandoc', 'PanConvert')
    path_multimarkdown = settings.value('path_multimarkdown','')

    if getattr( sys, 'frozen', False ):
            if platform.system() == 'Darwin' or os.name == 'posix':
                path_multimarkdown = which("multimarkdown")
                settings.setValue('path_multimarkdown', path_multimarkdown)
                settings.sync()
            else:
                args = ['where', 'multimarkdown']
                p = subprocess.Popen(
                    args,
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE)

                path_multimarkdown = str.rstrip(p.communicate(path_multimarkdown.encode('utf-8'))[0].decode('utf-8'))
                settings.setValue('path_multimarkdown', path_multimarkdown)
                settings.sync()
                return path_multimarkdown
    else:

        if platform.system() == 'Darwin' or os.name == 'posix':
            args = ['which', 'multimarkdown']
            p = subprocess.Popen(
                args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE)

            path_multimarkdown = str.rstrip(p.communicate(path_multimarkdown.encode('utf-8'))[0].decode('utf-8'))
            settings.setValue('path_multimarkdown', path_multimarkdown)
            settings.sync()
            return path_multimarkdown

        elif platform.system() == 'Windows':
            args = ['where', 'multimarkdown']
            p = subprocess.Popen(
                args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE)

            path_multimarkdown = str.rstrip(p.communicate(path_multimarkdown.encode('utf-8'))[0].decode('utf-8'))
            settings.setValue('path_multimarkdown', path_multimarkdown)
            settings.sync()
            return path_multimarkdown
Example #20
0
class Addon(clickpoints.Addon):
    def __init__(self, *args, **kwargs):

        clickpoints.Addon.__init__(self, *args, **kwargs)

        self.frame_number = except_error(self.db.getImageCount,
                                         TypeError,
                                         print_error=False,
                                         return_v=None)
        # information about the path, image dimensions
        self.db_info, self.all_frames = get_db_info_for_analysis(self.db)
        print_db_info(self.db_info)

        self.res_dict = defaultdict(
            list)  # dictionary that catches all results
        self.masks = None
        self.parameter_dict = copy.deepcopy(
            default_parameters)  # loading default parameters
        self.read_or_set_options(
        )  # reading the database folder and the previous FEM_mode, or fill in default values
        self.outfile_path = os.path.join(
            self.folder, "out.txt")  # path for output text file
        self.config_path = os.path.join(self.folder, "config.yaml")

        # loading some default settings
        if os.path.exists(self.config_path):
            print("found config at", self.config_path)
            self.parameter_dict = load_config(self.config_path,
                                              self.parameter_dict)
        # QT settings overwrite "default_parameters"
        # reading Qt settings file
        # on linux this file is saved at /home/user/.config/pyTFM
        self.settings = QSettings("pyTFM", "pyTFM")
        for key in self.parameter_dict.keys():
            if not self.settings.value(key) is None:
                self.parameter_dict[key] = self.settings.value(key)

        # TODO: consider to save settings in each database separately
        """ GUI Widgets"""
        # set the title and layout
        self.setWindowTitle("pyTFM" + "-" + pyTFM.__version__)
        self.setWindowIcon(qta.icon("fa.compress"))
        self.setMinimumWidth(400)
        self.setMinimumHeight(200)
        self.layout = QtWidgets.QGridLayout(self)
        self.layout.setColumnMinimumWidth(0, 150)

        # button to start calculation
        self.button_start = QtWidgets.QPushButton("start")
        self.button_start.clicked.connect(
            partial(self.start_thread, run_function=self.start))
        self.button_start.setToolTip(tooltips["button_start"])
        self.layout.addWidget(self.button_start, 0, 0)

        # button to select images:
        self.button_select_images = QtWidgets.QPushButton("image selection")
        self.button_select_images.clicked.connect(self.select_images)
        self.button_select_images.setToolTip(tooltips["image selection"])
        self.sub_layout1 = QtWidgets.QHBoxLayout()
        self.sub_layout1.addWidget(self.button_select_images)
        self.sub_layout1.addStretch()
        self.layout.addLayout(self.sub_layout1, 1, 0)

        # button to apply drift correction:
        self.correct_drift = QtWidgets.QPushButton("correct drift")
        self.correct_drift.clicked.connect(
            partial(self.start_thread, run_function=self.drift_correction))
        self.correct_drift.setToolTip(tooltips["correct drift"])
        self.sub_layout2 = QtWidgets.QHBoxLayout()
        self.sub_layout2.addWidget(self.correct_drift)
        self.sub_layout2.addStretch()
        self.layout.addLayout(self.sub_layout2, 2, 0)

        # check_boxes
        self.check_box_def = QtWidgets.QCheckBox("deformation")
        self.check_box_tra = QtWidgets.QCheckBox("traction forces")
        self.check_box_FEM = QtWidgets.QCheckBox("stress analysis")
        self.check_box_contract = QtWidgets.QCheckBox("force generation")

        self.check_box_def.setToolTip(tooltips["check_box_def"])
        self.check_box_tra.setToolTip(tooltips["check_box_tra"])
        self.check_box_FEM.setToolTip(tooltips["check_box_FEM"])
        self.check_box_contract.setToolTip(tooltips["check_box_contract"])

        self.layout.addWidget(self.check_box_def, 0, 1)
        self.layout.addWidget(self.check_box_tra, 1, 1)
        self.layout.addWidget(self.check_box_FEM, 2, 1)
        self.layout.addWidget(self.check_box_contract, 3, 1)

        # a gap
        self.layout.setRowMinimumHeight(4, 20)

        # # choosing single or all frames
        self.analysis_mode = QtWidgets.QComboBox()
        self.analysis_mode.addItems(["current frame", "all frames"])
        self.analysis_mode.setToolTip(tooltips["apply to"])
        self.layout.addWidget(self.analysis_mode, 5, 1)
        self.analysis_mode_descript = QtWidgets.QLabel()
        self.analysis_mode_descript.setText("apply to")
        self.layout.addWidget(self.analysis_mode_descript, 5, 0)

        # parameters
        self.parameter_labels = [
            "Youngs modulus [Pa]", "Poisson's ratio", "pixel size [µm]",
            "PIV overlap [µm]", "PIV window size [µm]", "gel height [µm]"
        ]
        self.param_dict_keys = [
            "young", "sigma", "pixelsize", "overlap", "window_size", "h"
        ]
        self.parameter_widgets, self.parameter_lables, last_line = add_parameter_from_list(
            self.parameter_labels, self.param_dict_keys, self.parameter_dict,
            self.layout, 6, self.parameters_changed)

        # adding to layout
        self.setLayout(self.layout)
        self.parameters_changed()  # initialize parameters dict

        # choosing type of cell system
        self.colony_type = QtWidgets.QComboBox()
        self.colony_type.addItems(["colony", "cell layer"])
        self.colony_type.setToolTip(tooltips["switch mode"])
        self.colony_type.setCurrentIndex(self.parameter_dict["FEM_mode_id"])
        # update parameters
        self.colony_type.currentTextChanged.connect(self.parameters_changed)
        # switch between cell layer and colony mode
        self.colony_type.currentTextChanged.connect(
            self.switch_colony_type_mode)
        self.parameter_widgets[
            "FEM_mode"] = self.colony_type  # adding to parameters dict
        self.parameter_lables["FEM_mode"] = ""  # label
        self.sub_layout3 = QtWidgets.QHBoxLayout()
        self.sub_layout3.addWidget(self.colony_type)

        # button for simple segmentation of membranes and cell area
        self.button_seg = QtWidgets.QPushButton("segmentation")
        self.button_seg.setToolTip(tooltips["segmentation"])
        self.button_seg.clicked.connect(self.segmentation)  # update parameters
        self.sub_layout3.addWidget(self.button_seg)
        self.sub_layout3.addStretch()
        self.layout.addLayout(self.sub_layout3, 3, 0)

    def read_or_set_options(self):
        self.folder = get_option_wrapper(self.db,
                                         "folder",
                                         unpack_funct=None,
                                         empty_return=lambda: "")
        if self.folder == "":
            self.folder = os.getcwd()
            self.db._AddOption(key="folder", value=self.folder)
            self.db.setOption(key="folder", value=self.folder)
        self.parameter_dict["FEM_mode"] = get_option_wrapper(
            self.db, "FEM_mode", empty_return=lambda: "")
        if self.parameter_dict["FEM_mode"] == "":
            self.parameter_dict["FEM_mode"] = default_parameters["FEM_mode"]
            self.db._AddOption(key="FEM_mode",
                               value=self.parameter_dict["FEM_mode"])
            self.db.setOption(key="FEM_mode",
                              value=self.parameter_dict["FEM_mode"])
        self.parameter_dict["FEM_mode_id"] = 0 if self.parameter_dict[
            "FEM_mode"] == "colony" else 1

    def select_images(self):  # for what do i need this??
        self._new_window = FileSelectWindow(self)
        self._new_window.show()

    def reload_all(self):  # reloading entire display ## could be optimized
        sys.stdout = open(os.devnull, 'w')
        for frame in self.db_info["cbd_frames_ref_dict"].keys():
            for layer in self.db_info["layers"]:
                self.cp.reloadImage(frame_index=frame,
                                    layer_id=self.db.getLayer(layer).id)
        sys.stdout = sys.__stdout__

    # reading paramteres and updating the dictionary
    def parameters_changed(self):
        self.parameter_dict = read_all_paramters(self.parameter_widgets,
                                                 self.parameter_dict)

    # decorator functions to handle diffrent outputs and writing to text file
    def calculate_general_properties(
            self,
            frames):  # calculation of colony area, number of cells in colony
        self.db_info, self.masks, self.res_dict = apply_to_frames(
            self.db,
            self.parameter_dict,
            analysis_function=general_properties,
            res_dict=self.res_dict,
            masks=self.masks,
            frames=frames,
            db_info=self.db_info)

    def calculate_deformation(self, frames):  # calculation of deformations

        self.db_info, self.masks, self.res_dict = apply_to_frames(
            self.db,
            self.parameter_dict,
            analysis_function=deformation,
            res_dict=self.res_dict,
            masks=self.masks,
            frames=frames,
            db_info=self.db_info)

    def calculate_traction(self, frames):  # calculation of traction forces
        self.db_info, self.masks, self.res_dict = apply_to_frames(
            self.db,
            self.parameter_dict,
            analysis_function=traction_force,
            res_dict=self.res_dict,
            masks=self.masks,
            frames=frames,
            db_info=self.db_info)

    def calculate_FEM_analysis(
            self, frames):  # calculation of various stress measures
        self.db_info, self.masks, self.res_dict = apply_to_frames(
            self.db,
            self.parameter_dict,
            analysis_function=FEM_full_analysis,
            res_dict=self.res_dict,
            masks=self.masks,
            frames=frames,
            db_info=self.db_info)

    def calculate_contractile_measures(
            self,
            frames):  # calculation of contractility and contractile energy
        self.db_info, self.masks, self.res_dict = apply_to_frames(
            self.db,
            self.parameter_dict,
            analysis_function=get_contractillity_contractile_energy,
            masks=self.masks,
            res_dict=self.res_dict,
            frames=frames,
            db_info=self.db_info)

    def set_frames(self):
        if self.mode == "current frame":  # only current frame
            frames = self.frame
        if self.mode == "all frames":  # all frames
            frames = self.all_frames
        return frames

    def drift_correction(
            self):  # calculation of contractility and contractile energy
        cdb_frame = self.cp.getCurrentFrame()
        self.frame = self.db_info["cbd_frames_ref_dict"][cdb_frame]
        self.mode = self.analysis_mode.currentText(
        )  # only current frame or all frames
        frames = self.set_frames()
        self.db_info, self.masks, self.res_dict = apply_to_frames(
            self.db,
            self.parameter_dict,
            analysis_function=simple_shift_correction,
            masks=self.masks,
            res_dict=self.res_dict,
            frames=frames,
            db_info=self.db_info)
        print("calculation complete")

    def segmentation(
            self):  # calculation of contractility and contractile energy
        self.cdb_frame = self.cp.getCurrentFrame()
        self.frame = self.db_info["cbd_frames_ref_dict"][self.cdb_frame]
        self._new_window_slider = SegSlider(self)
        self._new_window_slider.show()

    # switching the type of cell colony
    def switch_colony_type_mode(self, first=False):
        setup_mask_wrapper(self,
                           self.db,
                           self.db_info,
                           self.parameter_dict,
                           delete_all=False)
        self.cp.reloadMaskTypes(
        )  # reloading mask to display in clickpoints window
        try:
            self.db.setOption(key="FEM_mode",
                              value=self.parameter_dict["FEM_mode"])
        except KeyError:
            self.db._AddOption(key="FEM_mode",
                               value=self.parameter_dict["FEM_mode"])
            self.db.setOption(key="FEM_mode",
                              value=self.parameter_dict["FEM_mode"])

    def start(self):
        # store parameters in settings
        for key in self.param_dict_keys:
            self.settings.setValue(key, self.parameter_dict[key])
        self.settings.sync()

        # workaround because plt.figure() sometimes gets overloaded when other addons are imported
        if "figures" in list(plt.figure.__globals__.keys()):
            importlib.reload(plt)

        # generating objects needed for the following calculation, if they are not exsisting already
        print_parameters(self.parameter_dict)
        print("output file: ", self.outfile_path)
        self.db_info, self.all_frames = get_db_info_for_analysis(self.db)
        cdb_frame = self.cp.getCurrentFrame()
        self.frame = self.db_info["cbd_frames_ref_dict"][cdb_frame]
        self.mode = self.analysis_mode.currentText(
        )  # only current frame or all frames
        self.res_dict = defaultdict(lambda: defaultdict(list))

        frames = self.set_frames()
        print("analyzing frames = ", frames)
        self.masks = cells_masks(frames, self.db, self.db_info,
                                 self.parameter_dict)
        self.outfile_path = write_output_file(self.parameter_dict,
                                              "parameters",
                                              self.outfile_path,
                                              new_file=True)

        if self.check_box_def.isChecked():
            self.calculate_deformation(frames)
        if self.check_box_tra.isChecked():
            self.calculate_traction(frames)
        self.calculate_general_properties(frames)
        if self.check_box_FEM.isChecked():
            self.calculate_FEM_analysis(frames)
        if self.check_box_contract.isChecked():
            self.calculate_contractile_measures(frames)

        self.outfile_path = write_output_file(
            self.res_dict, "results", self.outfile_path,
            new_file=False)  # writing to output file
        print("calculation complete")

    # run in a separate thread to keep clickpoints gui responsive // now using QThread and stuff
    def start_thread(self, run_function=None):
        self.thread = Worker(self, run_function=run_function)
        self.thread.start()  # starting thread
        self.thread.finished.connect(
            self.reload_all)  # connecting function on thread finish

        # x.join()

    def buttonPressedEvent(self):
        # show the addon window when the button in ClickPoints is pressed
        self.show()

    # disable running in other thread other wise "figsize" is somehow overloaded
    async def run(self):
        pass
Example #21
0
class DevicesListWidget(QWidget):
    def __init__(self, parent, *args, **kwargs):
        super(DevicesListWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle("Devices list")
        self.setWindowState(Qt.WindowMaximized)
        self.setLayout(VLayout(margin=0, spacing=0))

        self.mqtt = parent.mqtt
        self.mdi = parent.mdi
        self.idx = None

        self.settings = QSettings()
        self.hidden_columns = self.settings.value("hidden_columns", [1, 2])

        self.tb = Toolbar(Qt.Horizontal, 16, Qt.ToolButtonTextBesideIcon)
        self.tb.addAction(QIcon("GUI/icons/add.png"), "Add", self.device_add)

        self.layout().addWidget(self.tb)

        self.device_list = TableView()
        self.model = parent.device_model
        self.telemetry_model = parent.telemetry_model
        self.sorted_device_model = QSortFilterProxyModel()
        self.sorted_device_model.setSourceModel(parent.device_model)
        self.device_list.setModel(self.sorted_device_model)
        self.device_list.setupColumns(columns, self.hidden_columns)
        self.device_list.setSortingEnabled(True)
        self.device_list.setWordWrap(True)
        self.device_list.setItemDelegate(DeviceDelegate())
        self.device_list.sortByColumn(DevMdl.TOPIC, Qt.AscendingOrder)
        self.device_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.layout().addWidget(self.device_list)

        self.device_list.clicked.connect(self.select_device)
        self.device_list.doubleClicked.connect(self.device_config)
        self.device_list.customContextMenuRequested.connect(self.show_list_ctx_menu)

        self.device_list.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
        self.device_list.horizontalHeader().customContextMenuRequested.connect(self.show_header_ctx_menu)

        self.ctx_menu = QMenu()
        self.ctx_menu_relays = None
        self.create_actions()

        self.build_header_ctx_menu()

    def create_actions(self):
        self.ctx_menu.addAction(QIcon("GUI/icons/configure.png"), "Configure", self.device_config)
        self.ctx_menu.addAction(QIcon("GUI/icons/delete.png"), "Remove", self.device_delete)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/refresh.png"), "Refresh", self.ctx_menu_refresh)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/on.png"), "Power ON", lambda: self.ctx_menu_power(state="ON"))
        self.ctx_menu.addAction(QIcon("GUI/icons/off.png"), "Power OFF", lambda: self.ctx_menu_power(state="OFF"))

        self.ctx_menu_relays = QMenu("Relays")
        self.ctx_menu_relays.setIcon(QIcon("GUI/icons/switch.png"))
        relays_btn = self.ctx_menu.addMenu(self.ctx_menu_relays)

        self.ctx_menu_relays.setEnabled(False)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/clear.png"), "Clear retained", self.ctx_menu_clean_retained)
        self.ctx_menu.addSeparator()

        self.ctx_menu_copy = QMenu("Copy")
        self.ctx_menu_copy.setIcon(QIcon("GUI/icons/copy.png"))
        copy_btn = self.ctx_menu.addMenu(self.ctx_menu_copy)

        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/restart.png"), "Restart", self.ctx_menu_restart)
        self.ctx_menu.addAction(QIcon("GUI/icons/web.png"), "Open WebUI", self.ctx_menu_webui)

        self.ctx_menu_copy.addAction("IP", lambda: self.ctx_menu_copy_value(DevMdl.IP))
        self.ctx_menu_copy.addAction("MAC", lambda: self.ctx_menu_copy_value(DevMdl.MAC))
        self.ctx_menu_copy.addAction("BSSID", lambda: self.ctx_menu_copy_value(DevMdl.BSSID))
        self.ctx_menu_copy.addSeparator()
        self.ctx_menu_copy.addAction("Topic", lambda: self.ctx_menu_copy_value(DevMdl.TOPIC))
        self.ctx_menu_copy.addAction("FullTopic", lambda: self.ctx_menu_copy_value(DevMdl.FULL_TOPIC))
        self.ctx_menu_copy.addAction("STAT topic", lambda: self.ctx_menu_copy_prefix_topic("STAT"))
        self.ctx_menu_copy.addAction("CMND topic", lambda: self.ctx_menu_copy_prefix_topic("CMND"))
        self.ctx_menu_copy.addAction("TELE topic", lambda: self.ctx_menu_copy_prefix_topic("TELE"))

        self.tb.addActions(self.ctx_menu.actions())
        self.tb.widgetForAction(relays_btn).setPopupMode(QToolButton.InstantPopup)
        self.tb.widgetForAction(copy_btn).setPopupMode(QToolButton.InstantPopup)

    def ctx_menu_copy_value(self, column):
        if self.idx:
            row = self.idx.row()
            value = self.model.data(self.model.index(row, column))
            QApplication.clipboard().setText(value)

    def ctx_menu_copy_prefix_topic(self, prefix):
        if self.idx:
            if prefix == "STAT":
                topic = self.model.statTopic(self.idx)
            elif prefix == "CMND":
                topic = self.model.commandTopic(self.idx)
            elif prefix == "TELE":
                topic = self.model.teleTopic(self.idx)
            QApplication.clipboard().setText(topic)

    def ctx_menu_clean_retained(self):
        if self.idx:
            relays = self.model.data(self.model.index(self.idx.row(), DevMdl.POWER))
            if relays and len(relays.keys()>1):
                cmnd_topic = self.model.cmndTopic(self.idx)

                for r in relays.keys():
                    self.mqtt.publish(cmnd_topic + r, retain=True)
                QMessageBox.information(self, "Clear retained", "Cleared reatined messages.")

    def ctx_menu_power(self, relay=None, state=None):
        if self.idx:
            relays = self.model.data(self.model.index(self.idx.row(), DevMdl.POWER))
            cmnd_topic = self.model.commandTopic(self.idx)
            if relay:
                self.mqtt.publish(cmnd_topic+relay, payload=state)

            elif relays:
                for r in relays.keys():
                    self.mqtt.publish(cmnd_topic+r, payload=state)

    def ctx_menu_restart(self):
        if self.idx:
            self.mqtt.publish("{}/restart".format(self.model.commandTopic(self.idx)), payload="1")

    def ctx_menu_refresh(self):
        if self.idx:
            for q in initial_queries:
                self.mqtt.publish("{}/status".format(self.model.commandTopic(self.idx)), payload=q)

    def ctx_menu_telemetry(self):
        if self.idx:
            self.mqtt.publish("{}/status".format(self.model.commandTopic(self.idx)), payload=8)

    def ctx_menu_bssid(self):
        if self.idx:
            bssid = self.model.bssid(self.idx)
            current = self.settings.value("BSSID/{}".format(bssid), "")
            alias, ok = QInputDialog.getText(self, "BSSID alias", "Alias for {}. Clear to remove.".format(bssid), text=current)
            if ok:
                self.settings.setValue("BSSID/{}".format(bssid), alias)
                self.model.refreshBSSID()

    def ctx_menu_webui(self):
        if self.idx:
            QDesktopServices.openUrl(QUrl("http://{}".format(self.model.ip(self.idx))))

    def show_list_ctx_menu(self, at):
        self.select_device(self.device_list.indexAt(at))
        self.ctx_menu.popup(self.device_list.viewport().mapToGlobal(at))

    def build_header_ctx_menu(self):
        self.hdr_ctx_menu = QMenu()
        for c in columns.keys():
            a = self.hdr_ctx_menu.addAction(columns[c][0])
            a.setData(c)
            a.setCheckable(True)
            a.setChecked(not self.device_list.isColumnHidden(c))
            a.toggled.connect(self.header_ctx_menu_toggle_col)

    def show_header_ctx_menu(self, at):
        self.hdr_ctx_menu.popup(self.device_list.horizontalHeader().viewport().mapToGlobal(at))

    def header_ctx_menu_toggle_col(self, state):
        self.device_list.setColumnHidden(self.sender().data(), not state)
        hidden_columns = [int(c) for c in columns.keys() if self.device_list.isColumnHidden(c)]
        self.settings.setValue("hidden_columns", hidden_columns)
        self.settings.sync()

    def select_device(self, idx):
        self.idx = self.sorted_device_model.mapToSource(idx)
        self.device = self.model.data(self.model.index(idx.row(), DevMdl.TOPIC))

        relays = self.model.data(self.model.index(self.idx.row(), DevMdl.POWER))
        if relays and len(relays.keys()) > 1:
            self.ctx_menu_relays.setEnabled(True)
            self.ctx_menu_relays.setEnabled(True)
            self.ctx_menu_relays.clear()

            for r in relays.keys():
                actR = self.ctx_menu_relays.addAction("{} ON".format(r))
                actR.triggered.connect(lambda st, x=r: self.ctx_menu_power(x, "ON"))
                actR = self.ctx_menu_relays.addAction("{} OFF".format(r))
                actR.triggered.connect(lambda st, x=r: self.ctx_menu_power(x, "OFF"))
                self.ctx_menu_relays.addSeparator()
        else:
            self.ctx_menu_relays.setEnabled(False)
            self.ctx_menu_relays.clear()

    def device_config(self, idx=None):
        dev_cfg = DevicesConfigWidget(self, self.model.topic(self.idx))
        self.mdi.addSubWindow(dev_cfg)
        dev_cfg.setWindowState(Qt.WindowMaximized)

    def device_add(self):
        rc = self.model.rowCount()
        self.model.insertRow(rc)
        dlg = DeviceEditDialog(self.model, rc)
        dlg.full_topic.setText("%prefix%/%topic%/")

        if dlg.exec_() == QDialog.Accepted:
            self.model.setData(self.model.index(rc, DevMdl.FRIENDLY_NAME), self.model.data(self.model.index(rc, DevMdl.TOPIC)))
            topic = dlg.topic.text()
            tele_dev = self.telemetry_model.addDevice(TasmotaDevice, topic)
            self.telemetry_model.devices[topic] = tele_dev
        else:
            self.model.removeRow(rc)

    def device_delete(self):
        if self.idx:
            topic = self.model.topic(self.idx)
            if QMessageBox.question(self, "Confirm", "Do you want to remove '{}' from devices list?".format(topic)) == QMessageBox.Yes:
                self.model.removeRows(self.idx.row(),1)
                tele_idx = self.telemetry_model.devices.get(topic)
                if tele_idx:
                    self.telemetry_model.removeRows(tele_idx.row(),1)

    def closeEvent(self, event):
        event.ignore()
Example #22
0
def save_folder_settings(folder_settings):
    global bot_folder_settings
    bot_folder_settings = folder_settings
    settings = QSettings('rlbotgui', 'preferences')
    settings.setValue(BOT_FOLDER_SETTINGS_KEY, bot_folder_settings)
    settings.sync()
Example #23
0
class SetupDialog(QDialog):
    def __init__(self, parent=None):

        super().__init__(parent)
        self.settings = QSettings()
        self._widgets()
        self._properties()
        self._layouts()
        self._connections()

    def _widgets(self):

        self.accountnameLabel = QLabel()
        self.masterkeyLabel = QLabel()
        self.confirmkeyLabel = QLabel()
        self.confirmationLabel = QLabel()

        self.accountnameLineEdit = QLineEdit()
        self.masterkeyLineEdit = QLineEdit()
        self.confirmkeyLineEdit = QLineEdit()

        self.setPushButton = QPushButton('&Set Account')

    def _properties(self):

        self.accountnameLabel.setObjectName('accountnameLabel')
        self.accountnameLabel.setText('Account name:')

        # Temporary hidden from view, possible usage in the future
        self.accountnameLabel.setEnabled(False)
        self.accountnameLineEdit.setEnabled(False)
        self.accountnameLabel.setVisible(False)
        self.accountnameLineEdit.setVisible(False)

        self.masterkeyLabel.setObjectName('masterkeyLabel')
        self.masterkeyLabel.setText('Master key:')

        self.masterkeyLineEdit.setObjectName('masterkeyLineEdit')
        self.masterkeyLineEdit.setPlaceholderText(' something hard to guess')
        self.masterkeyLineEdit.setEchoMode(QLineEdit.Password)

        self.confirmkeyLabel.setObjectName('confirmkeyLabel')
        self.confirmkeyLabel.setText('Confirm master key:')

        self.confirmkeyLineEdit.setObjectName('confirmkeyLineEdit')
        self.confirmkeyLineEdit.setPlaceholderText(
            ' making sure to avoid typos')
        self.confirmkeyLineEdit.setEchoMode(QLineEdit.Password)

        self.setPushButton.setObjectName('setPushButton')
        self.setPushButton.setEnabled(False)

        self.setWindowTitle('Setup Canda')
        self.resize(426, 116)

    def _layouts(self):

        grid = QGridLayout()
        grid.addWidget(self.accountnameLabel, 0, 0)
        grid.addWidget(self.accountnameLineEdit, 0, 1)
        grid.addWidget(self.masterkeyLabel, 1, 0)
        grid.addWidget(self.masterkeyLineEdit, 1, 1)
        grid.addWidget(self.confirmkeyLabel, 2, 0)
        grid.addWidget(self.confirmkeyLineEdit, 2, 1)
        grid.addWidget(self.confirmationLabel, 3, 1)

        row_button = QHBoxLayout()
        row_button.addStretch()
        row_button.addWidget(self.setPushButton)

        col_layout = QVBoxLayout()
        col_layout.addLayout(grid)
        col_layout.addLayout(row_button)

        self.setLayout(col_layout)

    def _connections(self):

        self.accountnameLineEdit.textChanged.connect(
            self.on_LineEdits_textChanged)
        self.masterkeyLineEdit.textChanged.connect(
            self.on_LineEdits_textChanged)
        self.confirmkeyLineEdit.textChanged.connect(
            self.on_LineEdits_textChanged)
        self.setPushButton.clicked.connect(self.on_setPushButton_clicked)

    def on_LineEdits_textChanged(self):

        # if self.confirmationLabel.text(): self.confirmationLabel.clear()

        # Enable of disable Set button if either of the three QLineEdits has a values
        # with_text = [self.accountnameLineEdit.text(), self.masterkeyLineEdit.text(), self.confirmkeyLineEdit.text()]
        with_text = [
            self.masterkeyLineEdit.text(),
            self.confirmkeyLineEdit.text()
        ]

        if all(with_text):
            self.setPushButton.setEnabled(True)
        else:
            self.setPushButton.setEnabled(False)

    def on_setPushButton_clicked(self):

        self.check_masterkey_typo()

    def check_masterkey_typo(self):

        # Check for master key typos before encrypting it
        if self.masterkeyLineEdit.text() == self.confirmkeyLineEdit.text():
            print(
                'password match, you may now proceed in encrypting the master key'
            )
            credentials = self.encrypt_user_credentials()
            self._write_settings(credentials)
            self.accept()
        else:
            self.confirmationLabel.setText('Master key does not match.')
            self.masterkeyLineEdit.setFocus(True)
            self.confirmkeyLineEdit.clear()
            self.setPushButton.setEnabled(False)

    def encrypt_user_credentials(self):
        """ Encrypt user inputted credentials.

            Return key, salt, token
        """

        return canda.set_masterkey3(self.masterkeyLineEdit.text())

    def _write_settings(self, data):
        """ Save encrypted credentials to QSettings. """

        self.settings.setValue('SALT', data[1])
        self.settings.setValue('LOGIN_TOKEN', data[2])
        self.settings.setValue('INITIAL_RUN', False)
        self.settings.sync()
        print('settings save.')

    def resizeEvent(self, QResizeEvent):

        print(f'{self.width()} x {self.height()}')
Example #24
0
class NodeeraMain(QMainWindow, Ui_NodeeraMain):

    displayWelcomeMsg = pyqtSignal(str)
    closeWelcomeMsg = pyqtSignal()
    """
    Create Ui_NodeeraMain and display it.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(NodeeraMain, self).__init__(parent)
        self.setupUi(self)
        self.parent = parent

        # object data
        self.pageDict = {}
        self.curPage = None
        self.helper = Helper()

        # get startup settings
        self.initSettings()

        # launch the welcome wagon
        self.welcomeDlg = HelloUserDlg(self)
        self.welcomeDlg.show()
        QApplication.processEvents()
        self.displayWelcomeMsg.emit("Starting NodeEra...")

        # setup stuff not covered by generated code
        icon = QIcon()
        icon.addPixmap(QPixmap("icons/RUN and DATA TAB/Disconnected.png"),
                       QIcon.Normal, QIcon.Off)
        self.actionOpen_Connection.setIcon(icon)

        # main window
        self.setTitle("No Connection")
        self.resize(self.winSize)
        self.move(self.position)

        # display welcome message
        self.displayWelcomeMsg.emit("Welcome To NodeEra")

        # display announcement message from website
        try:
            url = 'https://{}'.format(appPage)
            response = requests.get(url)
            if response.status_code == 200:
                start = response.text.find('class="display"') + 16
                end = response.text.find('</p>', start)
                self.displayWelcomeMsg.emit(response.text[start:end])
                self.displayWelcomeMsg.emit(
                    "For more information see www.singerlinks.com/nodeera")
            else:
                self.logMsg(
                    "Unable to access announcement page:{} http response:{}".
                    format(appPage, response.status_code))
                self.displayWelcomeMsg.emit(
                    "Unable to access announcement page:{} http response:{}".
                    format(appPage, response.status_code))

        except Exception as e:
            self.logMsg("Error accessing announcement page - {}".format(
                repr(e)))
            self.displayWelcomeMsg.emit(
                "Error accessing announcement page - {}".format(repr(e)))

        # auto open last used connection
        try:
            lastNeoConName = self.settings.value("NeoCon/LastUsed")
            if not lastNeoConName is None:
                neoDict = self.settings.value(
                    "NeoCon/connection/{}".format(lastNeoConName))
                self.openConnection(neoConName=lastNeoConName,
                                    neoConDict=neoDict)
                self.displayWelcomeMsg.emit(" ")
                self.displayWelcomeMsg.emit(
                    "Opened most recent connection: {}".format(lastNeoConName))

            self.setTitle(lastNeoConName)

        except:
            self.logMsg(
                "Unable to open last connection: {}".format(lastNeoConName))
            self.displayWelcomeMsg.emit(
                "Unable to open last connection: {}".format(lastNeoConName))

        # auto close the welcome dialog box
#        time.sleep(5)
#        self.closeWelcomeMsg.emit()

    def logMsg(self, msg):
        if logging:
            logging.info(msg)

    def initSettings(self, ):
        '''
        get the system settings needed to start NodeEra.
        If a system setting doesn't exist then create it with default value - this happens on initial startup
        '''
        self.settings = QSettings()
        try:
            self.expirationDate = self.helper.getText(
                self.settings.value("License/expirationDate"))
            if self.expirationDate is None:
                self.expirationDate = 'No expiration date set'
                self.settings.setValue(
                    "License/expirationDate",
                    self.helper.putText(self.expirationDate))
        except:
            self.expirationDate = 'No expiration date set'
            self.settings.setValue("License/expirationDate",
                                   self.helper.putText(self.expirationDate))

        try:
            self.currentVersion = self.settings.value("License/currentVersion")
            if self.currentVersion is None:
                self.currentVersion = currentVersion
                self.settings.setValue("License/currentVersion",
                                       self.currentVersion)
            elif self.currentVersion != currentVersion:
                self.currentVersion = currentVersion
                self.settings.setValue("License/currentVersion",
                                       self.currentVersion)
        except:
            self.currentVersion = currentVersion
            self.settings.setValue("License/currentVersion",
                                   self.currentVersion)

        try:
            self.winSize = self.settings.value("MainWindow/Size")
            if self.winSize is None:
                self.winSize = QSize(800, 500)
        except:
            self.winSize = QSize(800, 500)

        try:
            self.position = self.settings.value("MainWindow/Position")
            if self.position is None:
                self.position = QPoint(0, 0)
        except:
            self.position = QPoint(0, 0)

        try:
            self.recentList = self.settings.value("Default/RecentList")
            if self.recentList is None:
                self.recentList = []
                self.settings.setValue("Default/RecentList", self.recentList)
        except:
            self.recentList = []
            self.settings.setValue("Default/RecentList", self.recentList)

        try:
            self.defaultLoggingPath = self.settings.value(
                "Default/LoggingPath")
            if self.defaultLoggingPath is None:
                self.logDir = os.getcwd()
                self.logDir = os.path.realpath(os.path.abspath(self.logDir))
                self.settings.setValue("Default/LoggingPath", self.logDir)
        except:
            self.logDir = os.getcwd()
            self.logDir = os.path.realpath(os.path.abspath(self.logDir))
            self.settings.setValue("Default/LoggingPath", self.logDir)

        try:
            self.defaultProjPath = self.settings.value("Default/ProjPath")
            if self.defaultProjPath is None:
                self.defaultProjPath = os.getcwd()
                self.defaultProjPath = os.path.realpath(
                    os.path.abspath(self.defaultProjPath))
                self.settings.setValue("Default/ProjectPath",
                                       self.defaultProjPath)
        except:
            self.defaultProjPath = os.getcwd()
            self.defaultProjPath = os.path.realpath(
                os.path.abspath(self.defaultProjPath))
            self.settings.setValue("Default/ProjectPath", self.defaultProjPath)

        # default custom formats for diagram objects
        # Display Format - Instance Node
        try:
            test = self.settings.value("Default/Format/InstanceNode")
            if test is None:
                self.settings.setValue("Default/Format/InstanceNode",
                                       INodeFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/InstanceNode",
                                   INodeFormat().formatDict)

        # Display Format - Instance Relationship
        try:
            test = self.settings.value("Default/Format/InstanceRelation")
            if test is None:
                self.settings.setValue("Default/Format/InstanceRelation",
                                       IRelFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/InstanceRelation",
                                   IRelFormat().formatDict)

        # Display Format - Template Node
        try:
            test = self.settings.value("Default/Format/TemplateNode")
            if test is None:
                self.settings.setValue("Default/Format/TemplateNode",
                                       TNodeFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/TemplateNode",
                                   TNodeFormat().formatDict)

        # Display Format - Template Relationship
        try:
            test = self.settings.value("Default/Format/TemplateRelation")
            if test is None:
                self.settings.setValue("Default/Format/TemplateRelation",
                                       TRelFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/TemplateRelation",
                                   TRelFormat().formatDict)

        # page setup
        try:
            test = self.settings.value("Default/PageSetup")
            if test is None:
                self.settings.setValue("Default/PageSetup",
                                       PageSetup().objectDict)
        except:
            self.settings.setValue("Default/PageSetup", PageSetup().objectDict)

        # default project neocon
        try:
            defaultNeoConName = self.settings.value("NeoCon/Default")
            if defaultNeoConName is None:
                self.settings.setValue("NeoCon/Default", "LOCAL")
        except:
            self.settings.setValue("NeoCon/Default", "LOCAL")

        # LOCAL neocon definition
        try:
            self.localNeoCon = self.settings.value("NeoCon/connection/LOCAL")
            if self.localNeoCon is None:
                self.settings.setValue("NeoCon/connection/LOCAL",
                                       NeoDriver().localNeoConDict())
        except:
            self.settings.setValue("NeoCon/connection/LOCAL",
                                   NeoDriver().localNeoConDict())

        # default lexer font size
        try:
            defaultLexerFontSize = self.settings.value("Lexer/FontSize")
            if defaultLexerFontSize is None:
                self.settings.setValue("Lexer/FontSize", "10")
        except:
            self.settings.setValue("Lexer/FontSize", "10")

        # validate all neocons have the prompt dictionary key which was added in 1.04
        self.settings.beginGroup("NeoCon/connection")
        neoKeys = self.settings.childKeys()
        for key in neoKeys:
            neoDict = self.settings.value(key)
            promptVal = neoDict.get("prompt", None)
            if promptVal is None:
                neoDict["prompt"] = "False"
                self.settings.setValue(key, neoDict)

        self.settings.endGroup()

    def setTitle(self, filename):
        self.setWindowTitle("{} - {}".format(productName, filename))

    def setMenuAccess(self, ):
        '''
        determine what connection tab is currently selected and enable/disable menu items as needed
        '''
        # turn on all Settings menu items
        for action in self.menuSettings.actions():
            if type(action) == QAction and not action.isSeparator():
                action.setEnabled(True)

        try:
            # get tab widget (schema or project) that is currently active - if there isn't one this will cause an exception
            currentTab = self.stackedPageItems.currentWidget(
            ).tabPage.currentWidget()
            # enable all the schema actions
            for action in self.menuNeo.actions():
                if type(action) == QAction and not action.isSeparator():
                    action.setEnabled(True)
            for action in self.menuProject.actions():
                # enable project actions
                if type(action) == QAction and not action.isSeparator():
                    if currentTab.pageType == "PROJECT":
                        action.setEnabled(True)
                    else:
                        if action.text() in [
                                "New", "Open...", "Recent Projects"
                        ]:
                            action.setEnabled(True)
                        else:
                            action.setEnabled(False)

        except:
            # no connection tabs are open
            # disable all project menu actions
            for action in self.menuProject.actions():
                if type(action) == QAction and not action.isSeparator():
                    action.setEnabled(False)
            for action in self.menuNeo.actions():
                if type(action) == QAction and not action.isSeparator():
                    if action.text() in [
                            "Close Connection", "Generate Schema..."
                    ]:
                        action.setEnabled(False)
                    else:
                        action.setEnabled(True)

    ########################################################################
    #     NEO CONNECTION Dropdown Menu Actions
    ########################################################################
    @pyqtSlot()
    def on_actionOpen_Connection_triggered(self):
        """
        This slot provides functionality for the open connection button
        """
        d = dlgNeoCons(parent=self)
        if d.exec_():
            if d.selectedNeoConName:
                # make sure it isn't already opened
                if d.selectedNeoConName not in self.pageDict:
                    self.openConnection(neoConName=d.selectedNeoConName,
                                        neoConDict=d.selectedNeoConDict)
                else:
                    self.helper.displayErrMsg(
                        "NodeEra - Open Connection",
                        "Connection {} is already open.".format(
                            d.selectedNeoConName))
                    # switch to the page they tried to open
                    self.pageDict[d.selectedNeoConName].actionButton.trigger()

    def openConnection(self, neoConName=None, neoConDict=None):
        '''
        User selects a connection to open so create the schema page and display it
        '''
        # set the last used neocon in system settings
        self.settings.setValue("NeoCon/LastUsed", neoConName)
        # create a new toolbar button and add it to the toolbar
        newConAction = QAction(self)
        newConAction.setObjectName("newConnection")
        newConAction.setText("Neo4j - {}".format(neoConName))
        newConAction.setData(neoConName)

        newConAction.setToolTip(neoConDict["URL"])
        newConAction.setCheckable(True)
        newConAction.setChecked(True)
        newConAction.triggered.connect(self.connectionClicked)
        self.tbConnection.addAction(newConAction)

        # add a tabPage widget to the stacked widget
        newPageWidget = PageWidget(parent=self)
        newPageWidget.pageType = "Schema"
        widgetIndex = self.stackedPageItems.addWidget(newPageWidget)
        # save new pageItem
        newPageItem = PageItem(neoConName=neoConName,
                               actionButton=newConAction,
                               pageWidget=newPageWidget,
                               pageWidgetIndex=widgetIndex)
        self.pageDict[neoConName] = newPageItem
        # add the schema tab
        cypherTab = CypherPageWidget(parent=self, pageItem=newPageItem)
        newPageWidget.tabPage.addTab(cypherTab,
                                     "Schema - {}".format(neoConName))

        # click the new action to force selection logic
        newConAction.trigger()
        self.logMsg("Open Connection: {}".format(neoConName))

    @pyqtSlot()
    def connectionClicked(self):
        '''
        User clicks on a connection in the menu bar so switch to that stacked widget
        '''
        self.logMsg("connection clicked {}".format(self.sender().text()))
        # uncheck all the page action buttons
        for pageName in self.pageDict:
            self.pageDict[pageName].actionButton.setChecked(False)
        # check the one just clicked
        self.sender().setChecked(True)
        # save the current page name
        self.curPage = self.sender().data()
        # switch the stacked page widget to the one just clicked
        self.stackedPageItems.setCurrentIndex(
            self.pageDict[self.curPage].pageWidgetIndex)
        # update the main window title
        self.setTitle(self.curPage)
        # adjust the menu items
        self.setMenuAccess()

    @pyqtSlot()
    def on_actionClose_Connection_triggered(self):
        """
        Close the active connection and remove the page from the UI
        """
        if self.curPage:
            if self.curPage in self.pageDict:
                # must find the schema tab and tell it to close, it will tell all other tabs to close.  schema tab is always the first one (index=0)
                self.pageDict[self.curPage].pageWidget.closeSchemaTab()
                self.removeConnection()

    def removeConnection(self, ):
        '''if the tab page widget is responding to the close request it only needs this logic to remove the connection
        '''
        curPage = self.pageDict.get(self.curPage, None)
        if not curPage is None:
            # remove the pageWidget from the stacked widget
            self.stackedPageItems.removeWidget(
                self.pageDict[self.curPage].pageWidget)
            del self.pageDict[self.curPage].pageWidget
            # remove the action from menu's and toolbars
            self.tbConnection.removeAction(
                self.pageDict[self.curPage].actionButton)
            # take the page out of the dictionary
            del self.pageDict[self.curPage]
            # if any pages left select the first one
            if len(self.pageDict) > 0:
                for pageName in self.pageDict:
                    self.pageDict[pageName].actionButton.trigger()
                    break
            else:
                # there are no open connections and the home page is closed
                self.setTitle("No Connection")

    @pyqtSlot()
    def on_actionNeo4j_Connection_Manager_triggered(self):
        """
        Display the Connection Manager
        """
        d = dlgNeoCons(parent=self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionExit_triggered(self):
        """
        User selected the File / Exit menu item.  Tell all the open connections to close
        """
        self.closeOpenStuff()
        # close the app
        self.close()

    def closeEvent(self, event):
        # close open connections
        self.closeOpenStuff()
        #save the window state
        self.settings.setValue("MainWindow/Size", self.size())
        self.settings.setValue("MainWindow/Position", self.pos())

        event.accept()

    def closeOpenStuff(self):
        # get a list of all the keys in the pageDict dictionary
        keys = list(self.pageDict.keys())
        # iterate thru the list of dictionary keys.  this is required as the dictionary will be changing size, i.e. you can't simply iterate thru the dictionary
        for key in keys:
            pageItem = self.pageDict[key]
            actionButton = pageItem.actionButton
            actionButton.trigger()
            # must find the schema tab and tell it to close, it will tell all other tabs to close.  schema tab is always the first one (index=0)
            pageItem.pageWidget.closeSchemaTab()
            self.removeConnection()

#####################################################################
# SETTINGS DROPDOWNS
#####################################################################

    @pyqtSlot()
    def on_actionSystem_Preferences_triggered(self):
        """
        User selects the System Preferences menu item.  Display the system preferences dialog box.
        """
        self.editSystemPreferences()

    def editSystemPreferences(self, ):
        """
        User selects the System Preferences menu item.  Display the system preferences dialog box.
        """
        if not (self.settings is None):
            d = SystemPreferenceBox(self, settings=self.settings)
            if d.exec_():
                self.settings.sync()

#####################################################################
# PROJECT METHODS
#####################################################################

    @pyqtSlot()
    def on_actionNewProject_triggered(self):
        """
        Open new project
        """
        self.loadProject(fileName=None)

    @pyqtSlot()
    def on_actionOpenProject_triggered(self):
        """
        Open an existing project file
        """
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.ExistingFile)
        dlg.setAcceptMode(QFileDialog.AcceptOpen)
        dlg.setNameFilters(["NodeEra Project (*.mdl)", "all files (*.*)"])
        dlg.setDirectory(self.settings.value("Default/ProjPath"))
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            if fileNames:
                fileName = fileNames[0]
                self.loadProject(fileName=fileName)

    @pyqtSlot()
    def on_actionSaveProject_triggered(self):
        """
        Save the open project
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                newName = curPageWidget.tabPage.currentWidget().saveProject()
                # if this was an unsaved project then it was really a save as so the tab name has to be updated
                if newName is not None:
                    curPageWidget.tabPage.setTabText(
                        curPageWidget.tabPage.currentIndex(),
                        "Project: {} - {}".format(
                            newName, self.pageDict[self.curPage].neoConName))

    @pyqtSlot()
    def on_actionSaveProjectAs_triggered(self):
        """
        Save Project As
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                newName = curPageWidget.tabPage.currentWidget().saveProjectAs()
                if newName is not None:
                    curPageWidget.tabPage.setTabText(
                        curPageWidget.tabPage.currentIndex(),
                        "Project: {} - {}".format(
                            newName, self.pageDict[self.curPage].neoConName))

    @pyqtSlot()
    def on_actionReverse_Engineer_triggered(self):
        """
        User selects the Reverse Engineer menu item.  Display the Reverse Engineer dialog box.
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().reverseEngineerGraph()
            else:
                self.helper.displayErrMsg(
                    "Reverse Engineer", "{} not a project".format(
                        curPageWidget.tabPage.currentWidget().pageType))

    @pyqtSlot()
    def on_actionProjectProperties_triggered(self):
        """
        User selects the project properties menu item. Display the project properties dialog box.
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().editProjectProperties()
            else:
                self.helper.displayErrMsg(
                    "Project Properties", "{} not a project".format(
                        curPageWidget.tabPage.currentWidget().pageType))

    def getSchemaObject(self, ):
        curPageWidget = self.stackedPageItems.currentWidget()
        for ctr in range(0, curPageWidget.tabPage.count()):
            tab = curPageWidget.tabPage.widget(ctr)
            if tab.pageType == "CYPHER":
                return tab.schemaModel
        return None

    def getSchemaTab(self, ):
        curPageWidget = self.stackedPageItems.currentWidget()
        for ctr in range(0, curPageWidget.tabPage.count()):
            tab = curPageWidget.tabPage.widget(ctr)
            if tab.pageType == "CYPHER":
                return tab
        return None

    def loadProject(self, fileName=None):
        '''
        Load the project file with name fileName.  If fileName is None, create a new empty project.
        '''

        # create a temporary file name if its a new project
        if fileName is None:
            # update unnamed file counter
            global unNamedFileCounter
            unNamedFileCounter = unNamedFileCounter + 1
            shortName = "{}".format(
                "New Project-0{}".format(unNamedFileCounter))
        else:
            head, shortName = ntpath.split(QFileInfo(fileName).fileName())

        # make sure the project isn't already loaded
        curPageWidget = self.stackedPageItems.currentWidget()
        for ctr in range(0, curPageWidget.tabPage.count()):
            tab = curPageWidget.tabPage.widget(ctr)
            if tab.pageType == "PROJECT":
                if (not fileName is None) and (tab.fileName == fileName):
                    self.helper.displayErrMsg(
                        "Open Project",
                        "The project file: {} is already open.  It can only be open once."
                        .format(fileName))
                    return

        # create the project widget
        projectTab = ProjectPageWidget(parent=self,
                                       settings=self.settings,
                                       pageItem=self.pageDict[self.curPage],
                                       fileName=fileName)

        curPageWidget = self.stackedPageItems.currentWidget()

        # add the project widget as a tab on the current page widget
        x = curPageWidget.tabPage.addTab(
            projectTab,
            "Project: {} - {}".format(shortName,
                                      self.pageDict[self.curPage].neoConName))
        curPageWidget.tabPage.setCurrentIndex(x)

    @pyqtSlot()
    def on_actionOnline_Help_triggered(self):
        """
        User selects the Online Help menu item.  Dislay Online Help menu.
        """
        d = OnlineHelpDLG(self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionAbout_triggered(self):
        """
        User selects Help / About menu item.  Display the about dialog box
        """
        d = HelpAboutDLG(self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionGenerate_Schema_triggered(self):
        """
        User requests the generate schema dialog box from main menu
        """
        d = GenerateSchemaDlg(self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionForward_Engineer_triggered(self):
        """
        User requests to perform forward engineering from the open project from main menu
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().forwardEngineerGraph()
            else:
                self.logMsg(
                    "User requested to forward engineer but current tab is not a Project"
                )

    @pyqtSlot()
    def on_actionGenerate_Reports_triggered(self):
        """
        User selects the Generate Project Reports menu item.  Display the Generate Reports dialog box.
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().generateProjectReports()

    @pyqtSlot()
    def on_actionReset_User_Password_triggered(self):
        """
        User requests the change user password from main menu
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "CYPHER":
                curPageWidget.tabPage.currentWidget().resetPassword()

    @pyqtSlot(QAction)
    def on_menuRecent_Projects_triggered(self, action):
        """
        User clicked on a recent file menu item
        
        @param action DESCRIPTION
        @type QAction
        """
        self.loadProject(fileName=action.data())

    @pyqtSlot()
    def on_menuRecent_Projects_aboutToShow(self):
        """
        user hovering on recent projects menu item
        """
        recentList = self.settings.value("Default/RecentList")
        if len(recentList) == 0:
            return
        else:
            # remove any existing actions
            self.menuRecent_Projects.clear()
            for projectFile in recentList:
                # create actions for the recent files
                aSubAction = self.menuRecent_Projects.addAction(projectFile)
                aSubAction.setData(projectFile)
Example #25
0
class CoreSettings:
    def __init__(self):
        self.settings: QSettings = None
        self.app_name: str = None
        self.app_dir: Union[Path, Any] = None
        self.app_data_reader: AppDataReader = None
        self.app_data_writer: AppDataWriter = None
        self.app_data_cache: AppDataCache = None
        self.docs_location: Path = Path(
            QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation))

    def init(self):
        self.app_name = qApp.applicationName().lower()
        self.app_dir = Path(
            QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation))
        self.app_dir.mkdir(exist_ok=True)
        settings_file = f"{self.app_name}.ini"
        self.settings = QSettings(
            self.app_dir.joinpath(settings_file).as_posix(),
            QSettings.IniFormat)
        self.settings.sync()

    def init_logger(self):
        log_file = f"{self.app_name}.log"
        handlers = [
            logging.handlers.RotatingFileHandler(
                self.app_dir.joinpath(log_file),
                maxBytes=1_000_000,
                backupCount=1),
            logging.StreamHandler(),
        ]

        logging.basicConfig(
            handlers=handlers,
            format="%(asctime)s - %(filename)s:%(lineno)d - %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
            level=logging.DEBUG,
        )
        logging.captureWarnings(capture=True)

    def init_app_data(self):
        storage = self._db_from_current_user_project()
        self.app_data_reader = AppDataReader(storage.db)
        self.app_data_writer = AppDataWriter(storage.db)
        self.app_data_cache = AppDataCache(self.app_data_reader,
                                           self.app_data_writer)

    def new_app_data(self):
        """Used when a new project is created/opened and we just wanted to switch underlying
        db_table from AppDataReader and AppDataWriter without creating a new instance"""
        storage = self._db_from_current_user_project()
        self.app_data_reader.ldb = storage.db
        self.app_data_writer.ldb = storage.db

    def save_window_state(self, geometry, window_state):
        self.settings.setValue(GEOMETRY_KEY, geometry)
        self.settings.setValue(WINDOW_STATE_KEY, window_state)
        self.settings.sync()

    def save_configuration(self, app_config: AppConfiguration):
        self.settings.setValue(STARTUP_CHECK_KEY,
                               app_config.update_check_on_startup)
        self.settings.setValue(TLS_VERIFICATION_KEY,
                               app_config.tls_verification)
        self.settings.setValue(HTTP_PROXY_KEY, app_config.http_proxy)
        self.settings.setValue(HTTPS_PROXY_KEY, app_config.https_proxy)
        self.settings.setValue(REQUEST_TIMEOUT_SECS,
                               app_config.timeout_in_secs)
        self.settings.setValue(PRINT_SHARE_SERVER, app_config.print_server)
        self.settings.sync()

    def load_configuration(self):
        app_config = AppConfiguration()
        app_config.update_check_on_startup = str_to_bool(
            self.settings.value(STARTUP_CHECK_KEY,
                                AppConfiguration.update_check_on_startup))
        app_config.tls_verification = str_to_bool(
            self.settings.value(TLS_VERIFICATION_KEY,
                                AppConfiguration.tls_verification))
        app_config.http_proxy = self.settings.value(
            HTTP_PROXY_KEY, AppConfiguration.http_proxy)
        app_config.https_proxy = self.settings.value(
            HTTPS_PROXY_KEY, AppConfiguration.https_proxy)
        app_config.timeout_in_secs = self.settings.value(
            REQUEST_TIMEOUT_SECS, AppConfiguration.timeout_in_secs)
        app_config.print_server = self.settings.value(
            PRINT_SHARE_SERVER, AppConfiguration.print_server)
        return app_config

    def geometry(self):
        return self.settings.value(GEOMETRY_KEY, None)

    def window_state(self):
        return self.settings.value(WINDOW_STATE_KEY, None)

    def save_current_project(self, user_project: UserProject):
        self.settings.setValue(CURRENT_PROJECT_LOCATION_KEY,
                               user_project.location)
        self.settings.setValue(CURRENT_PROJECT_STATE_KEY, user_project.state)
        self.settings.sync()

    def load_current_project(self):
        current_project_location = self.settings.value(
            CURRENT_PROJECT_LOCATION_KEY, None)

        if not current_project_location:
            return self.create_new_project()

        return UserProject(
            location=current_project_location,
            state=self.settings.value(CURRENT_PROJECT_STATE_KEY),
        )

    def create_new_project(self):
        user_project = UserProject(
            location=self.docs_location.joinpath(
                random_project_name()).as_posix(),
            state=SavedState.UN_SAVED,
        )
        self.save_current_project(user_project)
        return user_project

    def _db_from_current_user_project(self):
        user_project: UserProject = self.load_current_project()
        data_location = user_project.location
        return Storage(data_location)
Example #26
0
class RattrapWindow(QMainWindow, Ui_Rattrap):
    def __init__(self, path, app_name):
        super().__init__()
        self.setupUi(self)
        self.path = path
        self.app_name = app_name
        self.settings = QSettings("Asocia", self.app_name)
        self.ratslap_name = ratslap.RatSlap.name()
        self.current_mode_name = None
        self.conn = DBHelper(self.get_path("settings.db"))
        self.tray_icon = QtWidgets.QSystemTrayIcon(self)
        self.usb_detector = USBDetector()
        self.thread = QThread()

        # Grouping similar items together.
        self.radio_buttons = [getattr(self, f"mode{i}") for i in "123"]
        self.combo_boxes = [self.color, self.rate]
        self.unchangeable_items = [getattr(self, f"dpi{i}")
                                   for i in "1234"] + [self.dpi_shift]
        self.buttons = [self.right, self.middle, self.left]
        self.buttons.extend(
            [getattr(self, f"g{str(i)}") for i in range(4, 10)])
        self.action_names = ["reset", "import", "export", "apply"]

        # Enable widgets, set icons for them, create actions
        self.setup_ui_design()

        # Connect signals and slots
        self.setup_ui_logic()

        skip_test_for_ratslap = False
        self.permission_granted = True
        self.mouse_connected = True
        try:
            ratslap_path = self.conn.select(
                "file_paths", ("path", ), program_name="ratslap").fetchone()[0]
        except OperationalError:
            ratslap_path = self.get_ratslap_path()
        else:
            try:
                ratslap.RatSlap(ratslap_path, skip_test_for_ratslap)
            except ratslap.NonValidPathError:
                ratslap_path = self.get_new_path(ratslap_path)
            except ratslap.MouseIsOfflineError:
                self.mouse_connected = False
            except ratslap.PermissionDeniedError:
                self.permission_granted = False
            finally:
                skip_test_for_ratslap = True

        self.ratslap = ratslap.RatSlap(ratslap_path, skip_test_for_ratslap)
        setattr(self.ratslap, 'run',
                self.catch_exceptions(getattr(self.ratslap, 'run')))
        self.mode1.setChecked(True)
        self.current_mode_is_set = False
        self.thread.start()

    def get_path(self, *p):
        return os.path.join(self.path, *p)

    def catch_exceptions(self, function):
        def wrapper(*args, **kwargs):
            try:
                result = function(*args, **kwargs)
            except ratslap.NonValidPathError:
                self.ratslap.path = self.get_new_path(self.ratslap.path)
                result = function(*args, **kwargs)
            except ratslap.PermissionDeniedError as e:
                self.handle_permission_denied_error(e)
                result = function(*args, **kwargs)
                self.permission_granted = True
            except ratslap.UnknownRatSlapError as e:
                # Maybe it's because computers are fast
                sleep(0.1)  # Let's wait a bit
                try:
                    result = function(*args, **kwargs)
                except Exception as e:
                    text = f"Error message was:\n{str(e)}\n{self.app_name} will now close."
                    self.exec_message_box("An error occured",
                                          text,
                                          icon_name="Critical")
                    self.quit()
                else:
                    print(
                        f"An error was occurred but it's gone after 0.1 seconds; "
                        f"time heals everything :) \nIf you are curious, the error was:\n{e}"
                    )
            except Exception as e:
                text = f"Error message was:\n{str(e)}\n{self.app_name} will now close."
                self.exec_message_box("An error occurred",
                                      text,
                                      icon_name="Critical")
                self.quit()
            return result

        return wrapper

    def get_new_path(self, previous_path):
        text = f"The previous path to '{self.ratslap_name}' program: '{previous_path}' is unreachable. " \
            f"If you want to continue using {self.app_name} please specify the path to '{self.ratslap_name}'"
        self.exec_message_box(f"Unable to reach '{self.ratslap_name}'",
                              text,
                              icon_name="Warning")
        return self.get_ratslap_path()

    def setup_ui_design(self):
        self.setWindowTitle(self.app_name)
        self.resize(303, 477)
        self.move(QApplication.desktop().screen().rect().center() -
                  self.rect().center())
        minimize_to_tray = self.settings.value("minimize_to_tray_when_closing",
                                               True,
                                               type=bool)
        self.action_minimize_to_tray.setChecked(minimize_to_tray)
        auto_start = self.settings.value("auto_start_on_boot",
                                         False,
                                         type=bool)
        auto_start_script_exists = os.path.exists(
            os.path.join(os.path.expanduser("~"),
                         f".config/autostart/{self.app_name}.desktop"))
        self.action_autostart.setChecked(auto_start
                                         and auto_start_script_exists)
        for widget in self.buttons + self.radio_buttons + [self.button_apply]:
            widget.setEnabled(True)

        self.set_icons_for_widgets()
        actions = {
            "show": f"Open {self.app_name}",
            "hide": "Minimize to tray",
            "quit": f"Quit {self.app_name}"
        }
        self.add_actions_to_tray(actions)
        self.tray_icon.show()

    def setup_ui_logic(self):
        self.bind_functions_to_buttons()
        self.connect_signals_and_slots_of_thread()
        self.bind_functions_to_actions()
        self.action_autostart.toggled.connect(
            self.create_or_remove_autostart_file)
        self.action_create_desktop_shortcut.triggered.connect(
            self.create_desktop_shortcut)

    def set_icons_for_widgets(self):
        for action_name in self.action_names:
            button = getattr(self, f"button_{action_name}")
            image_path = self.get_path("images", f"{action_name}_icon.png")
            icon = QIcon()
            icon.addPixmap(QPixmap(image_path))
            button.setIcon(icon)

        app_icon = QIcon(self.get_path("images", "logo.png"))
        self.tray_icon.setIcon(app_icon)
        self.setWindowIcon(app_icon)

    def add_actions_to_tray(self, actions):
        tray_menu = QtWidgets.QMenu(self, objectName="tray_menu")
        for action_name, desc in actions.items():
            action = QtWidgets.QAction(desc, self, objectName=action_name)
            tray_menu.addAction(action)

        self.tray_icon.setContextMenu(tray_menu)

    def bind_functions_to_buttons(self):
        for radio_btn in self.radio_buttons:
            radio_btn.clicked.connect(self.set_current_mode)
        for combo_box in self.combo_boxes:
            combo_box.currentTextChanged.connect(self.combo_box_changed)
        for button in self.buttons:
            button.clicked.connect(self.assign_shortcut)
        for name in self.action_names:
            button = getattr(self, f"button_{name}")
            function = getattr(self, f"on_{name}")
            button.clicked.connect(function)

    def bind_functions_to_actions(self):
        for action in self.tray_icon.contextMenu().actions():
            action_name = action.objectName()
            action.triggered.connect(getattr(self, action_name))

    def on_reset(self):
        for i in range(3, 6):
            title = f"Reset F{i}?"
            text = f"Do you want to reset profile F{i} to its defaults?"

            response = self.exec_message_box(
                title,
                text, ["No", "NoToAll", "YesToAll", "Yes"],
                "Question",
                special_buttons={
                    "EscapeButton": 2,
                    "DefaultButton": 4
                })
            if response == "YesToAll":
                self.ratslap.reset("all")
                self.conn.drop_table("profiles")
                self.set_current_mode()
                break
            elif response == "Yes":
                self.ratslap.reset(i)
                self.conn.delete_row("profiles", name=f"f{str(i)}")
                self.set_current_mode()
            elif response == "NoToAll":
                break

    def on_import(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "Import from file", self.path,
            f"All files (*);;{self.app_name} files (*.rat)",
            f"{self.app_name} files (*.rat)")
        if path:
            with open(path) as f:
                for i in range(3, 6):
                    self.ratslap.modify(i, **loads(f.readline()))
                    self.conn.delete_row("profiles", name=f"f{str(i)}")
                    self.set_current_mode()

    def on_export(self):
        path, _ = QtWidgets.QFileDialog.getSaveFileName(
            self, "Export to a file")
        if path:
            with open(f"{path}.rat", "w") as f:
                for i in range(3, 6):
                    dump(self.ratslap.parse_mode(i), f)
                    f.write("\n")

    def on_apply(self):
        for mode in ["f3", "f4", "f5"]:
            data = self.conn.select("profiles", "*", name=mode).fetchone()
            if data:
                cols = self.conn.get_column_names("profiles")
                changes = dict(zip(cols, data))
                self.ratslap.modify(mode, **changes)

    def assign_shortcut(self):
        button = self.sender()
        command_editor = CommandEditor(button, self)
        command_editor.setWindowModality(Qt.ApplicationModal)
        command_editor.show()

    def get_ratslap_path(self):
        path_valid, first_try = False, True
        path = None
        while not path_valid:
            if not first_try:
                title = "Non valid path"
                text = "The path you specified is not valid. Try again"
                self.exec_message_box(title, text)
            caption = f"Select the path to the '{self.ratslap_name}' program..."
            path, _ = QtWidgets.QFileDialog.getOpenFileName(self, caption)
            if path:
                try:
                    ratslap.RatSlap(path)
                except ratslap.NonValidPathError:
                    first_try = False
                except (ratslap.MouseIsOfflineError,
                        ratslap.PermissionDeniedError,
                        ratslap.UnknownRatSlapError):
                    path_valid = True
                else:
                    path_valid = True

            else:
                exit()
        self.conn.drop_table("file_paths")
        self.conn.create_table("file_paths", ["program_name", "path"])
        self.conn.insert_values("file_paths", **{
            "program_name": "ratslap",
            "path": path
        })
        return path

    def connect_signals_and_slots_of_thread(self):
        self.usb_detector.mouse_state_changed.connect(self.toggle_ui_state)
        self.usb_detector.moveToThread(self.thread)
        self.thread.started.connect(self.usb_detector.work)

    def toggle_ui_state(self, mouse_online):
        self.mouse_connected = mouse_online
        mouse_offline_message_box = self.findChild(
            QtWidgets.QMessageBox, "mouse_offline_message_box")
        if mouse_online:
            self.tray_icon.setToolTip(f"{self.app_name}\nMouse is online")
            if mouse_offline_message_box is not None:
                mouse_offline_message_box.hide()
            if self.isVisible():
                try:
                    self.set_current_mode()
                    self.permission_granted = True
                    self.current_mode_is_set = True
                except ratslap.PermissionDeniedError:
                    self.permission_granted = False
                except ratslap.MouseIsOfflineError:
                    pass

        for radio_btn in self.radio_buttons:
            if not radio_btn.isChecked():
                radio_btn.setEnabled(mouse_online and self.permission_granted)

        for name in self.action_names:
            button = getattr(self, f"button_{name}")
            button.setEnabled(mouse_online and self.permission_granted)

        if mouse_online and self.isHidden():
            self.show_tray_message("Mouse connected")

        elif not mouse_online:
            self.tray_icon.setToolTip(f"{self.app_name}\nMouse is offline")
            if self.isVisible():
                text = f"Please plug in your Logitech G300s mouse to continue using {self.app_name}"
                if mouse_offline_message_box is not None:
                    mouse_offline_message_box.show()
                else:
                    self.exec_message_box(
                        "Failed to find Logitech G300s",
                        text, ["Ok"],
                        "Information",
                        objectName="mouse_offline_message_box")
            else:
                if self.current_mode_is_set:
                    self.show_tray_message("Mouse disconnected")
                else:
                    self.show_tray_message("Failed to find Logitech G300s")

    def handle_permission_denied_error(self, e):
        self.permission_granted = False
        error = ratslap.Error(e, self.ratslap.path)
        title = error.get_name()
        text = "You do not have write access to the mouse."
        informative_text = f"Would you like {self.app_name} to help you with this?"
        details = error.get_full_error_message()
        response = self.exec_message_box(title,
                                         text,
                                         icon_name="Warning",
                                         button_names=["Yes", "No"],
                                         special_buttons={
                                             "DefaultButton": 1,
                                             "EscapeButton": 2
                                         },
                                         informativeText=informative_text,
                                         detailedText=details)
        if response == "Yes":
            file_name = "10-ratslap.rules"
            self.create_udev_rule_for_ratslap(file_name)
            self.prompt_user_to_move_the_file(file_name)
            self.exec_message_box(
                "Replug your mouse",
                "If you have done with moving the file and reloading"
                " the rules, plug out your mouse and replug it for "
                "changes to take the effect.")

    def prompt_user_to_move_the_file(self, file_name):
        title = "Move the file and reload the rules"
        text = f'A file named "{file_name}" created under {self.path}\n\n' \
            f'Move it to the path: /etc/udev/rules.d/ \n' \
            f'and then reload udevadm rules.'
        informative_text = "If you don't know how to do it, press Show Details button."
        details = f"Run the command below on terminal and then press Ok\n\n" \
            f"sudo mv {self.get_path(file_name)} /etc/udev/rules.d && " \
            f"sudo udevadm control --reload-rules"
        self.exec_message_box(title,
                              text,
                              informativeText=informative_text,
                              detailedText=details)

    def set_current_mode(self):
        current_mode_index = [i.isChecked()
                              for i in self.radio_buttons].index(True) + 3
        self.current_mode_name = "f" + str(current_mode_index)  # f3, f4 or f5
        self.ratslap.select_mode(self.current_mode_name)
        current_mode = self.get_mode(self.current_mode_name)

        for item in self.combo_boxes + self.unchangeable_items + self.buttons:
            name = item.objectName()
            try:
                item.setText(current_mode[name])
            except AttributeError:
                item.setCurrentText(current_mode[name].title())

    def combo_box_changed(self, value):
        property_name = self.sender().objectName()
        self.conn.update_value("profiles",
                               property_name,
                               value.lower(),
                               name=self.current_mode_name)

    def get_mode(self, mode):
        column_names = self.conn.get_column_names("defaults")
        self.conn.create_table("profiles", column_names)
        data = self.conn.select("profiles", "*", name=mode).fetchone()
        if data:
            return dict(zip(column_names, data))
        else:
            profile = self.ratslap.parse_mode(mode)
            self.conn.insert_values("profiles", **profile)
            return self.get_mode(mode)

    def show_tray_message(self, message, title=None):
        if title is None:
            title = self.app_name
        self.tray_icon.showMessage(title, message,
                                   QIcon(self.get_path("images", "logo.png")),
                                   1000)

    def exec_message_box(self,
                         title,
                         text,
                         button_names=None,
                         icon_name=None,
                         special_buttons=None,
                         **kwargs):
        msg_box = QtWidgets.QMessageBox(self, **kwargs)
        if not button_names:
            button_names = ["Ok"]

        for button_name in button_names:
            try:
                msg_box.addButton(getattr(QtWidgets.QMessageBox, button_name))
            except AttributeError as e:
                print(e, file=sys.stderr)
        if icon_name:
            icon = getattr(QtWidgets.QMessageBox, icon_name)
        else:
            icon = QtWidgets.QMessageBox.Information
        msg_box.setIcon(icon)
        msg_box.setWindowTitle(title)
        msg_box.setText(text)
        if special_buttons is not None:
            for button_name, index in special_buttons.items():
                method = getattr(msg_box, f"set{button_name}")
                button = getattr(msg_box, button_names[index - 1])
                method(button)

        response = msg_box.exec()
        for button_name in button_names:
            if response == getattr(msg_box, button_name):
                return button_name

    def create_udev_rule_for_ratslap(self, file_name):
        with open(self.get_path(file_name), "w") as f:
            rule = 'DRIVER=="usb", ' \
                   'ATTR{idProduct}=="c246", ' \
                   'ATTR{idVendor}=="046d", ' \
                   'ATTR{product}=="G300s Optical Gaming Mouse", ' \
                   'MODE="0666", ' \
                   'GROUP="%s"' % (os.getenv("USER"))
            f.write(rule)

    def create_or_remove_autostart_file(self):
        path = self.get_path(os.path.expanduser("~"), ".config/autostart/")
        file_name = f"{self.app_name}.desktop"
        if self.action_autostart.isChecked():
            if os.path.exists(path):
                option = "--run-in-background"
                self.create_dot_desktop_file(
                    file_name, path, f"Autostart {self.app_name} on startup",
                    option)
            else:

                self.exec_message_box(
                    "Sorry",
                    "We do not know how to perform this operation on your system.",
                    icon_name="Information")
                self.action_autostart.setChecked(False)
        else:
            if os.path.exists(self.get_path(path, file_name)):
                os.remove(self.get_path(path, file_name))

    def create_desktop_shortcut(self):
        path = self.get_path(os.path.expanduser("~"), "Desktop")
        file_name = f"{self.app_name}.desktop"
        if os.path.exists(os.path.join(path, file_name)):
            self.exec_message_box("Info", "Desktop shortcut already exists")
        else:
            self.create_dot_desktop_file(file_name, path,
                                         f"Launch {self.app_name}")
            self.exec_message_box(
                "Info", f"A file named {file_name} created on your desktop. "
                f"Right click on it and follow\n"
                f"Properties->Permissions->Allow executing file as program")

    def create_dot_desktop_file(self,
                                file_name,
                                path,
                                comment,
                                run_in_background=""):
        with open(os.path.join(path, file_name), "w") as f:
            f.write(
                f"[Desktop Entry]\n"
                f"Version=1.0\n"
                f"Type=Application\n"
                f"Exec={sys.executable} {self.get_path('main.py')} {run_in_background}\n"
                f"Hidden=false\n"
                f"NoDisplay=false\n"
                f"X-GNOME-Autostart-enabled=true\n"
                f"Name[en]={self.app_name}\n"
                f"Name={self.app_name}\n"
                f"Comment[en]={comment}\n"
                f"Comment={comment}\n"
                f"Icon={self.get_path('images', 'logo.png')}\n")

    def save_settings(self):
        minimize_to_tray = self.action_minimize_to_tray.isChecked()
        self.settings.setValue("minimize_to_tray_when_closing",
                               minimize_to_tray)

        auto_start = self.action_autostart.isChecked()
        self.settings.setValue("auto_start_on_boot", auto_start)
        self.settings.sync()

    def show(self):
        super().show()
        self.toggle_ui_state(self.mouse_connected)

    def _set_visible(self, visible):
        if visible:
            self.show()
        else:
            super().setVisible(False)

    def closeEvent(self, e):
        if not self.action_minimize_to_tray.isChecked():
            self.quit()
        else:
            e.ignore()
            self.hide()
            self.show_tray_message(f"{self.app_name} was minimized to tray")

    def quit(self):
        self.save_settings()
        self.conn.close()
        QtWidgets.qApp.quit()
Example #27
0
class Settings(QDialog, Ui_Settings):
    """Settings dialog"""

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)
        self.core = None
        self.plugins = []
        self.emumode = []
        self.combomap = {}

        self.qset = QSettings("m64py", "m64py")
        self.qset.setDefaultFormat(QSettings.IniFormat)

        self.add_items()
        self.connect_signals()

    def showEvent(self, event):
        self.set_config()

    def closeEvent(self, event):
        self.save_config()

    def add_items(self):
        self.combomap = {
            M64PLUGIN_RSP: (
                self.comboRSP, self.pushButtonRSP,
                Plugin(self.parent)),
            M64PLUGIN_GFX: (
                self.comboVideo, self.pushButtonVideo,
                Plugin(self.parent)),
            M64PLUGIN_AUDIO: (
                self.comboAudio, self.pushButtonAudio,
                Plugin(self.parent)),
            M64PLUGIN_INPUT: (
                self.comboInput, self.pushButtonInput,
                Input(self.parent))
        }

        self.emumode = [
            QRadioButton(self.tr("Pure Interpreter")),
            QRadioButton(self.tr("Cached Interpreter")),
            QRadioButton(self.tr("Dynamic Recompiler"))
        ]

        vbox = QVBoxLayout(self.groupEmuMode)
        for widget in self.emumode:
            vbox.addWidget(widget)

    def show_page(self, index=0):
        self.tabWidget.setCurrentIndex(index)
        self.show()

    def save_config(self):
        self.save_paths()
        self.save_plugins()
        if self.core and self.core.get_handle():
            self.save_video()
            self.save_core()
            self.core.config.save_file()
        self.qset.sync()

    def set_config(self):
        if self.core and self.core.get_handle():
            self.set_paths()
            self.set_plugins()
            self.set_video()
            self.set_core()

    def on_vidext_changed(self, state):
        self.parent.vidext = state
        self.comboResolution.setEnabled(not self.parent.vidext)
        self.checkFullscreen.setEnabled(not self.parent.vidext)
        self.parent.worker.quit()
        self.parent.worker.init()

    def connect_signals(self):
        self.browseLibrary.clicked.connect(lambda: self.browse_dialog(
            (self.pathLibrary, self.groupLibrary, False)))
        self.browsePlugins.clicked.connect(lambda: self.browse_dialog(
            (self.pathPlugins, self.groupPlugins, True)))
        self.browseData.clicked.connect(lambda: self.browse_dialog(
            (self.pathData, self.groupData, True)))
        self.browseROM.clicked.connect(lambda: self.browse_dialog(
            (self.pathROM, self.groupROM, True)))
        self.checkEnableVidExt.clicked.connect(self.on_vidext_changed)
        for plugin_type in self.combomap:
            self.connect_combo_signals(self.combomap[plugin_type])

    def connect_combo_signals(self, combomap):
        combo, button, settings = combomap
        if settings is not None:
            if combo != self.comboInput:
                combo.activated.connect(
                    lambda: self.set_section(combo, button, settings))
            button.clicked.connect(settings.show_dialog)

    def browse_dialog(self, args):
        widget, groupbox, directory = args
        dialog = QFileDialog()
        if directory:
            dialog.setFileMode(QFileDialog.Directory)
            path = dialog.getExistingDirectory(
                self, groupbox.title(), widget.text(), QFileDialog.ShowDirsOnly)
        else:
            dialog.setFileMode(QFileDialog.ExistingFile)
            path, _ = dialog.getOpenFileName(
                self, groupbox.title(), widget.text(),
                "%s (*%s);;All files (*)" % (groupbox.title(), DLL_FILTER))

        if not path:
            return

        widget.setText(path)
        if widget == self.pathLibrary:
            self.parent.worker.quit()
            if not self.parent.worker.core.get_handle():
                self.parent.worker.init(path)
                if self.parent.worker.core.get_handle():
                    self.core = self.parent.worker.core
                    self.set_core()
                    self.set_video()
                    self.parent.window_size_triggered(self.get_size_safe())
                    self.parent.state_changed.emit((True, False, False, False))
        elif widget == self.pathPlugins:
            self.parent.worker.plugins_shutdown()
            self.parent.worker.plugins_unload()
            self.parent.worker.plugins_load(path)
            self.parent.worker.plugins_startup()
            self.set_plugins()

    def get_int_safe(self, key, default):
        try:
            return int(self.qset.value(key, default))
        except ValueError:
            return default

    def get_size_safe(self):
        try:
            size = self.qset.value("size", SIZE_1X)
        except TypeError:
            size = SIZE_1X
        if not type(size) == tuple:
            size = SIZE_1X
        if len(size) != 2:
            size = SIZE_1X
        if type(size[0]) != int or type(size[1]) != int:
            size = SIZE_1X
        if size[0] <= 0 or size[1] <= 0:
            size = SIZE_1X
        return size

    def get_section(self, combo):
        plugin = combo.currentText()
        index = combo.findText(plugin)
        desc = combo.itemData(index)
        name = os.path.splitext(plugin)[0][12:]
        section = "-".join([n.capitalize() for n in name.split("-")[0:2]])
        return section, desc

    def set_section(self, combo, button, settings):
        if settings:
            if combo != self.comboInput:
                section, desc = self.get_section(combo)
                settings.set_section(section, desc)
                self.core.config.open_section(section)
                items = self.core.config.parameters[
                    self.core.config.section].items()
                if items:
                    button.setEnabled(True)
                else:
                    button.setEnabled(False)
            else:
                button.setEnabled(True)
        else:
            button.setEnabled(False)

    def set_paths(self):
        path_library = self.qset.value(
            "Paths/Library", find_library(CORE_NAME))
        path_data = self.qset.value(
            "Paths/Data", self.core.config.get_path("SharedData"))
        path_roms = self.qset.value("Paths/ROM")

        try:
            path_plugins = self.qset.value("Paths/Plugins", os.path.realpath(
                os.path.dirname(self.parent.worker.plugin_files[0])))
        except IndexError:
            path_plugins = ""

        try:
            self.pathROM.setText(path_roms)
        except TypeError:
            pass

        self.pathLibrary.setText(path_library)
        self.pathPlugins.setText(path_plugins)
        self.pathData.setText(path_data)

    def set_video(self):
        self.core.config.open_section("Video-General")

        self.set_resolution()

        self.checkEnableVidExt.setChecked(
            bool(self.get_int_safe("enable_vidext", 1)))

        self.checkFullscreen.setChecked(
            bool(self.core.config.get_parameter("Fullscreen")))
        self.checkFullscreen.setEnabled(not self.parent.vidext)

        self.checkVsync.setChecked(
            bool(self.core.config.get_parameter("VerticalSync")))
        self.checkVsync.setToolTip(
            self.core.config.get_parameter_help("VerticalSync").decode())

        if sys.platform == "win32":
            self.checkKeepAspect.setChecked(False)
            self.checkKeepAspect.setEnabled(False)
        else:
            keep_aspect = bool(self.get_int_safe("keep_aspect", 1))
            self.checkKeepAspect.setChecked(keep_aspect)

        disable_screensaver = bool(self.get_int_safe("disable_screensaver", 1))
        self.checkDisableScreenSaver.setChecked(disable_screensaver)

    def set_core(self):
        self.core.config.open_section("Core")
        mode = self.core.config.get_parameter("R4300Emulator")
        self.emumode[mode].setChecked(True)
        self.checkOSD.setChecked(
            self.core.config.get_parameter("OnScreenDisplay"))
        self.checkOSD.setToolTip(
            self.core.config.get_parameter_help("OnScreenDisplay").decode())
        self.checkNoCompiledJump.setChecked(
            self.core.config.get_parameter("NoCompiledJump"))
        self.checkNoCompiledJump.setToolTip(
            self.core.config.get_parameter_help("NoCompiledJump").decode())
        self.checkDisableExtraMem.setChecked(
            self.core.config.get_parameter("DisableExtraMem"))
        self.checkDisableExtraMem.setToolTip(
            self.core.config.get_parameter_help("DisableExtraMem").decode())

        delay_si = self.core.config.get_parameter("DelaySI")
        if delay_si is not None:
            self.checkDelaySI.setChecked(delay_si)
        else:
            self.checkDelaySI.setChecked(False)
            self.checkDelaySI.setEnabled(False)
        self.checkDelaySI.setToolTip(
            self.core.config.get_parameter_help("DelaySI").decode())

        count_per_op = self.core.config.get_parameter("CountPerOp")
        if count_per_op is not None:
            self.comboCountPerOp.setCurrentIndex(count_per_op)
        else:
            self.comboCountPerOp.setEnabled(False)
        self.comboCountPerOp.setToolTip(
            self.core.config.get_parameter_help("CountPerOp").decode())

    def set_plugins(self):
        plugin_map = self.core.plugin_map
        for plugin_type in self.combomap:
            combo, button, settings = self.combomap[plugin_type]
            combo.clear()
            for plugin in plugin_map[plugin_type].values():
                (plugin_handle, plugin_path, plugin_name,
                    plugin_desc, plugin_version) = plugin
                name = os.path.basename(plugin_path)
                combo.addItem(name)
                index = combo.findText(str(name))
                combo.setItemData(index, plugin_desc)
                combo.setItemData(index, plugin_desc, Qt.ToolTipRole)
            current = self.qset.value("Plugins/%s" % (
                PLUGIN_NAME[plugin_type]), PLUGIN_DEFAULT[plugin_type])
            index = combo.findText(current)
            if index == -1:
                index = 0
            combo.setCurrentIndex(index)
            self.set_section(combo, button, settings)

    def set_resolution(self):
        width = self.core.config.get_parameter("ScreenWidth")
        height = self.core.config.get_parameter("ScreenHeight")
        if (width, height) not in MODES:
            MODES.append((width, height))

        self.comboResolution.clear()
        for mode in MODES:
            w, h = mode
            self.comboResolution.addItem(
                "%sx%s" % (w, h), (w, h))

        index = self.comboResolution.findText(
            "%sx%s" % (width, height), Qt.MatchExactly)
        if index == -1: index = 0
        self.comboResolution.setCurrentIndex(index)
        self.comboResolution.setEnabled(not self.parent.vidext)

    def save_paths(self):
        self.qset.setValue("Paths/Library", self.pathLibrary.text())
        self.qset.setValue("Paths/Plugins", self.pathPlugins.text())
        self.qset.setValue("Paths/Data", self.pathData.text())
        self.qset.setValue("Paths/ROM", self.pathROM.text())

    def save_video(self):
        self.core.config.open_section("Video-General")
        if self.parent.vidext:
            width, height = self.get_size_safe()
        else:
            width, height = self.comboResolution.currentText().split("x")
        self.core.config.set_parameter("ScreenWidth", int(width))
        self.core.config.set_parameter("ScreenHeight", int(height))
        self.core.config.set_parameter("Fullscreen", self.checkFullscreen.isChecked())
        self.core.config.set_parameter("VerticalSync", self.checkVsync.isChecked())
        self.qset.setValue("keep_aspect", int(self.checkKeepAspect.isChecked()))
        self.qset.setValue("disable_screensaver", int(self.checkDisableScreenSaver.isChecked()))
        self.qset.setValue("enable_vidext", int(self.checkEnableVidExt.isChecked()))

    def save_core(self):
        self.core.config.open_section("Core")
        emumode = [n for n,m in enumerate(self.emumode) if m.isChecked()][0]
        self.core.config.set_parameter("R4300Emulator", emumode)
        self.core.config.set_parameter("OnScreenDisplay", self.checkOSD.isChecked())
        self.core.config.set_parameter("NoCompiledJump", self.checkNoCompiledJump.isChecked())
        self.core.config.set_parameter("DisableExtraMem", self.checkDisableExtraMem.isChecked())
        self.core.config.set_parameter("DelaySI", self.checkDelaySI.isChecked())
        self.core.config.set_parameter("CountPerOp", self.comboCountPerOp.currentIndex())
        self.core.config.set_parameter("SharedDataPath", self.pathData.text().encode())

    def save_plugins(self):
        for plugin_type in self.combomap:
            combo, button, settings = self.combomap[plugin_type]
            self.qset.setValue("Plugins/%s" % PLUGIN_NAME[plugin_type], combo.currentText())
Example #28
0
class TasmotaDevicesModel(QAbstractTableModel):
    def __init__(self, tasmota_env):
        super().__init__()
        self.settings = QSettings("{}/TDM/tdm.cfg".format(QDir.homePath()), QSettings.IniFormat)
        self.devices = QSettings("{}/TDM/devices.cfg".format(QDir.homePath()), QSettings.IniFormat)
        self.tasmota_env = tasmota_env
        self.columns = []

        for d in self.tasmota_env.devices:
            d.property_changed = self.notify_change
            d.module_changed = self.module_change

    def setupColumns(self, columns):
        self.beginResetModel()
        self.columns = columns
        self.endResetModel()

    def deviceAtRow(self, row):
        if len(self.tasmota_env.devices) > 0:
            return self.tasmota_env.devices[row]
        return None

    def notify_change(self, d, key):
        row = self.tasmota_env.devices.index(d)
        if key.startswith("POWER") and "Power" in self.columns:
            power_idx = self.columns.index("Power")
            idx = self.index(row, power_idx)
            self.dataChanged.emit(idx, idx)

        elif key in ("RSSI", "LWT"):
            fname_idx = self.columns.index("FriendlyName")
            idx = self.index(row, fname_idx)
            self.dataChanged.emit(idx, idx)

        elif key in self.columns:
            col = self.columns.index(key)
            idx = self.index(row, col)
            self.dataChanged.emit(idx, idx)

    def module_change(self, d):
        self.notify_change(d, "Module")

    def columnCount(self, parent=None):
        return len(self.columns)

    def rowCount(self, parent=None):
        return len(self.tasmota_env.devices)

    def flags(self, idx):
        return Qt.ItemIsSelectable | Qt.ItemIsEnabled

    def headerData(self, col, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.columns[col]

    def data(self, idx, role=Qt.DisplayRole):
        if idx.isValid():
            row = idx.row()
            col = idx.column()
            col_name = self.columns[col]
            d = self.tasmota_env.devices[row]

            if role in [Qt.DisplayRole, Qt.EditRole]:
                val = d.p.get(col_name, "")

                if col_name == "FriendlyName":
                    val = d.p.get("FriendlyName1", d.p['Topic'])

                elif col_name == "Module":
                    if val == 0:
                        return d.p['Template'].get('NAME', "Fetching template name...")
                    else:
                        return d.module()

                elif col_name == "Version" and val:
                    if "(" in val:
                        return val[0:val.index("(")]
                    return val

                elif col_name in ("Uptime", "Downtime") and val:
                    if val.startswith("0T"):
                        val = val.replace('0T', '')
                    val = val.replace('T', 'd ')

                elif col_name == "Core" and val:
                    return val.replace('_', '.')

                elif col_name == "Time" and val:
                    return val.replace('T', ' ')

                elif col_name == "Power":
                    return d.power()

                elif col_name == "Color":
                    return d.color()

                elif col_name == "CommandTopic":
                    return d.cmnd_topic()

                elif col_name == "StatTopic":
                    return d.stat_topic()

                elif col_name == "TeleTopic":
                    return d.tele_topic()

                elif col_name == "FallbackTopic":
                    return "cmnd/{}_fb/".format(d.p.get('MqttClient'))

                elif col_name == "BSSId":
                    alias = self.settings.value("BSSId/{}".format(val))
                    if alias:
                        return alias

                return val

            elif role == LWTRole:
                val = d.p.get('LWT', 'Offline')
                return val

            elif role == RestartReasonRole:
                val = d.p.get('RestartReason')
                return val

            elif role == RSSIRole:
                val = d.p.get('RSSI', 0)
                return val

            elif role == FirmwareRole:
                val = d.p.get('Version', "")
                return val

            elif role == Qt.TextAlignmentRole:
                # Left-aligned columns
                if col_name in ("FriendlyName", "Module", "RestartReason", "OtaUrl", "Hostname") or col_name.endswith("Topic"):
                    return Qt.AlignLeft | Qt.AlignVCenter | Qt.TextWordWrap

                # Right-aligned columns
                elif col_name in ("Uptime"):
                    return Qt.AlignRight | Qt.AlignVCenter

                else:
                    return Qt.AlignCenter

            elif role == Qt.DecorationRole and col_name == "FriendlyName":
                if d.p['LWT'] == "Online":
                    rssi = int(d.p.get("RSSI", 0))

                    if rssi > 0 and rssi < 50:
                        return QIcon("GUI/icons/status_low.png")

                    elif rssi < 75:
                        return QIcon("GUI/icons/status_medium.png")

                    elif rssi >= 75:
                        return QIcon("GUI/icons/status_high.png")

                return QIcon("GUI/icons/status_offline.png")

            elif role == Qt.InitialSortOrderRole:
                if col_name in ("Uptime", "Downtime"):
                    val = d.p.get(col_name, "")
                    if val:
                        d, hms = val.split("T")
                        h, m, s = hms.split(":")
                        return int(s) + int(m) * 60 + int(h) * 3600 + int(d) * 86400
                else:
                    return idx.data()

            elif role == Qt.ToolTipRole:
                if col_name == "Version":
                    val = d.p.get('Version')
                    if val:
                        return val[val.index("(")+1:val.index(")")]
                    return ""

                elif col_name == "BSSId":
                    return d.p.get('BSSId')

                elif col_name == "FriendlyName":
                    fns = [d.p['FriendlyName1']]

                    for i in range(2, 5):
                        fn = d.p.get("FriendlyName{}".format(i))
                        if fn:
                            fns.append(fn)
                    return "\n".join(fns)

    def addDevice(self, device):
        self.beginInsertRows(QModelIndex(), 0, 0)
        device.property_changed = self.notify_change
        device.module_changed = self.module_change
        self.endInsertRows()

    def removeRows(self, pos, rows, parent=QModelIndex()):
        if pos + rows <= self.rowCount():
            self.beginRemoveRows(parent, pos, pos + rows - 1)
            device = self.deviceAtRow(pos)
            self.tasmota_env.devices.pop(self.tasmota_env.devices.index(device))

            topic = device.p['Topic']
            self.settings.beginGroup("Devices")
            if topic in self.settings.childGroups():
                self.settings.remove(topic)
            self.settings.endGroup()

            self.endRemoveRows()
            return True
        return False

    def deleteDevice(self, idx):
        row = idx.row()
        mac = self.deviceAtRow(row).p['Mac'].replace(":", "-")
        self.devices.remove(mac)
        self.devices.sync()
        self.removeRows(row, 1)

    def columnIndex(self, column):
        return self.columns.index(column)
class AppSettings:
    """
    Manages application settings.

    To access settings through this class, make sure the settings key and
    default value are registered in known_settings.

    """
    def __init__(self, settings_file=None):
        """
        Load either the user specific settings or, if a file name is
        provided, specific settings from that file.

        """
        self._settings_file = settings_file
        self._logger = logging.getLogger(__name__)
        if settings_file is None:
            self._settings = QSettings()
        else:
            self._logger.info('Loading settings from ' + settings_file)
            self._settings = QSettings(settings_file, QSettings.IniFormat)

    @property
    def settings(self):
        """
        Provides direct access to the underlying QSettings that are used to
        read/store settings values.

        """
        return self._settings

    def date_value(self, key):
        """
        Reads the string value in *key* and tries to decode it into a
        datetime object. The string value is expected to have the format
        '2014-12-24 18:00:00'

        """
        date_str = self.value(key)
        if date_str is None:
            return None
        try:
            date = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
        except ValueError:
            self._logger.error(date_str + ' could not be decoded. Ignoring.')
            return None
        else:
            return date

    def value(self, key):
        """
        Returns the value that is stored for key or the default value if
        no value is stored.

        If the key is not known, the function will throw an exception.

        """
        if key not in known_settings.keys():
            raise Exception(key + ' is not a known registered setting')
        default = known_settings[key]
        if isinstance(default, collections.Container) or default is None:
            return self._settings.value(key, defaultValue=default)
        else:
            return self._settings.value(key,
                                        defaultValue=default,
                                        type=type(default))

    def set_value(self, key, value):
        """
        Sets the value for key

        If the key is not known, the function will throw an exception.

        """
        if key not in known_settings.keys():
            raise Exception(key + ' is not a known registered setting')
        return self._settings.setValue(key, value)

    def register_default_settings(self):
        """
        Writes the default value for each setting to the settings file

        """
        self._logger.info('Loading default settings')
        for key, value in known_settings.items():
            self._settings.setValue(key, value)
        self._settings.sync()
class CoverletterCreator(QtWidgets.QMainWindow, mainWindow.Ui_MainWindow):
    def __init__(self, parent=None):
        super(CoverletterCreator, self).__init__(parent)
        self.setupUi(self)

        self.mainTitle = "Coverletter Creator"
        self.config = QSettings()
        self.settings = SettingsHandler(parent=self, settings=self.config)

        self.clipboard = QtWidgets.QApplication.clipboard()

        self.actionNew.triggered.connect(self.new_project)
        self.actionSave.triggered.connect(self.save_project)
        self.actionSave_As.triggered.connect(self.saveas_project)
        self.actionOpen.triggered.connect(self.open_project)
        self.actionExit.triggered.connect(self.close)
        self.actionSettings.triggered.connect(self.settings.show)

        # Set default values
        self.filename = "Examples/example_project.xml"
        self.file_dirty = False

        self.readSettings()
        self.load_file(self.filename)

        self.pb_browsePhoto.clicked.connect(self.browse_photo)
        self.pb_generatePdf.clicked.connect(self.generate_pdf)
        self.pb_generateText.clicked.connect(self.generate_text)

        self.connect_all_fields()
        self.connect_mandatory_fields()

        # Connect all labels to click handler
        for child in self.centralwidget.findChildren(QtWidgets.QLabel):
            child.mousePressEvent = functools.partial(self.label_clicked,
                                                      source=child)
        for child in self.centralwidget.findChildren(QtWidgets.QCheckBox):
            child.mousePressEvent = functools.partial(self.checkbox_clicked,
                                                      source=child)
        self.RECEIPIENTGENDER.mousePressEvent = functools.partial(
            self.combobox_clicked, source=self.RECEIPIENTGENDER)
        self.RECEIPIENTSALUTATION.mousePressEvent = functools.partial(
            self.combobox_clicked, source=self.RECEIPIENTSALUTATION)

        self.COMPANYNAME.editingFinished.connect(
            lambda: self.COMPANYSHORTNAME.setText(self.COMPANYNAME.text()))

    def connect_all_fields(self):
        for child in self.centralwidget.findChildren(QtWidgets.QLineEdit):
            child.textChanged.connect(self.setWindowTitleUnsaved)
        for child in self.centralwidget.findChildren(QtWidgets.QPlainTextEdit):
            child.textChanged.connect(self.setWindowTitleUnsaved)
        for child in self.centralwidget.findChildren(QtWidgets.QCheckBox):
            child.clicked.connect(self.setWindowTitleUnsaved)
        for child in self.centralwidget.findChildren(SpellTextEdit):
            child.textChanged.connect(self.setWindowTitleUnsaved)
        for child in self.centralwidget.findChildren(QtWidgets.QComboBox):
            child.currentIndexChanged.connect(self.setWindowTitleUnsaved)

    def connect_mandatory_fields(self):
        mandatory_fields_list = [
            self.FIRSTNAME, self.LASTNAME, self.MOBILE, self.EMAIL,
            self.COMPANYNAME
        ]
        for textBox in mandatory_fields_list:
            textBox.textChanged[str].connect(
                lambda: self.pb_generatePdf.setEnabled(textBox.text() != ""))

        for textBox in mandatory_fields_list:
            textBox.textChanged[str].connect(
                lambda: self.pb_generateText.setEnabled(textBox.text() != ""))

    def label_clicked(self, event, source):
        var_code = source.accessibleName()
        self.clipboard.setText(str(var_code))
        event.accept()

    def checkbox_clicked(self, event, source):
        var_code = source.accessibleName()
        self.clipboard.setText(str(var_code))
        source.toggle()

    def combobox_clicked(self, event, source):
        var_code = source.accessibleName()
        self.clipboard.setText(str(var_code))
        source.showPopup()

    def setWindowTitleUnsaved(self):
        self.file_dirty = True
        _, fname = os.path.split(self.filename)
        self.setWindowTitle(self.mainTitle + " - " + fname + "*")

    def setWindowTitleSaved(self):
        self.file_dirty = False
        _, fname = os.path.split(self.filename)
        self.setWindowTitle(self.mainTitle + " - " + fname)

    def new_project(self):
        filename, _ = QFileDialog.getSaveFileName(self, "New Project", "./",
                                                  "XML Files (*.xml)")
        if filename:
            if ".xml" not in filename:
                filename = filename + '.xml'

            self.reset_all_fields()
            self.filename = filename
            self.setWindowTitleUnsaved()
        else:
            return

    def reset_all_fields(self):
        for child in self.centralwidget.findChildren(QtWidgets.QLineEdit):
            child.clear()
        for child in self.centralwidget.findChildren(QtWidgets.QPlainTextEdit):
            child.clear()
        for child in self.centralwidget.findChildren(QtWidgets.QCheckBox):
            child.setChecked(False)
        for child in self.centralwidget.findChildren(SpellTextEdit):
            child.clear()
        for child in self.centralwidget.findChildren(SpellTextEdit):
            child.clear()
        self.label_pic.clear()

    def save_project(self):
        try:
            open(self.filename, 'w')
        except OSError:
            filename, _ = QFileDialog.getSaveFileName(self, "Save Project",
                                                      "./",
                                                      "XML Files (*.xml)")
            if filename:
                self.filename = filename
            else:
                return
        self.root = self.generate_root()

        if ".xml" not in self.filename:
            self.filename = self.filename + '.xml'
        with open(self.filename, 'wb') as f:
            f.write(tostring(self.root, pretty_print=True))

        self.setWindowTitleSaved()

    def generate_root(self):
        root = Element('root')

        personal_info = Element('personal_info')
        root.append(personal_info)
        for qW in [
                self.FIRSTNAME, self.LASTNAME, self.MOBILE, self.EMAIL,
                self.HOMEPAGE, self.GITHUBNAME, self.LINKEDINNAME
        ]:
            child = Element(qW.objectName())
            child.text = qW.text()
            personal_info.append(child)

        personal_address = Element('PERSONALADDRESS')
        personal_address.text = self.PERSONALADDRESS.toPlainText()
        personal_info.append(personal_address)

        company_info = Element('company_info')
        root.append(company_info)
        for qW in [
                self.COMPANYNAME, self.COMPANYSHORTNAME, self.DEPARTMENT,
                self.LETTERTITLE, self.JOBTITLE, self.JOBREFID,
                self.RECEIPIENTNAME
        ]:
            child = Element(qW.objectName())
            child.text = qW.text()
            company_info.append(child)

        company_address = Element('COMPANYADDRESS')
        company_address.text = self.COMPANYADDRESS.toPlainText()
        company_info.append(company_address)

        RECEIPIENTGENDER = Element('RECEIPIENTGENDER')
        RECEIPIENTGENDER.text = str(self.RECEIPIENTGENDER.currentText())
        company_info.append(RECEIPIENTGENDER)

        RECEIPIENTSALUTATION = Element('RECEIPIENTSALUTATION')
        RECEIPIENTSALUTATION.text = str(
            self.RECEIPIENTSALUTATION.currentText())
        company_info.append(RECEIPIENTSALUTATION)

        about_me = Element('TEXTABOUTME')
        about_me.text = self.TEXTABOUTME.toPlainText()
        root.append(about_me)

        WhyFirm = Element('TEXTWHYTHISFIRM')
        WhyFirm.text = self.TEXTWHYTHISFIRM.toPlainText()
        root.append(WhyFirm)

        whyYou = Element('TEXTWHYYOU')
        whyYou.text = self.TEXTWHYYOU.toPlainText()
        root.append(whyYou)

        misc = Element('misc')
        root.append(misc)
        for qW in [
                self.CLOSINGSALUTATION, self.ENCLOSINGPREFIX, self.PHOTOPATH
        ]:
            child = Element(qW.objectName())
            child.text = qW.text()
            misc.append(child)
        for qW in [
                self.CERTIFICATESATTACHED,
                self.CVATTACHED,
                self.REFLETTERSATTACHED,
                self.TRANSCRIPTSATTACHED,
        ]:
            child = Element(qW.objectName())
            child.text = str(qW.isChecked())
            misc.append(child)

        return root

    def saveas_project(self):
        filename, _ = QFileDialog.getSaveFileName(self, "Save Project As",
                                                  "./", "XML Files (*.xml)")

        if filename:
            if ".xml" not in filename:
                filename = filename + '.xml'
            with open(filename, 'wb') as f:
                f.write(tostring(self.generate_root(), pretty_print=True))
            self.load_file(filename)

    def open_project(self):
        filename, _ = QFileDialog.getOpenFileName(self, "Open Project", "./",
                                                  "XML Files (*.xml)")
        if not filename:
            return

        if ".xml" not in filename:
            filename = filename + '.xml'

        self.load_file(filename)

    def load_file(self, filename):
        try:
            with open(filename, 'r') as f:
                self.root = XML(f.read())  #.replace("\n", ""))
            self.reset_all_fields()
            for element in self.root.iter():
                widget = self.findChild(QtWidgets.QLineEdit, str(element.tag))
                if widget is not None and element.text is not None:
                    widget.setText(str(element.text))
                else:
                    widget = self.findChild(QtWidgets.QPlainTextEdit,
                                            str(element.tag))
                    if widget is not None and element.text is not None:
                        widget.setPlainText(str(element.text))
                    else:
                        widget = self.findChild(QtWidgets.QComboBox,
                                                str(element.tag))
                        if widget is not None and element.text is not None:
                            index = widget.findText(element.text,
                                                    QtCore.Qt.MatchFixedString)
                            if index >= 0:
                                widget.setCurrentIndex(index)
                            elif str(element.text).isdigit():
                                widget.setCurrentIndex(int(element.text))
                            else:
                                widget.setCurrentText(str(element.text))
                        else:
                            widget = self.findChild(QtWidgets.QCheckBox,
                                                    str(element.tag))
                            if widget is not None and element.text is not None:
                                widget.setChecked(str(element.text) == 'True')
                            else:
                                widget = self.findChild(
                                    SpellTextEdit, str(element.tag))
                                if widget is not None and element.text is not None:
                                    widget.setChecked(
                                        str(element.text) == 'True')

            self.filename = filename
            self.get_photo(self.PHOTOPATH.text())
            self.setWindowTitleSaved()

        except FileNotFoundError:
            # Warning: File not found!
            self.filename = "untitled.xml"
            self.setWindowTitleUnsaved()
            self.file_dirty = False

        except XMLSyntaxError:
            QtWidgets.QMessageBox.critical(
                self, "XML Read Failed",
                "Cannot read xml file %s. \n\nMake sure the xml file is not blank "
                % filename)

    def browse_photo(self):
        fname, _ = QFileDialog.getOpenFileName(self, 'Open profile photo',
                                               './',
                                               "Image files (*.jpg *.png)")
        if fname:
            self.get_photo(fname)

    def get_photo(self, fname):
        image = QtGui.QImage(fname)
        if image.isNull():
            QtWidgets.QMessageBox.information(self, "Image Viewer",
                                              "Cannot load %s." % fname)
            return
        self.PHOTOPATH.setText(fname)
        self.label_pic.setPixmap(
            QtGui.QPixmap(fname).scaled(160, 160, QtCore.Qt.KeepAspectRatio,
                                        QtCore.Qt.FastTransformation))

    def generate_pdf(self):
        pdfcreator = PdfCreator(data=self.generate_root(), parent=self)
        pdfcreator.read_template(template=self.settings.latex_template)
        pdfcreator.convert_to_dict()
        pdfcreator.render_template()
        filename = self.COMPANYSHORTNAME.text() + '_' + self.JOBREFID.text(
        ) + '_Coverletter'
        filename = "".join(i for i in filename
                           if i not in ".\/:*?<>|").replace(r' ', '_')

        self.pb_generatePdf.setEnabled(False)
        try:
            pdfcreator.compile_xelatex(
                compiler=self.settings.get_latex_compiler(),
                pdfname=filename + ".pdf",
                outputDir=self.settings.latex_dir,
                open_pdf=self.settings.open_pdf,
                keep_tex=self.settings.keep_tex)
        except FileNotFoundError as e:
            QtWidgets.QMessageBox.critical(
                self, "PDF Compilation Failed: " + str(e),
                "Cannot complete command {}.".format(
                    self.settings.get_latex_compiler()))
        self.pb_generatePdf.setEnabled(True)

    def generate_text(self):
        textcreator = TextCreator(data=self.generate_root())
        try:
            textcreator.read_template(template=self.settings.text_template)
        except FileNotFoundError as e:
            QtWidgets.QMessageBox.critical(
                self, "Error: " + repr(e),
                "Cannot find template file {}.\n".format(
                    self.settings.text_template))
        textcreator.convert_to_dict()
        textcreator.render_template()
        filename = self.COMPANYSHORTNAME.text() + '_' + self.JOBREFID.text(
        ) + '_Coverletter'
        filename = "".join(i for i in filename
                           if i not in ".\/:    *?<>|").replace(r' ', '_')
        self.pb_generateText.setEnabled(False)
        textcreator.compile_text(textname=filename + ".txt",
                                 outputDir=self.settings.text_dir,
                                 open_text=self.settings.open_text)
        self.pb_generateText.setEnabled(True)

    def writeSettings(self):
        self.config.beginGroup("MainWindow")
        self.config.setValue("size", self.size())
        self.config.setValue("pos", self.pos())
        self.config.endGroup()

        if not self.file_dirty:
            self.config.beginGroup("Project")
            self.config.setValue("filename", str(self.filename))
            self.config.endGroup()

        self.config.sync()

    def readSettings(self):
        self.config.beginGroup("MainWindow")
        self.resize(self.config.value("size", QtCore.QSize(616, 466)))
        self.move(self.config.value("pos", QtCore.QPoint(200, 200)))
        self.config.endGroup()

        self.config.beginGroup("Project")
        self.filename = str(self.config.value("filename", self.filename))
        self.config.endGroup()

    # event : QCloseEvent
    def closeEvent(self, event):
        if self.file_dirty:
            choice = QtWidgets.QMessageBox.question(
                self, 'Project not saved', "Save Project before exit?",
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
                | QtWidgets.QMessageBox.Cancel)
            if choice == QtWidgets.QMessageBox.Yes:
                self.save_project()
                self.writeSettings()
                event.accept()
                #sys.exit()
            elif choice == QtWidgets.QMessageBox.Cancel:
                event.ignore()
            else:
                self.writeSettings()
                event.accept()
                #sys.exit()
        else:
            self.writeSettings()
            event.accept()
Example #31
0
    def save(self):
        """Saves application state to QSettings"""

        if system() == "Darwin":
            settings = QSettings(APP_NAME+".gitlab.io", APP_NAME)
        else:
            settings = QSettings(APP_NAME, APP_NAME)

        # Application state

        # Do not store the actual filename. Otherwise, after saving and closing
        # File -> Save would overwrite the last saved file.

        if self.last_file_input_path is not None:
            settings.setValue("last_file_input_path",
                              self.last_file_input_path)
        if self.last_file_output_path is not None:
            settings.setValue("last_file_output_path",
                              self.last_file_output_path)
        if self.last_file_import_path is not None:
            settings.setValue("last_file_import_path",
                              self.last_file_import_path)
        if self.last_file_export_path is not None:
            settings.setValue("last_file_export_path",
                              self.last_file_export_path)
        settings.setValue("max_file_history", self.max_file_history)
        settings.value("file_history", [], 'QStringList')
        if self.file_history:
            settings.setValue("file_history", self.file_history)
        settings.setValue("timeout", self.timeout)
        settings.setValue("refresh_timeout", self.refresh_timeout)
        settings.setValue("signature_key", self.signature_key)

        # GUI state
        for widget_name in self.widget_names:

            if widget_name == "main_window":
                widget = self.parent
            else:
                widget = getattr(self.parent, widget_name)

            # geometry
            geometry_name = widget_name + '/geometry'
            try:
                settings.setValue(geometry_name, widget.saveGeometry())
            except AttributeError:
                pass

            # state
            widget_state_name = widget_name + '/windowState'
            try:
                settings.setValue(widget_state_name, widget.saveState())
            except AttributeError:
                pass

            if isinstance(widget, QToolBar):
                toolbar_visibility_name = widget_name + '/visibility'
                settings.value(toolbar_visibility_name, [], bool)
                settings.setValue(toolbar_visibility_name,
                                  [a.isVisible() for a in widget.actions()])

            if widget_name == "entry_line":
                settings.setValue("entry_line_isvisible", widget.isVisible())

        settings.sync()
Example #32
0
import os
Example #33
0
class Preferences(QObject):
    prefsChanged = pyqtSignal()

    def __init__(self):
        QObject.__init__(self)
        self.reset()
        self._settings = QSettings()

    def _load_values(self, settings, get):
        pass

    def get_rect(self, name, default=None):
        r = self.get_value(name, default)
        if r is not None:
            return QRect(*r)
        else:
            return None

    def get_value(self, name, default=None):
        if self._settings.contains(name):
            result = adjust_after_deserialization(self._settings.value(name))
            if result is not None:
                return result
            else:
                # If result is None, but still present in self._settings, it usually means a value
                # like "@Invalid".
                return default
        else:
            return default

    def load(self):
        self.reset()
        self._load_values(self._settings)

    def reset(self):
        pass

    def _save_values(self, settings, set_):
        pass

    def save(self):
        self._save_values(self._settings)
        self._settings.sync()

    def set_rect(self, name, r):
        if isinstance(r, QRect):
            rectAsList = [r.x(), r.y(), r.width(), r.height()]
            self.set_value(name, rectAsList)

    def set_value(self, name, value):
        self._settings.setValue(name, normalize_for_serialization(value))

    def saveGeometry(self, name, widget):
        # We save geometry under a 7-sized int array: first item is a flag
        # for whether the widget is maximized, second item is a flag for whether
        # the widget is docked, third item is a Qt::DockWidgetArea enum value,
        # and the other 4 are (x, y, w, h).
        m = 1 if widget.isMaximized() else 0
        d = 1 if isinstance(widget,
                            QDockWidget) and not widget.isFloating() else 0
        area = widget.parent.dockWidgetArea(widget) if d else 0
        r = widget.geometry()
        rectAsList = [r.x(), r.y(), r.width(), r.height()]
        self.set_value(name, [m, d, area] + rectAsList)

    def restoreGeometry(self, name, widget):
        geometry = self.get_value(name)
        if geometry and len(geometry) == 7:
            m, d, area, x, y, w, h = geometry
            if m:
                widget.setWindowState(Qt.WindowMaximized)
            else:
                r = QRect(x, y, w, h)
                widget.setGeometry(r)
                if isinstance(widget, QDockWidget):
                    # Inform of the previous dock state and the area used
                    return bool(d), area
        return False, 0
class SourcePanel(ScrollAreaNoFrame):
    """
    Display Devices and This Computer sources, as well as the timeline
    """
    def __init__(self, rapidApp) -> None:
        super().__init__()
        assert rapidApp is not None
        self.rapidApp = rapidApp
        self.prefs = self.rapidApp.prefs

        self.settings = QSettings()
        self.settings.beginGroup("MainWindow")

        self.setObjectName("sourcePanelScrollArea")

        self.sourcePanelWidget = QWidget(parent=self)
        self.sourcePanelWidget.setObjectName("sourcePanelWidget")

        self.splitter = SourceSplitter(parent=self.sourcePanelWidget)
        self.splitter.setObjectName("sourcePanelSplitter")
        self.splitter.setOrientation(Qt.Vertical)
        self.setWidget(self.sourcePanelWidget)
        self.setWidgetResizable(True)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(self.splitter.handleWidth())
        self.sourcePanelWidget.setLayout(layout)

        self.thisComputerBottomFrameConnection = None
        self.thisComputerAltBottomFrameConnection = None

        self.frame_width = QApplication.style().pixelMetric(
            QStyle.PM_DefaultFrameWidth)

    def sourcesIsChecked(self) -> bool:
        """
        Determine if download sources are to be visible.
        :return: True if only widget to be displayed is the Timeline, else False
        """

        return self.rapidApp.sourceButton.isChecked() or (
            self.rapidApp.on_startup and self.rapidApp.sourceButtonSetting())

    def temporalProximityIsChecked(self) -> bool:
        """
        Determine if the Timeline is or is going to be visible. Works during startup.
        :return: True if the Timeline is or will be visible, else False
        """

        return self.rapidApp.proximityButton.isChecked() or (
            self.rapidApp.on_startup
            and self.rapidApp.proximityButtonSetting())

    def needSplitter(self) -> bool:
        """
        A splitter is used if the Timeline should be showed, and This Computer is
        toggled on and is to be shown.

        :return: True if splitter should be used, else False
        """
        return (self.temporalProximityIsChecked()
                and self.thisComputerToggleView.on()
                and self.sourcesIsChecked())

    def addSourceViews(self) -> None:
        """
        Add source widgets and timeline
        """

        self.deviceToggleView = self.rapidApp.deviceToggleView
        self.deviceView = self.rapidApp.deviceView
        self.thisComputerToggleView = self.rapidApp.thisComputerToggleView
        self.thisComputer = self.rapidApp.thisComputer
        self.temporalProximity = self.rapidApp.temporalProximity

        self.deviceToggleView.setSizePolicy(QSizePolicy.MinimumExpanding,
                                            QSizePolicy.Fixed)
        self.temporalProximity.setSizePolicy(QSizePolicy.Preferred,
                                             QSizePolicy.MinimumExpanding)

        layout = self.sourcePanelWidget.layout()  # type: QVBoxLayout
        layout.addWidget(self.deviceToggleView, 0)

        for widget in (
                self.deviceView,
                self.thisComputer,
                self.thisComputerToggleView.alternateWidget,
        ):
            self.verticalScrollBarVisible.connect(
                widget.containerVerticalScrollBar)

        for widget in self.temporalProximity.flexiFrameWidgets():
            self.verticalScrollBarVisible.connect(
                widget.containerVerticalScrollBar)
            self.horizontalScrollBarVisible.connect(
                widget.containerHorizontalScrollBar)

    def placeWidgets(self) -> None:
        """
        Place This Computer and Timeline widgets in the correct container
        """

        # Scenarios:
        # TL = Timeline (temporal proximity)
        # D = Device Toggle View
        # TC = This Computer Toggle View
        # TL only: TL in panel, D & TC hidden, splitter hidden
        # Sources showing only: D & TC in panel, TL hidden, splitter hidden
        # All showing: D in panel, and:
        #   if TC on, TC and TL in splitter, splitter showing
        #   if TC off, TC and TL in panel, splitter hidden

        layout = self.sourcePanelWidget.layout()  # type: QVBoxLayout
        if not self.needSplitter():
            if self.splitter.isVisible():
                self.settings.setValue("leftPanelSplitterSizes",
                                       self.splitter.saveState())
                self.settings.sync()
            layout.addWidget(self.thisComputerToggleView)
            layout.addWidget(self.temporalProximity)
            layout.addWidget(self.splitter)
            self.splitter.setVisible(False)
        else:
            layout.addWidget(self.splitter)
            self.splitter.addWidget(self.thisComputerToggleView)
            self.splitter.addWidget(self.temporalProximity)
            for index in range(self.splitter.count()):
                self.splitter.setCollapsible(index, False)
            self.handle = self.splitter.handle(1)
            self.handle.mousePress.connect(self.splitterHandleMousePress)
            self.handle.mouseReleased.connect(self.splitterHandleMouseRelease)
            self.splitter.setVisible(True)

            splitterSetting = self.settings.value("leftPanelSplitterSizes")
            if splitterSetting is not None:
                if not self.splitter.restoreState(splitterSetting):
                    logging.debug(
                        "Did not restore left splitter sizing because it is no "
                        "longer valid")

        self.setThisComputerToggleViewSizePolicy()

    def setThisComputerToggleViewSizePolicy(self) -> None:

        if self.thisComputerToggleView.on():
            if self.temporalProximityIsChecked():
                self.thisComputerToggleView.setSizePolicy(
                    QSizePolicy.Preferred, QSizePolicy.Preferred)
            else:
                self.thisComputerToggleView.setSizePolicy(
                    QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
        else:
            if self.temporalProximityIsChecked():
                self.thisComputerToggleView.setSizePolicy(
                    QSizePolicy.Preferred, QSizePolicy.Fixed)
            else:
                self.thisComputerToggleView.setSizePolicy(
                    QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)

    def setSourcesVisible(self, visible: bool) -> None:
        self.deviceToggleView.setVisible(visible)
        self.thisComputerToggleView.setVisible(visible)
        self.splitter.setVisible(self.needSplitter())
        if visible:
            # scroll up to make Devices and This Computer, if necessary
            if self.verticalScrollBar().isVisible():
                auto_scroll = self.prefs.auto_scroll
                if auto_scroll:
                    self.rapidApp.temporalProximityControls.setTimelineThumbnailAutoScroll(
                        on=False)
                self.verticalScrollBar().setValue(
                    self.verticalScrollBar().minimum())
                if auto_scroll:
                    self.rapidApp.temporalProximityControls.setTimelineThumbnailAutoScroll(
                        on=True)

    def setThisComputerBottomFrame(self,
                                   temporalProximityVisible: bool) -> None:
        """
        Connect or disconnect reaction of This Computer widget to the Scroll Area
        horizontal scroll bar becoming visible or not.

        Idea is to not react when the Timeline is visible, and react when it is hidden,
        which is when the This Computer widget is the bottommost widget.
        :param temporalProximityVisible: whether the timeline is visible
        """

        if temporalProximityVisible:
            if self.thisComputerBottomFrameConnection:
                self.horizontalScrollBarVisible.disconnect(
                    self.thisComputerBottomFrameConnection)
                self.thisComputerBottomFrameConnection = None
            if self.thisComputerAltBottomFrameConnection:
                self.horizontalScrollBarVisible.disconnect(
                    self.thisComputerAltBottomFrameConnection)
                self.thisComputerAltBottomFrameConnection = None
            # Always show the bottom edge frame, regardless of what the scroll area
            # scrollbar is doing
            self.thisComputer.containerHorizontalScrollBar(False)
            self.thisComputerToggleView.alternateWidget.containerHorizontalScrollBar(
                False)
        else:
            if self.thisComputerBottomFrameConnection is None:
                self.thisComputerBottomFrameConnection = (
                    self.horizontalScrollBarVisible.connect(
                        self.thisComputer.containerHorizontalScrollBar))
            if self.thisComputerAltBottomFrameConnection is None:
                self.thisComputerAltBottomFrameConnection = self.horizontalScrollBarVisible.connect(
                    self.thisComputerToggleView.alternateWidget.
                    containerHorizontalScrollBar)
            self.thisComputer.containerHorizontalScrollBar(
                self.horizontalScrollBar().isVisible())
            self.thisComputerToggleView.alternateWidget.containerHorizontalScrollBar(
                self.horizontalScrollBar().isVisible())

    def setTemporalProximityVisible(self, visible: bool) -> None:
        self.placeWidgets()
        self.setThisComputerBottomFrame(visible)
        self.temporalProximity.setVisible(visible)
        self.setThisComputerAltWidgetVisible(visible)

    def setThisComputerAltWidgetVisible(
            self, temporalProximityVisible: bool) -> None:
        if not self.thisComputerToggleView.on():
            self.thisComputerToggleView.alternateWidget.setVisible(
                not temporalProximityVisible)

    def setThisComputerState(self) -> None:
        self.placeWidgets()
        self.setThisComputerAltWidgetVisible(self.temporalProximityIsChecked())
        self.setThisComputerToggleViewSizePolicy()

    @pyqtSlot()
    def splitterHandleMousePress(self) -> None:
        y = self.handle.pos().y()
        if self.temporalProximity.state == TemporalProximityState.generated:
            self.temporalProximity.temporalProximityView.setMinimumHeight(20)
        else:
            stackedWidget = self.temporalProximity.stackedWidget
            if self.temporalProximity.state == TemporalProximityState.empty:
                self.temporalProximity.explanation.setChildPositions(
                    fixed=True)
            height = max(self.splitter.height(), self.height())
            self.splitter.setFixedHeight(
                height + stackedWidget.minimumSizeHint().height())
        self.handle.moveSplitter(y)

    @pyqtSlot()
    def splitterHandleMouseRelease(self) -> None:
        y = self.handle.pos().y()
        if self.temporalProximity.state == TemporalProximityState.generated:
            self.temporalProximity.setProximityHeight()
        else:
            self.temporalProximity.explanation.setChildPositions(fixed=False)
            self.temporalProximity.stackedWidget.onCurrentChanged(
                self.temporalProximity.state)
        self.setSplitterSize()
        self.handle.moveSplitter(y)

    def setSplitterSize(self) -> None:
        if self.needSplitter():
            bottom_frame = (0 if self.horizontalScrollBar().isVisible() else
                            self.frame_width)

            if self.temporalProximity.state == TemporalProximityState.generated:
                self.splitter.setFixedHeight(
                    +self.splitter.sizes()[0]  # handle position
                    + self.splitter.handleWidth() + self.frame_width +
                    self.temporalProximity.temporalProximityView.contentHeight(
                    ) + bottom_frame)
            else:
                stackedWidget = self.temporalProximity.stackedWidget
                devices_y = abs(
                    self.deviceToggleView.mapTo(self, QPoint(0, 0)).y())
                devices_height = self.splitter.mapTo(self, QPoint(
                    0, 0)).y() + devices_y
                # handle position + handle width:
                y = self.splitter.sizes()[0] + self.splitter.handleWidth()
                min_height = stackedWidget.minimumSizeHint().height()
                if self.height() - devices_height > y + min_height:
                    height = self.height() - y - devices_height
                else:
                    height = min_height

                self.splitter.setFixedHeight(y + height)
Example #35
0
class Preferences(QObject):
    prefsChanged = pyqtSignal()

    def __init__(self):
        QObject.__init__(self)
        self.reset()
        self._settings = QSettings()

    def _load_values(self, settings, get):
        pass

    def get_rect(self, name, default=None):
        r = self.get_value(name, default)
        if r is not None:
            return QRect(*r)
        else:
            return None

    def get_value(self, name, default=None):
        if self._settings.contains(name):
            result = adjust_after_deserialization(self._settings.value(name))
            if result is not None:
                return result
            else:
                # If result is None, but still present in self._settings, it usually means a value
                # like "@Invalid".
                return default
        else:
            return default

    def load(self):
        self.reset()
        self._load_values(self._settings)

    def reset(self):
        pass

    def _save_values(self, settings, set_):
        pass

    def save(self):
        self._save_values(self._settings)
        self._settings.sync()

    def set_rect(self, name, r):
        if isinstance(r, QRect):
            rectAsList = [r.x(), r.y(), r.width(), r.height()]
            self.set_value(name, rectAsList)

    def set_value(self, name, value):
        self._settings.setValue(name, normalize_for_serialization(value))

    def saveGeometry(self, name, widget):
        # We save geometry under a 5-sized int array: first item is a flag for whether the widget
        # is maximized and the other 4 are (x, y, w, h).
        m = 1 if widget.isMaximized() else 0
        r = widget.geometry()
        rectAsList = [r.x(), r.y(), r.width(), r.height()]
        self.set_value(name, [m] + rectAsList)

    def restoreGeometry(self, name, widget):
        l = self.get_value(name)
        if l and len(l) == 5:
            m, x, y, w, h = l
            if m:
                widget.setWindowState(Qt.WindowMaximized)
            else:
                r = QRect(x, y, w, h)
                widget.setGeometry(r)
Example #36
0
class Preferences:
    def __init__(self):
        self.reset()
        self._settings = QSettings()

    def _load_values(self, settings, get):
        pass

    def get_rect(self, name, default=None):
        r = self.get_value(name, default)
        if r is not None:
            return QRect(*r)
        else:
            return None

    def get_value(self, name, default=None):
        if self._settings.contains(name):
            result = adjust_after_deserialization(self._settings.value(name))
            if result is not None:
                return result
            else:
                # If result is None, but still present in self._settings, it usually means a value
                # like "@Invalid".
                return default
        else:
            return default

    def load(self):
        self.reset()
        self._load_values(self._settings)

    def reset(self):
        pass

    def _save_values(self, settings, set_):
        pass

    def save(self):
        self._save_values(self._settings)
        self._settings.sync()

    def set_rect(self, name, r):
        if isinstance(r, QRect):
            rectAsList = [r.x(), r.y(), r.width(), r.height()]
            self.set_value(name, rectAsList)

    def set_value(self, name, value):
        self._settings.setValue(name, normalize_for_serialization(value))

    def saveGeometry(self, name, widget):
        # We save geometry under a 5-sized int array: first item is a flag for whether the widget
        # is maximized and the other 4 are (x, y, w, h).
        m = 1 if widget.isMaximized() else 0
        r = widget.geometry()
        rectAsList = [r.x(), r.y(), r.width(), r.height()]
        self.set_value(name, [m] + rectAsList)

    def restoreGeometry(self, name, widget):
        l = self.get_value(name)
        if l and len(l) == 5:
            m, x, y, w, h = l
            if m:
                widget.setWindowState(Qt.WindowMaximized)
            else:
                r = QRect(x, y, w, h)
                widget.setGeometry(r)
Example #37
0
class Settings(QDialog, Ui_Settings):
    """Settings dialog"""
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)
        self.core = None
        self.plugins = []
        self.emumode = []
        self.combomap = {}

        self.qset = QSettings("m64py", "m64py")
        self.qset.setDefaultFormat(QSettings.IniFormat)

        self.add_items()
        self.connect_signals()

    def showEvent(self, event):
        self.set_config()

    def closeEvent(self, event):
        self.save_config()

    def add_items(self):
        self.combomap = {
            M64PLUGIN_RSP:
            (self.comboRSP, self.pushButtonRSP, Plugin(self.parent)),
            M64PLUGIN_GFX:
            (self.comboVideo, self.pushButtonVideo, Plugin(self.parent)),
            M64PLUGIN_AUDIO: (self.comboAudio, self.pushButtonAudio,
                              Plugin(self.parent)),
            M64PLUGIN_INPUT: (self.comboInput, self.pushButtonInput,
                              Input(self.parent))
        }

        self.emumode = [
            QRadioButton(self.tr("Pure Interpreter")),
            QRadioButton(self.tr("Cached Interpreter")),
            QRadioButton(self.tr("Dynamic Recompiler"))
        ]

        vbox = QVBoxLayout(self.groupEmuMode)
        for widget in self.emumode:
            vbox.addWidget(widget)

    def show_page(self, index=0):
        self.tabWidget.setCurrentIndex(index)
        self.show()

    def save_config(self):
        self.save_paths()
        self.save_plugins()
        if self.core and self.core.get_handle():
            self.save_video()
            self.save_core()
            self.core.config.save_file()
        self.qset.sync()

    def set_config(self):
        if self.core and self.core.get_handle():
            self.set_paths()
            self.set_plugins()
            self.set_video()
            self.set_core()

    def on_vidext_changed(self, state):
        self.parent.vidext = state
        self.comboResolution.setEnabled(not self.parent.vidext)
        self.checkFullscreen.setEnabled(not self.parent.vidext)
        self.parent.worker.quit()
        self.parent.worker.init()

    def connect_signals(self):
        self.browseLibrary.clicked.connect(lambda: self.browse_dialog(
            (self.pathLibrary, self.groupLibrary, False)))
        self.browsePlugins.clicked.connect(lambda: self.browse_dialog(
            (self.pathPlugins, self.groupPlugins, True)))
        self.browseData.clicked.connect(lambda: self.browse_dialog(
            (self.pathData, self.groupData, True)))
        self.browseROM.clicked.connect(lambda: self.browse_dialog(
            (self.pathROM, self.groupROM, True)))
        self.checkEnableVidExt.clicked.connect(self.on_vidext_changed)
        for plugin_type in self.combomap:
            self.connect_combo_signals(self.combomap[plugin_type])

    def connect_combo_signals(self, combomap):
        combo, button, settings = combomap
        if settings is not None:
            if combo != self.comboInput:
                combo.activated.connect(
                    lambda: self.set_section(combo, button, settings))
            button.clicked.connect(settings.show_dialog)

    def browse_dialog(self, args):
        widget, groupbox, directory = args
        dialog = QFileDialog()
        if directory:
            dialog.setFileMode(QFileDialog.Directory)
            path = dialog.getExistingDirectory(self, groupbox.title(),
                                               widget.text(),
                                               QFileDialog.ShowDirsOnly)
        else:
            dialog.setFileMode(QFileDialog.ExistingFile)
            path, _ = dialog.getOpenFileName(
                self, groupbox.title(), widget.text(),
                "%s (*%s);;All files (*)" % (groupbox.title(), DLL_FILTER))

        if not path:
            return

        widget.setText(path)
        if widget == self.pathLibrary:
            self.parent.worker.quit()
            if not self.parent.worker.core.get_handle():
                self.parent.worker.init(path)
                if self.parent.worker.core.get_handle():
                    self.core = self.parent.worker.core
                    self.set_core()
                    self.set_video()
                    self.parent.window_size_triggered(self.get_size_safe())
                    self.parent.state_changed.emit((True, False, False, False))
        elif widget == self.pathPlugins:
            self.parent.worker.plugins_shutdown()
            self.parent.worker.plugins_unload()
            self.parent.worker.plugins_load(path)
            self.parent.worker.plugins_startup()
            self.set_plugins()

    def get_int_safe(self, key, default):
        try:
            return int(self.qset.value(key, default))
        except ValueError:
            return default

    def get_size_safe(self):
        try:
            size = self.qset.value("size", SIZE_1X)
        except TypeError:
            size = SIZE_1X
        if not type(size) == tuple:
            size = SIZE_1X
        if len(size) != 2:
            size = SIZE_1X
        if type(size[0]) != int or type(size[1]) != int:
            size = SIZE_1X
        if size[0] <= 0 or size[1] <= 0:
            size = SIZE_1X
        return size

    def get_section(self, combo):
        plugin = combo.currentText()
        index = combo.findText(plugin)
        desc = combo.itemData(index)
        name = os.path.splitext(plugin)[0][12:]
        section = "-".join([n.capitalize() for n in name.split("-")[0:2]])
        return section, desc

    def set_section(self, combo, button, settings):
        if settings:
            if combo != self.comboInput:
                section, desc = self.get_section(combo)
                settings.set_section(section, desc)
                self.core.config.open_section(section)
                items = self.core.config.parameters[
                    self.core.config.section].items()
                if items:
                    button.setEnabled(True)
                else:
                    button.setEnabled(False)
            else:
                button.setEnabled(True)
        else:
            button.setEnabled(False)

    def set_paths(self):
        path_library = self.qset.value("Paths/Library",
                                       find_library(CORE_NAME))
        path_data = self.qset.value("Paths/Data",
                                    self.core.config.get_path("SharedData"))
        path_roms = self.qset.value("Paths/ROM")

        try:
            path_plugins = self.qset.value(
                "Paths/Plugins",
                os.path.realpath(
                    os.path.dirname(self.parent.worker.plugin_files[0])))
        except IndexError:
            path_plugins = ""

        try:
            self.pathROM.setText(path_roms)
        except TypeError:
            pass

        self.pathLibrary.setText(path_library)
        self.pathPlugins.setText(path_plugins)
        self.pathData.setText(path_data)

    def set_video(self):
        self.core.config.open_section("Video-General")

        self.set_resolution()

        self.checkEnableVidExt.setChecked(
            bool(self.get_int_safe("enable_vidext", 1)))

        self.checkFullscreen.setChecked(
            bool(self.core.config.get_parameter("Fullscreen")))
        self.checkFullscreen.setEnabled(not self.parent.vidext)

        self.checkVsync.setChecked(
            bool(self.core.config.get_parameter("VerticalSync")))
        self.checkVsync.setToolTip(
            self.core.config.get_parameter_help("VerticalSync").decode())

        if sys.platform == "win32":
            self.checkKeepAspect.setChecked(False)
            self.checkKeepAspect.setEnabled(False)
        else:
            keep_aspect = bool(self.get_int_safe("keep_aspect", 1))
            self.checkKeepAspect.setChecked(keep_aspect)

        disable_screensaver = bool(self.get_int_safe("disable_screensaver", 1))
        self.checkDisableScreenSaver.setChecked(disable_screensaver)

    def set_core(self):
        self.core.config.open_section("Core")
        mode = self.core.config.get_parameter("R4300Emulator")
        self.emumode[mode].setChecked(True)
        self.checkOSD.setChecked(
            self.core.config.get_parameter("OnScreenDisplay"))
        self.checkOSD.setToolTip(
            self.core.config.get_parameter_help("OnScreenDisplay").decode())
        self.checkNoCompiledJump.setChecked(
            self.core.config.get_parameter("NoCompiledJump"))
        self.checkNoCompiledJump.setToolTip(
            self.core.config.get_parameter_help("NoCompiledJump").decode())
        self.checkDisableExtraMem.setChecked(
            self.core.config.get_parameter("DisableExtraMem"))
        self.checkDisableExtraMem.setToolTip(
            self.core.config.get_parameter_help("DisableExtraMem").decode())

        delay_si = self.core.config.get_parameter("DelaySI")
        if delay_si is not None:
            self.checkDelaySI.setChecked(delay_si)
        else:
            self.checkDelaySI.setChecked(False)
            self.checkDelaySI.setEnabled(False)
        self.checkDelaySI.setToolTip(
            self.core.config.get_parameter_help("DelaySI").decode())

        count_per_op = self.core.config.get_parameter("CountPerOp")
        if count_per_op is not None:
            self.comboCountPerOp.setCurrentIndex(count_per_op)
        else:
            self.comboCountPerOp.setEnabled(False)
        self.comboCountPerOp.setToolTip(
            self.core.config.get_parameter_help("CountPerOp").decode())

    def set_plugins(self):
        plugin_map = self.core.plugin_map
        for plugin_type in self.combomap:
            combo, button, settings = self.combomap[plugin_type]
            combo.clear()
            for plugin in plugin_map[plugin_type].values():
                (plugin_handle, plugin_path, plugin_name, plugin_desc,
                 plugin_version) = plugin
                name = os.path.basename(plugin_path)
                combo.addItem(name)
                index = combo.findText(str(name))
                combo.setItemData(index, plugin_desc)
                combo.setItemData(index, plugin_desc, Qt.ToolTipRole)
            current = self.qset.value(
                "Plugins/%s" % (PLUGIN_NAME[plugin_type]),
                PLUGIN_DEFAULT[plugin_type])
            index = combo.findText(current)
            if index == -1:
                index = 0
            combo.setCurrentIndex(index)
            self.set_section(combo, button, settings)

    def set_resolution(self):
        width = self.core.config.get_parameter("ScreenWidth")
        height = self.core.config.get_parameter("ScreenHeight")
        if (width, height) not in MODES:
            MODES.append((width, height))

        self.comboResolution.clear()
        for mode in MODES:
            w, h = mode
            self.comboResolution.addItem("%sx%s" % (w, h), (w, h))

        index = self.comboResolution.findText("%sx%s" % (width, height),
                                              Qt.MatchExactly)
        if index == -1: index = 0
        self.comboResolution.setCurrentIndex(index)
        self.comboResolution.setEnabled(not self.parent.vidext)

    def save_paths(self):
        self.qset.setValue("Paths/Library", self.pathLibrary.text())
        self.qset.setValue("Paths/Plugins", self.pathPlugins.text())
        self.qset.setValue("Paths/Data", self.pathData.text())
        self.qset.setValue("Paths/ROM", self.pathROM.text())

    def save_video(self):
        self.core.config.open_section("Video-General")
        if self.parent.vidext:
            width, height = self.get_size_safe()
        else:
            width, height = self.comboResolution.currentText().split("x")
        self.core.config.set_parameter("ScreenWidth", int(width))
        self.core.config.set_parameter("ScreenHeight", int(height))
        self.core.config.set_parameter("Fullscreen",
                                       self.checkFullscreen.isChecked())
        self.core.config.set_parameter("VerticalSync",
                                       self.checkVsync.isChecked())
        self.qset.setValue("keep_aspect",
                           int(self.checkKeepAspect.isChecked()))
        self.qset.setValue("disable_screensaver",
                           int(self.checkDisableScreenSaver.isChecked()))
        self.qset.setValue("enable_vidext",
                           int(self.checkEnableVidExt.isChecked()))

    def save_core(self):
        self.core.config.open_section("Core")
        emumode = [n for n, m in enumerate(self.emumode) if m.isChecked()][0]
        self.core.config.set_parameter("R4300Emulator", emumode)
        self.core.config.set_parameter("OnScreenDisplay",
                                       self.checkOSD.isChecked())
        self.core.config.set_parameter("NoCompiledJump",
                                       self.checkNoCompiledJump.isChecked())
        self.core.config.set_parameter("DisableExtraMem",
                                       self.checkDisableExtraMem.isChecked())
        self.core.config.set_parameter("DelaySI",
                                       self.checkDelaySI.isChecked())
        self.core.config.set_parameter("CountPerOp",
                                       self.comboCountPerOp.currentIndex())
        self.core.config.set_parameter("SharedDataPath",
                                       self.pathData.text().encode())

    def save_plugins(self):
        for plugin_type in self.combomap:
            combo, button, settings = self.combomap[plugin_type]
            self.qset.setValue("Plugins/%s" % PLUGIN_NAME[plugin_type],
                               combo.currentText())
Example #38
0
class SettingsDlg(QDialog):
    """Dialog for manipulating settings for display and PPE settings"""
    INTERVAL =  0x0001
    AUTOTRY =   0x0002
    HANDLE =    0x0004
    EMAIL =     0x0008
    CONTINUE =  0x0010
    ACCOUNTS =  0x0020
    STATE =     0x0040
    SIZE =      0x0080
    POS =       0x0100
    SPLITTERS = 0x0200
    EMPTY =     0x0400
    DIGITS =    0x0800

    # lambda for whether a setting is actually a string and true (happens automatically with QSettings)
    str_bool = lambda val: bool(val) and (not isinstance(val, str) or (isinstance(val, str) and val != 'false'))
    
    def __init__(self, parent=None):
        super(SettingsDlg, self).__init__(parent)
        self.setWindowTitle("Settings")
        overall_layout = QVBoxLayout()
        self.setLayout(overall_layout)

        # get relevant data to populate settings panel
        data = shelve.open('/etc/ppe/data')
        interval = autotry = 900
        try:
            interval = data['interval']
            autotry = data['autotry']
        except KeyError:
            pass
        data.close()

        self.settings = QSettings("Scott Stewart", "qPPE")
        self.settings.beginGroup("Settings Dialog")

        # make tabwidget divided between general and view settings
        tab_widget = QTabWidget()
        overall_layout.addWidget(tab_widget)
        general_widget = QWidget()
        view_widget = QWidget()
        general_layout = QGridLayout()
        general_widget.setLayout(general_layout)
        view_layout = QGridLayout()
        view_widget.setLayout(view_layout)
        tab_widget.addTab(general_widget, "&General")
        tab_widget.addTab(view_widget, "&View")

        # check interval is combo/spinbox for type (sec, min) and number of sec/mins, keeping the two consistent and updated w/ a variable for secs
        interval_label = QLabel("&Check interval:")
        self.interval = TimeSpinBox(self, interval)
        interval_label.setBuddy(self.interval)
        general_layout.addWidget(interval_label, 0, 0)
        general_layout.addWidget(self.interval, 0, 1)
    
        # do autotry the same as check interval
        autotry_label = QLabel("&Autotry interval:")
        self.autotry = TimeSpinBox(self, autotry)
        autotry_label.setBuddy(self.autotry)
        general_layout.addWidget(autotry_label, 1, 0)
        general_layout.addWidget(self.autotry, 1, 1)

        # checkbox on whether to check email, uses setting if available,controls visibility of subsequent settings
        self.handle_ppe = self.constructCheckBox("Automatically &handle scheduling checks?", "handle_ppe", True)
        general_layout.addWidget(self.handle_ppe, 2, 0, 1, 2)

        # checkbox on whether to send emails if PPE is being handled by the app or should be closed on exit, usability dependent on handle_ppe
        self.send_emails = self.constructCheckBox("&Send email notifiations?", "send_emails", False)
        self.continue_running = self.constructCheckBox("Continue &running PPE after close?", "continue_running", True)
        
        # frame holding options dependent on handling
        handle_widgets = QFrame()
        handle_layout = QVBoxLayout()
        handle_widgets.setLayout(handle_layout)
        handle_widgets.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        handle_widgets.setEnabled(self.handle_ppe.checkState())
        handle_layout.addWidget(self.send_emails)
        handle_layout.addWidget(self.continue_running)
        self.handle_ppe.stateChanged.connect(lambda state: handle_widgets.setEnabled(state))
        general_layout.addWidget(handle_widgets, 3, 0, 2, 2)

        # checkbox on whether to keep account selection visible on main window
        self.view_accounts = self.constructCheckBox("&Show account choices?", "view_accounts", True)
        view_layout.addWidget(self.view_accounts, 0, 0, 1, 2)
        
        # checkbox on whether to show empty grades
        self.show_empty = self.constructCheckBox("Show &empty grades?", "show_empty", False)
        view_layout.addWidget(self.show_empty, 1, 0, 1, 2)

        # checkbox on whether to save application state
        self.save_state = self.constructCheckBox("Save &application state?", "save_state", True)
        view_layout.addWidget(self.save_state, 2, 0, 1, 2)

        # custom spinbox on the number of digits to display for percentages
        digit_label = QLabel("P&recision of percentagess:")
        self.digits = PercentSpinBox(self, int(self.settings.value('digits', 1)))
        digit_label.setBuddy(self.digits)
        view_layout.addWidget(digit_label, 3, 0)
        view_layout.addWidget(self.digits, 3, 1)

        # checkboxes on whther to save size, powition, splitters, etc, contingent on save_state
        self.save_size = self.constructCheckBox("Save &window size?", "save_size", True)
        self.save_pos = self.constructCheckBox("Save window &position?", "save_pos", True)
        self.save_splitters = self.constructCheckBox("Save window &geometry?", "save_splitters", False)

        # frame holding options dependent on handling
        state_widgets = QFrame()
        state_layout = QVBoxLayout()
        state_widgets.setLayout(state_layout)
        state_widgets.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        state_widgets.setEnabled(self.save_state.checkState())
        state_layout.addWidget(self.save_size)
        state_layout.addWidget(self.save_pos)
        state_layout.addWidget(self.save_splitters)
        self.save_state.stateChanged.connect(lambda state: state_widgets.setEnabled(state))
        view_layout.addWidget(state_widgets, 4, 0, 3, 2)

        view_layout.setRowStretch(5, 1)
        # ok/cancel buttons on custom accept
        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        overall_layout.addWidget(buttons)
    
    def constructCheckBox(self, text, setting_text, default):
        box = QCheckBox(text)
        setting = self.settings.value(setting_text)
        if setting is not None:
            box.setCheckState(SettingsDlg.str_bool(setting))
        else:
            box.setCheckState(default)
            self.settings.setValue(setting_text, default)
        box.setTristate(False)
        return box

    def accept(self):
        '''Updates a bitmask for changes since the beginning of the dialog and closes the dialog'''
        self.changes = 0

        data = shelve.open('/etc/ppe/data')
        if not 'interval' in data or self.interval.value() != data['interval']:
            data['interval'] = self.interval.value()
            self.changes |= self.INTERVAL
        if not 'autotry' in data or self.autotry.value() != data['autotry']:
            data['autotry'] = self.autotry.value()
            self.changes |= self.AUTOTRY
        data.close()
        
        if self.handle_ppe.isChecked() != SettingsDlg.str_bool(self.settings.value('handle_ppe')):
            self.settings.setValue('handle_ppe', self.handle_ppe.isChecked())
            self.changes |= self.HANDLE
        if self.send_emails.isChecked() != SettingsDlg.str_bool(self.settings.value('send_emails')):
            self.settings.setValue('send_emails', self.send_emails.isChecked())
            self.changes |= self.EMAIL
        if self.continue_running.isChecked() != SettingsDlg.str_bool(self.settings.value('continue_running')):
            self.settings.setValue('continue_running', self.continue_running.isChecked())
            self.changes |= self.CONTINUE
        if self.view_accounts.isChecked() != SettingsDlg.str_bool(self.settings.value('view_accounts')):
            self.settings.setValue('view_accounts', self.view_accounts.isChecked())
            self.changes |= self.ACCOUNTS
        if self.save_state.isChecked() != SettingsDlg.str_bool(self.settings.value('save_state')):
            self.settings.setValue('save_state', self.save_state.isChecked())
            self.changes |= self.STATE
        if self.save_size.isChecked() != SettingsDlg.str_bool(self.settings.value('save_size')):
            self.settings.setValue('save_size', self.save_size.isChecked())
            self.changes |= self.SIZE
        if self.save_pos.isChecked() != SettingsDlg.str_bool(self.settings.value('save_pos')):
            self.settings.setValue('save_pos', self.save_pos.isChecked())
            self.changes |= self.POS
        if self.save_splitters.isChecked() != SettingsDlg.str_bool(self.settings.value('save_splitters')):
            self.settings.setValue('save_splitters', self.save_splitters.isChecked())
            self.changes |= self.SPLITTERS
        if self.show_empty.isChecked() != SettingsDlg.str_bool(self.settings.value('show_empty')):
            self.settings.setValue('show_empty', self.show_empty.isChecked())
            self.changes |= self.EMPTY
        if self.digits.value() != self.settings.value('digits'):
            self.settings.setValue('digits', self.digits.value())
            self.changes |= self.DIGITS
        self.settings.sync()
        self.settings.endGroup()

        QDialog.accept(self)
Example #39
0
    def initSettings(self):
        """Load settings file if exists, create new otherwise
        """

        folder_name = os.path.dirname(os.path.abspath(__file__))
        settings_path = os.path.join(folder_name, 'settings.ini')

        if not os.path.exists(settings_path):
            settings = QSettings(settings_path, QSettings.IniFormat)

            # fonts for various fields
            settings.setValue(
                'display/fonts/meta_title',
                QFont('Serif', 14, QFont.Bold | QFont.Capitalize))
            settings.setValue('display/fonts/meta_authors', QFont('Serif', 11))
            settings.setValue('display/fonts/meta_keywords',
                              QFont('Times', 11, QFont.StyleItalic))
            settings.setValue('display/fonts/statusbar', QFont('Serif', 10)),
            settings.setValue('display/fonts/doc_table', QFont('Serif', 10)),
            settings.setValue('display/fonts/bibtex', QFont('Serif', 10)),
            settings.setValue('display/fonts/notes', QFont('Serif', 10)),
            settings.setValue('display/fonts/scratch_pad', QFont('Serif', 10)),

            # highlight folder containing a doc
            settings.setValue('display/folder/highlight_color_br',
                              QBrush(QColor(200, 200, 255)))

            settings.setValue('export/bib/omit_fields', OMIT_KEYS)
            settings.setValue('export/bib/path_type', 'absolute')
            settings.setValue('export/ris/path_type', 'absolute')

            # storage recently opened database
            settings.setValue('file/recent_open', [])
            settings.setValue('file/recent_open_num', 2)
            settings.setValue('file/auto_open_last', 1)

            # default storage folder
            storage_folder = os.path.join(str(pathlib.Path.home()),
                                          'Documents/MeiTingTrunk')
            settings.setValue('saving/storage_folder', storage_folder)

            # file copy/link
            settings.setValue('saving/file_move_manner', 'link')
            # 'copy' or 'link'

            # auto save
            settings.setValue('saving/auto_save_min', 5),

            # rename pdf files in storage
            settings.setValue('saving/rename_files', 1)
            settings.setValue('saving/rename_file_replace_space', 1)

            # min score to flag a duplication
            settings.setValue('duplicate_min_score', 60)

            settings.setValue('import/default_add_action', 'Add PDF File')

            # search fields
            settings.setValue('search/search_fields', [
                'Authors', 'Title', 'Abstract', 'Keywords', 'Tags', 'Notes',
                'Publication'
            ])
            settings.setValue('search/desend_folder', True)

            # view control
            settings.setValue('view/show_widgets', [
                'Toggle Filter List', 'Toggle Tab Pane', 'Toggle Meta Tab',
                'Toggle Notes Tab', 'Toggle BibTex Tab',
                'Toggle Scratch Pad Tab', 'Toggle Status bar'
            ])

            settings.sync()
        else:
            settings = QSettings(settings_path, QSettings.IniFormat)

        #---------------Make sure output folder exists---------------
        storage_folder = settings.value('saving/storage_folder')
        self.logger.info('storage_folder=%s' % storage_folder)

        storage_folder = os.path.expanduser(storage_folder)
        if not os.path.exists(storage_folder):
            os.makedirs(storage_folder)

            self.logger.info('Create folder %s' % storage_folder)

        return settings
Example #40
0
# This test is playing with configuration settings and checking that works.

from PyQt5.QtCore import QSettings
from PyQt5.QtCore import QCoreApplication

import sys

app = QCoreApplication([])
app.setOrganizationName("BOGUS_NAME")
app.setOrganizationDomain("bogosity.com")
app.setApplicationName("BOGUS")
settings = QSettings()
byte_string = b'\xde\xad\xbe\xef'
settings.clear()
settings.setValue("bogus_byte_string",byte_string)
settings.sync()
return_string = settings.value("bogus_byte_string",b'\x00\x00\x00\x00')
if sys.version_info >= (3,):
    assert return_string == byte_string, (repr(return_string), "!=", byte_string)
print("OK.")

# This test is using signals and will only work if PySide properly accepts
# compiled functions as callables.

from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QMetaObject

class Communicate(QObject):
    speak = pyqtSignal(int)
    def __init__(self,name = "",parent = None):
        QObject.__init__(self,parent)
        self.setObjectName(name)
Example #41
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.mode = ['lineart', 'gray', 'color']
        self.resolution = ['75', '100', '150', '200', '300', '600', '1200']
        self.compression = ['None', 'JPEG']
        self.scanFolder = os.getcwd()
        self.ver = sane.init()

        self.ui = uic.loadUi("mainwindow.ui", self)
        #self.ui = Ui_MainWindow()
        #self.ui.setupUi(self)

        self.dialog = QDialog()
        self.message = QMessageBox()

        self.threadpool = QThreadPool()

        self.settings = QSettings("bibuweb.de", "Scan2Folder")

        self.progressBar = None

        self.configWin = ConfigWindow(self)
        self.configWin.ui.scanButton.clicked.connect(self.configScan)

        self.ui.resolutions.addItems(self.resolution)
        self.ui.resolutions.setCurrentIndex(
            self.ui.resolutions.findText('300'))

        self.ui.btnOpenDir.clicked.connect(self.openDir)
        self.ui.btnStartscan.clicked.connect(self.startScanJob)
        self.ui.btnOcr.clicked.connect(self.ocr_startProcess)

        self.ui.actionCalibrate.triggered.connect(self.configureWindow)
        self.configWin.ui.saveButton.clicked.connect(self.saveConfig)

        # Change Color back after error
        self.ui.filename.cursorPositionChanged.connect(self.leditcolor)

        self.ui.scanpath.cursorPositionChanged.connect(self.leditcolor)
        self.ui.scanpath.textChanged.connect(self.scanPathCanged)

        self.is_dev = True
        self.dev_available = False
        self.dev_connected = False
        self.adf = False
        self.dev = None
        self.devices = []
        self.scanStatus = False
        self.btnStyle = ""

        self.contrast = 1
        self.brightness = 1
        self.color = 1
        self.sharpness = 1
        self.scanPath = ""
        self.ocr = False
        self.crop = False
        self.cropSize = {'left': 1, 'top': 1, 'width': 1, 'height': 1}
        self.ocrFiles = []
        self.tempocr = None

        if self.settings.contains("ocr"):
            print("Load: ", self.settings.value('ocr'))
            if self.settings.value('ocr') == 'true':
                self.ocr = True
                self.ui.actionEnable_OCR.setChecked(True)
                self.configWin.ui.OCR_Enabled.setChecked(True)
                self.configWin.ui.OCR_Box.setEnabled(True)

            else:
                self.ui.actionEnable_OCR.setChecked(False)
                self.configWin.ui.OCR_Enabled.setChecked(False)
                self.configWin.ui.OCR_Box.setEnabled(False)
            ## connect Signal here and not before loading settings
            ## if not, you never will get the stored value because QAction is triggered when ever the value changed
            self.configWin.ui.OCR_Enabled.stateChanged.connect(self.ocrConfig)

        if self.settings.contains('crop'):
            if self.settings.value('crop') == 'true':
                self.crop = True
            self.configWin.ui.checkCrop.setChecked(self.crop)

        if self.settings.contains('cropSize'):
            #print(self.settings.value('cropSize'))
            self.cropSize = self.settings.value('cropSize')
            self.configWin.ui.cropX.setValue(self.cropSize['left'])
            self.configWin.ui.cropY.setValue(self.cropSize['top'])
            self.configWin.ui.cropW.setValue(self.cropSize['width'])
            self.configWin.ui.cropH.setValue(self.cropSize['height'])

        if self.settings.contains("path"):
            self.ui.scanpath.setText(self.settings.value("path"))
            self.scanPath = self.settings.value("path")
            self.createCompleter()

        if self.settings.contains('contrast'):
            self.brightness = self.settings.value('brightness')

            self.contrast = self.settings.value('contrast')
            self.configWin.ui.brigthnessLcd.setValue(float(self.brightness))
            self.configWin.ui.brigthnesSlider.setValue(
                int(float(self.brightness) * 10))
            self.configWin.ui.contrastLcd.setValue(float(self.contrast))
            self.configWin.ui.contrastSlider.setValue(
                int(float(self.contrast) * 10))

        if self.settings.contains('color'):
            self.color = self.settings.value('color')
            self.configWin.ui.colorLcd.setValue(float(self.color))
            self.configWin.ui.colorSlider.setValue(int(float(self.color) * 10))

        if self.settings.contains("sharpness"):
            self.sharpness = self.settings.value('sharpness')
            self.configWin.ui.sharpnessLcd.setValue(float(self.sharpness))
            self.configWin.ui.sharpnessSlider.setValue(
                int(float(self.sharpness) * 10))

    def closeEvent(self, event):
        #if not set, process keeps running in background
        self.scanStatus = False

    def openDir(self):
        fileDlg = QFileDialog()
        self.scanFolder = fileDlg.getExistingDirectory(
            self, 'Scan Folder', self.scanFolder,
            QFileDialog.DontUseNativeDialog)
        self.ui.scanpath.setText(self.scanFolder)
        self.settings.setValue("path", self.scanFolder)
        self.settings.sync()

    def startThread(self, fn, resultFn=None, complete=None):
        worker = Worker(
            fn)  # Any other args, kwargs are passed to the run function
        if resultFn is not None:
            worker.signals.result.connect(resultFn)
        if complete is not None:
            worker.signals.finished.connect(complete)
        #worker.signals.progress.connect(self.scannerProgress)
        self.threadpool.start(worker)

    def thread_complete(self):
        self.scannerProgress(100)
        time.sleep(1)
        self.dialog.close()

        if self.dev_available:
            self.show()
        else:
            #TODO: put error dlg here
            self.message.setText(
                "No scanner found\n Check your Configuration!")
            self.message.exec()
            print("Error: No Devices found")

        print("THREAD COMPLETE! ", self.threadpool.activeThreadCount())

    @pyqtSlot(str)
    def scanPathCanged(self, path):
        self.scanPath = path
        self.createCompleter()

    def createCompleter(self):
        ff = glob.glob(self.scanPath + "/*.pdf")
        files = []
        for f in ff:
            files.append(os.path.basename(f).split('.')[0])
        completer = QCompleter(files)
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.ui.filename.setCompleter(completer)

    def scannerLookup(self):

        #self.dialog.setModal(True)

        self.uidlg = Ui_Dialog()
        self.uidlg.setupUi(self.dialog)

        self.dialog.show()

    def checkScanMode(self):
        mode = ""
        if self.ui.btnBuW.isChecked():
            mode = self.ui.btnBuW.text()
        elif self.ui.btnGray.isChecked():
            mode = self.ui.btnGray.text()
        elif self.ui.btnColor.isChecked():
            mode = self.ui.btnColor.text()
        print(mode)
        return mode

    def scannerAddToDlg(self, result):
        self.devices = result
        if len(self.devices) > 0:
            self.dev_available = True
            for i, dev in enumerate(result):
                self.ui.comboBox.addItem(dev[i])
        else:
            return

    def scannerProgress(self, val):
        self.uidlg.progressBar.setValue(val)

    def scanners(self):
        self.scannerLookup()
        self.startThread(sane.get_devices, self.scannerAddToDlg,
                         self.thread_complete)

    def scannerCheck(self):
        self.statusBar().showMessage("looking up for scanner ....")
        print(self.devices[0])
        count = 0
        while self.is_dev:

            try:
                #ToDo: check index from

                self.dev = sane.open(self.devices[0][0])

            except:
                print("no scanner connected, waiting...", self.dev)
            if self.dev is not None:
                self.is_dev = False
                self.dev_connected = True
                print("scanner connected")
            time.sleep(3)
            ## Stop process after 3 times to avoid endless loop if no device is available
            ## due started as thread
            count += 1
            if count > 2:
                self.is_dev = False
                self.statusBar().showMessage("No Scanner connected!")

    def commonThreadEnd(self):
        print("Thread ended")

    def scanDocThreadEnded(self):
        self.statusBar().showMessage("Job stopped")
        self.scanStatus = False
        self.setLedStatus()

    def scannerCheckThreadEnd(self):
        print("Lookup Thread ended")

        if self.dev_connected:
            self.startThread(self.scanDocuments, None, self.scanDocThreadEnded)

    def setScannerStatus(self):
        if self.dev_connected:
            self.setLedStatus()
            self.statusBar().showMessage("Scanner connected", 10)
            self.setScanButton("running")
        else:
            self.setScanButton('stopped')

    def setLedStatus(self):
        if self.scanStatus:
            pix = QPixmap(":/images/square_green.svg")
        else:
            pix = QPixmap(":/images/square_red.svg")

        self.ui.statusLed.setPixmap(pix)

    def scanDocuments(self):
        ip = self.devices[0][0].split('=')[1]
        print(ip)
        url = 'http://' + ip + XML_PATH
        self.dev.mode = self.checkScanMode()
        self.dev.resolution = int(self.ui.resolutions.currentText())
        imgNr = 0
        savePath = self.ui.scanpath.text() + "/"
        imgPrefix = self.ui.filename.text() + "_"
        #self.dev.contrast = 900
        #self.dev.brightness = self.brightness
        while self.scanStatus:
            btnreq = urlopen(url)
            soup = bs4.BeautifulSoup(str(btnreq.read()), 'lxml')
            if soup.startscan.string == str(1):
                #print("Pressed")
                if soup.adfloaded.string == str(1):
                    self.adf = True
                    print("ADF Source")
                    self.dev.source = 'ADF'
                    imIter = self.dev.multi_scan()

                    while self.adf:
                        try:
                            im = imIter.next()
                            imgNr = imgNr + 1
                            img = imgPrefix + str(imgNr) + ".png"
                            im.save(savePath + img)
                            if self.ocr:
                                self.ocrFiles.append(savePath + img)
                        except:
                            self.adf = False
                            break
                else:
                    self.adf = False
                    imgNr = imgNr + 1
                    img = imgPrefix + str(imgNr) + ".png"
                    self.dev.start()
                    im = self.dev.snap()
                    self.enhanceImage(im, savePath, img)
                    if self.ocr:
                        self.ocrFiles.append(savePath + img)
            time.sleep(3)

    def enhanceImage(self, image, path, pf):
        brightness = ImageEnhance.Brightness(image)
        image = brightness.enhance(float(self.brightness))
        contrast = ImageEnhance.Contrast(image)
        image = contrast.enhance(float(self.contrast))
        colour = ImageEnhance.Color(image)
        image = colour.enhance(float(self.color))
        sharpness = ImageEnhance.Sharpness(image)
        image = sharpness.enhance(float(self.sharpness))
        print("image saved ", self.ui.scanpath.text() + "/" + pf)
        image.save(path + pf)

    @pyqtSlot()
    def leditcolor(self):
        self.ui.scanpath.setStyleSheet("background-color:rgb(255, 255, 255)")
        self.ui.filename.setStyleSheet("background-color:rgb(255, 255, 255)")

    def startScanJob(self):

        # print("Path: ",self.scanpath.text())
        # print("Mode: ",mode)
        # print("Resolution: ", self.resolutions.currentText())
        # print("File: ", self.filename.text())

        if len(self.ui.scanpath.text()) == 0:
            msg = QMessageBox()
            msg.setText("Please enter file path!")
            msg.exec()
            self.ui.scanpath.setStyleSheet(
                "background-color:rgb(255, 170, 127)")
            return

        if len(self.ui.filename.text()) == 0:
            msg = QMessageBox()
            msg.setText("Please enter file name prefix!")
            msg.exec()
            self.ui.filename.setStyleSheet(
                "background-color:rgb(255, 170, 127)")
            return

        if not self.scanStatus:
            self.setScanButton("starting")
            self.startThread(self.scannerCheck, self.setScannerStatus,
                             self.scannerCheckThreadEnd)
            self.scanStatus = True
            self.ui.scanpath.setEnabled(False)
            self.ui.filename.setEnabled(False)
        else:
            self.scanStatus = False
            self.setScanButton("stopped")
            self.ui.scanpath.setEnabled(True)
            self.ui.filename.setEnabled(True)
            self.ui.filename.clear()

            if self.ocr and len(self.ocrFiles) > 0:
                self.ui.btnOcr.setEnabled(True)
                self.tempocr = tempfile.NamedTemporaryFile(delete=False)
                for f in self.ocrFiles:
                    self.tempocr.write(str(f + "\n").encode())
                self.tempocr.close()

    def setScanButton(self, status):

        if status == "starting":
            self.btnStyle = self.ui.btnStartscan.styleSheet()

            self.ui.btnStartscan.setStyleSheet("background-color: yellow")
            self.ui.btnStartscan.setText("Starting...")

        if status == "running":
            self.ui.btnStartscan.setStyleSheet("background-color: red")
            self.ui.btnStartscan.setText("Stop")
            self.statusBar().showMessage("Scan job is running..")

        if status == "stopped":
            self.ui.btnStartscan.setText("Sart Scan")
            self.ui.btnStartscan.setStyleSheet(self.btnStyle)

    def configureWindow(self):

        if self.dev is not None:
            self.configWin.ui.scanButton.setEnabled(True)
            self.configWin.ui.scanButton.setText("Start Scan")
        else:
            self.configWin.ui.scanButton.setEnabled(False)
            self.configWin.ui.scanButton.setText("Sart Scan Service first")

        self.configWin.show()

    def ocr_startProcess(self):
        self.progressDlg = QProgressDialog(self)
        self.progressDlg.setWindowTitle("OCR Process")
        self.progressDlg.setLabelText("OCR Process in Progress ...")
        self.progressDlg.setAutoClose(False)
        self.progressDlg.setAutoReset(False)
        self.progressDlg.setModal(True)
        self.startThread(self.ocr_process, None, self.ocr_stopped)

    def ocr_process(self):

        if len(self.ocrFiles) > 0:

            val = 0
            ### add one more for pdf create process
            max = len(self.ocrFiles) + 1
            self.progressDlg.setRange(0, max)

            for f in self.ocrFiles:
                val += 1

                self.progressDlg.setValue(val)

                #TODO: if is checked
                ocrt.deskew(f)
                #TODO: if is checked
                #NOTE: this is crop and resize in one step
                #      size and dpi are predifined to A4 300
                print(self.cropSize)
                if self.cropSize['width'] > 1:
                    ocrt.crop_resize(f, self.cropSize["left"],
                                     self.cropSize["top"],
                                     self.cropSize["width"],
                                     self.cropSize["height"])
                #TODO: if is checked
                ocrt.check_orientation(f)

            print(self.tempocr.name)
            ## works in python 3.9+
            #pdfname = self.ocrFiles[0].removesuffix("_1.png")
            pdfname, suff = self.ocrFiles[0].rsplit("_1.png")
            print(pdfname)
            ### this runs in its own process
            self.progressDlg.setLabelText("OCR Process finishing ...")
            ocrt.create_pdf(self.tempocr.name, pdfname)
            ####
            ## Workaround to get a correct finished process
            ## while pytesseract uses subprocces which can not be handled in this thread
            ####
            while not os.path.isfile(pdfname + ".pdf"):
                time.sleep(3)
            self.progressDlg.setValue(val + 1)
            os.unlink(self.tempocr.name)
            self.ocrFiles.clear()
        else:
            return

    def ocr_stopped(self):
        print("OCR finished")
        self.progressDlg.close()

    def configScan(self):
        self.dev.resolution = int(self.ui.resolutions.currentText())
        self.dev.mode = self.checkScanMode()
        self.dev.start()
        im = self.dev.snap()
        pix = ImageQt.ImageQt(im.convert('RGBA'))
        #self.configWin.im = im
        #self.configWin.ui.view.setPixmap(self.configWin.pixmap.fromImage(pix))
        self.configWin.pixmapItem.setPixmap(QPixmap.fromImage(pix))
        self.configWin.ui.view.fitInView(self.configWin.pixmapItem,
                                         Qt.KeepAspectRatio)
        self.configWin.pixmapItem.grabMouse()
        self.configWin.setBufferImage()
        self.configWin.enhanceImage()
        #im = None

    @pyqtSlot()
    def saveConfig(self):
        self.brightness = self.configWin.ui.brigthnessLcd.value()
        self.contrast = self.configWin.ui.contrastLcd.value()
        self.color = self.configWin.ui.colorLcd.value()
        self.sharpness = self.configWin.ui.sharpnessLcd.value()
        self.crop = self.configWin.ui.checkCrop.isChecked()

        self.settings.setValue('brightness', self.brightness)
        self.settings.setValue('contrast', self.contrast)
        self.settings.setValue('color', self.color)
        self.settings.setValue('sharpness', self.sharpness)
        self.settings.setValue('ocr', self.ocr)
        self.settings.setValue('crop', self.crop)
        self.settings.setValue('cropSize', self.cropSize)
        self.settings.sync()
        self.configWin.close()

    @pyqtSlot(int)
    def ocrConfig(self, state):
        if state == Qt.Checked:
            self.ocr = True
            self.configWin.ui.OCR_Box.setEnabled(True)
        else:
            self.ocr = False
            self.configWin.ui.OCR_Box.setEnabled(False)

    def closeEvent(self, e):
        if self.tempocr is not None:
            if os.path.exists(self.tempocr.name):
                os.unlink(self.tempocr.name)
        if self.configWin.isVisible():
            self.configWin.close()

        e.accept()
Example #42
0
    def closeEvent(self, event):

        reg = QSettings()
        reg.setValue("reset wills width", self.size().width())
        reg.sync()
Example #43
0
class LoginWindow(QWidget):
    tryLogin = pyqtSignal(dict, name="tryLogin")
    loginSuccess = pyqtSignal(name="loginSuccess")

    def __init__(self, state, device):
        super().__init__()

        self.settings = QSettings("Capstone", "posture-of-success")

        self.state = state
        self.device = device
        self.is_waiting = False
        self.login = QNetworkAccessManager()
        self.login.finished.connect(self.login_response)

        self.error_dialog = QErrorMessage()

        # Setup UI
        self.setWindowTitle("성공의 자세")
        self.setWindowIcon(QIcon('icon.png'))
        self.setGeometry(300, 300, 560, 460)

        label = QLabel("로그인")
        label.setProperty("class", "huge")

        self.id_field = QLineEdit(self.settings.value("login/id", ""))
        self.id_field.setPlaceholderText("Email")
        self.pw_field = QLineEdit(self.settings.value("login/pw", ""))
        self.pw_field.setPlaceholderText("Password")
        self.pw_field.setEchoMode(QLineEdit.Password)
        self.pw_field.returnPressed.connect(self.login_clicked)

        fields_box = QVBoxLayout()
        fields_box.addWidget(self.id_field)
        fields_box.addWidget(self.pw_field)

        self.login_button = QPushButton("로그인")
        register_button = QPushButton("회원가입")
        register_button.setProperty("class", "inverted")

        self.save_login_checkbox = QCheckBox("자동 로그인")

        self.device_status = QLabel()

        grid = QGridLayout()
        grid.addWidget(self.save_login_checkbox, 0, 0)
        grid.addWidget(self.login_button, 0, 1)
        grid.addWidget(self.device_status, 1, 0)
        grid.addWidget(register_button, 1, 1)
        grid.setSpacing(20)

        login_box = QVBoxLayout()
        login_box.addStretch(1)
        login_box.addWidget(label)
        login_box.addLayout(fields_box)
        login_box.addLayout(grid)
        login_box.addStretch(1)

        login_box.setContentsMargins(50, 50, 50, 50)
        login_box.setSpacing(20)

        frame = QWidget()
        frame.setLayout(login_box)
        frame.setProperty("class", "frame")

        main_layout = QVBoxLayout()
        main_layout.addWidget(frame)
        main_layout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(main_layout)
        self.setProperty("class", "root")
        self.setContentsMargins(0, 0, 0, 0)
        self.setAttribute(Qt.WA_TranslucentBackground)
        # self.setWindowFlags(Qt.FramelessWindowHint)

        # Connect
        self.update_status()
        self.device.connectedChanged.connect(self.update_status)
        self.login_button.clicked.connect(self.login_clicked)
        register_button.clicked.connect(register)

        if self.settings.value("login/id", "") != "":
            self.save_login_checkbox.setChecked(True)
            self.login_clicked()

    def login_clicked(self):
        if not self.is_waiting:
            print("login clicked")
            self.is_waiting = True
            self.login_button.setEnabled(False)
            data = {
                "email": self.id_field.text(),
                "password": self.pw_field.text()
            }

            req = QNetworkRequest(QUrl(SERVER_BASE_ADDR +
                                       "/api/device/signin"))
            req.setRawHeader("Content-Type".encode('utf-8'),
                             "application/json".encode('utf-8'))
            self.login.post(req, json.dumps(data).encode('utf-8'))

    def login_response(self, response: QNetworkReply):
        self.is_waiting = False
        self.login_button.setEnabled(True)

        err = response.error()
        if err == QNetworkReply.NoError:
            reply = str(response.readAll(), 'utf-8')
            reply_json = json.loads(reply)
            print(reply_json)
            if "success" in reply_json and reply_json["success"]:
                self.state.login(reply_json["email"], reply_json["score"])
                self.state.sensor_values = eval(reply_json["sensor_data"])
                self.loginSuccess.emit()
                self.close()
            else:
                self.error_dialog.showMessage('아이디나 비밀번호가 맞지 않습니다!')
        else:
            self.error_dialog.showMessage("서버 연결에 실패했습니다. 에러 코드=" + str(err))

    def save_login(self, id, pw):
        self.settings.setValue("login/id", id)
        self.settings.setValue("login/pw", pw)
        self.settings.sync()

    def update_status(self):
        if self.device.is_connected():
            self.device_status.setText("장치가 연결되었습니다.")
        else:
            self.device_status.setText("장치 연결을 기다리는 중...")

    def logout(self):
        self.state.logout()
        self.show()

    def closeEvent(self, event: QCloseEvent):
        if self.save_login_checkbox.isChecked():
            print("saving login info")
            self.save_login(self.id_field.text(), self.pw_field.text())
        else:
            print("deleting login info")
            self.save_login("", "")
        if not self.state.is_logged_in():
            QCoreApplication.exit()
Example #44
0
 def save_settings(self):
     settings = QSettings()
     settings.setValue('settings/path_train', self._path_train)
     settings.setValue('settings/key_name', self._key_name)
     settings.setValue('settings/key_index', self._key_idx)
     settings.sync()
Example #45
0
class TasmotaDevicesModel(QAbstractTableModel):
    def __init__(self, *args, **kwargs):
        super(TasmotaDevicesModel, self).__init__(*args, **kwargs)
        self.settings = QSettings()
        self.settings.beginGroup("Devices")
        self._devices = []

        for d in self.settings.childGroups():
            self.loadDevice(d, self.settings.value("{}/full_topic".format(d)),
                            self.settings.value("{}/friendly_name".format(d)))

        self.settings.endGroup()

    def addDevice(self, topic, full_topic, lwt="undefined"):
        rc = self.rowCount()
        self.beginInsertRows(QModelIndex(), rc, rc)
        self._devices.append([lwt, topic, full_topic, topic] +
                             ([''] * (len(columns) - 4)))
        self.settings.beginGroup("Devices")
        self.settings.setValue("{}/full_topic".format(topic), full_topic)
        self.settings.setValue("{}/friendly_name".format(topic), full_topic)
        self.settings.endGroup()
        self.endInsertRows()
        return self.index(rc, 0)

    def loadDevice(self, topic, full_topic, friendly_name="", lwt="undefined"):
        rc = self.rowCount()
        self.beginInsertRows(QModelIndex(), rc, rc)
        self._devices.append([
            lwt, topic, full_topic, friendly_name if friendly_name else topic
        ] + ([''] * (len(columns) - 4)))
        self.endInsertRows()
        return True

    def findDevice(self, topic):
        split_topic = topic.split('/')
        possible_topic = split_topic[1]

        if possible_topic in ('tele', 'stat'):
            possible_topic = split_topic[0]

        for i, d in enumerate(self._devices):
            full_topic = d[DevMdl.FULL_TOPIC] + "(?P<reply>.*)"
            full_topic = full_topic.replace("%topic%", "(?P<topic>.*?)")
            full_topic = full_topic.replace("%prefix%", "(?P<prefix>.*?)")
            match = re.fullmatch(full_topic, topic)

            if match:
                found = match.groupdict()
                if found['topic'] == d[DevMdl.TOPIC]:
                    found.update({'index': self.index(i, DevMdl.LWT)})
                    return found_obj(found)

        return found_obj({
            'index': QModelIndex(),
            'topic': possible_topic,
            'reply': split_topic[-1]
        })

    def columnCount(self, parent=None):
        return len(columns)

    def rowCount(self, parent=None):
        return len(self._devices)

    def insertRows(self, pos, rows, parent=QModelIndex()):
        self.beginInsertRows(parent, pos, pos + rows - 1)
        for i in range(rows):
            self._devices.append(['undefined'] + ([''] * (len(columns) - 1)))
        self.endInsertRows()
        return True

    def removeRows(self, pos, rows, parent=QModelIndex()):
        if pos + rows <= self.rowCount():
            self.beginRemoveRows(parent, pos, pos + rows - 1)
            for r in range(rows):
                d = self._devices[pos][DevMdl.TOPIC]
                self.settings.beginGroup("Devices")
                if d in self.settings.childGroups():
                    self.settings.remove(d)
                self.settings.endGroup()
                self._devices.pop(pos + r)
            self.endRemoveRows()
            return True
        return False

    def headerData(self, col, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            if col <= len(columns):
                return columns[col][0]
            else:
                return ''

    def data(self, idx, role=Qt.DisplayRole):
        if idx.isValid():
            row = idx.row()
            col = idx.column()

            if role in (Qt.DisplayRole, Qt.EditRole):
                val = self._devices[row][col]
                if val and col == DevMdl.UPTIME:
                    if val.startswith("0T"):
                        val = val.replace('0T', '')
                    return val.replace('T', 'd ')

                elif val and col == DevMdl.MODULE:
                    return modules.get(val, 'Unknown')

                elif val and col == DevMdl.FIRMWARE:
                    return val.replace('(', ' (')

                elif col == DevMdl.LOADAVG:
                    if val:
                        return val
                    return "n/a" if self._devices[row][
                        DevMdl.LWT] == 'online' else ''

                elif col == DevMdl.BSSID:
                    alias = self.settings.value("BSSID/{}".format(val))
                    if alias:
                        return alias

                return self._devices[row][col]

            elif role == Qt.TextAlignmentRole:
                if col in (DevMdl.RSSI, DevMdl.MAC, DevMdl.IP, DevMdl.SSID,
                           DevMdl.BSSID, DevMdl.CHANNEL, DevMdl.POWER,
                           DevMdl.LOADAVG, DevMdl.CORE, DevMdl.TELEPERIOD):
                    return Qt.AlignCenter

                elif col == DevMdl.UPTIME:
                    return Qt.AlignRight | Qt.AlignVCenter

                elif col == DevMdl.RESTART_REASON:
                    return Qt.AlignLeft | Qt.AlignVCenter | Qt.TextWordWrap

            elif role == Qt.BackgroundColorRole and col == DevMdl.RSSI:
                rssi = self._devices[row][DevMdl.RSSI]
                if rssi:
                    rssi = int(rssi)
                    if rssi < 50:
                        return QColor("#ef4522")
                    elif rssi > 75:
                        return QColor("#7eca27")
                    else:
                        return QColor("#fcdd0f")

            elif role == Qt.ToolTipRole:
                if col == DevMdl.FIRMWARE:
                    return self._devices[row][DevMdl.FIRMWARE]

                elif col == DevMdl.FRIENDLY_NAME:
                    return "Topic: {}\nFull topic: {}".format(
                        self._devices[row][DevMdl.TOPIC],
                        self._devices[row][DevMdl.FULL_TOPIC])

    def setData(self, idx, val, role=Qt.EditRole):
        row = idx.row()
        col = idx.column()

        if role == Qt.EditRole:
            dev = self._devices[row][DevMdl.TOPIC]
            old_val = self._devices[row][col]
            if val != old_val:
                self.settings.beginGroup("Devices")
                if col == DevMdl.FRIENDLY_NAME:
                    self.settings.setValue("{}/friendly_name".format(dev), val)
                elif col == DevMdl.FULL_TOPIC:
                    self.settings.setValue("{}/full_topic".format(dev), val)
                self.settings.endGroup()
                self._devices[row][col] = val
                self.dataChanged.emit(idx, idx)
                self.settings.sync()
                return True
        return False

    def flags(self, idx):
        return Qt.ItemIsSelectable | Qt.ItemIsEnabled

    def updateValue(self, idx, column, val):
        if idx.isValid():
            row = idx.row()
            idx = self.index(row, column)
            self.setData(idx, val)

    def topic(self, idx):
        if idx.isValid():
            row = idx.row()
            return self._devices[row][DevMdl.TOPIC]
        return None

    def friendly_name(self, idx):
        if idx.isValid():
            row = idx.row()
            return self._devices[row][DevMdl.FRIENDLY_NAME]
        return None

    def commandTopic(self, idx):
        if idx.isValid():
            row = idx.row()
            return self._devices[row][DevMdl.FULL_TOPIC].replace(
                "%prefix%", "cmnd").replace("%topic%",
                                            self._devices[row][DevMdl.TOPIC])
        return None

    def statTopic(self, idx):
        if idx.isValid():
            row = idx.row()
            return self._devices[row][DevMdl.FULL_TOPIC].replace(
                "%prefix%", "stat").replace("%topic%",
                                            self._devices[row][DevMdl.TOPIC])
        return None

    def teleTopic(self, idx):
        if idx.isValid():
            row = idx.row()
            return self._devices[row][DevMdl.FULL_TOPIC].replace(
                "%prefix%", "tele").replace("%topic%",
                                            self._devices[row][DevMdl.TOPIC])
        return None

    def isDefaultTemplate(self, idx):
        if idx.isValid():
            return self._devices[idx.row()][DevMdl.FULL_TOPIC] in [
                "%prefix%/%topic%/", "%topic%/%prefix%/"
            ]

    def bssid(self, idx):
        if idx.isValid():
            row = idx.row()
            return self._devices[row][DevMdl.BSSID]
        return None

    def power(self, idx):
        if idx.isValid():
            row = idx.row()
            return self._devices[row][DevMdl.POWER]
        return None

    def refreshBSSID(self):
        first = self.index(0, DevMdl.BSSID)
        last = self.index(self.rowCount(), DevMdl.BSSID)
        self.dataChanged.emit(first, last)
Example #46
0
class SettingsWindow(QtWidgets.QWidget, settingsUI.Ui_settingsForm):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.settings = QSettings("trik-maze-gui-gen", "preferences")

        if self.settings.value('locale', 'ru') == 'en':
            self.setEnglish()
        else:
            self.setRussian()

        self.colorLabel.mousePressEvent = (self.controlColor)
        self.telegramChannel.mousePressEvent = (self.copyLink)
        self.colorLine = self.settings.value('colorLineValue', '000000')
        self.colorLabel.setStyleSheet('QLabel {background-color: #' +
                                      str(self.colorLine) + ';}')

        self.lineSlider.valueChanged.connect(self.updateValueLine)
        self.mazeSlider.valueChanged.connect(self.updateValueMaze)
        self.MazeLoopsCheckBox.stateChanged.connect(self.updateValueMazeLoops)
        self.excersizeTime.timeChanged.connect(self.updateValueTimeLimit)

        self.lineSlider.setValue(
            self.settings.value('lineCellSizeValue', type=int))
        self.mazeSlider.setValue(
            self.settings.value('mazeCellSizeValue', type=int))
        self.MazeLoopsCheckBox.setCheckState(
            self.settings.value('mazeLoopsValue', type=QtCore.Qt.CheckState))
        self.excersizeTime.setTime(
            self.settings.value('timeLimitValue', type=QtCore.QTime))

    def copyLink(self, event):
        pyperclip.copy('https://t.me/maze_gui_gen')

    def updateValueMaze(self):
        # <html><head/><body><p align="center">2</p></body></html>
        value = "<html><head/><body><p align=\"center\">" + str(
            self.getSliderMaze()) + "</p></body></html>"
        self.mazeCellSizeValue.setText(value)
        self.settings.setValue('mazeCellSizeValue', self.mazeSlider.value())
        self.settings.sync()

    def updateValueLine(self):
        value = "<html><head/><body><p align=\"center\">" + str(
            self.getSliderLine()) + "</p></body></html>"
        self.lineCellSizeValue.setText(value)
        self.settings.setValue('lineCellSizeValue', self.lineSlider.value())
        self.settings.sync()

    def updateValueMazeLoops(self):
        self.settings.setValue('mazeLoopsValue',
                               self.MazeLoopsCheckBox.checkState())
        self.settings.sync()

    def updateValueTimeLimit(self):
        self.settings.setValue('timeLimitValue', self.excersizeTime.time())
        self.settings.sync()

    def getSliderMaze(self) -> int:
        return self.mazeSlider.value()

    def rgb_to_hex(self, rgb):
        return '%02x%02x%02x' % rgb

    def getSliderLine(self) -> int:
        return self.lineSlider.value()

    def getMazeCheckBox(self):
        return self.MazeLoopsCheckBox.isChecked()

    def getTimelimit(self, event):
        v = self.excersizeTime.time().toString()
        v = [int(vi) for vi in v.split(':')][1:3]
        return v

    def controlColor(self, event):
        color = QtWidgets.QColorDialog.getColor()
        if color:
            rgb = (color.getRgb()[0:3])
            hex_color = self.rgb_to_hex(rgb)
            self.colorLabel.setStyleSheet('QLabel {background-color: #' +
                                          str(hex_color) + ';}')
            self.colorLine = hex_color
            self.settings.setValue('colorLineValue', hex_color)
            self.settings.sync()

    def setRussian(self):
        self.MazeLoopsLabel.setText('Лабиринт с циклами')
        self.groupBox.setTitle('Настройки для генерирования полей')
        self.lineCellSizeLabel.setText('Размер ячейки с линией')
        self.mazeCellSizeLabel.setText('Размер ячейки для лабиринта')
        self.timelimitLabel.setText('Временное ограничение для задания')
        self.lineColorLabel.setText('Цвет линии')
        self.InfoLabel.setText(
            'По вопросам и проблемам свяжитесь со мной в telegram: @robot_lev')
        self.telegramChannel.setText(
            'Нажмите, чтобы скопировать ссылку на telegram канал: https://t.me/maze_gui_gen'
        )

    def setEnglish(self):
        self.MazeLoopsLabel.setText('Maze with loops')
        self.groupBox.setTitle('Settings for fields generation')
        self.lineCellSizeLabel.setText('Line cell size')
        self.mazeCellSizeLabel.setText('Maze cell size')
        self.timelimitLabel.setText('Timelimit for excersize')
        self.lineColorLabel.setText('Line color')
        self.InfoLabel.setText(
            'For any issues contact me on telegram: @robot_lev')
        self.telegramChannel.setText(
            'Press to copy link to telegram channel: https://t.me/maze_gui_gen'
        )
Example #47
0
    import sys
    import inspect
    from os.path import dirname, abspath, join, exists
    #when in CLI use inspect to locate the source directory
    src_dir = join(dirname(abspath(inspect.getfile(inspect.currentframe()))), 'src')
    sys.path.append(src_dir)

__author__ = 'saflores'


from PyQt5 import QtWidgets
from PyQt5.QtCore import QSettings
from gui.ui import UI
import sys

app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()

##### check if settings exist, otherwise initialize them #####
mySettings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'Sogeti', 'validate')

if not exists(mySettings.fileName()):
    mySettings.setValue("report/imageQuality", 120)
    mySettings.sync()
    print("settings written to " + mySettings.fileName())
##############################################################

ui = UI(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Example #48
0
    'style': 'Fusion',
    'color-scheme': 'Persepolis Light Blue',
    'icons': 'Papirus-Light',
    'font': 'Ubuntu',
    'font-size': 9,
    'aria2_path': ''
}

# this loop is checking values in persepolis_setting . if value is not
# valid then value replaced by default_setting_dict value
for key in default_setting_dict.keys():

    setting_value = persepolis_setting.value(key, default_setting_dict[key])
    persepolis_setting.setValue(key, setting_value)

persepolis_setting.sync()

# this section  creates temporary download folder and download folder and
# download sub folders if they did not existed.
download_path_temp = persepolis_setting.value('download_path_temp')
download_path = persepolis_setting.value('download_path')

folder_list = [download_path_temp, download_path]

# add subfolders to folder_list if user checked subfolders check box in setting window.
if persepolis_setting.value('subfolder') == 'yes':
    for folder in ['Audios', 'Videos', 'Others', 'Documents', 'Compressed']:
        folder_list.append(os.path.join(download_path, folder))

# create folders in folder_list
for folder in folder_list:
Example #49
0
File: tdmgr.py Project: une18/tdm
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self._version = __version__
        self.setWindowIcon(QIcon(":/logo.png"))
        self.setWindowTitle("Tasmota Device Manager {}".format(self._version))

        self.unknown = []
        self.env = TasmotaEnvironment()
        self.device = None

        self.topics = []
        self.mqtt_queue = []
        self.fulltopic_queue = []

        # ensure TDM directory exists in the user directory
        if not os.path.isdir("{}/TDM".format(QDir.homePath())):
            os.mkdir("{}/TDM".format(QDir.homePath()))

        self.settings = QSettings("{}/TDM/tdm.cfg".format(QDir.homePath()), QSettings.IniFormat)
        self.devices = QSettings("{}/TDM/devices.cfg".format(QDir.homePath()), QSettings.IniFormat)
        self.setMinimumSize(QSize(1000, 600))

        # configure logging
        logging.basicConfig(filename="{}/TDM/tdm.log".format(QDir.homePath()),
                            level=self.settings.value("loglevel", "INFO"),
                            datefmt="%Y-%m-%d %H:%M:%S",
                            format='%(asctime)s [%(levelname)s] %(message)s')
        logging.info("### TDM START ###")

        # load devices from the devices file, create TasmotaDevices and add the to the envvironment
        for mac in self.devices.childGroups():
            self.devices.beginGroup(mac)
            device = TasmotaDevice(self.devices.value("topic"), self.devices.value("full_topic"), self.devices.value("friendly_name"))
            device.debug = self.devices.value("debug", False, bool)
            device.p['Mac'] = mac.replace("-", ":")
            device.env = self.env
            self.env.devices.append(device)

            # load device command history
            self.devices.beginGroup("history")
            for k in self.devices.childKeys():
                device.history.append(self.devices.value(k))
            self.devices.endGroup()
            
            self.devices.endGroup()

        self.device_model = TasmotaDevicesModel(self.env)

        self.setup_mqtt()
        self.setup_main_layout()
        self.add_devices_tab()
        self.build_mainmenu()
        # self.build_toolbars()
        self.setStatusBar(QStatusBar())

        pbSubs = QPushButton("Show subscriptions")
        pbSubs.setFlat(True)
        pbSubs.clicked.connect(self.showSubs)
        self.statusBar().addPermanentWidget(pbSubs)

        self.queue_timer = QTimer()
        self.queue_timer.timeout.connect(self.mqtt_publish_queue)
        self.queue_timer.start(250)

        self.auto_timer = QTimer()
        self.auto_timer.timeout.connect(self.auto_telemetry)

        self.load_window_state()

        if self.settings.value("connect_on_startup", False, bool):
            self.actToggleConnect.trigger()

        self.tele_docks = {}
        self.consoles = []

    def setup_main_layout(self):
        self.mdi = QMdiArea()
        self.mdi.setActivationOrder(QMdiArea.ActivationHistoryOrder)
        self.mdi.setTabsClosable(True)
        self.setCentralWidget(self.mdi)

    def setup_mqtt(self):
        self.mqtt = MqttClient()
        self.mqtt.connecting.connect(self.mqtt_connecting)
        self.mqtt.connected.connect(self.mqtt_connected)
        self.mqtt.disconnected.connect(self.mqtt_disconnected)
        self.mqtt.connectError.connect(self.mqtt_connectError)
        self.mqtt.messageSignal.connect(self.mqtt_message)

    def add_devices_tab(self):
        self.devices_list = ListWidget(self)
        sub = self.mdi.addSubWindow(self.devices_list)
        sub.setWindowState(Qt.WindowMaximized)
        self.devices_list.deviceSelected.connect(self.selectDevice)
        self.devices_list.openConsole.connect(self.openConsole)
        self.devices_list.openRulesEditor.connect(self.openRulesEditor)
        self.devices_list.openTelemetry.connect(self.openTelemetry)
        self.devices_list.openWebUI.connect(self.openWebUI)

    def load_window_state(self):
        wndGeometry = self.settings.value('window_geometry')
        if wndGeometry:
            self.restoreGeometry(wndGeometry)

    def build_mainmenu(self):
        mMQTT  = self.menuBar().addMenu("MQTT")
        self.actToggleConnect = QAction(QIcon(":/disconnect.png"), "Connect")
        self.actToggleConnect.setCheckable(True)
        self.actToggleConnect.toggled.connect(self.toggle_connect)
        mMQTT.addAction(self.actToggleConnect)

        mMQTT.addAction(QIcon(), "Broker", self.setup_broker)
        mMQTT.addAction(QIcon(), "Autodiscovery patterns", self.patterns)

        mMQTT.addSeparator()
        mMQTT.addAction(QIcon(), "Clear obsolete retained LWTs", self.clear_LWT)

        mMQTT.addSeparator()
        mMQTT.addAction(QIcon(), "Auto telemetry period", self.auto_telemetry_period)

        self.actToggleAutoUpdate = QAction(QIcon(":/auto_telemetry.png"), "Auto telemetry")
        self.actToggleAutoUpdate.setCheckable(True)
        self.actToggleAutoUpdate.toggled.connect(self.toggle_autoupdate)
        mMQTT.addAction(self.actToggleAutoUpdate)

        mSettings = self.menuBar().addMenu("Settings")
        mSettings.addAction(QIcon(), "BSSId aliases", self.bssid)
        mSettings.addSeparator()
        mSettings.addAction(QIcon(), "Preferences", self.prefs)

        # mExport = self.menuBar().addMenu("Export")
        # mExport.addAction(QIcon(), "OpenHAB", self.openhab)

    def build_toolbars(self):
        main_toolbar = Toolbar(orientation=Qt.Horizontal, iconsize=24, label_position=Qt.ToolButtonTextBesideIcon)
        main_toolbar.setObjectName("main_toolbar")

    def initial_query(self, device, queued=False):
        for c in initial_commands():
            cmd, payload = c
            cmd = device.cmnd_topic(cmd)

            if queued:
                self.mqtt_queue.append([cmd, payload])
            else:
                self.mqtt.publish(cmd, payload, 1)

    def setup_broker(self):
        brokers_dlg = BrokerDialog()
        if brokers_dlg.exec_() == QDialog.Accepted and self.mqtt.state == self.mqtt.Connected:
            self.mqtt.disconnect()

    def toggle_autoupdate(self, state):
        if state == True:
            if self.mqtt.state == self.mqtt.Connected:
                for d in self.env.devices:
                    self.mqtt.publish(d.cmnd_topic('STATUS'), payload=8)
            self.auto_timer.setInterval(self.settings.value("autotelemetry", 5000, int))
            self.auto_timer.start()
        else:
            self.auto_timer.stop()

    def toggle_connect(self, state):
        if state and self.mqtt.state == self.mqtt.Disconnected:
            self.broker_hostname = self.settings.value('hostname', 'localhost')
            self.broker_port = self.settings.value('port', 1883, int)
            self.broker_username = self.settings.value('username')
            self.broker_password = self.settings.value('password')

            self.mqtt.hostname = self.broker_hostname
            self.mqtt.port = self.broker_port

            if self.broker_username:
                self.mqtt.setAuth(self.broker_username, self.broker_password)
            self.mqtt.connectToHost()
        elif not state and self.mqtt.state == self.mqtt.Connected:
            self.mqtt_disconnect()

    def auto_telemetry(self):
        if self.mqtt.state == self.mqtt.Connected:
            for d in self.env.devices:
                self.mqtt.publish(d.cmnd_topic('STATUS'), payload=8)

    def mqtt_connect(self):
        self.broker_hostname = self.settings.value('hostname', 'localhost')
        self.broker_port = self.settings.value('port', 1883, int)
        self.broker_username = self.settings.value('username')
        self.broker_password = self.settings.value('password')

        self.mqtt.hostname = self.broker_hostname
        self.mqtt.port = self.broker_port

        if self.broker_username:
            self.mqtt.setAuth(self.broker_username, self.broker_password)

        if self.mqtt.state == self.mqtt.Disconnected:
            self.mqtt.connectToHost()

    def mqtt_disconnect(self):
        self.mqtt.disconnectFromHost()

    def mqtt_connecting(self):
        self.statusBar().showMessage("Connecting to broker")

    def mqtt_connected(self):
        self.actToggleConnect.setIcon(QIcon(":/connect.png"))
        self.actToggleConnect.setText("Disconnect")
        self.statusBar().showMessage("Connected to {}:{} as {}".format(self.broker_hostname, self.broker_port, self.broker_username if self.broker_username else '[anonymous]'))

        self.mqtt_subscribe()

    def mqtt_subscribe(self):
        # clear old topics
        self.topics.clear()
        custom_patterns.clear()

        # load custom autodiscovery patterns
        self.settings.beginGroup("Patterns")
        for k in self.settings.childKeys():
            custom_patterns.append(self.settings.value(k))
        self.settings.endGroup()

        # expand fulltopic patterns to subscribable topics
        for pat in default_patterns:    # tasmota default and SO19
            self.topics += expand_fulltopic(pat)

        # check if custom patterns can be matched by default patterns
        for pat in custom_patterns:
            if pat.startswith("%prefix%") or pat.split('/')[1] == "%prefix%":
                continue  # do nothing, default subcriptions will match this topic
            else:
                self.topics += expand_fulltopic(pat)

        for d in self.env.devices:
            # if device has a non-standard pattern, check if the pattern is found in the custom patterns
            if not d.is_default() and d.p['FullTopic'] not in custom_patterns:
                # if pattern is not found then add the device topics to subscription list.
                # if the pattern is found, it will be matched without implicit subscription
                self.topics += expand_fulltopic(d.p['FullTopic'])

        # passing a list of tuples as recommended by paho
        self.mqtt.subscribe([(topic, 0) for topic in self.topics])

    @pyqtSlot(str, str)
    def mqtt_publish(self, t, p):
        self.mqtt.publish(t, p)

    def mqtt_publish_queue(self):
        for q in self.mqtt_queue:
            t, p = q
            self.mqtt.publish(t, p)
            self.mqtt_queue.pop(self.mqtt_queue.index(q))

    def mqtt_disconnected(self):
        self.actToggleConnect.setIcon(QIcon(":/disconnect.png"))
        self.actToggleConnect.setText("Connect")
        self.statusBar().showMessage("Disconnected")

    def mqtt_connectError(self, rc):
        reason = {
            1: "Incorrect protocol version",
            2: "Invalid client identifier",
            3: "Server unavailable",
            4: "Bad username or password",
            5: "Not authorized",
        }
        self.statusBar().showMessage("Connection error: {}".format(reason[rc]))
        self.actToggleConnect.setChecked(False)

    def mqtt_message(self, topic, msg):
        # try to find a device by matching known FullTopics against the MQTT topic of the message
        device = self.env.find_device(topic)
        if device:
            if topic.endswith("LWT"):
                if not msg:
                    msg = "Offline"
                device.update_property("LWT", msg)

                if msg == 'Online':
                    # known device came online, query initial state
                    self.initial_query(device, True)

            else:
                # forward the message for processing
                device.parse_message(topic, msg)
                if device.debug:
                    logging.debug("MQTT: %s %s", topic, msg)

        else:            # unknown device, start autodiscovery process
            if topic.endswith("LWT"):
                self.env.lwts.append(topic)
                logging.info("DISCOVERY: LWT from an unknown device %s", topic)

                # STAGE 1
                # load default and user-provided FullTopic patterns and for all the patterns,
                # try matching the LWT topic (it follows the device's FullTopic syntax

                for p in default_patterns + custom_patterns:
                    match = re.fullmatch(p.replace("%topic%", "(?P<topic>.*?)").replace("%prefix%", "(?P<prefix>.*?)") + ".*$", topic)
                    if match:
                        # assume that the matched topic is the one configured in device settings
                        possible_topic = match.groupdict().get('topic')
                        if possible_topic not in ('tele', 'stat'):
                            # if the assumed topic is different from tele or stat, there is a chance that it's a valid topic
                            # query the assumed device for its FullTopic. False positives won't reply.
                            possible_topic_cmnd = p.replace("%prefix%", "cmnd").replace("%topic%", possible_topic) + "FullTopic"
                            logging.debug("DISCOVERY: Asking an unknown device for FullTopic at %s", possible_topic_cmnd)
                            self.mqtt_queue.append([possible_topic_cmnd, ""])

            elif topic.endswith("RESULT") or topic.endswith("FULLTOPIC"):      # reply from an unknown device
                # STAGE 2
                full_topic = loads(msg).get('FullTopic')
                if full_topic:
                    # the device replies with its FullTopic
                    # here the Topic is extracted using the returned FullTopic, identifying the device
                    parsed = parse_topic(full_topic, topic)
                    if parsed:
                        # got a match, we query the device's MAC address in case it's a known device that had its topic changed
                        logging.debug("DISCOVERY: topic %s is matched by fulltopic %s", topic, full_topic)

                        d = self.env.find_device(topic=parsed['topic'])
                        if d:
                            d.update_property("FullTopic", full_topic)
                        else:
                            logging.info("DISCOVERY: Discovered topic=%s with fulltopic=%s", parsed['topic'], full_topic)
                            d = TasmotaDevice(parsed['topic'], full_topic)
                            self.env.devices.append(d)
                            self.device_model.addDevice(d)
                            logging.debug("DISCOVERY: Sending initial query to topic %s", parsed['topic'])
                            self.initial_query(d, True)
                            self.env.lwts.remove(d.tele_topic("LWT"))
                        d.update_property("LWT", "Online")

    def export(self):
        fname, _ = QFileDialog.getSaveFileName(self, "Export device list as...", directory=QDir.homePath(), filter="CSV files (*.csv)")
        if fname:
            if not fname.endswith(".csv"):
                fname += ".csv"

            with open(fname, "w", encoding='utf8') as f:
                column_titles = ['mac', 'topic', 'friendly_name', 'full_topic', 'cmnd_topic', 'stat_topic', 'tele_topic', 'module', 'module_id', 'firmware', 'core']
                c = csv.writer(f)
                c.writerow(column_titles)

                for r in range(self.device_model.rowCount()):
                    d = self.device_model.index(r,0)
                    c.writerow([
                        self.device_model.mac(d),
                        self.device_model.topic(d),
                        self.device_model.friendly_name(d),
                        self.device_model.fullTopic(d),
                        self.device_model.commandTopic(d),
                        self.device_model.statTopic(d),
                        self.device_model.teleTopic(d),
                        # modules.get(self.device_model.module(d)),
                        self.device_model.module(d),
                        self.device_model.firmware(d),
                        self.device_model.core(d)
                    ])

    def bssid(self):
        BSSIdDialog().exec_()

    def patterns(self):
        PatternsDialog().exec_()

    # def openhab(self):
    #     OpenHABDialog(self.env).exec_()

    def showSubs(self):
        QMessageBox.information(self, "Subscriptions", "\n".join(sorted(self.topics)))

    def clear_LWT(self):
        dlg = ClearLWTDialog(self.env)
        if dlg.exec_() == ClearLWTDialog.Accepted:
            for row in range(dlg.lw.count()):
                itm = dlg.lw.item(row)
                if itm.checkState() == Qt.Checked:
                    topic = itm.text()
                    self.mqtt.publish(topic, retain=True)
                    self.env.lwts.remove(topic)
                    logging.info("MQTT: Cleared %s", topic)

    def prefs(self):
        dlg = PrefsDialog()
        if dlg.exec_() == QDialog.Accepted:
            update_devices = False

            devices_short_version = self.settings.value("devices_short_version", True, bool)
            if devices_short_version != dlg.cbDevShortVersion.isChecked():
                update_devices = True
                self.settings.setValue("devices_short_version", dlg.cbDevShortVersion.isChecked())


            update_consoles = False

            console_font_size = self.settings.value("console_font_size", 9)
            if console_font_size != dlg.sbConsFontSize.value():
                update_consoles = True
                self.settings.setValue("console_font_size", dlg.sbConsFontSize.value())

            console_word_wrap = self.settings.value("console_word_wrap", True, bool)
            if console_word_wrap != dlg.cbConsWW.isChecked():
                update_consoles = True
                self.settings.setValue("console_word_wrap", dlg.cbConsWW.isChecked())

            if update_consoles:
                for c in self.consoles:
                    c.console.setWordWrapMode(dlg.cbConsWW.isChecked())
                    new_font = QFont(c.console.font())
                    new_font.setPointSize(dlg.sbConsFontSize.value())
                    c.console.setFont(new_font)

        self.settings.sync()

    def auto_telemetry_period(self):
        curr_val = self.settings.value("autotelemetry", 5000, int)
        period, ok = QInputDialog.getInt(self, "Set AutoTelemetry period", "Values under 5000ms may cause increased ESP LoadAvg", curr_val, 1000)
        if ok:
            self.settings.setValue("autotelemetry", period)
            self.settings.sync()

    @pyqtSlot(TasmotaDevice)
    def selectDevice(self, d):
        self.device = d

    @pyqtSlot()
    def openTelemetry(self):
        if self.device:
            tele_widget = TelemetryWidget(self.device)
            self.addDockWidget(Qt.RightDockWidgetArea, tele_widget)
            self.mqtt_publish(self.device.cmnd_topic('STATUS'), "8")

    @pyqtSlot()
    def openConsole(self):
        if self.device:
            console_widget = ConsoleWidget(self.device)
            self.mqtt.messageSignal.connect(console_widget.consoleAppend)
            console_widget.sendCommand.connect(self.mqtt.publish)
            self.addDockWidget(Qt.BottomDockWidgetArea, console_widget)
            console_widget.command.setFocus()
            self.consoles.append(console_widget)

    @pyqtSlot()
    def openRulesEditor(self):
        if self.device:
            rules = RulesWidget(self.device)
            self.mqtt.messageSignal.connect(rules.parseMessage)
            rules.sendCommand.connect(self.mqtt_publish)
            self.mdi.setViewMode(QMdiArea.TabbedView)
            self.mdi.addSubWindow(rules)
            rules.setWindowState(Qt.WindowMaximized)
            rules.destroyed.connect(self.updateMDI)
            self.mqtt_queue.append((self.device.cmnd_topic("ruletimer"), ""))
            self.mqtt_queue.append((self.device.cmnd_topic("rule1"), ""))
            self.mqtt_queue.append((self.device.cmnd_topic("Var"), ""))
            self.mqtt_queue.append((self.device.cmnd_topic("Mem"), ""))

    @pyqtSlot()
    def openWebUI(self):
        if self.device and self.device.p.get('IPAddress'):
            url = QUrl("http://{}".format(self.device.p['IPAddress']))

            try:
                webui = QWebEngineView()
                webui.load(url)

                frm_webui = QFrame()
                frm_webui.setWindowTitle("WebUI [{}]".format(self.device.p['FriendlyName1']))
                frm_webui.setFrameShape(QFrame.StyledPanel)
                frm_webui.setLayout(VLayout(0))
                frm_webui.layout().addWidget(webui)
                frm_webui.destroyed.connect(self.updateMDI)

                self.mdi.addSubWindow(frm_webui)
                self.mdi.setViewMode(QMdiArea.TabbedView)
                frm_webui.setWindowState(Qt.WindowMaximized)

            except NameError:
                QDesktopServices.openUrl(QUrl("http://{}".format(self.device.p['IPAddress'])))

    def updateMDI(self):
        if len(self.mdi.subWindowList()) == 1:
            self.mdi.setViewMode(QMdiArea.SubWindowView)
            self.devices_list.setWindowState(Qt.WindowMaximized)

    def closeEvent(self, e):
        self.settings.setValue("version", self._version)
        self.settings.setValue("window_geometry", self.saveGeometry())
        self.settings.setValue("views_order", ";".join(self.devices_list.views.keys()))

        self.settings.beginGroup("Views")
        for view, items in self.devices_list.views.items():
            self.settings.setValue(view, ";".join(items[1:]))
        self.settings.endGroup()

        self.settings.sync()

        for d in self.env.devices:
            mac = d.p.get('Mac')
            topic = d.p['Topic']
            full_topic = d.p['FullTopic']
            friendly_name = d.p['FriendlyName1']

            if mac:
                self.devices.beginGroup(mac.replace(":", "-"))
                self.devices.setValue("topic", topic)
                self.devices.setValue("full_topic", full_topic)
                self.devices.setValue("friendly_name", friendly_name)

                for i, h in enumerate(d.history):
                    self.devices.setValue("history/{}".format(i), h)
                self.devices.endGroup()
        self.devices.sync()

        e.accept()
Example #50
0
class frmAccess(QDialog, Ui_frmAccess):
    databaseCreated = pyqtSignal(ConnectionQt)

    def __init__(self, module, settingsSection, settings=None, parent=None):
        QDialog.__init__(self, parent)
        if settings == None:
            self.settings = QSettings()
        else:
            self.settings = settings
        self.settingsSection = settingsSection
        self.module = module

        self.setModal(True)
        self.setupUi(self)
        self.setResources()
        self.resize(
            self.settings.value(self.settingsSection + "/qdialog_size",
                                QSize(200, 60)))
        self.parent = parent

        self.languages = TranslationLanguageManager()
        self.languages.load_all()
        self.languages.selected = self.languages.find_by_id(
            self.settings.value(self.settingsSection + "/language", "en"))
        self.languages.qcombobox(self.cmbLanguages, self.languages.selected)

        self.con = ConnectionQt()  #Pointer to connection

        self.setTitle(self.tr("Log in PostreSQL database"))

        self.cmbProfiles_update()
        current_profile = self.settings.value(
            self.settingsSection + "/current_profile", "")
        if current_profile == "":
            self.txtDB.setText(
                self.settings.value(self.settingsSection + "/db", ""))
            self.txtPort.setText(
                self.settings.value(self.settingsSection + "/port", "5432"))
            self.txtUser.setText(
                self.settings.value(self.settingsSection + "/user",
                                    "postgres"))
            self.txtServer.setText(
                self.settings.value(self.settingsSection + "/server",
                                    "127.0.0.1"))
        else:
            self.cmbProfiles.setCurrentText(current_profile)

    ## Reimplements QDialog.exec_ method to make an autologin if PGPASSWORD environment variable is detected.
    def exec_(self):
        try:
            self.password = environ['PGPASSWORD']
            debug("Password automatically set from environment variable")
            self.txtPass.setText(self.password)
            self.cmdYN.accepted.emit()
        except:
            self.txtPass.setFocus()
            QDialog.exec_(self)
        self.settings.setValue(self.settingsSection + "/qdialog_size",
                               self.size())
        self.settings.sync()

    def setResources(self,
                     pixmap=":/reusingcode/frmaccess_pixmap.png",
                     icon=":/reusingcode/frmaccess_icon.png",
                     database_new=":/reusingcode/database_new.png",
                     profile_new=":/reusingcode/profile_new.png",
                     profile_update=":/reusingcode/profile_update.png",
                     profile_delete=":/reusingcode/button_cancel.png"):
        self.lblPixmap.setPixmap(QPixmap(pixmap))
        self.setWindowIcon(QIcon(icon))
        self.cmdDatabaseNew.setIcon(QIcon(database_new))
        self.cmdProfileNew.setIcon(QIcon(profile_new))
        self.cmdProfileUpdate.setIcon(QIcon(profile_update))
        self.cmdProfileDelete.setIcon(QIcon(profile_delete))

    def setTitle(self, text):
        self.setWindowTitle(text)

    def setLabel(self, text):
        self.lbl.setText(text)

    def setLanguagesVisible(self, boolean):
        if boolean == False:
            self.lblLanguage.hide()
            self.cmbLanguages.hide()

    def setProfilesVisible(self, boolean):
        if boolean == False:
            self.lineProfile.hide()
            self.lblProfile.hide()
            self.cmbProfiles.hide()
            self.cmdProfileNew.hide()
            self.cmdProfileUpdate.hide()
            self.cmdProfileDelete.hide()

    @pyqtSlot(int)
    def on_cmbLanguages_currentIndexChanged(self, stri):
        self.languages.selected = self.languages.find_by_id(
            self.cmbLanguages.itemData(self.cmbLanguages.currentIndex()))
        self.settings.setValue(self.settingsSection + "/language",
                               self.languages.selected.id)
        self.languages.cambiar(self.languages.selected.id, self.module)
        self.retranslateUi(self)

    @pyqtSlot(str)
    def on_cmbProfiles_currentTextChanged(self, stri):
        self.txtDB.setText(
            self.settings.value(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/db", "xulpymoney"))
        self.txtPort.setText(
            self.settings.value(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/port", "5432"))
        self.txtUser.setText(
            self.settings.value(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/user", "postgres"))
        self.txtServer.setText(
            self.settings.value(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/server", "127.0.0.1"))

    def __save_current_profile(self):
        if self.cmbProfiles.currentText() == "":
            self.settings.setValue(self.settingsSection + "/db",
                                   self.txtDB.text())
            self.settings.setValue(self.settingsSection + "/port",
                                   self.txtPort.text())
            self.settings.setValue(self.settingsSection + "/user",
                                   self.txtUser.text())
            self.settings.setValue(self.settingsSection + "/server",
                                   self.txtServer.text())
            self.settings.setValue(
                self.settingsSection + "/language",
                self.cmbLanguages.itemData(self.cmbLanguages.currentIndex()))
            self.settings.setValue(self.settingsSection + "/current_profile",
                                   "")
        else:
            self.settings.setValue(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/db", self.txtDB.text())
            self.settings.setValue(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/port", self.txtPort.text())
            self.settings.setValue(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/user", self.txtUser.text())
            self.settings.setValue(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/server",
                self.txtServer.text())
            self.settings.setValue(
                self.settingsSection + "_profile_" +
                self.cmbProfiles.currentText() + "/language",
                self.cmbLanguages.itemData(self.cmbLanguages.currentIndex()))
            self.settings.setValue(self.settingsSection + "/current_profile",
                                   self.cmbProfiles.currentText())
        self.settings.sync()

    @pyqtSlot()
    def on_cmdYN_accepted(self):
        self.__save_current_profile()
        self.con.init__create(self.txtUser.text(), self.txtPass.text(),
                              self.txtServer.text(), self.txtPort.text(),
                              self.txtDB.text())
        self.con.connect()
        if self.con.is_active():
            self.accept()
        else:
            qmessagebox(
                self.tr("Error conecting to {} database in {} server").format(
                    self.con.db, self.con.server))

    @pyqtSlot()
    def on_cmdYN_rejected(self):
        self.reject()

    def on_cmdProfileNew_released(self):
        name = qinputbox_string(self.tr("Profile name"))
        self.cmbProfiles.addItem(name)
        self.settings.setValue(self.settingsSection + "/db", self.txtDB.text())

    def on_cmdProfileUpdate_released(self):
        before = self.cmbProfiles.currentText()
        after = qinputbox_string(self.tr("Profile name"))
        self.cmbProfiles.setItemText(self.cmbProfiles.currentIndex(), after)
        self.settings.remove(self.settingsSection + "_profile_" + before)
        self.__save_current_profile()

    def on_cmdProfileDelete_released(self):
        self.settings.remove(self.settingsSection + "_profile_" +
                             self.cmbProfiles.currentText())
        self.settings.setValue(self.settingsSection + "/current_profile", "")
        self.cmbProfiles_update()

    ## @return List of string with profile names
    def __list_of_profiles(self):
        r = []
        for group in self.settings.childGroups():
            if group.startswith(self.settingsSection + "_profile_"):
                r.append(group.replace(self.settingsSection + "_profile_", ""))
        print(r)
        return r

    def cmbProfiles_update(self, selected=None):
        profiles = self.__list_of_profiles()
        self.cmbProfiles.blockSignals(True)
        self.cmbProfiles.clear()
        for profile in profiles:
            self.cmbProfiles.addItem(profile)

        #Force without signals to be in -1. There were problems when 0 is selected, becouse it didn't emit anything
        self.cmbProfiles.setCurrentIndex(-1)
        if selected is None:
            self.cmbProfiles.blockSignals(False)
        else:
            self.cmbProfiles.blockSignals(False)
            self.cmbProfiles.setCurrentIndex(
                self.cmbProfiles.findData(selected.id))

    def on_cmdDatabaseNew_released(self):
        respuesta = QMessageBox.warning(
            self, self.windowTitle(),
            self.tr("Do you want to create {} database in {}?".format(
                self.txtDB.text(), self.cmbLanguages.currentText())),
            QMessageBox.Ok | QMessageBox.Cancel)
        if respuesta == QMessageBox.Ok:
            admin_pg = AdminPG(self.txtUser.text(), self.txtPass.text(),
                               self.txtServer.text(), self.txtPort.text())

            if admin_pg.db_exists(self.txtDB.text()) == True:
                qmessagebox(self.tr("Xulpymoney database already exists"))
                return

            if admin_pg.create_db(self.txtDB.text()) == False:
                qmessagebox(self.newdb.error)
            else:
                self.__save_current_profile()
                self.con = admin_pg.connect_to_database(self.txtDB.text(),
                                                        connectionqt=True)
                if self.con.is_active():
                    self.databaseCreated.emit(self.con)
                    self.accept()
                else:
                    qmessagebox(
                        self.
                        tr("Error conecting to {} database in {} server, after creating database"
                           ).format(self.con.db, self.con.server))
Example #51
0
class Backup:
    '''
    A utility to store and restore settings for use in testing. Be careful not to lose data.
    '''
    setname = 'settings.zst'

    def __init__(self, backuploc=None, theDate=None):
        '''
        Store the directory settings in self. The initial strings for the DB are in settings. If initialize is
        called, they are gone. Likeise, restoration will depend on reinitializing settings
        '''

        self.settings = QSettings('zero_substance', 'structjour')
        self.apisettings = QSettings('zero_substance/stockapi', 'structjour')
        self.chartsettings = QSettings('zero_substance/chart', 'structjour')

        if backuploc is None:
            if not os.path.exists(self.settings.value('journal')):
                msg = f"Journal location {self.settings.value('journal')} does not exist"
                logging.error(msg)
                raise ValueError(msg)
            self.rootdir = os.path.normpath(
                os.path.join(self.settings.value('journal'), 'backup'))
        else:
            self.rootdir = backuploc
        d = pd.Timestamp(
            theDate) if theDate is not None else pd.Timestamp.now()
        self.bdir = os.path.join(self.rootdir,
                                 d.strftime("backup_%Y%m%d_%H.%M.%S"))

        self.bu_settings = os.path.join(self.bdir, self.setname)

        self.dbtrade = self.settings.value('tradeDb')
        self.dbstructjour = self.settings.value('structjourDb')

        self.setkeys = []
        self.setvals = []
        self.apisetkeys = []
        self.apisetvals = []

        # print(self.bu_settings)

    def initializeSettings(self):
        '''
        Remove all settings except zero_substance/structjour/journal
        '''
        for key in self.settings.allKeys():
            if key != 'journal':
                self.settings.remove(key)
        self.apisettings.clear()
        self.chartsettings.clear()
        self.settings.sync()
        self.apisettings.sync()
        self.chartsettings.sync()

    def createDir(self):
        try:
            if not os.path.exists(self.rootdir):
                os.mkdir(self.rootdir)
            if not os.path.exists(self.bdir):
                os.mkdir(self.bdir)
        except Exception as ex:
            logging.error(ex)
            logging.error('Failed to create backup directory. ' + str(ex))
            raise ValueError(ex)
        pass

    def removePickle(self):
        if os.path.exists(self.bu_settings):
            os.remove(self.bu_settings)

    def initializeVars(self):
        self.setkeys = []
        self.setvals = []

        self.apisetkeys = []
        self.apisetvals = []

        self.chartkeys = []
        self.chartvals = []

    def backupDatabase(self, theDir=None):
        '''
        Helper method for backup.
        If either db file is not found, change the backup dir name to include
        'FAILED'. That will prevent a bad restore and retain files and settings
        in the directory
        '''
        self.bdir = self.bdir if theDir is None else theDir
        if not os.path.exists(self.bdir):
            raise ValueError(f'Backup directory {self.bdir} does not exist')

        dbtrade2 = os.path.split(self.dbtrade)[1]
        dbstructjour2 = os.path.split(self.dbstructjour)[1]
        dbtrade2 = os.path.normpath(os.path.join(self.bdir, dbtrade2))
        dbstructjour2 = os.path.normpath(os.path.join(self.bdir,
                                                      dbstructjour2))
        try:
            copyfile(self.dbtrade, dbtrade2)
        except FileNotFoundError:
            logging.error(
                f'Trade database does not exist at {self.dbtrade} and cannot be copied'
            )
            changebdir = self.bdir[0:-17] + "FAILED_" + self.bdir[-17:]
            os.rename(self.bdir, changebdir)
            self.bdir = changebdir
            dbstructjour2 = os.path.normpath(
                os.path.join(self.bdir,
                             os.path.split(dbstructjour2)[1]))
        else:
            logging.info(f'Trade database has been backed up to {dbtrade2}')
        if dbtrade2 != dbstructjour2:
            logging.info(f'Trade database has been backed up to {dbtrade2}')
            try:
                copyfile(self.dbstructjour, dbstructjour2)
            except FileNotFoundError:
                logging.error(
                    f'Structjour database does not exist at {self.dbstructjour} and cannot be copied'
                )
                if self.bdir.find('FAILED_') == -1:
                    changedir = self.bdir[0:-17] + "FAILED_" + self.bdir[-17:]
                    os.rename(self.bdir, changedir)

            else:

                logging.info(
                    f'Structjour database has been backed up to {dbstructjour2}'
                )

    def restoreDatabase(self, theDir=None):
        self.bdir = self.bdir if theDir is None else theDir
        if not os.path.exists(self.bdir):
            raise ValueError(f'Backup directory {self.bdir} does not exist.')
        dbtrade = self.settings.value('tradeDb')
        dbstructjour = self.settings.value('structjourDb')

        dbt = os.path.join(self.bdir, os.path.split(dbtrade)[1])
        dbs = os.path.join(self.bdir, os.path.split(dbstructjour)[1])

        if os.path.exists(dbt):
            copyfile(dbt, dbtrade)
            logging.info(f'Db restored {dbt}')
        else:
            logging.error(f'Backup file {dbt} does not exist.')
        if dbs != dbt:
            if os.path.exists(dbs):
                copyfile(dbs, dbstructjour)
                logging.info(f'Db restored {dbs}')
            else:
                logging.error(f'Backup file {dbt} does not exist.')

    def storeSettings(self, replacePickle=False):
        self.createDir()
        if os.path.exists(self.bu_settings):
            if not replacePickle:
                return
        self.initializeVars()
        self.setkeys = self.settings.allKeys()
        for k in self.setkeys:
            self.setvals.append(self.settings.value(k))

        self.apisetkeys = self.apisettings.allKeys()
        for k in self.apisetkeys:
            self.apisetvals.append(self.apisettings.value(k))

        self.chartkeys = self.chartsettings.allKeys()
        for k in self.chartkeys:
            self.chartvals.append(self.chartsettings.value(k))

        setsnkeys = [
            self.setkeys, self.setvals, self.apisetkeys, self.apisetvals,
            self.chartkeys, self.chartvals
        ]

        with open(self.bu_settings, "wb") as f:
            '''Cannot pickle qsettings objects- so we pickle a list'''
            pickle.dump((setsnkeys), f)

        logging.info(
            f'Settings have been backed up to file {self.bu_settings}')

    def restoreSettings(self, theDir=None):
        theDir = self.mostRecent() if theDir is None else theDir
        bu_settings = os.path.join(theDir, self.setname)
        if os.path.exists(bu_settings):
            with open(bu_settings, "rb") as f:
                setsnkeys = pickle.load(f)
                for k, v in zip(setsnkeys[0], setsnkeys[1]):
                    self.settings.setValue(k, v)

                for k2, v2 in zip(setsnkeys[2], setsnkeys[3]):
                    self.apisettings.setValue(k2, v2)

                for k2, v2 in zip(setsnkeys[4], setsnkeys[5]):
                    self.chartsettings.setValue(k2, v2)
            logging.info(f'Settings backed up to file {bu_settings}')

        else:
            logging.error(f'No settings backup found at {bu_settings}')

    def backup(self):
        self.storeSettings()
        self.backupDatabase()

    def restore(self, theDir=None):
        self.bdir = self.mostRecent() if theDir is None else theDir
        self.bdir = os.path.normpath(self.bdir)
        if not os.path.exists(self.bdir):
            raise ValueError(f'Backup directory {self.bdir} does not exist')
        self.restoreSettings(self.bdir)
        self.restoreDatabase(self.bdir)

    def mostRecent(self):

        thedirs = os.listdir(self.rootdir)
        maxdate = ''
        maxdir = None
        for thedir in thedirs:
            if thedir.startswith('backup_2'):
                d = thedir[7:].replace('.', ':')
                if d > maxdate:
                    maxdir = thedir

        return os.path.join(self.rootdir, maxdir) if maxdir is not None else ''

    def _clearJournalDir(self):
        '''For Testing ONLY. TODO implement a seperate backup/restore for this one string'''
        # jdir = self.settings('journal')
        self.settings.remove('journal')

    def _restoreJournalDir(self):
        '''For Testing'''
        pass
Example #52
0
# valid then value replaced by default_setting_dict value
for key in default_setting_dict.keys():

    setting_value = persepolis_setting.value(key, default_setting_dict[key])
    persepolis_setting.setValue(key, setting_value)

# download files is downloading in temporary folder(download_path_temp) and then they will be moved to user download folder(download_path) after completion.
# Check that mount point is available of not!
if not(os.path.exists(persepolis_setting.value('download_path_temp'))):
    persepolis_setting.setValue('download_path_temp', default_setting_dict['download_path_temp'])

if not(os.path.exists(persepolis_setting.value('download_path'))):
    persepolis_setting.setValue('download_path', default_setting_dict['download_path'])


persepolis_setting.sync()

# this section  creates temporary download folder and download folder and
# download sub folders if they did not existed.
download_path_temp = persepolis_setting.value('download_path_temp')
download_path = persepolis_setting.value('download_path')


folder_list = [download_path_temp, download_path]

# add subfolders to folder_list if user checked subfolders check box in setting window.
if persepolis_setting.value('subfolder') == 'yes':
    for folder in ['Audios', 'Videos', 'Others', 'Documents', 'Compressed']:
        folder_list.append(os.path.join(download_path, folder))

# create folders in folder_list
Example #53
0
 def save_general_settings(self):
     settings = QSettings()
     settings.setValue(SETTINGS_VIEWER_PATH, self.input_viewer_path.text())
     settings.setValue(SETTINGS_TOGGLE_PREVIEW,
                       self.chkbox_toggle_preivew.isChecked())
     settings.sync()
Example #54
0
class FilePicker(QtWidgets.QDialog, ui_filepicker.Ui_Dialog):
    def __init__(self, parent=None, fs_url=u"~/", file_pattern=u'All Files (*)', title=u'FS File Picker',
                 default_filename=None, show_save_action=False, show_dirs_only=False):
        super(FilePicker, self).__init__(parent)
        frame = inspect.stack()[1][0]
        self.scope = who_called_me(frame)
        self.setupUi(self)
        self.settings = QSettings("fs_filepicker", self.scope)
        self.setWindowIcon(QIcon(icons('fs_logo.png', origin='fs')))
        self.file_icon = icons('text-x-generic.png')
        self.dir_icon = icons('folder.png')
        self.selected_dir = None
        self.selected_file_pattern = None
        self.filename = None
        self.wparm = None
        self.setWindowTitle(title)
        stored_fs_url = self.settings.value("fs_urls", fs_url)
        self.fs_home_url = u"~/"
        self.fs_root_url = root_url()
        if isinstance(fs_url, list):
            fs_url = fs_url + [self.fs_home_url, self.fs_root_url]
        else:
            fs_url = [fs_url] + [self.fs_home_url, self.fs_root_url]
        self.fs_url = fs_url[0]
        if isinstance(stored_fs_url, list):
            for _fs_url in sorted(list(set(stored_fs_url + fs_url))):
                if fs_url_exists(_fs_url):
                    self.ui_fs_serverlist.addItem(_fs_url)
        self.active_url = self.fs_url
        self.authentification = None
        self.parent_url = self.fs_url
        self.fs = None
        self.file_list_items = []
        self.directory_history = []
        self.last_index = 0
        self.last_dir_index = 0
        self.default_filename = default_filename
        self.file_pattern = file_pattern
        self.show_save_action = show_save_action
        self.show_dirs_only = show_dirs_only
        self.button_icons()
        self.show_action()
        self.configure()
        self.ui_FileType.currentIndexChanged.connect(self.selection_file_type)
        self.ui_SelectedName.textChanged.connect(self.selection_name)
        self.ui_Cancel.clicked.connect(self.cancel)
        self.action_buttons()
        self.ui_FileList.itemClicked.connect(self.show_name)
        self.ui_mkdir.clicked.connect(self.make_dir)
        self.ui_other_fs.clicked.connect(self.other_fs_button)
        self.ui_FileList.cellClicked.connect(self.onCellClicked)
        self.ui_FileList.cellDoubleClicked.connect(self.onCellDoubleClicked)
        self.ui_FileList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.ui_DirList.currentIndexChanged.connect(self.selection_directory)
        self.ui_fs_serverlist.clicked.connect(self.fs_select_other)
        self.ui_fs_serverlist.customContextMenuRequested.connect(self.fs_select_other_context)
        # ToDo check order of calls
        self.active_url = self.fs_url
        self.select_fs()

    def configure(self):
        if isinstance(self.file_pattern, list):
            stored_file_type = self.settings.value("selected_file_pattern", self.file_pattern[0])
            try:
                index = self.file_pattern.index(stored_file_type)
            except ValueError:
                index = 0
            for pattern in self.file_pattern:
                self.ui_FileType.addItem(pattern)
            self.ui_FileType.setCurrentIndex(index)
        else:
            self.ui_FileType.addItems([self.file_pattern])
        if self.default_filename is not None:
            name, extension = self.default_filename.split('.')
            idx = 0
            for pattern in self.file_pattern:
                if u".{}".format(extension) in pattern:
                    self.ui_FileType.setCurrentIndex(idx)
                idx += 1
        if self.show_dirs_only:
            self.ui_label_filename.hide()
            self.ui_label_filetype.hide()
            self.ui_FileType.hide()
            self.ui_SelectedName.hide()

    def button_icons(self):
        """
        Set icon image to button
        """
        self.ui_mkdir.setText("")
        self.ui_mkdir.setIcon(QIcon(icons('folder-new.png')))
        self.ui_other_fs.setText("")
        self.ui_other_fs.setIconSize(QtCore.QSize(64, 64))
        self.ui_other_fs.setIcon(QIcon(icons('fs_logo.png', origin=u'fs')))

    def other_fs_button(self):
        fs_url, ok = QInputDialog.getText(self, 'Other FS Urls', 'Enter FS Url:')
        if ok:
            if fs_url_exists(fs_url):
                self.ui_fs_serverlist.setVisible(True)
                all_urls = [self.ui_fs_serverlist.item(idx).text() for idx in range(self.ui_fs_serverlist.count())]
                if fs_url not in all_urls:
                    self.ui_fs_serverlist.addItem(fs_url)
                self.save_settings()
            else:
                msg = u'"%s" Url not valid' % fs_url
                QErrorMessage(self).showMessage(msg)
                logging.info(msg)

    def fs_select_other(self):
        url = self.ui_fs_serverlist.currentItem().text()
        # ToDo needs a check for archives
        self.active_url = fs.path.forcedir(url)
        self.select_fs()

    def fs_select_other_context(self):
        """
        simple context option, removes item from list
        """
        url = self.ui_fs_serverlist.currentItem().text()
        selected = QMessageBox.information(self, u"Remove FS Dir", url, QMessageBox.Ok | QMessageBox.Cancel)
        if selected == QMessageBox.Ok:
            self.ui_fs_serverlist.clear()
            for item in self.settings.value("fs_urls"):
                if item != url:
                    self.ui_fs_serverlist.addItem(item)
            self.save_settings()

    def select_fs(self):
        """
        loads the selected fs to the file list ui
        """
        self.directory_history = []
        self.wparm = None
        if self.fs:
            self.fs.close()
        try:
            self.fs = fs.open_fs(self.active_url)
        except (IOError, fs.errors.CreateFailed):
            logging.error(u"{} does not exist!".format(self.active_url))
            exit()
        try:
            parseresult = parse(self.active_url)
        except fs.opener.errors.ParseError:
            parseresult = None
        if parseresult is not None and parseresult.username is not None:
            self.authentification = "{}:{}@".format(parseresult.username, parseresult.password)
            self.active_url = self.active_url.replace(self.authentification, u"")
        self.browse_folder()

    def action_buttons(self):
        """
        Open / Save button action connect
        """
        try:
            self.ui_Action.clicked.connect(self.action)
        except AttributeError:
            pass

    def browse_folder(self, subdir=u"."):
        """
        list folder in drop down
        """
        if self.show_save_action:
            self.ui_Action.setEnabled(True)
        if self.show_dirs_only:
            self.ui_Action.setEnabled(True)
        self.ui_DirList.clear()
        if subdir == u".":
            _sub_dir = self.active_url
        else:
            _sub_dir = subdir
        if len(self.directory_history) == 0:
            self.directory_history.append(_sub_dir)
        for item in reversed(self.directory_history):
            self.ui_DirList.addItem(item)
        self.ui_DirList.setCurrentIndex(self.last_dir_index)

    def selection_directory(self):
        """
        Fills the filenames based on file_type into a FileList, also directories
        """
        self.wparm = None
        if not self.show_save_action:
            self.ui_SelectedName.setText(u"")
        QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        self.selected_dir = self.ui_DirList.currentText()
        self.ui_FileList.clearContents()
        file_type = self.ui_FileType.currentText()
        self.file_list_items = []
        self.dir_list_items = []
        self.ui_FileList.verticalHeader().setVisible(False)
        self.ui_FileList.horizontalHeader().setVisible(True)
        self.ui_FileList.setHorizontalHeaderLabels([u'Name', u'Size', u'Modified'])
        self.ui_FileList.setShowGrid(False)
        self.ui_FileList.setSizeAdjustPolicy(
            QtWidgets.QAbstractScrollArea.AdjustToContents)

        if self.selected_dir == self.active_url:
            _sel_dir = u""
        else:
            _sel_dir = self.selected_dir
        # on clearing ui_DirList also index changes and makes an additional call of that method
        if self.ui_DirList.count() > 0:
            try:
                names = self.fs.listdir(_sel_dir)
                # cleanup not valid names
                # ToDo improve make those problematic files not clickable
                for item in names:
                    _item = fs.path.combine(_sel_dir, item)
                    try:
                        self.fs.isdir(_item)
                    except (TypeError, fs.errors.PermissionDenied):
                        names.remove(item)
                        logging.error("item name %s removed from list" % item)
                for item in sorted(names):
                    _item = fs.path.combine(_sel_dir, item)
                    try:
                        self.selected_file_pattern = get_extension_from_string(file_type)
                        if not self.fs.isdir(_item) and match_extension(item, self.selected_file_pattern):
                            if not self.show_dirs_only:
                                info = self.get_info(_item)
                                self.file_list_items.append({_item: info})
                        elif self.fs.isdir(_item):
                            info = self.get_info(_item)
                            self.dir_list_items.append({_item: info})
                    except (fs.errors.PermissionDenied, fs.errors.OperationFailed):
                        logging.info(u"can't access {}".format(item))
            except UnicodeDecodeError as e:
                logging.error(u"Error: {}".format(e))

        self.ui_FileList.setRowCount(len(self.file_list_items) + len(self.dir_list_items))
        index = 0
        for item in self.dir_list_items:
            self.table_row(item, index, self.dir_icon, FOLDER_SPACES, folder=True)
            index = index + 1
        for item in self.file_list_items:
            self.table_row(item, index, self.file_icon, FILES_SPACES, folder=False)
            index = index + 1
        if self.last_index == 0 and not self.show_save_action:
            self.ui_FileList.clearSelection()
            if self.ui_FileList.currentItem() is not None:
                self.ui_SelectedName.setText(self.ui_FileList.currentItem().text())
        self.ui_FileList.resizeRowsToContents()
        QtWidgets.QApplication.restoreOverrideCursor()

    def table_row(self, item, index, icon, spaces, folder):
        info = list(item.values())[0]
        _mod_time, _size = human_readable_info(info)
        if folder:
            _size = u"Folder"
        self.ui_FileList.setCellWidget(index, 0, WidgetImage(fs.path.basename(list(item)[0]),
                                                             icon, item))
        time.sleep(0.001)
        _item = " " * spaces + fs.path.basename(list(item)[0])
        _ti = TableWidgetItem(_item)
        if _size == u"Folder":
            _ti.setWhatsThis("Directory")
        else:
            _ti.setWhatsThis(u"File")
        self.ui_FileList.setItem(index, 0, TableWidgetItem(_ti))
        self.ui_FileList.setItem(index, 1, TableWidgetItem(_size))
        self.ui_FileList.setItem(index, 2, TableWidgetItem(_mod_time))

    def get_info(self, _item, namespaces=[u'details', u'access', u'stat']):
        try:
            info = self.fs.getinfo(_item, namespaces=namespaces)
            time.sleep(0.001)
        except (fs.errors.ResourceNotFound, UnicodeEncodeError):
            info = None
        return info

    @QtCore.pyqtSlot(int, int)
    def onCellClicked(self, row, column):
        """
        Action for ui_FileList WidgetImageText
        :param row: position
        :param column: position
        """
        # Any cell click is always in column 0
        column = 0
        self.wparm = self.ui_FileList.cellWidget(row, column)
        if self.wparm is not None:
            if "text" in self.wparm.img:
                self.ui_SelectedName.setText(self.wparm.text)
            if self.show_dirs_only and "folder" in self.wparm.img:
                self.ui_SelectedName.setText(self.wparm.text)

    @QtCore.pyqtSlot(int, int)
    def onCellDoubleClicked(self, row, column):
        """
        Action for ui_FileList WidgetImageText on doubleclick
        :param row: position
        :param column: position
        """
        column = 0
        self.wparm = self.ui_FileList.cellWidget(row, column)
        try:
            if self.wparm is not None:
                if "folder" in self.wparm.img:
                    self.directory_history.append(list(self.wparm.value.keys())[0])
                    self.browse_folder(subdir=list(self.wparm.value.keys())[0])
                    if not self.show_save_action:
                        self.ui_SelectedName.setText(None)
                    self.selection_name()
                if "text" in self.wparm.img:
                    self.ui_SelectedName.setText(self.wparm.text)
                    self.action()
        except AttributeError:
            pass

    def selection_file_type(self):
        """
        Action for line edit of file type
        """
        self.selection_directory()
        self.ui_FileList.clearSelection()
        if not self.show_save_action:
            self.ui_SelectedName.setText(None)
        if self.show_save_action:
            text = self.ui_SelectedName.text()
            new_text = text.split('.')[0]
            self.ui_SelectedName.setText(new_text)

    def selection_name(self):
        """
        Action for filename changes, line edit text input
        """
        if not self.show_save_action and not self.show_dirs_only:
            self.ui_Action.setEnabled(False)
        self.filename = self.ui_SelectedName.text()
        if self.ui_DirList.currentText() == self.active_url:
            dirname = u""
        else:
            dirname = self.ui_DirList.currentText()
        if self.wparm is not None:
            _dirname = fs.path.forcedir(u'.')
            if self.wparm.value == u'{}{}'.format(_dirname, self.wparm.text):
                dirname = fs.path.dirname(u'{}{}'.format(_dirname, self.wparm.text))
            else:
                dirname = self.selected_dir
        if not self.show_dirs_only:
            _filename = fs.path.combine(dirname, self.filename)
            _file_names = [list(name)[0] for name in self.file_list_items]
            if dirname == fs.path.forcedir(u'.'):
                _file_names = [fs.path.combine(dirname, list(name)[0]) for name in self.file_list_items]
            if _filename in _file_names:
                self.ui_Action.setEnabled(True)
                index = _file_names.index(_filename) + len(self.dir_list_items)
                self.ui_FileList.selectRow(index)
            else:
                if not self.show_save_action:
                    self.ui_Action.setEnabled(False)
                self.ui_FileList.clearSelection()

    def show_name(self):
        """
        Action for showing clicked name as filename
        """
        try:
            self.filename = self.ui_SelectedName.text()
        except AttributeError:
            self.filename = u""
        if self.filename != u"":
            self.ui_SelectedName.setText(self.filename)
            info = self.get_info(self.filename, namespaces=None)
            if info is not None and info.is_file:
                self.ui_Action.setEnabled(True)

    def cancel(self):
        """
        Action on cancel button
        """
        self.filename = None
        self.close()

    def show_action(self):
        """
        Changes the Open Button into a Save Button

        :param show_save_action: True for showing the Save dialog
        """
        if self.show_save_action:
            self.ui_SelectedName.setEnabled(True)
            self.ui_Action.setText("Save")
            if self.default_filename is not None:
                self.ui_SelectedName.setText(self.default_filename)
        if self.show_dirs_only:
            self.ui_SelectedName.setEnabled(True)
            self.ui_Action.setText("Get Directory")

    def make_dir(self):
        """
        Shows the make dir dialog und creates a new directory
        """
        new_dir_name, ok = QtWidgets.QInputDialog.getText(self, u"New Folder", u"Enter a new folder name:",
                                                          QtWidgets.QLineEdit.Normal, "")
        if ok:
            if self.ui_DirList.currentText() == self.active_url:
                dirname = u""
            else:
                dirname = self.ui_DirList.currentText()
            new_dir = fs.path.combine(dirname, new_dir_name)
            if not self.fs.isdir(new_dir):
                try:
                    self.fs.makedir(new_dir)
                except fs.errors.ResourceNotFound:
                    logging.error(u"Can't create {}".format(new_dir))
                self.last_dir_index = list(reversed(self.directory_history)).index(self.selected_dir)
                self.browse_folder(subdir=self.selected_dir)
            else:
                ok = QtWidgets.QMessageBox.warning(self, u"New Folder", u"Can't create this Folder: {}".format(new_dir))

    def action(self):
        """
        Action on Open / Save button
        """
        self.filename = self.ui_SelectedName.text()
        if self.filename == u"" or self.filename is None:
            return

        dirname = fs.path.forcedir(u'.')
        if self.wparm is not None:
            dirname = self.selected_dir
        if dirname.startswith(self.active_url):
            filename = u"{}{}".format(fs.path.forcedir(self.active_url), self.filename)
        else:
            # We can't use fs.path.join and also not fs.path.abspath because of protocol url
            filename = u"{}{}{}".format(fs.path.forcedir(self.active_url),
                                        fs.path.forcedir(dirname), self.filename)
        filename = filename.replace(fs.path.forcedir(u'.'), u'')
        if self.show_save_action and not self.show_dirs_only:
            self.save_settings()
            self.filename = self.ui_SelectedName.text()
            if self.filename == u"":
                return
            info = self.get_info(fs.path.split(filename)[1], namespaces=None)
            if info is not None and info.is_dir:
                sel = QtWidgets.QMessageBox.warning(
                    self, u"Warning",
                    u"You can't create a file with this name: {0}".format(self.filename),
                    QtWidgets.QMessageBox.No)
            elif info is not None and info.is_file:
                sel = QtWidgets.QMessageBox.question(
                    self, u"Replace Filename",
                    u"This will replace the filename: {0}. Continue?".format(self.filename),
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
                if sel == QtWidgets.QMessageBox.Yes:
                    self.filename = filename
                    self.close()
                else:
                    pass
            else:
                self.filename = filename
                self.close()
        else:
            self.filename = filename
            self.close()

    def save_settings(self):
        items = []
        for index in range(self.ui_fs_serverlist.count()):
            items.append(self.ui_fs_serverlist.item(index).text())
        self.settings.setValue('fs_urls', items)
        selected_file_pattern = self.ui_FileType.currentText()
        self.settings.setValue("selected_file_pattern", selected_file_pattern)
        self.settings.sync()
Example #55
0
 def _commit(self):
     if not self.fake_db:
         conf = QSettings()
         conf.setValue("memoirs",
                       [Message.build_file(msg) for key, msg in self._db.items()])
         conf.sync()
Example #56
0
class TrayStarter(QSystemTrayIcon):
    """
    Class implementing a starter for the system tray.
    """
    def __init__(self):
        """
        Constructor
        """
        super(TrayStarter, self).__init__(
            UI.PixmapCache.getIcon(
                Preferences.getTrayStarter("TrayStarterIcon")))
        
        self.maxMenuFilePathLen = 75
        
        self.rsettings = QSettings(
            QSettings.IniFormat,
            QSettings.UserScope,
            Globals.settingsNameOrganization,
            Globals.settingsNameRecent)
        
        self.recentProjects = []
        self.__loadRecentProjects()
        self.recentMultiProjects = []
        self.__loadRecentMultiProjects()
        self.recentFiles = []
        self.__loadRecentFiles()
        
        self.activated.connect(self.__activated)
        
        self.__menu = QMenu(self.tr("Eric6 tray starter"))
        
        self.recentProjectsMenu = QMenu(
            self.tr('Recent Projects'), self.__menu)
        self.recentProjectsMenu.aboutToShow.connect(
            self.__showRecentProjectsMenu)
        self.recentProjectsMenu.triggered.connect(self.__openRecent)
        
        self.recentMultiProjectsMenu = \
            QMenu(self.tr('Recent Multiprojects'), self.__menu)
        self.recentMultiProjectsMenu.aboutToShow.connect(
            self.__showRecentMultiProjectsMenu)
        self.recentMultiProjectsMenu.triggered.connect(self.__openRecent)
        
        self.recentFilesMenu = QMenu(self.tr('Recent Files'), self.__menu)
        self.recentFilesMenu.aboutToShow.connect(self.__showRecentFilesMenu)
        self.recentFilesMenu.triggered.connect(self.__openRecent)
        
        act = self.__menu.addAction(
            self.tr("Eric6 tray starter"), self.__about)
        font = act.font()
        font.setBold(True)
        act.setFont(font)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            self.tr("QRegExp editor"), self.__startQRegExp)
        self.__menu.addAction(
            self.tr("Python re editor"), self.__startPyRe)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("uiPreviewer.png"),
            self.tr("UI Previewer"), self.__startUIPreviewer)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("trPreviewer.png"),
            self.tr("Translations Previewer"), self.__startTRPreviewer)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("unittest.png"),
            self.tr("Unittest"), self.__startUnittest)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("ericWeb.png"),
            self.tr("eric6 Web Browser"), self.__startHelpViewer)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("diffFiles.png"),
            self.tr("Compare Files"), self.__startDiff)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("compareFiles.png"),
            self.tr("Compare Files side by side"), self.__startCompare)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("sqlBrowser.png"),
            self.tr("SQL Browser"), self.__startSqlBrowser)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("ericSnap.png"),
            self.tr("Snapshot"), self.__startSnapshot)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("iconEditor.png"),
            self.tr("Icon Editor"), self.__startIconEditor)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("pluginInstall.png"),
            self.tr("Install Plugin"), self.__startPluginInstall)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("pluginUninstall.png"),
            self.tr("Uninstall Plugin"), self.__startPluginUninstall)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("pluginRepository.png"),
            self.tr("Plugin Repository"), self.__startPluginRepository)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("configure.png"),
            self.tr('Preferences'), self.__startPreferences)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("erict.png"),
            self.tr("eric6 IDE"), self.__startEric)
        self.__menu.addAction(
            UI.PixmapCache.getIcon("editor.png"),
            self.tr("eric6 Mini Editor"), self.__startMiniEditor)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("configure.png"),
            self.tr('Configure Tray Starter'), self.__showPreferences)
        self.__menu.addSeparator()
        
        # recent files
        self.menuRecentFilesAct = self.__menu.addMenu(self.recentFilesMenu)
        # recent multi projects
        self.menuRecentMultiProjectsAct = self.__menu.addMenu(
            self.recentMultiProjectsMenu)
        # recent projects
        self.menuRecentProjectsAct = self.__menu.addMenu(
            self.recentProjectsMenu)
        self.__menu.addSeparator()
        
        self.__menu.addAction(
            UI.PixmapCache.getIcon("exit.png"),
            self.tr('Quit'), qApp.quit)
    
    def __loadRecentProjects(self):
        """
        Private method to load the recently opened project filenames.
        """
        rp = self.rsettings.value(Globals.recentNameProject)
        if rp is not None:
            for f in rp:
                if QFileInfo(f).exists():
                    self.recentProjects.append(f)
    
    def __loadRecentMultiProjects(self):
        """
        Private method to load the recently opened multi project filenames.
        """
        rmp = self.rsettings.value(Globals.recentNameMultiProject)
        if rmp is not None:
            for f in rmp:
                if QFileInfo(f).exists():
                    self.recentMultiProjects.append(f)
    
    def __loadRecentFiles(self):
        """
        Private method to load the recently opened filenames.
        """
        rf = self.rsettings.value(Globals.recentNameFiles)
        if rf is not None:
            for f in rf:
                if QFileInfo(f).exists():
                    self.recentFiles.append(f)
    
    def __activated(self, reason):
        """
        Private slot to handle the activated signal.
        
        @param reason reason code of the signal
            (QSystemTrayIcon.ActivationReason)
        """
        if reason == QSystemTrayIcon.Context or \
           reason == QSystemTrayIcon.MiddleClick:
            self.__showContextMenu()
        elif reason == QSystemTrayIcon.DoubleClick:
            self.__startEric()
    
    def __showContextMenu(self):
        """
        Private slot to show the context menu.
        """
        self.menuRecentProjectsAct.setEnabled(len(self.recentProjects) > 0)
        self.menuRecentMultiProjectsAct.setEnabled(
            len(self.recentMultiProjects) > 0)
        self.menuRecentFilesAct.setEnabled(len(self.recentFiles) > 0)
        
        pos = QCursor.pos()
        x = pos.x() - self.__menu.sizeHint().width()
        pos.setX(x > 0 and x or 0)
        y = pos.y() - self.__menu.sizeHint().height()
        pos.setY(y > 0 and y or 0)
        self.__menu.popup(pos)
    
    def __startProc(self, applName, *applArgs):
        """
        Private method to start an eric6 application.
        
        @param applName name of the eric6 application script (string)
        @param *applArgs variable list of application arguments
        """
        proc = QProcess()
        applPath = os.path.join(getConfig("ericDir"), applName)
        
        args = []
        args.append(applPath)
        for arg in applArgs:
            args.append(arg)
        
        if not os.path.isfile(applPath) or \
                not proc.startDetached(sys.executable, args):
            E5MessageBox.critical(
                self,
                self.tr('Process Generation Error'),
                self.tr(
                    '<p>Could not start the process.<br>'
                    'Ensure that it is available as <b>{0}</b>.</p>'
                ).format(applPath),
                self.tr('OK'))
    
    def __startMiniEditor(self):
        """
        Private slot to start the eric6 Mini Editor.
        """
        self.__startProc("eric6_editor.py", "--config={0}".format(
            Utilities.getConfigDir()))
    
    def __startEric(self):
        """
        Private slot to start the eric6 IDE.
        """
        self.__startProc("eric6.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startPreferences(self):
        """
        Private slot to start the eric6 configuration dialog.
        """
        self.__startProc("eric6_configure.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startPluginInstall(self):
        """
        Private slot to start the eric6 plugin installation dialog.
        """
        self.__startProc("eric6_plugininstall.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startPluginUninstall(self):
        """
        Private slot to start the eric6 plugin uninstallation dialog.
        """
        self.__startProc("eric6_pluginuninstall.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startPluginRepository(self):
        """
        Private slot to start the eric6 plugin repository dialog.
        """
        self.__startProc("eric6_pluginrepository.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startHelpViewer(self):
        """
        Private slot to start the eric6 web browser.
        """
        self.__startProc("eric6_webbrowser.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startUIPreviewer(self):
        """
        Private slot to start the eric6 UI previewer.
        """
        self.__startProc("eric6_uipreviewer.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startTRPreviewer(self):
        """
        Private slot to start the eric6 translations previewer.
        """
        self.__startProc("eric6_trpreviewer.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startUnittest(self):
        """
        Private slot to start the eric6 unittest dialog.
        """
        self.__startProc("eric6_unittest.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startDiff(self):
        """
        Private slot to start the eric6 diff dialog.
        """
        self.__startProc("eric6_diff.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startCompare(self):
        """
        Private slot to start the eric6 compare dialog.
        """
        self.__startProc("eric6_compare.py", "--config={0}".format(
            Utilities.getConfigDir()))
    
    def __startSqlBrowser(self):
        """
        Private slot to start the eric6 sql browser dialog.
        """
        self.__startProc("eric6_sqlbrowser.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startIconEditor(self):
        """
        Private slot to start the eric6 icon editor dialog.
        """
        self.__startProc("eric6_iconeditor.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startSnapshot(self):
        """
        Private slot to start the eric6 snapshot dialog.
        """
        self.__startProc("eric6_snap.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startQRegExp(self):
        """
        Private slot to start the eric6 QRegExp editor dialog.
        """
        self.__startProc("eric6_qregexp.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __startPyRe(self):
        """
        Private slot to start the eric6 Python re editor dialog.
        """
        self.__startProc("eric6_re.py", "--config={0}".format(
            Utilities.getConfigDir()))

    def __showRecentProjectsMenu(self):
        """
        Private method to set up the recent projects menu.
        """
        self.recentProjects = []
        self.rsettings.sync()
        self.__loadRecentProjects()
        
        self.recentProjectsMenu.clear()
        
        idx = 1
        for rp in self.recentProjects:
            if idx < 10:
                formatStr = '&{0:d}. {1}'
            else:
                formatStr = '{0:d}. {1}'
            act = self.recentProjectsMenu.addAction(
                formatStr.format(
                    idx, Utilities.compactPath(rp, self.maxMenuFilePathLen)))
            act.setData(rp)
            idx += 1
    
    def __showRecentMultiProjectsMenu(self):
        """
        Private method to set up the recent multi projects menu.
        """
        self.recentMultiProjects = []
        self.rsettings.sync()
        self.__loadRecentMultiProjects()
        
        self.recentMultiProjectsMenu.clear()
        
        idx = 1
        for rmp in self.recentMultiProjects:
            if idx < 10:
                formatStr = '&{0:d}. {1}'
            else:
                formatStr = '{0:d}. {1}'
            act = self.recentMultiProjectsMenu.addAction(
                formatStr.format(
                    idx, Utilities.compactPath(rmp, self.maxMenuFilePathLen)))
            act.setData(rmp)
            idx += 1
    
    def __showRecentFilesMenu(self):
        """
        Private method to set up the recent files menu.
        """
        self.recentFiles = []
        self.rsettings.sync()
        self.__loadRecentFiles()
        
        self.recentFilesMenu.clear()
        
        idx = 1
        for rf in self.recentFiles:
            if idx < 10:
                formatStr = '&{0:d}. {1}'
            else:
                formatStr = '{0:d}. {1}'
            act = self.recentFilesMenu.addAction(
                formatStr.format(
                    idx, Utilities.compactPath(rf, self.maxMenuFilePathLen)))
            act.setData(rf)
            idx += 1
    
    def __openRecent(self, act):
        """
        Private method to open a project or file from the list of recently
        opened projects or files.
        
        @param act reference to the action that triggered (QAction)
        """
        filename = act.data()
        if filename:
            self.__startProc("eric6.py", filename)
    
    def __showPreferences(self):
        """
        Private slot to set the preferences.
        """
        from Preferences.ConfigurationDialog import ConfigurationDialog
        dlg = ConfigurationDialog(
            None, 'Configuration', True, fromEric=True,
            displayMode=ConfigurationDialog.TrayStarterMode)
        dlg.preferencesChanged.connect(self.preferencesChanged)
        dlg.show()
        dlg.showConfigurationPageByName("trayStarterPage")
        dlg.exec_()
        QApplication.processEvents()
        if dlg.result() == QDialog.Accepted:
            dlg.setPreferences()
            Preferences.syncPreferences()
            self.preferencesChanged()
    
    def preferencesChanged(self):
        """
        Public slot to handle a change of preferences.
        """
        self.setIcon(
            UI.PixmapCache.getIcon(
                Preferences.getTrayStarter("TrayStarterIcon")))

    def __about(self):
        """
        Private slot to handle the About dialog.
        """
        from Plugins.AboutPlugin.AboutDialog import AboutDialog
        dlg = AboutDialog()
        dlg.exec_()
Example #57
0
class SubSettings:
    """A wrapper to QSettings. Provides an interface to all available Subconvert options."""

    def __init__(self):
        # The following settings will cause saving config files to e.g.
        # ~/.config/subconvert/subconvert.ini
        organization = "subconvert"
        mainConfFile = "subconvert"
        programStateFile = "state"

        self._settings = QSettings(QSettings.IniFormat, QSettings.UserScope, organization, mainConfFile)
        self._programState = QSettings(QSettings.IniFormat, QSettings.UserScope, organization, programStateFile)

    def sync(self):
        self._settings.sync()
        self._programState.sync()

    def getUseDefaultDirectory(self):
        return self._settings.value("gui/use_default_dirs", True)

    def setUseDefaultDirectory(self, val):
        self._settings.setValue("gui/use_default_dirs", val)

    #
    # Last directory from which a file has been opened
    #

    def getLatestDirectory(self):
        if self.getUseDefaultDirectory():
            ret = self._programState.value("gui/latest_dir", QDir.homePath())
            if ret:
                return ret
        return QDir.homePath()

    def setLatestDirectory(self, val):
        self._programState.setValue("gui/latest_dir", val)

    #
    # Subtitle "property files" paths, number etc.
    #

    def getPropertyFilesPath(self):
        defaultDirName = "pfiles"
        defaultPath = os.path.join(os.path.dirname(self._programState.fileName()), defaultDirName)
        return self._programState.value("pfiles/path", defaultPath)

    def setPropertyFilesPath(self, val):
        self._programState.setValue("pfiles/path", val)

    def getMaxRememberedPropertyFiles(self):
        defaultMaxValue = 5
        return self._programState.value("pfiles/max", defaultMaxValue)

    def setMaxRememberedPropertyFiles(self, val):
        self._programState.setValue("pfiles/max", val)

    def getLatestPropertyFiles(self):
        return self._programState.value("pfiles/latest", [])

    def addPropertyFile(self, val):
        maxPropertyFiles = self.getMaxRememberedPropertyFiles() - 1
        propertyFiles = self.getLatestPropertyFiles()
        if val in propertyFiles:
            propertyFiles.remove(val)
        else:
            propertyFiles = propertyFiles[:maxPropertyFiles]
        propertyFiles.insert(0, val)
        self._programState.setValue("pfiles/latest", propertyFiles)

    def removePropertyFile(self, val):
        propertyFiles = self.getLatestPropertyFiles()
        try:
            index = propertyFiles.index(val)
            del propertyFiles[index]
            self._programState.setValue("pfiles/latest", propertyFiles)
        except ValueError:
            pass

    #
    # Generic functions for windows/widgets. Please note that passed QWidgets must have previously
    # set objects names via QWidget::setObjectName(str) method. The convention is to use underscores
    # as words separators (e.g. main_window, my_super_widget, etc.).
    #

    def setGeometry(self, widget, val):
        SubAssert(widget.objectName() != "", "Widget's name isn't set!")
        self._programState.setValue("gui/%s/geometry" % widget.objectName(), val)

    def getGeometry(self, widget, default=QByteArray()):
        SubAssert(widget.objectName() != "", "Widget's name isn't set!")
        return self._programState.value("gui/%s/geometry" % widget.objectName(), default)

    def setState(self, widget, val):
        SubAssert(widget.objectName() != "", "Widget's name isn't set!")
        self._programState.setValue("gui/%s/state" % widget.objectName(), val)

    def getState(self, widget, default=QByteArray()):
        SubAssert(widget.objectName() != "", "Widget's name isn't set!")
        return self._programState.value("gui/%s/state" % widget.objectName(), default)

    def setHidden(self, widget, val):
        SubAssert(widget.objectName() != "", "Widget's name isn't set!")
        self._programState.setValue("gui/%s/hidden" % widget.objectName(), val)

    def getHidden(self, widget, default=True):
        SubAssert(widget.objectName() != "", "Widget's name isn't set!")
        return str2Bool(self._programState.value("gui/%s/hidden" % widget.objectName(), default))