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
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_()