示例#1
0
    def loadTsContent(self, key: str) -> bool:
        """
        Load the contents of an existing translation file into the disk cache into the translator.

        The file must be entered in the disk cache before calling this method, in
        Otherwise, nothing will be done.

        @param key Sha1 key that identifies the file in the disk cache
        @return TRUE if the operation was successful
        """
        if self._id_module == "sys":
            ts_file = filedir("./system_module/translations/%s.%s" %
                              (self._id_module, self._lang))
        else:
            if application.PROJECT.conn_manager is None:
                raise Exception("Project is not connected yet")
            ts_file = filedir("%s/cache/%s/%s/file.ts/%s.%s/%s" % (
                application.PROJECT.tmpdir,
                application.PROJECT.conn_manager.useConn("default").DBName(),
                self._id_module,
                self._id_module,
                self._lang,
                key,
            ))
        # qmFile = self.AQ_DISKCACHE_DIRPATH + "/" + key + ".qm"

        ret_ = False
        if not self._translation_from_qm:
            ret_ = self.load_ts("%s.ts" % ts_file)
            if not ret_:
                self.logger.warning("For some reason, i cannot load '%s.ts'",
                                    ts_file)
        else:

            qm_file = "%s.qm" % ts_file
            if os.path.exists(qm_file):
                if ts_file in (None, ""):
                    return False

            else:
                from . import fltranslations

                trans = fltranslations.FLTranslations()
                trans.lrelease("%s.ts" % ts_file, qm_file,
                               not self._multi_lang)

            ret_ = self.load(qm_file)
            if not ret_:
                self.logger.warning("For some reason, i cannot load '%s'",
                                    qm_file)

        return ret_
示例#2
0
    def __init__(
        self, parent: Optional[Any] = None, name: str = "FLDataTable", popup: bool = False
    ):
        """Inicialize."""

        super().__init__(parent)

        if parent:
            self._parent = parent

        self.setObjectName(name)

        self.readonly_ = False
        self.editonly_ = False
        self.insertonly_ = False
        self.refreshing_ = False
        self.filter_ = ""
        self.sort_ = ""
        self.rowSelected = -1
        self.colSelected = -1
        self.primarysKeysChecked_ = []
        self.persistentFilter_ = ""
        self.widthCols_ = {}

        self.pixOk_ = utils_base.filedir("./core/images/icons", "unlock.png")
        self.pixNo_ = utils_base.filedir("./core/images/icons", "lock.png")
        self.paintFieldMtd_ = None
        self.refreshing_ = False
        self.popup_ = False
        self.showAllPixmaps_ = False
        self.onlyTable_ = False
        self.function_get_color = None
        self.changingNumRows_ = False
        self.cursor_ = None

        self._v_header = self.verticalHeader()
        self._v_header.setDefaultSectionSize(22)
        self._h_header = self.horizontalHeader()
        self._h_header.setDefaultSectionSize(120)
        self._h_header.setSectionResizeMode(QtWidgets.QHeaderView.Interactive)
        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.setAlternatingRowColors(True)
        self.setSortingEnabled(True)
        self.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.fltable_iface = None
        self.popup_ = popup
示例#3
0
def setup_gui(app: QtWidgets.QApplication, options: Values) -> None:
    """Configure GUI app."""
    from pineboolib.core.utils.utils_base import filedir
    from PyQt5 import QtGui

    noto_fonts = [
        "NotoSans-BoldItalic.ttf",
        "NotoSans-Bold.ttf",
        "NotoSans-Italic.ttf",
        "NotoSans-Regular.ttf",
    ]
    for fontfile in noto_fonts:
        QtGui.QFontDatabase.addApplicationFont(
            filedir("./core/fonts/Noto_Sans", fontfile))

    style_app: str = settings.config.value("application/style", "Fusion")
    app.setStyle(style_app)  # type: ignore

    default_font = settings.config.value("application/font", None)
    if default_font is None:
        font = QtGui.QFont("Noto Sans", 9)
        font.setBold(False)
        font.setItalic(False)
    else:
        # FIXME: FLSettings.readEntry does not return an array
        font = QtGui.QFont(default_font[0], int(default_font[1]),
                           int(default_font[2]), default_font[3] == "true")

    app.setFont(font)
示例#4
0
    def __init__(self) -> None:
        """Constructor."""
        # self._conn = None
        self.dgi = None
        self.tree = None
        self.root = None
        self.alternative_folder = None
        self.apppath = ""
        self.tmpdir = settings.config.value("ebcomportamiento/temp_dir")
        self.parser = None
        # self.main_form_name: Optional[str] = None
        self.delete_cache = False
        self.parse_project = False
        self.translator_ = []  # FIXME: Add proper type
        self.actions = {}  # FIXME: Add proper type
        self.tables = {}  # FIXME: Add proper type
        self.files = {}  # FIXME: Add proper type
        self.areas = {}
        self.modules = {}
        self.options = Values()
        if self.tmpdir is None:
            self.tmpdir = utils_base.filedir("%s/Pineboo/tempdata" %
                                             Path.home())
            settings.config.set_value("ebcomportamiento/temp_dir", self.tmpdir)

        if not os.path.exists(self.tmpdir):
            Path(self.tmpdir).mkdir(parents=True, exist_ok=True)

        self._session_func_ = None
        self._conn_manager = pnconnectionmanager.PNConnectionManager()
        self.pending_conversion_list = []
示例#5
0
    def setCurrent(val: Optional[str] = None) -> None:
        """
        Change current working folder.

        @param val. Ruta especificada
        """
        os.chdir(val or filedir("."))
示例#6
0
    def initScript(self) -> None:
        """Inicialize main script."""

        self.createUi(
            utils_base.filedir("plugins/mainform/eneboo_mdi/mainform.ui"))

        self.container_ = self
        self.init()
def load_model(nombre):
    """Import and return sqlAlchemy model for given table name."""

    if nombre is None:
        return

    # if nombre in processed_:
    #    return None

    # processed_.append(nombre)

    # nombre_qsa = nombre.replace("_model", "")
    # model_name = nombre_qsa[0].upper() + nombre_qsa[1:]
    # mod = getattr(qsa_dict_modules, model_name, None)
    # if mod is None:
    #    mod = base_model(nombre)
    #    if mod:
    #        setattr(qsa_dict_modules, model_name, mod)  # NOTE: Use application.qsadictmodules

    db_name = application.PROJECT.conn_manager.mainConn().DBName()

    module = None
    file_path = filedir(
        config.value("ebcomportamiento/temp_dir"),
        "cache",
        db_name,
        "models",
        "%s_model.py" % nombre,
    )
    if os.path.exists(file_path):

        module_path = "%s_model" % (nombre)
        # if module_path in sys.modules:
        #    # print("Recargando", module_path)
        #    try:
        #        module = importlib.reload(sys.modules[module_path])
        #    except Exception as exc:
        #        logger.warning("Error recargando módulo:\n%s\n%s", exc, traceback.format_exc())
        #        pass
        # else:
        # print("Cargando", module_path)
        try:
            spec = importlib.util.spec_from_file_location(
                module_path, file_path)  # type: ignore
            module = importlib.util.module_from_spec(spec)  # type: ignore
            sys.modules[spec.name] = module
            spec.loader.exec_module(module)
        except Exception as exc:
            LOGGER.warning("Error cargando módulo:\n%s\n%s", exc,
                           traceback.format_exc())
            pass
            # models_[nombre] = mod

    # if mod:
    #    setattr(qsa_dict_modules, model_name, mod)

    # print(3, nombre, mod)
    return module
示例#8
0
    def setUpClass(cls) -> None:
        """Ensure pineboo is initialized for testing."""
        from pineboolib.core.utils.utils_base import filedir

        db_name = "temp_db"
        dirs = [True, filedir("./application/staticloader/tests/fixtures")]
        config.set_value("StaticLoader/%s/enabled" % (db_name),
                         True)  # Para activar carga estática
        config.set_value("StaticLoader/%s/dirs" % db_name, dirs)
        init_testing()
示例#9
0
 def staticLoaderSetup(self) -> None:
     """
     Display dialog box to configure static load from local disk.
     """
     ui = cast(
         QtWidgets.QDialog,
         self.createUI(
             utils_base.filedir(
                 "./system_module/forms/FLStaticLoaderUI.ui")),
     )
     pnmodulesstaticloader.PNStaticLoader.setup(self.static_db_info_, ui)
示例#10
0
    def init_conn(self, connection: "pnconnection.PNConnection") -> None:
        """Initialize project with a connection."""
        # if self._conn is not None:
        #    del self._conn
        #    self._conn = None

        self._conn_manager.setMainConn(connection)
        self.apppath = utils_base.filedir("..")

        self.delete_cache = settings.config.value(
            "ebcomportamiento/deleteCache", False)
        self.parse_project = settings.config.value(
            "ebcomportamiento/parseProject", False)
示例#11
0
    def test_basic(self) -> None:
        """Test basic functions."""
        from pineboolib.application.parsers.mtdparser import pnmtdparser
        from pineboolib.core.utils.utils_base import filedir
        import os

        file = filedir(
            "%s/cache/temp_db/sys/file.mtd/flmodules_model.py"
            % config.value("ebcomportamiento/temp_dir")
        )
        if os.path.exists(file):
            os.remove(file)
        pnmtdparser.mtd_parse("flmodules")
        self.assertTrue(os.path.exists(file))
示例#12
0
    def test_formRecord(self) -> None:
        """Test formRecord widget."""

        mng_modules = application.PROJECT.conn_manager.managerModules()
        from pineboolib.core.utils.utils_base import filedir

        file_1 = filedir(
            "./application/parsers/qt3uiparser/tests/fixtures/form_record_qt3.ui"
        )
        widget = mng_modules.createUI(file_1)
        self.assertTrue(widget)
        bt_01 = widget.findChild(QtWidgets.QWidget, "pb_uno",
                                 QtCore.Qt.FindChildrenRecursively)
        self.assertTrue(bt_01)
示例#13
0
    def test_mainForm(self) -> None:
        """Test mainForm widget."""

        mng_modules = application.PROJECT.conn_manager.managerModules()
        from pineboolib.core.utils.utils_base import filedir

        file_1 = filedir(
            "./application/parsers/qt3uiparser/tests/fixtures/main_form_qt3.ui"
        )
        widget = mng_modules.createUI(file_1)
        self.assertTrue(widget)

        action = widget.findChild(QtWidgets.QAction, "ebcomportamiento")
        self.assertTrue(action)
示例#14
0
    def loadAllIdModules(self) -> None:
        """
        Load the list of all module identifiers.
        """

        self.list_all_id_modules_ = []
        self.list_all_id_modules_.append("sys")
        self.dict_info_mods_ = {}

        q = pnsqlquery.PNSqlQuery(None, "dbAux")
        q.setTablesList("flmodules,flareas")
        q.setSelect(
            "idmodulo,flmodules.idarea,flmodules.descripcion,version,icono,flareas.descripcion"
        )
        q.setFrom(
            "flmodules left join flareas on flmodules.idarea = flareas.idarea")
        q.setWhere("1 = 1")
        q.setForwardOnly(True)
        q.exec_()
        # q.exec_("SELECT idmodulo,flmodules.idarea,flmodules.descripcion,version,icono,flareas.descripcion "
        #        "FROM flmodules left join flareas on flmodules.idarea = flareas.idarea")

        sys_module_found_ = False
        while q.next():
            info_module_ = FLInfoMod()
            info_module_.idModulo = str(q.value(0))
            info_module_.idArea = str(q.value(1))
            info_module_.descripcion = str(q.value(2))
            info_module_.version = str(q.value(3))
            info_module_.icono = str(q.value(4))
            info_module_.areaDescripcion = str(q.value(5))
            self.dict_info_mods_[info_module_.idModulo.upper()] = info_module_

            if not info_module_.idModulo == "sys":
                self.list_all_id_modules_.append(info_module_.idModulo)
            else:
                sys_module_found_ = True

        if not sys_module_found_:
            info_module_ = FLInfoMod()
            info_module_.idModulo = "sys"
            info_module_.idArea = "sys"
            info_module_.descripcion = "Administracion"
            info_module_.version = "0.0"
            info_module_.icono = self.contentFS(
                "%s/%s" % (utils_base.filedir("./system_module"), "/sys.xpm"))
            info_module_.areaDescripcion = "Sistema"
            self.dict_info_mods_[info_module_.idModulo.upper()] = info_module_
def load_models() -> None:
    """Load all sqlAlchemy models."""

    from pineboolib.application.qsadictmodules import QSADictModules

    if application.PROJECT.conn_manager is None:
        raise Exception("Project is not connected yet")

    main_conn = application.PROJECT.conn_manager.mainConn()

    db_name = main_conn.DBName()
    tables = main_conn.tables()

    QSADictModules.save_other("Base", main_conn.declarative_base())
    QSADictModules.save_other("session", main_conn.session())
    QSADictModules.save_other("engine", main_conn.engine())

    for table in tables:
        try:
            mod = base_model(table)
        except Exception:
            mod = None

        if mod is not None:
            model_name = "%s%s" % (table[0].upper(), table[1:])
            class_ = getattr(mod, model_name, None)
            if class_ is not None:
                QSADictModules.save_other(model_name, class_)

    for root, dirs, files in os.walk(
            filedir(config.value("ebcomportamiento/temp_dir"), "cache",
                    db_name, "models")):
        for nombre in files:  # Buscamos los presonalizados
            if nombre.endswith("pyc"):
                continue
            nombre = nombre.replace("_model.py", "")
            mod = load_model(nombre)
            if mod is not None:
                model_name = "%s%s" % (nombre[0].upper(), nombre[1:])

                class_ = getattr(mod, model_name, None)
                if class_ is not None:
                    QSADictModules.save_other(model_name, class_)
示例#16
0
    def load(self) -> None:
        """Load widget and show."""

        from pineboolib import application
        from pineboolib.core.utils.utils_base import filedir

        dlg_ = filedir(
            "plugins/dgi/dgi_qt/dgi_objects/dlg_about/about_pineboo.ui")
        version_ = application.PROJECT.version
        self.ui: Any = application.PROJECT.conn_manager.managerModules(
        ).createUI(dlg_, None, self)
        if self.ui is None:
            raise Exception("Error creating UI About Dialog")
        self.ui.lbl_version.setText("Pineboo %s" % str(version_))
        self.ui.btn_close.clicked.connect(self.ui.close)
        self.ui.btn_clipboard.clicked.connect(self.to_clipboard)
        self.ui.show()

        self.ui.lbl_librerias.setText(self.load_components())
示例#17
0
    def __init__(self):
        """Inicialize."""
        splash_path = filedir(
            "./core/images/splashscreen/%s240.png" %
            ("dbadmin"
             if config.value("application/dbadmin_enabled") else "quick"))

        splash_pix = QtGui.QPixmap(splash_path)
        self._splash = QtWidgets.QSplashScreen(splash_pix,
                                               QtCore.Qt.WindowStaysOnTopHint)
        self._splash.setMask(splash_pix.mask())

        frameGm = self._splash.frameGeometry()
        screen = QtWidgets.QApplication.desktop().screenNumber(
            QtWidgets.QApplication.desktop().cursor().pos())
        centerPoint = QtWidgets.QApplication.desktop().screenGeometry(
            screen).center()
        frameGm.moveCenter(centerPoint)
        self._splash.move(frameGm.topLeft())
示例#18
0
    def load(self) -> None:
        """
        Load the dlgconnect form.
        """
        from pineboolib.fllegacy.flmanagermodules import FLManagerModules

        dlg_ = filedir("loader/dlgconnect/dlgconnect.ui")

        self._user_interface: Any = FLManagerModules.createUI(dlg_, None, self)
        if not self._user_interface:
            raise Exception("Error creating dlgConnect")
        # Centrado en pantalla
        frame_geo = self.frameGeometry()
        screen = QtWidgets.QApplication.desktop().screenNumber(
            QtWidgets.QApplication.desktop().cursor().pos())
        center_point = QtWidgets.QApplication.desktop().screenGeometry(
            screen).center()
        frame_geo.moveCenter(center_point)
        self.move(frame_geo.topLeft())

        self._user_interface.pbLogin.clicked.connect(self.open)
        self._user_interface.tbOptions.clicked.connect(self.toggleOptions)
        self._user_interface.pbSaveConnection.clicked.connect(self.saveProfile)
        self._user_interface.tbDeleteProfile.clicked.connect(
            self.deleteProfile)
        self._user_interface.tbEditProfile.clicked.connect(self.editProfile)
        self.cleanProfileForm()
        self._user_interface.cbDBType.currentIndexChanged.connect(
            self.updatePort)
        self._user_interface.cbProfiles.currentIndexChanged.connect(
            self.enablePassword)
        self._user_interface.cbAutoLogin.stateChanged.connect(
            self.cbAutoLogin_checked)
        self._user_interface.le_profiles.setText(self.profile_dir)
        self._user_interface.tb_profiles.clicked.connect(
            self.change_profile_dir)
        self.showOptions(False)
        self.loadProfiles()
        self._user_interface.leDescription.textChanged.connect(
            self.updateDBName)
        self._user_interface.installEventFilter(self)
示例#19
0
    def loadControls(self) -> None:
        """Load form controls."""

        self.bottomToolbar = QtWidgets.QFrame()
        if self.bottomToolbar:
            self.bottomToolbar.setMaximumHeight(64)
            self.bottomToolbar.setMinimumHeight(16)
            hblay = QtWidgets.QHBoxLayout()
            hblay.setContentsMargins(0, 0, 0, 0)
            hblay.setSpacing(0)
            hblay.addStretch()
            self.bottomToolbar.setLayout(hblay)
            self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus)
            self.layout_.addWidget(self.bottomToolbar)

        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy(0),
                                           QtWidgets.QSizePolicy.Policy(0))
        sizePolicy.setHeightForWidth(True)

        pbSize = self.iconSize
        if settings.config.value("application/isDebuggerMode", False):

            pushButtonExport = QtWidgets.QToolButton(self)
            pushButtonExport.setObjectName("pushButtonExport")
            pushButtonExport.setSizePolicy(sizePolicy)
            pushButtonExport.setMinimumSize(pbSize)
            pushButtonExport.setMaximumSize(pbSize)
            pushButtonExport.setIcon(
                QtGui.QIcon(
                    utils_base.filedir("./core/images/icons",
                                       "gtk-properties.png")))
            pushButtonExport.setShortcut(Qt.QKeySequence(self.tr("F3")))
            pushButtonExport.setWhatsThis("Exportar a XML(F3)")
            pushButtonExport.setToolTip("Exportar a XML(F3)")
            pushButtonExport.setFocusPolicy(QtCore.Qt.NoFocus)
            self.bottomToolbar.layout().addWidget(pushButtonExport)
            pushButtonExport.clicked.connect(self.exportToXml)

            if settings.config.value("ebcomportamiento/show_snaptshop_button",
                                     False):
                push_button_snapshot = QtWidgets.QToolButton(self)
                push_button_snapshot.setObjectName("pushButtonSnapshot")
                push_button_snapshot.setSizePolicy(sizePolicy)
                push_button_snapshot.setMinimumSize(pbSize)
                push_button_snapshot.setMaximumSize(pbSize)
                push_button_snapshot.setIcon(
                    QtGui.QIcon(
                        utils_base.filedir("./core/images/icons",
                                           "gtk-paste.png")))
                push_button_snapshot.setShortcut(Qt.QKeySequence(
                    self.tr("F8")))
                push_button_snapshot.setWhatsThis("Capturar pantalla(F8)")
                push_button_snapshot.setToolTip("Capturar pantalla(F8)")
                push_button_snapshot.setFocusPolicy(QtCore.Qt.NoFocus)
                self.bottomToolbar.layout().addWidget(push_button_snapshot)
                push_button_snapshot.clicked.connect(self.saveSnapShot)

            spacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
            self.bottomToolbar.layout().addItem(spacer)

        if not self.pushButtonAccept:
            self.pushButtonAccept = QtWidgets.QToolButton(self)
            self.pushButtonAccept.setObjectName("pushButtonAccept")
            self.pushButtonAccept.clicked.connect(self.accept)

        self.pushButtonAccept.setSizePolicy(sizePolicy)
        self.pushButtonAccept.setMaximumSize(pbSize)
        self.pushButtonAccept.setMinimumSize(pbSize)
        self.pushButtonAccept.setIcon(
            QtGui.QIcon(
                utils_base.filedir("./core/images/icons", "gtk-save.png")))
        # pushButtonAccept->setAccel(Qt.QKeySequence(Qt::Key_F10)); FIXME
        self.pushButtonAccept.setFocus()
        self.pushButtonAccept.setWhatsThis(
            "Seleccionar registro actual y cerrar formulario (F10)")
        self.pushButtonAccept.setToolTip(
            "Seleccionar registro actual y cerrar formulario (F10)")
        self.pushButtonAccept.setFocusPolicy(QtCore.Qt.NoFocus)
        self.bottomToolbar.layout().addWidget(self.pushButtonAccept)
        self.pushButtonAccept.show()

        if not self.pushButtonCancel:
            self.pushButtonCancel = QtWidgets.QToolButton(self)
            self.pushButtonCancel.setObjectName("pushButtonCancel")
            self.pushButtonCancel.clicked.connect(self.reject)

        self.pushButtonCancel.setSizePolicy(sizePolicy)
        self.pushButtonCancel.setMaximumSize(pbSize)
        self.pushButtonCancel.setMinimumSize(pbSize)
        self.pushButtonCancel.setIcon(
            QtGui.QIcon(
                utils_base.filedir("./core/images/icons", "gtk-stop.png")))
        self.pushButtonCancel.setFocusPolicy(QtCore.Qt.NoFocus)
        # pushButtonCancel->setAccel(Esc); FIXME
        self.pushButtonCancel.setWhatsThis(
            "Cerrar formulario sin seleccionar registro (Esc)")
        self.pushButtonCancel.setToolTip(
            "Cerrar formulario sin seleccionar registro (Esc)")
        self.bottomToolbar.layout().addWidget(self.pushButtonCancel)
        self.pushButtonCancel.show()
        if self.cursor_ is None:
            raise Exception("Cursor is empty!.")
        self.cursor_.setEdition(False)
        self.cursor_.setBrowse(False)
        self.cursor_.recordChoosed.connect(self.accept)
示例#20
0
    def loadControls(self) -> None:
        """Load widgets for this form."""
        if self.pushButtonAcceptContinue:
            self.pushButtonAcceptContinue.hide()

        if self.pushButtonAccept:
            self.pushButtonAccept.hide()

        if self.pushButtonCancel:
            self.pushButtonCancel.hide()

        if self.pushButtonFirst:
            self.pushButtonFirst.hide()

        if self.pushButtonPrevious:
            self.pushButtonPrevious.hide()

        if self.pushButtonNext:
            self.pushButtonNext.hide()

        if self.pushButtonLast:
            self.pushButtonLast.hide()

        if self.bottomToolbar and self.toolButtonClose:
            self.toolButtonClose.hide()

        self.bottomToolbar = QtWidgets.QFrame()

        if self.bottomToolbar:
            self.bottomToolbar.setMinimumSize(self.iconSize)
            hblay = QtWidgets.QHBoxLayout()
            hblay.setContentsMargins(0, 0, 0, 0)
            hblay.setSpacing(0)
            hblay.addStretch()
            self.bottomToolbar.setLayout(hblay)
            self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus)
            self.layout_.addWidget(self.bottomToolbar)

        else:
            raise Exception("bottomToolbar is missing!")
        # if self.layout:
        #    self.layout = None
        # Limpiamos la toolbar

        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy(0),
                                           QtWidgets.QSizePolicy.Policy(0))
        sizePolicy.setHeightForWidth(True)

        pbSize = self.iconSize

        if settings.config.value("application/isDebuggerMode", False):

            pushButtonExport = QtWidgets.QToolButton()
            pushButtonExport.setObjectName("pushButtonExport")
            pushButtonExport.setSizePolicy(sizePolicy)
            pushButtonExport.setMinimumSize(pbSize)
            pushButtonExport.setMaximumSize(pbSize)
            pushButtonExport.setIcon(
                QtGui.QIcon(
                    utils_base.filedir("./core/images/icons",
                                       "gtk-properties.png")))
            pushButtonExport.setShortcut(Qt.QKeySequence(self.tr("F3")))
            pushButtonExport.setWhatsThis("Exportar a XML(F3)")
            pushButtonExport.setToolTip("Exportar a XML(F3)")
            pushButtonExport.setFocusPolicy(QtCore.Qt.NoFocus)
            self.bottomToolbar.layout().addWidget(pushButtonExport)
            pushButtonExport.clicked.connect(self.exportToXml)

            if settings.config.value("ebcomportamiento/show_snaptshop_button",
                                     False):
                push_button_snapshot = QtWidgets.QToolButton()
                push_button_snapshot.setObjectName("pushButtonSnapshot")
                push_button_snapshot.setSizePolicy(sizePolicy)
                push_button_snapshot.setMinimumSize(pbSize)
                push_button_snapshot.setMaximumSize(pbSize)
                push_button_snapshot.setIcon(
                    QtGui.QIcon(
                        utils_base.filedir("./core/images/icons",
                                           "gtk-paste.png")))
                push_button_snapshot.setShortcut(Qt.QKeySequence(
                    self.tr("F8")))
                push_button_snapshot.setWhatsThis("Capturar pantalla(F8)")
                push_button_snapshot.setToolTip("Capturar pantalla(F8)")
                push_button_snapshot.setFocusPolicy(QtCore.Qt.NoFocus)
                self.bottomToolbar.layout().addWidget(push_button_snapshot)
                push_button_snapshot.clicked.connect(self.saveSnapShot)

            spacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
            self.bottomToolbar.layout().addItem(spacer)

        if self.cursor().modeAccess() in (self.cursor().Edit,
                                          self.cursor().Browse):
            if not self.pushButtonFirst:
                self.pushButtonFirst = QtWidgets.QToolButton()
                self.pushButtonFirst.setObjectName("pushButtonFirst")
                self.pushButtonFirst.setIcon(
                    QtGui.QIcon(
                        utils_base.filedir("./core/images/icons",
                                           "gtk-goto-first-ltr.png")))
                self.pushButtonFirst.clicked.connect(self.firstRecord)
                self.pushButtonFirst.setSizePolicy(sizePolicy)
                self.pushButtonFirst.setMaximumSize(pbSize)
                self.pushButtonFirst.setMinimumSize(pbSize)
                self.pushButtonFirst.setShortcut(Qt.QKeySequence(
                    self.tr("F5")))
                self.pushButtonFirst.setWhatsThis(
                    "Aceptar los cambios e ir al primer registro (F5)")
                self.pushButtonFirst.setToolTip(
                    "Aceptar los cambios e ir al primer registro (F5)")
                self.pushButtonFirst.setFocusPolicy(QtCore.Qt.NoFocus)
                self.bottomToolbar.layout().addWidget(self.pushButtonFirst)
                # self.pushButtonFirst.show()

            if not self.pushButtonPrevious:
                self.pushButtonPrevious = QtWidgets.QToolButton()
                self.pushButtonPrevious.setObjectName("pushButtonPrevious")
                self.pushButtonPrevious.setIcon(
                    QtGui.QIcon(
                        utils_base.filedir("./core/images/icons",
                                           "gtk-go-back-ltr.png")))
                self.pushButtonPrevious.clicked.connect(self.previousRecord)
                self.pushButtonPrevious.setSizePolicy(sizePolicy)
                self.pushButtonPrevious.setMaximumSize(pbSize)
                self.pushButtonPrevious.setMinimumSize(pbSize)
                self.pushButtonPrevious.setShortcut(
                    Qt.QKeySequence(self.tr("F6")))
                self.pushButtonPrevious.setWhatsThis(
                    "Aceptar los cambios e ir al registro anterior (F6)")
                self.pushButtonPrevious.setToolTip(
                    "Aceptar los cambios e ir al registro anterior (F6)")
                self.pushButtonPrevious.setFocusPolicy(QtCore.Qt.NoFocus)
                self.bottomToolbar.layout().addWidget(self.pushButtonPrevious)
                # self.pushButtonPrevious.show()

            if not self.pushButtonNext:
                self.pushButtonNext = QtWidgets.QToolButton()
                self.pushButtonNext.setObjectName("pushButtonNext")
                self.pushButtonNext.setIcon(
                    QtGui.QIcon(
                        utils_base.filedir("./core/images/icons",
                                           "gtk-go-back-rtl.png")))
                self.pushButtonNext.clicked.connect(self.nextRecord)
                self.pushButtonNext.setSizePolicy(sizePolicy)
                self.pushButtonNext.setMaximumSize(pbSize)
                self.pushButtonNext.setMinimumSize(pbSize)
                self.pushButtonNext.setShortcut(Qt.QKeySequence(self.tr("F7")))
                self.pushButtonNext.setWhatsThis(
                    "Aceptar los cambios e ir al registro siguiente (F7)")
                self.pushButtonNext.setToolTip(
                    "Aceptar los cambios e ir al registro siguiente (F7)")
                self.pushButtonNext.setFocusPolicy(QtCore.Qt.NoFocus)
                self.bottomToolbar.layout().addWidget(self.pushButtonNext)
                # self.pushButtonNext.show()

            if not self.pushButtonLast:
                self.pushButtonLast = QtWidgets.QToolButton()
                self.pushButtonLast.setObjectName("pushButtonLast")
                self.pushButtonLast.setIcon(
                    QtGui.QIcon(
                        utils_base.filedir("./core/images/icons",
                                           "gtk-goto-last-ltr.png")))
                self.pushButtonLast.clicked.connect(self.lastRecord)
                self.pushButtonLast.setSizePolicy(sizePolicy)
                self.pushButtonLast.setMaximumSize(pbSize)
                self.pushButtonLast.setMinimumSize(pbSize)
                self.pushButtonLast.setShortcut(Qt.QKeySequence(self.tr("F8")))
                self.pushButtonLast.setWhatsThis(
                    "Aceptar los cambios e ir al último registro (F8)")
                self.pushButtonLast.setToolTip(
                    "Aceptar los cambios e ir al último registro (F8)")
                self.pushButtonLast.setFocusPolicy(QtCore.Qt.NoFocus)
                self.bottomToolbar.layout().addWidget(self.pushButtonLast)
                # self.pushButtonLast.show()

        if not self.cursor().modeAccess() == self.cursor().Browse:
            self.pushButtonAcceptContinue = QtWidgets.QToolButton()
            self.pushButtonAcceptContinue.setObjectName(
                "pushButtonAcceptContinue")
            self.pushButtonAcceptContinue.clicked.connect(self.acceptContinue)
            self.pushButtonAcceptContinue.setSizePolicy(sizePolicy)
            self.pushButtonAcceptContinue.setMaximumSize(pbSize)
            self.pushButtonAcceptContinue.setMinimumSize(pbSize)
            self.pushButtonAcceptContinue.setIcon(
                QtGui.QIcon(
                    utils_base.filedir("./core/images/icons",
                                       "gtk-refresh.png")))
            self.pushButtonAcceptContinue.setShortcut(
                Qt.QKeySequence(self.tr("F9")))
            self.pushButtonAcceptContinue.setWhatsThis(
                "Aceptar los cambios y continuar con la edición de un nuevo registro (F9)"
            )
            self.pushButtonAcceptContinue.setToolTip(
                "Aceptar los cambios y continuar con la edición de un nuevo registro (F9)"
            )
            self.pushButtonAcceptContinue.setFocusPolicy(QtCore.Qt.NoFocus)
            self.bottomToolbar.layout().addWidget(
                self.pushButtonAcceptContinue)
            if not self.showAcceptContinue_:
                self.pushButtonAcceptContinue.close()
                # self.pushButtonAcceptContinue.show()

            if not self.pushButtonAccept:
                self.pushButtonAccept = QtWidgets.QToolButton()
                self.pushButtonAccept.setObjectName("pushButtonAccept")
                self.pushButtonAccept.clicked.connect(self.accept)

            self.pushButtonAccept.setSizePolicy(sizePolicy)
            self.pushButtonAccept.setMaximumSize(pbSize)
            self.pushButtonAccept.setMinimumSize(pbSize)
            self.pushButtonAccept.setIcon(
                QtGui.QIcon(
                    utils_base.filedir("./core/images/icons", "gtk-save.png")))
            self.pushButtonAccept.setShortcut(Qt.QKeySequence(self.tr("F10")))
            self.pushButtonAccept.setWhatsThis(
                "Aceptar los cambios y cerrar formulario (F10)")
            self.pushButtonAccept.setToolTip(
                "Aceptar los cambios y cerrar formulario (F10)")
            self.pushButtonAccept.setFocusPolicy(QtCore.Qt.NoFocus)
            self.bottomToolbar.layout().addWidget(self.pushButtonAccept)
            # self.pushButtonAccept.show()

        if not self.pushButtonCancel:
            self.pushButtonCancel = QtWidgets.QToolButton()
            self.pushButtonCancel.setObjectName("pushButtonCancel")
            try:
                self.cursor().autoCommit.connect(self.disablePushButtonCancel)
            except Exception:
                pass

            self.pushButtonCancel.clicked.connect(self.reject)

        self.pushButtonCancel.setSizePolicy(sizePolicy)
        self.pushButtonCancel.setMaximumSize(pbSize)
        self.pushButtonCancel.setMinimumSize(pbSize)
        self.pushButtonCancel.setShortcut(Qt.QKeySequence(self.tr("Esc")))
        self.pushButtonCancel.setIcon(
            QtGui.QIcon(
                utils_base.filedir("./core/images/icons", "gtk-stop.png")))
        if not self.cursor().modeAccess() == self.cursor().Browse:
            self.pushButtonCancel.setFocusPolicy(QtCore.Qt.NoFocus)
            self.pushButtonCancel.setWhatsThis(
                "Cancelar los cambios y cerrar formulario (Esc)")
            self.pushButtonCancel.setToolTip(
                "Cancelar los cambios y cerrar formulario (Esc)")
        else:
            self.pushButtonCancel.setFocusPolicy(QtCore.Qt.StrongFocus)
            self.pushButtonCancel.setFocus()
            # pushButtonCancel->setAccel(4096); FIXME
            self.pushButtonCancel.setWhatsThis(
                "Aceptar y cerrar formulario (Esc)")
            self.pushButtonCancel.setToolTip(
                "Aceptar y cerrar formulario (Esc)")

        # pushButtonCancel->setDefault(true);
        self.bottomToolbar.layout().addItem(
            QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed,
                                  QtWidgets.QSizePolicy.Fixed))
        self.bottomToolbar.layout().addWidget(self.pushButtonCancel)
        # self.pushButtonAccept.show()

        self.setFocusPolicy(QtCore.Qt.NoFocus)

        # self.toolButtonAccept = QtGui.QToolButton()
        # self.toolButtonAccept.setIcon(QtGui.QIcon(utils_base.filedir("./core/images/icons","gtk-add.png")))
        # self.toolButtonAccept.clicked.connect(self.validateForm)
        # self.bottomToolbar.layout.addWidget(self.toolButtonAccept)
        self.inicializeControls()
示例#21
0
class ProjectConfig:
    """
    Read and write XML on profiles. Represents a database connection configuration.
    """

    SAVE_VERSION = VERSION_1_2  #: Version for saving

    #: Folder where to read/write project configs.
    profile_dir: str = filedir(
        config.value("ebcomportamiento/profiles_folder",
                     "%s/Pineboo/profiles" % Path.home()))

    version: VersionNumber  #: Version number for the profile read.
    fernet: Optional[Fernet]  #: Cipher used, if any.

    database: str  #: Database Name, file path to store it, or :memory:
    host: Optional[str]  #: DB server Hostname. None for local files.
    port: Optional[int]  #: DB server port. None for local files.
    username: Optional[str]  #: Database User login name.
    password: Optional[str]  #: Database User login password.
    type: str  #: Driver Type name to use when connecting
    project_password: str  #: Password to cipher when load/saving. Empty string for no ciphering.
    password_required: bool  #: True if a password is required to read data. (Was partially loaded.)
    description: str  #: Project name in GUI
    filename: str  #: File path to read / write this project from / to

    def __init__(
        self,
        database: Optional[str] = None,
        host: Optional[str] = None,
        port: Optional[int] = None,
        type: Optional[str] = None,
        username: Optional[str] = None,
        password: Optional[str] = None,
        load_xml: Optional[str] = None,
        connstring: Optional[str] = None,
        description: Optional[str] = None,
        filename: Optional[str] = None,
        project_password: str = "",
    ) -> None:
        """Initialize."""
        self.project_password = project_password
        self.password_required = False
        self.version = self.SAVE_VERSION
        self.fernet = None

        if connstring:
            username, password, type, host, port, database = self.translate_connstring(
                connstring)
        elif load_xml:
            self.filename = os.path.join(
                self.profile_dir,
                load_xml if load_xml.endswith("xml") else "%s.xml" % load_xml)
            self.load_projectxml()
            return
        if database is None:
            raise ValueError(
                "Database is mandatory. Or use load_xml / connstring params")
        if type is None:
            raise ValueError(
                "Type is mandatory. Or use load_xml / connstring params")
        self.database = database
        self.host = host
        self.port = port
        self.type = type
        self.username = username
        self.password = password
        self.description = description if description else "unnamed"
        if filename is None:
            file_basename = self.description.lower().replace(" ", "_")
            self.filename = os.path.join(self.profile_dir,
                                         "%s.xml" % file_basename)
        else:
            self.filename = os.path.join(self.profile_dir, filename)

    def get_uri(self, show_password: bool = False) -> str:
        """Get connection as an URI."""
        host_port = ""
        if self.host:
            host_port += self.host
        if self.port:
            host_port += ":%d" % self.port

        user_pass = ""
        if self.username:
            user_pass += self.username
        if self.password:
            if show_password:
                user_pass += ":%s" % self.password
            else:
                pass_bytes: bytes = hashlib.sha256(
                    self.password.encode()).digest()
                user_pass += ":*" + base64.b64encode(pass_bytes).decode()[:4]

        if user_pass:
            user_pass = "******" % user_pass

        uri = host_port + user_pass

        if self.database:
            if uri:
                uri += "/"
            uri += self.database

        return "[%s]://%s" % (self.type, uri)

    def __repr__(self) -> str:
        """Display the information in text mode."""
        if self.project_password:
            # 4 chars in base-64 is 3 bytes. 256**3 should be enough to know if you have the wrong
            # password.
            pass_bytes: bytes = hashlib.sha256(
                self.project_password.encode()).digest()
            passwd = "-" + base64.b64encode(pass_bytes).decode()[:4]
        else:
            passwd = ""
        return "<ProjectConfig%s name=%r uri=%r>" % (
            passwd,
            self.description,
            self.get_uri(show_password=False),
        )

    def __eq__(self, other: Any) -> bool:
        """Test for equality."""
        if not isinstance(other, ProjectConfig):
            return False
        if other.type != self.type:
            return False
        if other.get_uri(show_password=True) != self.get_uri(
                show_password=True):
            return False
        if other.description != self.description:
            return False
        if other.project_password != self.project_password:
            return False
        return True

    def load_projectxml(self) -> bool:
        """Collect the connection information from an xml file."""

        file_name = self.filename
        if not os.path.isfile(file_name):
            raise ValueError("El proyecto %r no existe." % file_name)

        tree = ET.parse(file_name)
        root = tree.getroot()
        version = VersionNumber(root.get("Version"), default="1.0")
        self.version = version
        self.description = ""
        for xmldescription in root.findall("name"):
            self.description = xmldescription.text or ""
        profile_pwd = ""
        for profile in root.findall("profile-data"):
            profile_pwd = getattr(profile.find("password"), "text", "")
            if profile_pwd:
                break

        self.password_required = True
        self.checkProfilePasswordForVersion(self.project_password, profile_pwd,
                                            version)

        if self.project_password and self.version > VERSION_1_1:
            key_salt = hashlib.sha256(profile_pwd.encode()).digest()
            key = hashlib.pbkdf2_hmac("sha256", self.project_password.encode(),
                                      key_salt, 10000)
            key64 = base64.urlsafe_b64encode(key)
            self.fernet = Fernet(key64)
        else:
            self.fernet = None

        from pineboolib.application.database.pnsqldrivers import PNSqlDrivers

        sql_drivers_manager = PNSqlDrivers()
        self.database = self.retrieveCipherSubElement(root, "database-name")
        for db in root.findall("database-server"):
            self.host = self.retrieveCipherSubElement(db, "host")
            port_text = self.retrieveCipherSubElement(db, "port")
            self.port = int(port_text) if port_text else None
            self.type = self.retrieveCipherSubElement(db, "type")

            # FIXME: Move this to project, or to the connection handler.
            if self.type not in sql_drivers_manager.aliasList():
                LOGGER.warning(
                    "Esta versión de pineboo no soporta el driver '%s'" %
                    self.type)

        for credentials in root.findall("database-credentials"):
            self.username = self.retrieveCipherSubElement(
                credentials, "username")
            self.password = self.retrieveCipherSubElement(
                credentials, "password")
            if self.password and self.fernet is None:
                self.password = base64.b64decode(self.password).decode()
        self.password_required = False

        return True

    @classmethod
    def encodeProfilePasswordForVersion(cls, password: str,
                                        save_version: VersionNumber) -> str:
        """
        Hash a password for a profile/projectconfig using the protocol for specified version.
        """
        if password == "":
            return ""
        if save_version < VERSION_1_1:
            return password

        if save_version < VERSION_1_2:
            return hashlib.sha256(password.encode()).hexdigest()
        # Minimum salt size recommended is 8 bytes
        # multiple of 3 bytes as it is shorter in base64
        salt = os.urandom(9)
        hmac = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 10000)
        dict_passwd = {
            # Algorithm:
            # .. pbkdf2: short algorithm name
            # .. sha256: hash function used
            # .. 4: number of zeroes used on iterations
            "algorithm": "pbkdf2-sha256-4",
            "salt": base64.b64encode(salt).decode(),
            "hash": base64.b64encode(hmac).decode(),
        }
        hashed_password = "******" % dict_passwd

        return hashed_password

    @classmethod
    def checkProfilePasswordForVersion(cls, user_pwd: str, profile_pwd: str,
                                       version: VersionNumber) -> None:
        """
        Check a saved password against a user-supplied one.

        user_pwd: User-supplied password in clear text.
        profile_pwd: Raw data saved as password in projectconfig file.
        version: Version number used for checks.

        This function returns None and raises PasswordMismatchError if the password is wrong.
        We can only check if it is good. It's not a good idea to check if two encoded passwords
        are the same, because most secure methods will store different encoded versions every
        time we try to encode again.
        """
        if not profile_pwd:
            return

        if version < VERSION_1_1:
            if user_pwd == profile_pwd:
                return
            raise PasswordMismatchError("La contraseña es errónea")

        if version < VERSION_1_2:
            user_hash = hashlib.sha256(user_pwd.encode()).hexdigest()
            if profile_pwd == user_hash:
                return
            raise PasswordMismatchError("La contraseña es errónea")

        algo, *algo_extra = profile_pwd.split(":")
        if algo != "pbkdf2-sha256-4":
            raise Exception("Unsupported password algorithm %r" % algo)

        salt64, hash64 = algo_extra

        salt = base64.b64decode(salt64.encode())

        user_hash2 = hashlib.pbkdf2_hmac("sha256", user_pwd.encode(), salt,
                                         10000)
        user_hash64 = base64.b64encode(user_hash2).decode()
        if user_hash64 == hash64:
            return

        raise PasswordMismatchError("La contraseña es errónea")

    def createCipherSubElement(self, parent: ET.Element, tagname: str,
                               text: str) -> ET.Element:
        """Create a XML SubElement ciphered if self.fernet is present."""
        child = ET.SubElement(parent, tagname)
        if self.fernet is None:
            child.text = text
            return child
        # NOTE: This method returns ciphertext even for empty strings! This is intended.
        # ... this is to avoid anyone knowing if a field is empty or not.
        if len(text) < 64:
            # Right Pad with new line at least up to 64 bytes. Avoid giving out field size.
            text = text.ljust(64, "\n")
        encoded_bytes = self.fernet.encrypt(text.encode())
        encoded_text = base64.b64encode(encoded_bytes).decode()
        child.set("cipher-method", "cryptography.Fernet")
        child.set("cipher-text", encoded_text)
        return child

    def retrieveCipherSubElement(self, parent: ET.Element,
                                 tagname: str) -> str:
        """Get a XML SubElement ciphered if self.fernet is present."""
        child = parent.find(tagname)
        if child is None:
            raise ValueError("Tag %r not present" % tagname)

        cipher_method = child.get("cipher-method")
        if cipher_method is None:
            return child.text or ""
        if self.fernet is None:
            raise Exception(
                "Tried to load ciphered tag %r with no loaded cipher" %
                tagname)
        cipher_text = child.get("cipher-text")
        if cipher_method != "cryptography.Fernet":
            raise ValueError("Cipher method %r not supported." % cipher_method)

        if not cipher_text:
            raise ValueError("Missing ciphertext for %r" % tagname)

        cipher_bytes = base64.b64decode(cipher_text.encode())
        text = self.fernet.decrypt(cipher_bytes).decode()
        text = text.rstrip("\n")
        return text

    def save_projectxml(self, overwrite_existing: bool = True) -> None:
        """
        Save the connection.
        """
        profile = ET.Element("Profile")
        profile.set("Version", str(self.SAVE_VERSION))
        description = self.description
        filename = self.filename
        if not os.path.exists(self.profile_dir):
            os.mkdir(self.profile_dir)

        if not overwrite_existing and os.path.exists(filename):
            raise ProfileAlreadyExistsError

        passwDB = self.password or ""

        profile_user = ET.SubElement(profile, "profile-data")
        profile_password = ET.SubElement(profile_user, "password")
        profile_password.text = self.encodeProfilePasswordForVersion(
            self.project_password, self.SAVE_VERSION)
        if self.project_password and self.SAVE_VERSION > VERSION_1_1:
            key_salt = hashlib.sha256(profile_password.text.encode()).digest()
            key = hashlib.pbkdf2_hmac("sha256", self.project_password.encode(),
                                      key_salt, 10000)
            key64 = base64.urlsafe_b64encode(key)
            self.fernet = Fernet(key64)
        else:
            # Mask the password if no cipher is used!
            passwDB = base64.b64encode(passwDB.encode()).decode()
            self.fernet = None
        name = ET.SubElement(profile, "name")
        name.text = description
        dbs = ET.SubElement(profile, "database-server")
        self.createCipherSubElement(dbs, "type", text=self.type)
        self.createCipherSubElement(dbs, "host", text=self.host or "")
        self.createCipherSubElement(dbs,
                                    "port",
                                    text=str(self.port) if self.port else "")

        dbc = ET.SubElement(profile, "database-credentials")
        self.createCipherSubElement(dbc, "username", text=self.username or "")
        self.createCipherSubElement(dbc, "password", text=passwDB)

        self.createCipherSubElement(profile,
                                    "database-name",
                                    text=self.database)

        pretty_print_xml(profile)

        tree = ET.ElementTree(profile)

        tree.write(filename, xml_declaration=True, encoding="utf-8")
        self.version = self.SAVE_VERSION

    @classmethod
    def translate_connstring(
            cls, connstring: str) -> Tuple[str, str, str, str, int, str]:
        """
        Translate a DSN connection string into user, pass, etc.

        Accept a "connstring" parameter that has the form user @ host / dbname
        and returns all parameters separately. It takes into account the
        default values ​​and the different abbreviations that exist.
        """
        user = "******"
        passwd = ""
        host = "127.0.0.1"
        port = "5432"
        driver_alias = "PostgreSQL (PSYCOPG2)"
        user_pass = None
        host_port = None
        if "/" not in connstring:
            dbname = connstring
            if not re.match(r"\w+", dbname):
                raise ValueError("base de datos no valida")
            return user, passwd, driver_alias, host, int(port), dbname

        uphpstring = connstring[:connstring.rindex("/")]
        dbname = connstring[connstring.rindex("/") + 1:]
        up, hp = uphpstring.split("@")
        conn_list = [None, None, up, hp]
        _user_pass, _host_port = conn_list[-2], conn_list[-1]

        if _user_pass:
            user_pass = _user_pass.split(":") + ["", "", ""]
            user, passwd, driver_alias = (
                user_pass[0],
                user_pass[1] or passwd,
                user_pass[2] or driver_alias,
            )
            if user_pass[3]:
                raise ValueError(
                    "La cadena de usuario debe tener el formato user:pass:driver."
                )

        if _host_port:
            host_port = _host_port.split(":") + [""]
            host, port = host_port[0], host_port[1] or port
            if host_port[2]:
                raise ValueError("La cadena de host debe ser host:port.")

        if not re.match(r"\w+", user):
            raise ValueError("Usuario no valido")
        if not re.match(r"\w+", dbname):
            raise ValueError("base de datos no valida")
        if not re.match(r"\d+", port):
            raise ValueError("puerto no valido")
        LOGGER.debug(
            "user:%s, passwd:%s, driver_alias:%s, host:%s, port:%s, dbname:%s",
            user,
            "*" * len(passwd),
            driver_alias,
            host,
            port,
            dbname,
        )
        return user, passwd, driver_alias, host, int(port), dbname
示例#22
0
    def run(self) -> bool:
        """Run project. Connects to DB and loads data."""

        self.pending_conversion_list = []

        if self.actions:
            del self.actions

        if self.tables:
            del self.tables

        self.actions = {}
        self.tables = {}

        if self.dgi is None:
            raise Exception("DGI not loaded")

        if not self.conn_manager or "main_conn" not in self.conn_manager.connections_dict.keys(
        ):
            raise exceptions.NotConnectedError(
                "Cannot execute Pineboo Project without a connection in place")

        conn = self.conn_manager.mainConn()
        db_name = conn.DBName()
        # TODO: Refactorizar esta función en otras más sencillas
        # Preparar temporal

        if self.delete_cache and os.path.exists(path._dir(
                "cache/%s" % db_name)):

            self.message_manager().send("splash", "showMessage",
                                        ["Borrando caché ..."])
            LOGGER.debug("DEVELOP: delete_cache Activado\nBorrando %s",
                         path._dir("cache/%s" % db_name))
            for root, dirs, files in os.walk(path._dir("cache/%s" % db_name),
                                             topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                for name in dirs:
                    os.rmdir(os.path.join(root, name))

        else:
            keep_images = settings.config.value(
                "ebcomportamiento/keep_general_cache", False)
            if keep_images is False:
                for file_name in os.listdir(self.tmpdir):
                    if file_name.find(".") > -1 and not file_name.endswith(
                            "sqlite3"):
                        file_path = os.path.join(self.tmpdir, file_name)
                        try:
                            os.remove(file_path)
                        except Exception:
                            LOGGER.warning(
                                "No se ha podido borrar %s al limpiar la cache",
                                file_path)
                            pass

        if not os.path.exists(path._dir("cache")):
            os.makedirs(path._dir("cache"))

        if not os.path.exists(path._dir("cache/%s" % db_name)):
            os.makedirs(path._dir("cache/%s" % db_name))

        # Conectar:

        # Se verifica que existen estas tablas
        for table in (
                "flareas",
                "flmodules",
                "flfiles",
                "flgroups",
                "fllarge",
                "flserial",
                "flusers",
                "flvar",
                "flmetadata",
                "flsettings",
                "flupdates",
                "flmetadata",
                "flseqs",
                "flsettings",
        ):
            if not self.conn_manager.manager().existsTable(table):
                self.conn_manager.manager().createSystemTable(table)

        cursor_ = self.conn_manager.dbAux().cursor()
        self.areas = {}
        cursor_.execute(
            """ SELECT idarea, descripcion FROM flareas WHERE 1 = 1""")
        for idarea, descripcion in list(cursor_):
            self.areas[idarea] = AreaStruct(idarea=idarea,
                                            descripcion=descripcion)

        self.areas["sys"] = AreaStruct(idarea="sys",
                                       descripcion="Area de Sistema")

        # Obtener módulos activos
        cursor_.execute(
            """ SELECT idarea, idmodulo, descripcion, icono FROM flmodules WHERE bloqueo = %s """
            % conn.driver().formatValue("bool", "True", False))

        self.modules = {}

        for idarea, idmodulo, descripcion, icono in cursor_:
            icono = xpm.cache_xpm(icono)
            self.modules[idmodulo] = module.Module(idarea, idmodulo,
                                                   descripcion, icono)

        file_object = open(
            utils_base.filedir(utils_base.get_base_dir(), "system_module",
                               "sys.xpm"), "r")
        icono = file_object.read()
        file_object.close()
        # icono = clearXPM(icono)

        self.modules["sys"] = module.Module("sys", "sys", "Administración",
                                            icono)

        cursor_.execute(
            """ SELECT idmodulo, nombre, sha FROM flfiles WHERE NOT sha = '' ORDER BY idmodulo, nombre """
        )

        file_1 = open(path._dir("project.txt"), "w")
        self.files = {}

        count = 0

        list_files: List[str] = []

        for idmodulo, nombre, sha in list(cursor_):
            if not self.dgi.accept_file(nombre):
                continue

            count += 1
            if idmodulo not in self.modules:
                continue  # I
            fileobj = file.File(idmodulo, nombre, sha, db_name=db_name)
            if nombre in self.files:
                LOGGER.warning("run: file %s already loaded, overwritting..." %
                               nombre)
            self.files[nombre] = fileobj
            self.modules[idmodulo].add_project_file(fileobj)
            file_1.write(fileobj.filekey + "\n")

            fileobjdir = os.path.dirname(path._dir("cache", fileobj.filekey))
            file_name = path._dir("cache", fileobj.filekey)
            if not os.path.exists(fileobjdir):
                os.makedirs(fileobjdir)

            if os.path.exists(file_name):
                if file_name.endswith(".qs"):
                    folder_path = os.path.dirname(file_name)
                    static_flag = "%s/STATIC" % folder_path
                    file_name_py = "%s.py" % file_name[:-3]
                    if os.path.exists(static_flag):
                        os.remove(static_flag)
                        if os.path.exists(file_name):
                            os.remove(file_name)
                        if os.path.exists(file_name_py):
                            os.remove(file_name_py)

                    elif os.path.exists(file_name_py):
                        continue

                elif file_name.endswith(".mtd"):
                    if settings.config.value(
                            "ebcomportamiento/orm_enabled",
                            False) and not settings.config.value(
                                "ebcomportamiento/orm_parser_disabled", False):
                        if os.path.exists(
                                "%s_model.py" %
                                path._dir("cache", fileobj.filekey[:-4])):
                            continue
                else:
                    continue

            cur2 = self.conn_manager.useConn("dbAux").cursor()
            sql = (
                "SELECT contenido FROM flfiles WHERE idmodulo = %s AND nombre = %s AND sha = %s"
                % (
                    conn.driver().formatValue("string", idmodulo, False),
                    conn.driver().formatValue("string", nombre, False),
                    conn.driver().formatValue("string", sha, False),
                ))
            cur2.execute(sql)
            for (contenido, ) in list(cur2):

                encode_ = "utf-8" if str(nombre).endswith(
                    (".kut", ".ts", ".py")) else "ISO-8859-15"

                folder = path._dir(
                    "cache",
                    "/".join(
                        fileobj.filekey.split("/")
                        [:len(fileobj.filekey.split("/")) - 1]),
                )
                if os.path.exists(folder) and not os.path.exists(
                        file_name
                ):  # Borra la carpeta si no existe el fichero destino
                    for root, dirs, files in os.walk(folder):
                        for file_item in files:
                            os.remove(os.path.join(root, file_item))

                if contenido and not os.path.exists(file_name):
                    self.message_manager().send(
                        "splash", "showMessage",
                        ["Volcando a caché %s..." % nombre])
                    file_2 = open(file_name, "wb")
                    txt = contenido.encode(encode_, "replace")
                    file_2.write(txt)
                    file_2.close()

            if self.parse_project and nombre.endswith(".qs"):
                if os.path.exists(file_name):
                    list_files.append(file_name)

        file_1.close()
        self.message_manager().send("splash", "showMessage",
                                    ["Convirtiendo a Python ..."])

        if list_files:
            self.parse_script_list(list_files)

        # Cargar el núcleo común del proyecto

        for root, dirs, files in os.walk(
                utils_base.filedir(utils_base.get_base_dir(),
                                   "system_module")):
            # list_files = []
            for nombre in files:
                if root.find("modulos") == -1:
                    fileobj = file.File("sys",
                                        nombre,
                                        basedir=root,
                                        db_name=db_name)
                    self.files[nombre] = fileobj
                    self.modules["sys"].add_project_file(fileobj)

                    # if self.parse_project and nombre.endswith(".qs"):
                    # self.parseScript(path._dir(root, nombre))
                    #    list_files.append(path._dir(root, nombre))

            # self.parse_script_lists(list_files)

        if settings.config.value(
                "ebcomportamiento/orm_enabled",
                False) and not settings.config.value(
                    "ebcomportamiento/orm_load_disabled", False):
            self.message_manager().send("splash", "showMessage",
                                        ["Cargando objetos ..."])
            from pineboolib.application.parsers.mtdparser import pnormmodelsfactory

            pnormmodelsfactory.load_models()

        # FIXME: ACLs needed at this level?
        # self.acl_ = FLAccessControlLists()
        # self.acl_.init()

        return True
示例#23
0
    def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.DisplayRole) -> Any:
        """
        Retrieve information about a record.

        (overload of QAbstractTableModel)
        Could return alignment, backgroun color, value... depending on role.

        @param index. Register position
        @param role. information type required
        @return solicited data
        """

        row = index.row()
        col = index.column()
        field = self.metadata().indexFieldObject(col)
        _type = field.type()
        res_color_function: List[str] = []
        if _type != "check":

            # r = [x for x in self._data[row]]
            # self._data[row] = r
            # d = r[col]
            # self.seekRow(row)
            # d = self._current_row_data[col]
            # d = self._data[row][col]
            result: Any = None
            if row not in self.grid_row_tmp.keys():
                self.grid_row_tmp = {}
                self.grid_row_tmp[row] = self.driver_sql().getRow(
                    row, self._curname, self.cursorDB()
                )
                if not self.grid_row_tmp[row]:  # refresh grid if cursor is deleted.
                    self.refresh()
                    return

            tuple = self.grid_row_tmp[row]
            if tuple:
                result = tuple[col]

        else:
            primary_key = str(self.value(row, self.metadata().primaryKey()))
            if primary_key not in self._check_column.keys():
                result = QtWidgets.QCheckBox()
                self._check_column[primary_key] = result

        if self.parent_view and role in [QtCore.Qt.BackgroundRole, QtCore.Qt.ForegroundRole]:
            fun_get_color, iface = self.parent_view.functionGetColor()
            if fun_get_color is not None:
                context_ = None
                fun_name_ = None
                if fun_get_color.find(".") > -1:
                    list_ = fun_get_color.split(".")
                    from pineboolib.application.safeqsa import SafeQSA

                    qsa_widget = SafeQSA.get_any(list_[0])
                    fun_name_ = list_[1]
                    if qsa_widget:
                        context_ = qsa_widget.iface
                else:
                    context_ = iface
                    fun_name_ = fun_get_color

                function_color = getattr(context_, fun_name_, None)
                if function_color is not None:
                    field_name = field.name()
                    field_value = result
                    cursor = self._parent
                    selected = False
                    res_color_function = function_color(
                        field_name, field_value, cursor, selected, _type
                    )
                else:
                    raise Exception(
                        "No se ha resuelto functionGetColor %s desde %s" % (fun_get_color, context_)
                    )
        # print("Data ", index, role)
        # print("Registros", self.rowCount())
        # roles
        # 0 QtCore.Qt.DisplayRole
        # 1 QtCore.Qt.DecorationRole
        # 2 QtCore.Qt.EditRole
        # 3 QtCore.Qt.ToolTipRole
        # 4 QtCore.Qt.StatusTipRole
        # 5 QtCore.Qt.WhatThisRole
        # 6 QtCore.Qt.FontRole
        # 7 QtCore.Qt.TextAlignmentRole
        # 8 QtCore.Qt.BackgroundRole
        # 9 QtCore.Qt.ForegroundRole

        if role == QtCore.Qt.CheckStateRole and _type == "check":
            if primary_key in self._check_column.keys():
                if self._check_column[primary_key].isChecked():
                    return QtCore.Qt.Checked

            return QtCore.Qt.Unchecked

        elif role == QtCore.Qt.TextAlignmentRole:
            result = QtCore.Qt.AlignVCenter
            if _type in ("int", "double", "uint"):
                result = result | QtCore.Qt.AlignRight
            elif _type in ("bool", "date", "time"):
                result = result | QtCore.Qt.AlignCenter
            elif _type in ("unlock", "pixmap"):
                result = result | QtCore.Qt.AlignHCenter

            return result

        elif role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
            if not field.visible():
                result = None
            # r = self._vdata[row]
            elif _type == "bool":
                if result in (True, "1"):
                    result = "Sí"
                else:
                    result = "No"

            elif _type in ("unlock", "pixmap"):

                result = None

            elif _type in ("string", "stringlist", "timestamp") and not result:
                result = ""

            elif _type == "time" and result:
                result = str(result)

            elif _type == "date":
                # Si es str lo paso a datetime.date
                if isinstance(result, str):
                    if len(result.split("-")[0]) == 4:
                        result = date_conversion.date_amd_to_dma(result)

                    if result:
                        list_ = result.split("-")
                        result = datetime.date(int(list_[2]), int(list_[1]), int(list_[0]))

                if isinstance(result, datetime.date):
                    # Cogemos el locale para presentar lo mejor posible la fecha
                    try:
                        locale.setlocale(locale.LC_TIME, "")
                        if os.name == "nt":
                            date_format = "%%d/%%m/%%y"
                        else:
                            date_format = locale.nl_langinfo(locale.D_FMT)
                        date_format = date_format.replace("y", "Y")  # Año con 4 dígitos
                        date_format = date_format.replace("/", "-")  # Separadores
                        result = result.strftime(date_format)
                    except AttributeError:
                        import platform

                        self.logger.warning(
                            "locale specific date format is not yet implemented for %s",
                            platform.system(),
                        )

            elif _type == "check":
                return

            elif _type == "double":
                if result is not None:
                    # d = QtCore.QLocale.system().toString(float(d), "f", field.partDecimal())
                    result = utils_base.format_double(
                        result, field.partInteger(), field.partDecimal()
                    )
            elif _type in ("int", "uint"):
                if result is not None:
                    result = QtCore.QLocale.system().toString(int(result))
            if self.parent_view is not None:
                self.parent_view.resize_column(col, result)

            return result

        elif role == QtCore.Qt.DecorationRole:
            pixmap = None
            if _type in ("unlock", "pixmap") and self.parent_view:
                row_height = self.parent_view.rowHeight(row)  # Altura row
                row_width = self.parent_view.columnWidth(col)

                if _type == "unlock":
                    if result in (True, "1"):
                        pixmap = QtGui.QPixmap(
                            utils_base.filedir("./core/images/icons", "unlock.png")
                        )
                    else:
                        pixmap = QtGui.QPixmap(
                            utils_base.filedir("./core/images/icons", "lock.png")
                        )
                else:
                    if not self._parent.private_cursor._is_system_table:
                        data = self.db().connManager().manager().fetchLargeValue(result)
                    else:
                        data = xpm.cache_xpm(result)

                    pixmap = QtGui.QPixmap(data)
                    if not pixmap.isNull():
                        new_size = row_height - 1
                        if new_size > row_width:
                            new_size = row_width

                        pixmap = pixmap.scaled(new_size, new_size)

                if self.parent_view.showAllPixmap() or row == self.parent_view.cur.at():
                    if pixmap and not pixmap.isNull() and self.parent_view:
                        new_pixmap = QtGui.QPixmap(row_width, row_height)  # w , h
                        center_width = (row_width - pixmap.width()) / 2
                        center_height = (row_height - pixmap.height()) / 2
                        new_pixmap.fill(QtCore.Qt.transparent)
                        painter = Qt.QPainter(new_pixmap)
                        painter.drawPixmap(
                            center_width, center_height, pixmap.width(), pixmap.height(), pixmap
                        )

                        pixmap = new_pixmap

            return pixmap

        elif role == QtCore.Qt.BackgroundRole:
            if _type == "bool":
                if result in (True, "1"):
                    result = QtGui.QBrush(QtCore.Qt.green)
                else:
                    result = QtGui.QBrush(QtCore.Qt.red)

            elif _type == "check":
                obj_ = self._check_column[primary_key]
                result = (
                    QtGui.QBrush(QtCore.Qt.green)
                    if obj_.isChecked()
                    else QtGui.QBrush(QtCore.Qt.white)
                )

            else:
                if res_color_function and len(res_color_function) and res_color_function[0] != "":
                    color_ = QtGui.QColor(res_color_function[0])
                    style_ = getattr(QtCore.Qt, res_color_function[2], None)
                    result = QtGui.QBrush(color_)
                    result.setStyle(style_)
                else:
                    result = None

            return result

        elif role == QtCore.Qt.ForegroundRole:
            if _type == "bool":
                if result in (True, "1"):
                    result = QtGui.QBrush(QtCore.Qt.black)
                else:
                    result = QtGui.QBrush(QtCore.Qt.white)
            else:
                if res_color_function and len(res_color_function) and res_color_function[1] != "":
                    color_ = QtGui.QColor(res_color_function[1])
                    style_ = getattr(QtCore.Qt, res_color_function[2], None)
                    result = QtGui.QBrush(color_)
                    result.setStyle(style_)
                else:
                    result = None

            return result

        # else:
        #    print("role desconocido", role)

        return None
示例#24
0
    def cargarConfiguracion(self) -> None:
        """Load configuration."""
        w = self.w_
        w.findChild(QtWidgets.QWidget, u"cbFLTableDC").setChecked(
            self.leerValorLocal("FLTableDoubleClick")
        )
        w.findChild(QtWidgets.QWidget, u"cbFLTableSC").setChecked(
            self.leerValorLocal("FLTableShortCut")
        )
        w.findChild(QtWidgets.QWidget, u"cbFLTableCalc").setChecked(
            self.leerValorLocal("FLTableExport2Calc")
        )
        w.findChild(QtWidgets.QWidget, u"cbDebuggerMode").setChecked(
            self.leerValorLocal("isDebuggerMode")
        )
        w.findChild(QtWidgets.QWidget, u"cbSLConsola").setChecked(self.leerValorLocal("SLConsola"))
        w.findChild(QtWidgets.QWidget, u"leCallFunction").setText(
            self.leerValorLocal("ebCallFunction")
        )
        w.findChild(QtWidgets.QWidget, u"leMaxPixImages").setText(
            self.leerValorLocal("maxPixImages")
        )
        w.findChild(QtWidgets.QWidget, u"leNombreVertical").setText(
            self.leerValorGlobal("verticalName")
        )
        w.findChild(QtWidgets.QWidget, u"cbFLLarge").setChecked(
            self.leerValorGlobal("FLLargeMode") == "True"
        )
        w.findChild(QtWidgets.QWidget, u"cbPosInfo").setChecked(
            self.leerValorGlobal("PosInfo") == "True"
        )
        w.findChild(QtWidgets.QWidget, u"cbMobile").setChecked(self.leerValorLocal("mobileMode"))
        w.findChild(QtWidgets.QWidget, u"cbDeleteCache").setChecked(
            self.leerValorLocal("deleteCache")
        )
        w.findChild(QtWidgets.QWidget, u"cbParseProject").setChecked(
            self.leerValorLocal("parseProject")
        )
        w.findChild(QtWidgets.QWidget, u"cbActionsMenuRed").setChecked(
            self.leerValorLocal("ActionsMenuRed")
        )
        w.findChild(QtWidgets.QWidget, u"cbSpacerLegacy").setChecked(
            self.leerValorLocal("spacerLegacy")
        )
        w.findChild(QtWidgets.QWidget, u"cbParseModulesOnLoad").setChecked(
            self.leerValorLocal("parseModulesOnLoad")
        )
        w.findChild(QtWidgets.QWidget, u"cb_traducciones").setChecked(
            self.leerValorLocal("translations_from_qm")
        )
        w.findChild(QtWidgets.QWidget, "le_temporales").setText(self.leerValorLocal("temp_dir"))
        w.findChild(QtWidgets.QWidget, "cb_kut_debug").setChecked(
            self.leerValorLocal("kugar_debug_mode")
        )
        w.findChild(QtWidgets.QWidget, "cb_no_borrar_cache").setChecked(
            self.leerValorLocal("keep_general_cache")
        )
        w.findChild(QtWidgets.QWidget, "cb_snapshot").setChecked(
            self.leerValorLocal("show_snaptshop_button")
        )
        w.findChild(QtWidgets.QWidget, "cb_imagenes").setChecked(
            self.leerValorLocal("no_img_cached")
        )
        w.findChild(QtWidgets.QWidget, "cb_dbadmin").setChecked(
            self.leerValorLocal("dbadmin_enabled")
        )
        w.findChild(QtWidgets.QWidget, "cb_orm_enabled").setChecked(
            self.leerValorLocal("orm_enabled")
        )
        w.findChild(QtWidgets.QWidget, "cb_disable_mtdparser").setChecked(
            self.leerValorLocal("orm_parser_disabled")
        )
        w.findChild(QtWidgets.QWidget, "cb_disable_orm_load").setChecked(
            self.leerValorLocal("orm_load_disabled")
        )
        autoComp = self.leerValorLocal("autoComp")
        if not autoComp or autoComp == "OnDemandF4":
            autoComp = "Bajo Demanda (F4)"
        elif autoComp == "NeverAuto":
            autoComp = "Nunca"
        else:
            autoComp = "Siempre"
        w.findChild(QtWidgets.QWidget, u"cbAutoComp").setCurrentText = autoComp

        w.findChild(QtWidgets.QWidget, u"leCO").hide()
        self.colorActual_ = self.leerValorLocal("colorObligatorio")
        if not self.colorActual_:
            self.colorActual_ = "#FFE9AD"

        w.findChild(QtWidgets.QWidget, u"leCO").setStyleSheet(
            "background-color:" + self.colorActual_
        )

        # Actualizaciones.
        from pineboolib.core.utils.utils_base import filedir
        import os

        if os.path.exists(filedir("../.git")):
            w.findChild(QtWidgets.QWidget, "cb_git_activar").setChecked(
                self.leerValorLocal("git_updates_enabled")
            )
            ruta = self.leerValorLocal("git_updates_repo")
            if ruta is False:
                ruta = "https://github.com/Aulla/pineboo.git"
            w.findChild(QtWidgets.QWidget, "le_git_ruta").setText(ruta)
            self.module_connect(
                w.findChild(QtWidgets.QWidget, "pb_git_test"),
                u"clicked()",
                self,
                "search_git_updates",
            )
        else:
            w.findChild(QtWidgets.QWidget, "tbwLocales").setTabEnabled(5, False)

        w.findChild(QtWidgets.QWidget, u"leCO").show()
示例#25
0
    def createUI(
        file_name: str,
        connection: Optional["iconnection.IConnection"] = None,
        parent: Optional["QtWidgets.QWidget"] = None,
    ) -> "QtWidgets.QWidget":
        """
        Create a form from its description file.

        Use the FLManagerModules :: contentCached () method to get the XML text it describes the formula.

        @param file_name Name of the file that contains the description of the form.
        @param parent. Parent widget
        @return QWidget corresponding to the built form.
        """

        if ".ui" not in file_name:
            file_name += ".ui"

        form_path = file_name if os.path.exists(file_name) else path._path(
            file_name)
        conn_manager = application.PROJECT.conn_manager

        if "main_conn" in conn_manager.connections_dict.keys():
            mng_modules = conn_manager.managerModules()
            if mng_modules.static_db_info_ and mng_modules.static_db_info_.enabled_:
                ret_ui = mng_modules.contentStatic(file_name, True)

                if ret_ui is not None:
                    form_path = ret_ui

        if form_path is None:
            # raise AttributeError("File %r not found in project" % n)
            logger.debug("createUI: No se encuentra el fichero %s", file_name)

            return QtWidgets.QWidget()

        tree = utils_base.load2xml(form_path)

        if not tree:
            return parent or QtWidgets.QWidget()

        root_ = tree.getroot()

        UIVersion = root_.get("version")
        if UIVersion is None:
            UIVersion = "1.0"
        if parent is None:

            wid = root_.find("widget")
            if wid is None:
                raise Exception(
                    "No parent provided and also no <widget> found")
            xclass = wid.get("class")
            if xclass is None:
                raise Exception("class was expected")

            if UIVersion < "4.0":
                if xclass == "QMainWindow":
                    parent = qmainwindow.QMainWindow()
                elif xclass in ["QDialog", "QWidget"]:
                    parent = qdialog.QDialog()
            else:
                if xclass == "QMainWindow":
                    parent = QtWidgets.QMainWindow()
                elif xclass in ["QDialog", "QWidget"]:
                    parent = QtWidgets.QDialog()

            if parent is None:
                raise Exception("xclass not found %s" % xclass)

        if hasattr(parent, "widget"):
            w_ = parent.widget  # type: ignore [attr-defined] # noqa F821
        else:
            w_ = parent

        logger.info("Procesando %s (v%s)", file_name, UIVersion)
        if UIVersion < "4.0":
            qt3ui.load_ui(form_path, w_)
        else:
            from PyQt5 import uic  # type: ignore

            qtWidgetPlugings = utils_base.filedir("plugins/custom_widgets")
            if qtWidgetPlugings not in uic.widgetPluginPath:
                logger.warning("Añadiendo path %s a uic.widgetPluginPath",
                               qtWidgetPlugings)
                uic.widgetPluginPath.append(qtWidgetPlugings)
            uic.loadUi(form_path, w_)

        return w_
示例#26
0
    def contentCached(self, file_name: str, sha_key=None) -> Optional[str]:
        """
        Get the contents of a file, using the memory and disk cache.

        This method first looks for the content of the requested file in the
        Internal cache, if not, you get it with the FLManagerModules :: content () method.

        @param file_name File name.
        @return QString with the contents of the file or None in case of error.
        """
        sys_table: bool = False

        if file_name.endswith(".mtd"):
            if file_name[0:3] == "sys":
                sys_table = True
            else:
                sys_table = self.conn_.connManager().manager().isSystemTable(
                    file_name)

        if not sys_table and self.static_db_info_ and self.static_db_info_.enabled_:
            str_ret = self.contentStatic(file_name)
            if str_ret is not None:
                return str_ret

        if file_name in self.filesCached_.keys():
            return self.filesCached_[file_name]

        data = None
        modId: str
        name_: str = file_name[:file_name.index(".")]
        ext_: str = file_name[file_name.index(".") + 1:]
        type_: Optional[str] = None
        if ext_ == "kut":
            type_ = "reports/"
        elif ext_ == "qs":
            type_ = "scritps/"
        elif ext_ == "mtd":
            type_ = "tables/"
        elif ext_ == "ui":
            type_ = "forms/"
        elif ext_ == "qry":
            type_ = "queries/"
        elif ext_ == "ts":
            type_ = "translations/"
        elif ext_ == "xml":
            type_ = ""

        if sys_table:
            modId = "sys"
        else:
            modId = self.idModuleOfFile(file_name)
            if not sha_key:
                cursor = self.conn_.execute_query(
                    "SELECT sha FROM flfiles WHERE nombre='%s'" % file_name)

                for contenido in cursor:
                    sha_key = contenido[0]

        # if not PROJECT._DGI:
        #    raise Exception("DGI not loaded")

        # if PROJECT.DGI.alternative_content_cached():
        #    data = project.DGI.content_cached(
        #        project.tmpdir, self.conn_.DBName(), modId, ext_, name_, sha_key
        #    )
        #    if data is not None:
        #        return data

        if data is None:
            """Ruta por defecto"""
            if os.path.exists("%s/cache/%s/%s/file.%s/%s" %
                              (application.PROJECT.tmpdir, self.conn_.DBName(),
                               modId, ext_, name_)):
                utf8_ = True if ext_ == "kut" else False
                data = self.contentFS(
                    "%s/cache/%s/%s/file.%s/%s/%s.%s" % (
                        application.PROJECT.tmpdir,
                        self.conn_.DBName(),
                        modId,
                        ext_,
                        name_,
                        sha_key,
                        ext_,
                    ),
                    utf8_,
                )

        if data is None:
            if os.path.exists(
                    utils_base.filedir("./system_module/%s%s.%s" %
                                       (type_, name_, ext_))):
                data = self.contentFS(
                    utils_base.filedir("./system_module/%s%s.%s" %
                                       (type_, name_, ext_)))
            else:
                data = self.content(file_name)

        if data is not None:
            self.filesCached_[file_name] = data
        return data
示例#27
0
 def set_current(self, new_path: Optional[str] = None) -> None:
     """Set new patch."""
     os.chdir(new_path or filedir("."))
示例#28
0
    def loadControls(self) -> None:
        """Load form controls."""

        if self.pushButtonCancel:
            self.pushButtonCancel.hide()

        if self.bottomToolbar and self.toolButtonClose:
            self.toolButtonClose.hide()
        self.bottomToolbar = QtWidgets.QFrame()

        if self.bottomToolbar is None:
            raise Exception("bottomToolBar is empty!")

        if self.iconSize is not None:
            self.bottomToolbar.setMinimumSize(self.iconSize)

        hblay = QtWidgets.QHBoxLayout()

        hblay.setContentsMargins(0, 0, 0, 0)
        hblay.setSpacing(0)
        hblay.addStretch()
        self.bottomToolbar.setLayout(hblay)
        self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus)
        if self.layout_ is not None:
            self.layout_.addWidget(self.bottomToolbar)
        # if self.layout:
        #    self.layout = None
        # Limpiamos la toolbar

        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy(0),
                                           QtWidgets.QSizePolicy.Policy(0))
        sizePolicy.setHeightForWidth(True)

        pbSize = self.iconSize

        if settings.config.value("application/isDebuggerMode", False):

            pushButtonExport = QtWidgets.QToolButton()
            pushButtonExport.setObjectName("pushButtonExport")
            pushButtonExport.setSizePolicy(sizePolicy)
            pushButtonExport.setMinimumSize(pbSize)
            pushButtonExport.setMaximumSize(pbSize)
            pushButtonExport.setIcon(
                QtGui.QIcon(
                    utils_base.filedir("./core/images/icons",
                                       "gtk-properties.png")))
            pushButtonExport.setShortcut(QtGui.QKeySequence(self.tr("F3")))
            pushButtonExport.setWhatsThis(
                QtWidgets.QApplication.translate("FLFormDB",
                                                 "Exportar a XML(F3)"))
            pushButtonExport.setToolTip(
                QtWidgets.QApplication.translate("FLFormDB",
                                                 "Exportar a XML(F3)"))
            pushButtonExport.setFocusPolicy(QtCore.Qt.NoFocus)
            self.bottomToolbar.layout().addWidget(pushButtonExport)
            pushButtonExport.clicked.connect(self.exportToXml)

            if settings.config.value("ebcomportamiento/show_snaptshop_button",
                                     False):
                push_button_snapshot = QtWidgets.QToolButton()
                push_button_snapshot.setObjectName("pushButtonSnapshot")
                push_button_snapshot.setSizePolicy(sizePolicy)
                push_button_snapshot.setMinimumSize(pbSize)
                push_button_snapshot.setMaximumSize(pbSize)
                push_button_snapshot.setIcon(
                    QtGui.QIcon(
                        utils_base.filedir("./core/images/icons",
                                           "gtk-paste.png")))
                push_button_snapshot.setShortcut(
                    QtGui.QKeySequence(self.tr("F8")))
                push_button_snapshot.setWhatsThis("Capturar pantalla(F8)")
                push_button_snapshot.setToolTip("Capturar pantalla(F8)")
                push_button_snapshot.setFocusPolicy(QtCore.Qt.NoFocus)
                self.bottomToolbar.layout().addWidget(push_button_snapshot)
                push_button_snapshot.clicked.connect(self.saveSnapShot)

            spacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
            self.bottomToolbar.layout().addItem(spacer)

        if not self.pushButtonCancel:
            self.pushButtonCancel = QtWidgets.QToolButton()
            self.pushButtonCancel.setObjectName("pushButtonCancel")
            cast(QtCore.pyqtSignal, self.pushButtonCancel.clicked).connect(
                cast(Callable, self.close))

        self.pushButtonCancel.setSizePolicy(sizePolicy)
        self.pushButtonCancel.setMaximumSize(pbSize)
        self.pushButtonCancel.setMinimumSize(pbSize)
        self.pushButtonCancel.setIcon(
            QtGui.QIcon(
                utils_base.filedir("./core/images/icons", "gtk-stop.png")))
        # self.pushButtonCancel.setFocusPolicy(QtCore.Qt.StrongFocus)
        # self.pushButtonCancel.setFocus()
        self.pushButtonCancel.setShortcut(QtGui.QKeySequence(self.tr("Esc")))
        self.pushButtonCancel.setWhatsThis("Cerrar formulario (Esc)")
        self.pushButtonCancel.setToolTip("Cerrar formulario (Esc)")
        self.bottomToolbar.layout().addWidget(self.pushButtonCancel)
        self.setFocusPolicy(QtCore.Qt.NoFocus)
示例#29
0
 def installPrefix(self) -> str:
     """Get folder where app is installed."""
     return filedir("..")