Пример #1
0
class Project(object):
    logger = logging.getLogger("main.Project")
    conn = None  # Almacena la conexión principal a la base de datos
    debugLevel = 100
    mainFormName = "Pineboo"
    version = "0.3"
    _initModules = None
    main_window = None
    translators = None
    multiLangEnabled_ = False
    multiLangId_ = QtCore.QLocale().name()[:2].upper()
    translator_ = None
    acl_ = None
    _DGI = None

    def __init__(self, DGI):
        self._DGI = DGI
        self.tree = None
        self.root = None
        self.dbserver = None
        self.dbauth = None
        self.dbname = None
        self.apppath = None
        self.tmpdir = None
        self.parser = None
        self._initModules = []
        if self._DGI.useDesktop():
            if self._DGI.localDesktop():
                self.main_window = importlib.import_module(
                    "pineboolib.plugins.mainform.%s.%s" %
                    (self.mainFormName.lower(),
                     self.mainFormName.lower())).mainWindow
            else:
                self.main_window = self._DGI.mainForm().mainWindow
        self.deleteCache = False
        self.parseProject = False

        self.translator_ = []
        self.actions = {}
        self.tables = {}
        self.files = {}
        self.cur = None
        if not self._DGI.localDesktop():
            self._DGI.extraProjectInit()

    def __del__(self):
        self.writeState()

    def setDebugLevel(self, q):
        Project.debugLevel = q
        qt3ui.Options.DEBUG_LEVEL = q

    """
    Para especificar si usa fllarge unificado o multiple (Eneboo/Abanq)
    """

    def singleFLLarge(self):
        return FLUtil().sqlSelect("flsettings", "valor",
                                  "flkey='FLLargeMode'") == "False"

    """
    Retorna si hay o no acls cargados
    """

    def acl(self):
        return self.acl_

    def consoleShown(self):
        return True

    def load_db(self, dbname, host, port, user, passwd, driveralias):
        self.dbserver = DBServer()
        self.dbserver.host = host
        self.dbserver.port = port
        self.dbserver.type = driveralias
        self.dbauth = DBAuth()
        self.dbauth.username = user
        self.dbauth.password = passwd
        self.dbname = dbname
        self.apppath = filedir("..")
        self.tmpdir = filedir("../tempdata")

        self.actions = {}
        self.tables = {}
        pineboolib.project = self

    def load(self, filename):
        # self.parser = etree.XMLParser(
        #    ns_clean=True,
        #    encoding="UTF-8",
        #    remove_blank_text=True,
        #)
        self.tree = etree.ElementTree.parse(filename)
        self.root = self.tree.getroot()
        self.dbserver = DBServer(one(self.root.find("database-server")))
        self.dbauth = DBAuth(one(self.root.find("database-credentials")))
        self.dbname = one(self.root.find("database-name").text)
        self.apppath = one(self.root.find("application-path").text)
        self.tmpdir = filedir("../tempdata")
        if not getattr(self.dbserver, "host", None):
            self.dbserver.host = None

        if not getattr(self.dbserver, "port", None):
            self.dbserver.port = None

        if not getattr(self.dbserver, "type", None):
            self.dbserver.type = None

        if not self.dbauth:
            self.dbauth.username = None
            self.dbauth.password = None

        self.actions = {}
        self.tables = {}
        pineboolib.project = self

    def coalesce_path(self, *filenames):
        for filename in filenames:
            if filename is None:
                return None
            if filename in self.files:
                return self.files[filename].path()
        raise IOError("None of the files specified were found: %s",
                      repr(filenames))

    def path(self, filename):
        if filename not in self.files:
            self.logger.error("Fichero %s no encontrado en el proyecto.",
                              filename,
                              stack_info=False)
            return None
        return self.files[filename].path()

    def dir(self, *x):
        return os.path.join(self.tmpdir, *x)

    def run(self):
        # TODO: Refactorizar esta función en otras más sencillas
        # Preparar temporal
        if self.deleteCache and not not os.path.exists(
                self.dir("cache/%s" % self.dbname)):
            self.logger.debug("DEVELOP: DeleteCache Activado\nBorrando %s",
                              self.dir("cache/%s" % self.dbname))
            for root, dirs, files in os.walk(self.dir("cache/%s" %
                                                      self.dbname),
                                             topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                for name in dirs:
                    os.rmdir(os.path.join(root, name))
            # borrando de share
            # for root, dirs, files in os.walk(self.dir("../share/pineboo"), topdown=False):
            #    for name in files:
            #        if name.endswith("qs.py") or name.endswith("qs.py.debug") or name.endswith("qs.xml"):
            #            os.remove(os.path.join(root, name))

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

        # Conectar:

        if not self.conn:
            self.conn = PNConnection(self.dbname, self.dbserver.host,
                                     self.dbserver.port, self.dbauth.username,
                                     self.dbauth.password, self.dbserver.type)
        if self.conn.conn is False:
            return False

        # Se verifica que existen estas tablas
        for table in ("flareas", "flmodules", "flfiles", "flgroups", "fllarge",
                      "flserial", "flusers", "flvar"):
            self.conn.manager().createSystemTable(table)

        util = FLUtil()
        util.writeSettingEntry(u"DBA/lastDB", self.dbname)
        self.cur = self.conn.cursor()
        self.areas = {}
        self.cur.execute(
            """ SELECT idarea, descripcion FROM flareas WHERE 1 = 1""")
        for idarea, descripcion in self.cur:
            self.areas[idarea] = Struct(idarea=idarea, descripcion=descripcion)

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

        # Obtener modulos activos
        self.cur.execute(
            """ SELECT idarea, idmodulo, descripcion, icono FROM flmodules WHERE bloqueo = %s """
            % self.conn.driver().formatValue("bool", "True", False))
        self.modules = {}
        for idarea, idmodulo, descripcion, icono in self.cur:
            icono = clearXPM(icono)
            self.modules[idmodulo] = Module(self, idarea, idmodulo,
                                            descripcion, icono)

        file_object = open(filedir("..", "share", "pineboo", "sys.xpm"), "r")
        icono = file_object.read()
        file_object.close()
        icono = clearXPM(icono)

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

        # Descargar proyecto . . .

        self.cur.execute(
            """ SELECT idmodulo, nombre, sha FROM flfiles ORDER BY idmodulo, nombre """
        )
        size_ = len(self.cur.fetchall())
        self.cur.execute(
            """ SELECT idmodulo, nombre, sha FROM flfiles ORDER BY idmodulo, nombre """
        )
        f1 = open(self.dir("project.txt"), "w")
        self.files = {}
        if self._DGI.useDesktop() and self._DGI.localDesktop():
            tiempo_ini = time.time()
        if not os.path.exists(self.dir("cache")):
            raise AssertionError
        # if self.parseProject:
        if self._DGI.useDesktop() and self._DGI.localDesktop():
            util.createProgressDialog("Pineboo", size_)
        p = 0
        for idmodulo, nombre, sha in self.cur:
            p = p + 1
            if self._DGI.useDesktop() and self._DGI.localDesktop():
                util.setProgress(p)
                util.setLabelText("Convirtiendo %s." % nombre)
            if idmodulo not in self.modules:
                continue  # I
            fileobj = File(self, idmodulo, nombre, sha)
            if nombre in self.files:
                self.logger.warn(
                    "run: file %s already loaded, overwritting..." % nombre)
            self.files[nombre] = fileobj
            self.modules[idmodulo].add_project_file(fileobj)
            f1.write(fileobj.filekey + "\n")
            if os.path.exists(self.dir("cache", fileobj.filekey)):
                continue
            fileobjdir = os.path.dirname(self.dir("cache", fileobj.filekey))
            if not os.path.exists(fileobjdir):
                os.makedirs(fileobjdir)

            cur2 = self.conn.cursor()
            sql = "SELECT contenido FROM flfiles WHERE idmodulo = %s AND nombre = %s AND sha = %s" % (
                self.conn.driver().formatValue("string", idmodulo, False),
                self.conn.driver().formatValue("string", nombre, False),
                self.conn.driver().formatValue("string", sha, False))
            cur2.execute(sql)
            for (contenido, ) in cur2:
                f2 = open(self.dir("cache", fileobj.filekey), "wb")
                # La cadena decode->encode corrige el bug de guardado de
                # AbanQ/Eneboo
                txt = ""
                try:
                    # txt = contenido.decode("UTF-8").encode("ISO-8859-15")
                    txt = contenido.encode("ISO-8859-15")
                except Exception:
                    self.logger.exception("Error al decodificar %s %s",
                                          idmodulo, nombre)
                    # txt = contenido.decode("UTF-8","replace").encode("ISO-8859-15","replace")
                    txt = contenido.encode("ISO-8859-15", "replace")

                f2.write(txt)

            if self.parseProject and nombre.endswith(".qs"):
                self.parseScript(self.dir("cache", fileobj.filekey))

        if self._DGI.useDesktop() and self._DGI.localDesktop():
            tiempo_fin = time.time()
            self.logger.info(
                "Descarga del proyecto completo a disco duro: %.3fs",
                (tiempo_fin - tiempo_ini))

        # Cargar el núcleo común del proyecto
        idmodulo = 'sys'
        for root, dirs, files in os.walk(filedir("..", "share", "pineboo")):
            for nombre in files:
                if root.find("modulos") == -1:
                    fileobj = File(self, idmodulo, nombre, basedir=root)
                    self.files[nombre] = fileobj
                    self.modules[idmodulo].add_project_file(fileobj)
                    if self.parseProject and nombre.endswith(".qs"):
                        self.parseScript(self.dir(root, nombre))

        if self._DGI.useDesktop() and self._DGI.localDesktop():
            try:
                util.destroyProgressDialog()
            except Exception as e:
                self.logger.error(e)

        self.loadTranslations()
        self.readState()
        self.acl_ = FLAccessControlLists()
        self.acl_.init_()

    def saveGeometryForm(self, name, geo):
        name = "geo/%s" % name
        FLSettings().writeEntry(name, geo)

    def loadGeometryForm(self, name):
        name = "geo/%s" % name
        return FLSettings().readEntry(name, None)

    @decorators.NotImplementedDebug
    def readState(self):
        pass

    @decorators.NotImplementedDebug
    def writeState(self):
        pass

    def call(self, function, aList, objectContext=None, showException=True):
        # FIXME: No deberíamos usar este método. En Python hay formas mejores
        # de hacer esto.
        self.logger.trace("JS.CALL: fn:%s args:%s ctx:%s",
                          function,
                          aList,
                          objectContext,
                          stack_info=True)

        # Tipicamente flfactalma.iface.beforeCommit_articulos()
        if function[-2:] == "()":
            function = function[:-2]

        aFunction = function.split(".")
        if not aFunction[0] in self.actions:
            if len(aFunction) > 1:
                self.logger.error("No existe la acción %s en el módulo %s",
                                  aFunction[1], aFunction[0])
            else:
                self.logger.error("No existe la acción %s", aFunction[0])
            return False

        funAction = self.actions[aFunction[0]]

        if aFunction[1] == "iface" or len(aFunction) == 2:
            mW = funAction.load()
            funScript = mW.iface
        elif aFunction[1] == "widget":
            fR = None
            funAction.load_script(aFunction[0], fR)
            funScript = fR.iface
        else:
            return False

        if not funScript:
            self.logger.error(
                "No existe el script para la acción %s en el módulo %s",
                aFunction[0], aFunction[0])
            return False

        if len(aFunction) > 2:
            last_ = aFunction[2]
        else:
            last_ = aFunction[1]

        fn = getattr(funScript, last_, None)

        if fn is None:
            self.logger.error("No existe la función %s en %s", last_,
                              aFunction[0])
            return True  # FIXME: Esto devuelve true? debería ser false, pero igual se usa por el motor para detectar propiedades

        try:
            if aList:
                return fn(*aList)
            else:
                return fn()
        except Exception:
            if showException:
                self.logger.exception("js.call: error al llamar %s", function)

        return None

    def loadTranslations(self):
        translatorsCopy = None
        # if self.translators:
        #     translatorsCopy = copy.copy(self.translators)
        #     for it in translatorsCopy:
        #         self.removeTranslator(it)

        lang = QtCore.QLocale().name()[:2]
        for module in self.modules.keys():
            self.loadTranslationFromModule(module, lang)

        if translatorsCopy:
            for it in translatorsCopy:
                item = it
                if item.sysTrans_:
                    self.installTranslator(item)
                else:
                    item.deletelater()

    @decorators.BetaImplementation
    def trMulti(self, s, l):
        backMultiEnabled = self.multiLangEnabled_
        ret = self.translate("%s_MULTILANG" % l.upper().s)
        self.multiLangEnabled_ = backMultiEnabled
        return ret

    @decorators.BetaImplementation
    def setMultiLang(self, enable, langid):
        self.multiLangEnabled_ = enable
        if enable and langid:
            self.multiLangId_ = langid.upper()

    def loadTranslationFromModule(self, idM, lang):
        self.installTranslator(self.createModTranslator(idM, lang, True))
        # self.installTranslator(self.createModTranslator(idM, "mutliLang"))

    def installTranslator(self, tor):
        if not tor:
            return
        else:
            qApp.installTranslator(tor)
            self.translator_.append(tor)

    @decorators.NotImplementedWarn
    def createSysTranslator(self, lang, loadDefault):
        pass

    def createModTranslator(self, idM, lang, loadDefault=False):
        fileTs = "%s.%s.ts" % (idM, lang)
        key = self.conn.managerModules().shaOfFile(fileTs)

        if key is not None or idM == "sys":
            tor = FLTranslator(self, "%s_%s" % (idM, lang),
                               lang == "multilang")

            if tor.loadTsContent(key):
                return tor

        return self.createModTranslator(idM, "es") if loadDefault else None

    @decorators.NotImplementedWarn
    def initToolBox(self):
        pass

    def parseScript(self, scriptname):
        # Intentar convertirlo a Python primero con flscriptparser2
        if not os.path.isfile(scriptname):
            raise IOError
        python_script_path = (scriptname + ".xml.py").replace(
            ".qs.xml.py", ".qs.py")
        if not os.path.isfile(
                python_script_path) or pineboolib.no_python_cache:
            self.logger.info("Convirtiendo a Python . . . %s", scriptname)
            from pineboolib.flparser import postparse
            try:
                postparse.pythonify(scriptname)
            except Exception as e:
                self.logger.warn("El fichero %s no se ha podido convertir: %s",
                                 scriptname, e)

    def reinitP(self):
        if self.acl_:
            self.acl_.init_()

        self.call("sys.widget.init()", [], None, True)

    def resolveDGIObject(self, name):
        obj_ = getattr(self._DGI, name, None)
        if obj_:
            return obj_

        self.logger.warn(
            "Project.resolveSDIObject no puede encontra el objeto %s en %s",
            name, self._DGI.alias())

    def test(self, name=None):
        dirlist = os.listdir(filedir("../pineboolib/plugins/test"))
        testDict = {}
        for f in dirlist:
            if not f[0:2] == "__":
                f = f[:f.find(".py")]
                mod_ = importlib.import_module("pineboolib.plugins.test.%s" %
                                               f)
                test_ = getattr(mod_, f)
                testDict[f] = test_

        maxValue = 0
        value = 0
        result = None
        resultValue = 0
        if name:
            try:
                t = testDict[name]()
                maxValue = t.maxValue()
                value = t.run()
            except Exception:
                result = False
        else:

            for test in testDict.keys():
                print("test", test)
                t = testDict[test]()
                maxValue = maxValue + t.maxValue
                v = t.run()
                print("result", test, v, "/", t.maxValue)
                value = value + v

        if result is None and maxValue > 0:
            resultValue = value

        result = "%s/%s" % (resultValue, maxValue)

        return result
Пример #2
0
    def run(self):
        # TODO: Refactorizar esta función en otras más sencillas
        # Preparar temporal
        if self.deleteCache and not not os.path.exists(
                self.dir("cache/%s" % self.dbname)):
            self.logger.debug("DEVELOP: DeleteCache Activado\nBorrando %s",
                              self.dir("cache/%s" % self.dbname))
            for root, dirs, files in os.walk(self.dir("cache/%s" %
                                                      self.dbname),
                                             topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                for name in dirs:
                    os.rmdir(os.path.join(root, name))
            # borrando de share
            # for root, dirs, files in os.walk(self.dir("../share/pineboo"), topdown=False):
            #    for name in files:
            #        if name.endswith("qs.py") or name.endswith("qs.py.debug") or name.endswith("qs.xml"):
            #            os.remove(os.path.join(root, name))

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

        # Conectar:

        if not self.conn:
            self.conn = PNConnection(self.dbname, self.dbserver.host,
                                     self.dbserver.port, self.dbauth.username,
                                     self.dbauth.password, self.dbserver.type)
        if self.conn.conn is False:
            return False

        # Se verifica que existen estas tablas
        for table in ("flareas", "flmodules", "flfiles", "flgroups", "fllarge",
                      "flserial", "flusers", "flvar"):
            self.conn.manager().createSystemTable(table)

        util = FLUtil()
        util.writeSettingEntry(u"DBA/lastDB", self.dbname)
        self.cur = self.conn.cursor()
        self.areas = {}
        self.cur.execute(
            """ SELECT idarea, descripcion FROM flareas WHERE 1 = 1""")
        for idarea, descripcion in self.cur:
            self.areas[idarea] = Struct(idarea=idarea, descripcion=descripcion)

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

        # Obtener modulos activos
        self.cur.execute(
            """ SELECT idarea, idmodulo, descripcion, icono FROM flmodules WHERE bloqueo = %s """
            % self.conn.driver().formatValue("bool", "True", False))
        self.modules = {}
        for idarea, idmodulo, descripcion, icono in self.cur:
            icono = clearXPM(icono)
            self.modules[idmodulo] = Module(self, idarea, idmodulo,
                                            descripcion, icono)

        file_object = open(filedir("..", "share", "pineboo", "sys.xpm"), "r")
        icono = file_object.read()
        file_object.close()
        icono = clearXPM(icono)

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

        # Descargar proyecto . . .

        self.cur.execute(
            """ SELECT idmodulo, nombre, sha FROM flfiles ORDER BY idmodulo, nombre """
        )
        size_ = len(self.cur.fetchall())
        self.cur.execute(
            """ SELECT idmodulo, nombre, sha FROM flfiles ORDER BY idmodulo, nombre """
        )
        f1 = open(self.dir("project.txt"), "w")
        self.files = {}
        if self._DGI.useDesktop() and self._DGI.localDesktop():
            tiempo_ini = time.time()
        if not os.path.exists(self.dir("cache")):
            raise AssertionError
        # if self.parseProject:
        if self._DGI.useDesktop() and self._DGI.localDesktop():
            util.createProgressDialog("Pineboo", size_)
        p = 0
        for idmodulo, nombre, sha in self.cur:
            p = p + 1
            if self._DGI.useDesktop() and self._DGI.localDesktop():
                util.setProgress(p)
                util.setLabelText("Convirtiendo %s." % nombre)
            if idmodulo not in self.modules:
                continue  # I
            fileobj = File(self, idmodulo, nombre, sha)
            if nombre in self.files:
                self.logger.warn(
                    "run: file %s already loaded, overwritting..." % nombre)
            self.files[nombre] = fileobj
            self.modules[idmodulo].add_project_file(fileobj)
            f1.write(fileobj.filekey + "\n")
            if os.path.exists(self.dir("cache", fileobj.filekey)):
                continue
            fileobjdir = os.path.dirname(self.dir("cache", fileobj.filekey))
            if not os.path.exists(fileobjdir):
                os.makedirs(fileobjdir)

            cur2 = self.conn.cursor()
            sql = "SELECT contenido FROM flfiles WHERE idmodulo = %s AND nombre = %s AND sha = %s" % (
                self.conn.driver().formatValue("string", idmodulo, False),
                self.conn.driver().formatValue("string", nombre, False),
                self.conn.driver().formatValue("string", sha, False))
            cur2.execute(sql)
            for (contenido, ) in cur2:
                f2 = open(self.dir("cache", fileobj.filekey), "wb")
                # La cadena decode->encode corrige el bug de guardado de
                # AbanQ/Eneboo
                txt = ""
                try:
                    # txt = contenido.decode("UTF-8").encode("ISO-8859-15")
                    txt = contenido.encode("ISO-8859-15")
                except Exception:
                    self.logger.exception("Error al decodificar %s %s",
                                          idmodulo, nombre)
                    # txt = contenido.decode("UTF-8","replace").encode("ISO-8859-15","replace")
                    txt = contenido.encode("ISO-8859-15", "replace")

                f2.write(txt)

            if self.parseProject and nombre.endswith(".qs"):
                self.parseScript(self.dir("cache", fileobj.filekey))

        if self._DGI.useDesktop() and self._DGI.localDesktop():
            tiempo_fin = time.time()
            self.logger.info(
                "Descarga del proyecto completo a disco duro: %.3fs",
                (tiempo_fin - tiempo_ini))

        # Cargar el núcleo común del proyecto
        idmodulo = 'sys'
        for root, dirs, files in os.walk(filedir("..", "share", "pineboo")):
            for nombre in files:
                if root.find("modulos") == -1:
                    fileobj = File(self, idmodulo, nombre, basedir=root)
                    self.files[nombre] = fileobj
                    self.modules[idmodulo].add_project_file(fileobj)
                    if self.parseProject and nombre.endswith(".qs"):
                        self.parseScript(self.dir(root, nombre))

        if self._DGI.useDesktop() and self._DGI.localDesktop():
            try:
                util.destroyProgressDialog()
            except Exception as e:
                self.logger.error(e)

        self.loadTranslations()
        self.readState()
        self.acl_ = FLAccessControlLists()
        self.acl_.init_()