def sqlInsert(self, t, fL, vL, connName="default"): """ Realiza la inserción de un registro en una tabla mediante un objeto FLSqlCursor @param t Nombre de la tabla @param fL Lista separada con comas de los nombres de los campos @param vL Lista separada con comas de los valores correspondientes @param connName Nombre de la conexion @return Verdadero en caso de realizar la inserción con éxito, falso en cualquier otro caso """ from pineboolib.fllegacy.FLSqlCursor import FLSqlCursor fL = fL.split(",") vL = vL.split(",") if not len(fL) == len(vL): return False c = FLSqlCursor(t, True, connName) c.setModeAccess(FLSqlCursor.Insert) c.refreshBuffer() i = 0 for f in fL: if vL[i] is None: c.bufferSetNull(f) else: c.setValueBuffer(f, vL[i]) i = i + 1 return c.commitBuffer()
def initCursor(self): filtro = None self._cursorLoaded = True if not self._foreignField: return if not self._fieldRelation: return if not self._tableName: return if self._loaded: tipo = self._cursor.model().fieldType(self._fieldRelation) foranea = self._parent.parentWidget().cursor().valueBuffer( self._foreignField) if foranea is None: #print("FLTable(%s): campo foraneo \"%s.%s\" no encontrado." % (self._tableName,self._parent.parentWidget()._cursor.table(), self._foreignField)) return if tipo is "uint": self._foreignFilter = "%s = %s" % ( self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer( self._foreignField)) else: self._foreignFilter = "%s = '%s'" % ( self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer( self._foreignField)) #print("Filtro:%s" % filtro) self._cursor.setMainFilter(self._foreignFilter) self._cursor.refresh() else: self._cursor = FLSqlCursor(self._tableName)
def __init__(self, *args, **kwargs): parent = None name = None action = None if isinstance(args[0], str): # @param actionName Nombre de la acción asociada al formulario if len(args) == 2: parent = args[1] name = args[0] self.setAction(name) action = self.action if action is None: return table = action.table if not table: return self.cursor_ = FLSqlCursor(table, True, "default", None, None, self) self.accepted_ = False elif isinstance(args[0], FLSqlCursor): # @param cursor Objeto FLSqlCursor para asignar a este formulario # @param actionName Nombre de la acción asociada al formulario if len(args) == 3: parent = args[2] name = args[1] self.cursor_ = args[0] action = self.cursor_._action elif len(args) == 2: action = args[0] parent = args[1] name = action.name() self.cursor_ = FLSqlCursor(action.table(), True, "default", None, None, self) if not parent: parent = QtWidgets.QApplication.activeModalWidget() super(FLFormSearchDB, self).__init__(parent, action, load=True) self.setFocusPolicy(QtCore.Qt.NoFocus) if not name: print("FLFormSearchDB : Nombre de acción vacío") return if not action: print("FLFormSearchDB : No existe la acción", name) return self.eventloop = QtCore.QEventLoop()
def init(self): """ Acciones de inicialización. """ self.initCount_ = self.initCount_ + 1 self.createSystemTable("flmetadata") self.createSystemTable("flseqs") if not self.db_.dbAux(): return q = FLSqlQuery(None, self.db_.dbAux()) # q.setForwardOnly(True) self.createSystemTable("flsettings") if not q.exec_("SELECT * FROM flsettings WHERE flkey = 'sysmodver'"): if pineboolib.project.conn.driver().cascadeSupport(): q.exec_("DROP TABLE flsettings CASCADE") else: q.exec_("DROP TABLE flsettings") self.createSystemTable("flsettings") if not self.dictKeyMetaData_: self.dictKeyMetaData_ = {} # self.dictKeyMetaData_.setAutoDelete(True) else: self.dictKeyMetaData_.clear() q.exec_("SELECT tabla,xml FROM flmetadata") while q.next(): self.dictKeyMetaData_[q.value(0)] = q.value(1) q.exec_("SELECT * FROM flsettings WHERE flkey = 'sysmodver'") if not q.next(): if pineboolib.project.conn.driver().cascadeSupport(): q.exec_("DROP TABLE flmetadata CASCADE") else: q.exec_("DROP TABLE flmetadata") self.createSystemTable("flmetadata") c = FLSqlCursor("flmetadata", True, self.db_.dbAux()) for key, value in self.dictKeyMetaData_: buffer = c.primeInsert() buffer.setValue("tabla", key) buffer.setValue("xml", value) c.insert() if not self.cacheMetaData_: self.cacheMetaData_ = [] if not self.cacheAction_: self.cacheAction_ = [] if not self.cacheMetaDataSys_: self.cacheMetaDataSys_ = []
def initCursor(self): filtro = None self._cursorLoaded = True if not self._foreignField: return if not self._fieldRelation: return if not self._tableName: return if self._loaded: tipo = self._cursor.model().fieldType(self._fieldRelation) foranea = self._parent.parentWidget().cursor().valueBuffer(self._foreignField) if foranea is None: #print("FLTable(%s): campo foraneo \"%s.%s\" no encontrado." % (self._tableName,self._parent.parentWidget()._cursor.table(), self._foreignField)) return if tipo is "uint": self._foreignFilter = "%s = %s" % (self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer(self._foreignField)) else: self._foreignFilter = "%s = '%s'" % (self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer(self._foreignField)) #print("Filtro:%s" % filtro) self._cursor.setMainFilter(self._foreignFilter) self._cursor.refresh() else: self._cursor = FLSqlCursor(self._tableName)
def init(self): self.initCount_ = self.initCount_ + 1 tmpTMD = self.createSystemTable("flmetadata") tmpTMD = self.createSystemTable("flseqs") if not self.db_.dbAux(): return q = FLSqlQuery(None, self.db_.dbAux()) q.setForwardOnly(True) tmpTMD = self.createSystemTable("flsettings") if not q.exec_("SELECT * FROM flsettings WHERE flkey = 'sysmodver'"): q.exec_("DROP TABLE flsettings CASCADE") tmpTMD = self.createSystemTable("flsettings") if not self.dictKeyMetaData_: self.dictKeyMetaData_ = {} #self.dictKeyMetaData_.setAutoDelete(True) else: self.dictKeyMetaData_.clear() q.exec_("SELECT tabla,xml FROM flmetadata") while q.next(): self.dictKeyMetaData_.insert(q.value(0), q.value(1)) q.exec_("SELECT * FROM flsettings WHERE flkey = 'sysmodver'") if not q.next(): q.exec_("DROP TABLE flmetadata CASCADE") tmpTMD = self.createSystemTable("flmetadata") c = FLSqlCursor("flmetadata", True, self.db_.dbAux()) for key, value in self.dictKeyMetaData_: buffer = c.primeInsert() buffer.setValue("tabla", key) buffer.setValue("xml", value) c.insert() if not self.cacheMetaData_: self.cacheMetaData_ = [] if not self.cacheAction_: self.cacheAction_ = [] if not self.cacheMetaDataSys_: self.cacheMetaDataSys_ = []
def inicialize2(self, *args, **kwargs): actionName = str(args[0][0]) parent = args[0][1] f = args[1] if parent: self.parent_ = parent else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), actionName, f) self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = None print(FLUtil.translate("sys", "FLFormDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action( actionName) if not self.action_: print( FLUtil.translate( "sys", "FLFormDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True, "default", 0, 0, self) self.name_ = self.action_.name() self.initForm()
def cleanupMetaData(self): """ Limpieza la tabla flmetadata, actualiza el cotenido xml con el de los fichero .mtd actualmente cargados """ # util = FLUtil() if not self.existsTable("flfiles") or not self.existsTable( "flmetadata"): return q = FLSqlQuery(None, self.db_.dbAux()) c = FLSqlCursor("flmetadata", True, self.db_.dbAux()) buffer = None table = "" # q.setForwardOnly(True) # c.setForwardOnly(True) if not self.dictKeyMetaData_: self.dictKeyMetaData_ = {} else: self.dictKeyMetaData_.clear() self.loadTables() self.db_.managerModules().loadKeyFiles() self.db_.managerModules().loadAllIdModules() self.db_.managerModules().loadIdAreas() q.exec_("SELECT tabla, xml FROM flmetadata") while q.next(): self.dictKeyMetaData_[str(q.value(0))] = str(q.value(1)) q.exec_( "SELECT nombre, sha FROM flfiles WHERE nombre LIKE '%.mtd'") while q.next(): table = str(q.value(0)) table = table.replace(".mtd", "") if not self.existsTable(table): self.createTable(table) tmd = self.metadata(table) if not tmd: qWarning("FLManager::cleanupMetaDAta " + QApplication.tr( "No se ha podido crear los metadatatos para la tabla %1" ).arg(table)) c.select("tabla='%s'" % table) if c.next(): buffer = c.primeUpdate() buffer.setValue("xml", str(q.value(1))) c.update() self.dictKeyMetaData_[table] = str(q.value(1))
def __init__(self, *args, **kwargs): parent = None name = None action = None if isinstance(args[0], str): #@param actionName Nombre de la acción asociada al formulario if len(args) == 2: parent = args[1] name = args[0] self.cursor_ = FLSqlCursor(name, True, "default", None, None, self) action = self.cursor_.action() self.accepted_ = False elif isinstance(args[0], FLSqlCursor): #@param cursor Objeto FLSqlCursor para asignar a este formulario #@param actionName Nombre de la acción asociada al formulario if len(args) > 2: action = args[1] name = action.name if len(args) == 3: parent = args[2] self.cursor_ = args[0] super(FLFormSearchDB, self).__init__(parent, action) self.setFocusPolicy(QtCore.Qt.NoFocus) if not name: print("FLFormSearchDB : Nombre de acción vacío") return if not action: print("FLFormSearchDB : No existe la acción", name) return self.initForm()
def runTransaction(self, f, oParam): curT = FLSqlCursor("flfiles") curT.transaction(False) # gui = self.interactiveGUI() # if gui: # AQS.Application_setOverrideCursor(AQS.WaitCursor); errorMsg = None try: valor = f(oParam) errorMsg = getattr(oParam, "errorMsg", None) if valor: curT.commit() else: curT.rollback() # if gui: # AQS.Application_restoreOverrideCursor(); if errorMsg is None: self.warnMsgBox( self.translate(u"Error al ejecutar la función")) else: self.warnMsgBox(errorMsg) return False except Exception: curT.rollback() # if gui: # AQS.Application_restoreOverrideCursor(); if errorMsg is None: self.warnMsgBox( self.translate(u"Error al ejecutar la función")) else: self.warnMsgBox(errorMsg) return False # if gui: # AQS.Application_restoreOverrideCursor(); return valor
def init1(self, actionName, parent=None): self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = False print( FLUtil.translate("app", "FLFormSearchDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action( actionName) if not self.action_: print( FLUtil.translate( "app", "FLFormSearchDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True, "default", 0, 0, self) self.name_ = self.action_.name() self.initForm()
def init1(self, actionName, parent = None): self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = False print(FLUtil.translate("app","FLFormSearchDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action(actionName) if not self.action_: print(FLUtil.translate("app","FLFormSearchDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True,"default", 0, 0, self) self.name_ = self.action_.name() self.initForm()
def __init__(self, *args, **kwargs): parent = None name = None action = None if isinstance(args[0], str): #@param actionName Nombre de la acción asociada al formulario if len(args) == 2: parent = args[1] name = args[0] self.cursor_ = FLSqlCursor(name, True, "default", None, None, self) action = self.cursor_.action() self.accepted_ = False elif isinstance(args[0], FLSqlCursor): #@param cursor Objeto FLSqlCursor para asignar a este formulario #@param actionName Nombre de la acción asociada al formulario if len(args) > 2: action = args[1] name = action.name if len(args) == 3: parent = args[2] self.cursor_ = args[0] super(FLFormSearchDB,self).__init__(parent, action) self.setFocusPolicy(QtCore.Qt.NoFocus) if not name: print("FLFormSearchDB : Nombre de acción vacío") return if not action: print("FLFormSearchDB : No existe la acción", name) return self.initForm()
def runTransaction(self, f, oParam): curT = FLSqlCursor("flfiles") curT.transaction(False) # gui = self.interactiveGUI() # if gui: # AQS.Application_setOverrideCursor(AQS.WaitCursor); errorMsg = None try: valor = f(oParam) errorMsg = getattr(oParam, "errorMsg", None) if valor: curT.commit() else: curT.rollback() # if gui: # AQS.Application_restoreOverrideCursor(); if errorMsg is None: self.warnMsgBox(self.translate(u"Error al ejecutar la función")) else: self.warnMsgBox(errorMsg) return False except Exception: curT.rollback() # if gui: # AQS.Application_restoreOverrideCursor(); if errorMsg is None: self.warnMsgBox(self.translate(u"Error al ejecutar la función")) else: self.warnMsgBox(errorMsg) return False # if gui: # AQS.Application_restoreOverrideCursor(); return valor
def inicialize2(self,*args, **kwargs): actionName = str(args[0][0]) parent = args[0][1] f = args[1] if parent: self.parent_ = parent else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), actionName, f) self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = None print(FLUtil.translate("sys","FLFormDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action(actionName) if not self.action_: print(FLUtil.translate("sys","FLFormDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True, "default", 0, 0, self) self.name_ = self.action_.name() self.initForm()
def sqlDelete(self, t, w, connName="default"): """ Borra uno o más registros en una tabla mediante un objeto FLSqlCursor @param t Nombre de la tabla @param w Sentencia where para identificar los registros a borrar. @param connName Nombre de la conexion @return Verdadero en caso de realizar la inserción con éxito, falso en cualquier otro caso """ from pineboolib.fllegacy.FLSqlCursor import FLSqlCursor c = FLSqlCursor(t, True, connName) c.setForwardOnly(True) # if not c.select(w): # return False c.select(w) while c.next(): c.setModeAccess(FLSqlCursor.Del) c.refreshBuffer() if not c.commitBuffer(): return False return True
def loaded(self): #Asi damos tiempo a que el control se añada al formulario self._loaded = True value = None while True: #Ahora podemos buscar el cursor ... porque ya estamos añadidos al formulario parent_cursor = getattr(self._parent,"_cursor", None) if parent_cursor: #print("FLFIeldDB(%s):Pariente %s con cursor encontrado" % (self._fieldAlias, self._parent)) break new_parent = self._parent.parentWidget() if new_parent is None: print("FLFIeldDB(%s):No se ha encontrado al padre con cursor" % self._fieldAlias) break self._parent = new_parent self._cursor = self._parent.parentWidget()._cursor if not self._cursor: self._cursor = self._parent._cursor #Si es un dato externo ... if not self._tableName is None and not self._tableName == "": self._editable = False cursorFr = FLSqlCursor(self._tableName) if not cursorFr._model is None and not isinstance(cursorFr._model, DefFun): #Para las tablas qye no existen #print("El tipo model es %s" % type(cursorFr._model)) self._tipo = cursorFr._model.fieldType(self._fieldRelation) valueForeignField = self._cursor.valueBuffer(self._foreignField) if not valueForeignField is None and not valueForeignField == "": if self._tipo == 'uint': filtro = "%s = %s" % (self._fieldRelation, str(valueForeignField)) else: filtro = "%s = '%s'" % (self._fieldRelation, str(valueForeignField)) cursorFr.setMainFilter(filtro) cursorFr.refresh() cursorFr.first() value = cursorFr.valueBuffer(self._fieldName) else: value="" else: print("FLFieldDB: Campo %s.%s no encontrada." % (self._tableName, self._fieldName)) value="" else: self._tableName = self._cursor.table().name #print("Solicitando Alias de %s a tabla %s" % (self._fieldName, self._tableName)) self.setFieldAlias(self._cursor._model.alias(self._fieldName)) self._tipo = self._cursor._model.fieldType(self._fieldName) value = self._cursor.valueBuffer(self._fieldName) #print("\n\nCampo = %s.%s, Tipo = %s\nvalue = \"%s\"\nEditable = %s" % (self._tableName, self.fieldName, self._tipo, value, self._editable)) if self._tipo == 'string' or self._tipo == 'uint' or self._tipo == 'double' or self._tipo == 'date' or self._tipo == 'serial': self._dataControl = QtGui.QLineEdit() elif self._tipo == 'bool': self._dataControl = QtGui.QCheckBox() elif self._tipo == 'stringlist': self._dataControl = QtGui.QLineEdit() else: print("FLFIeldDB(%s):Tipo de dato desconocido (%s) en %s.%s.¿Existe ese campo?" % (self._fieldAlias, self._tipo , self._tableName, self._fieldName )) self._dataControl = QtGui.QLineEdit() self._layout.addWidget(self._dataControl) if value: self.setValue(str(value)) self.refresh()
class FLTableDB(QtGui.QWidget): _tableView = None _vlayout = None _lineEdit = None _comboBox_1 = None _comboBox_2 = None topWidget = QtGui.QWidget showed = False def __init__(self, parent = None, action_or_cursor = None, *args): print("FLTableDB:", parent, action_or_cursor , args) # TODO: Falta el lineeditsearch y el combo, que los QS lo piden super(FLTableDB,self).__init__(parent,*args) # TODO: LA inicialización final hay que hacerla más tarde, en el primer # show(), porque sino obligas a tenerlo todo preparado en el constructor. self._tableView = QtGui.QTableView() self._lineEdit = QtGui.QLineEdit() _label1 = QtGui.QLabel() _label2 = QtGui.QLabel() self._comboBox_1 = QtGui.QComboBox() self._comboBox_2 = QtGui.QComboBox() _label1.setText("Buscar") _label2.setText("en") self._vlayout = QtGui.QVBoxLayout() _hlayout = QtGui.QHBoxLayout() self._tableView._v_header = self._tableView.verticalHeader() self._tableView._v_header.setDefaultSectionSize(18) self._tableView._h_header = self._tableView.horizontalHeader() self._tableView._h_header.setDefaultSectionSize(70) _hlayout.addWidget(_label1) _hlayout.addWidget(self._lineEdit) _hlayout.addWidget(_label2) _hlayout.addWidget(self._comboBox_1) _hlayout.addWidget(self._comboBox_2) self._vlayout.addLayout(_hlayout) self._vlayout.addWidget(self._tableView) self.setLayout(self._vlayout) self._parent = parent while True: parent_cursor = getattr(self._parent,"_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent print(self._parent) self._tableView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self._tableView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self._tableView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self._tableView.setAlternatingRowColors(True) if action_or_cursor is None and parent_cursor: action_or_cursor = parent_cursor if isinstance(action_or_cursor,FLSqlCursor): self._cursor = action_or_cursor elif isinstance(action_or_cursor,str): self._cursor = FLSqlCursor(action_or_cursor) else: self._cursor = None if self._cursor: self._tableView._h_header.setResizeMode(QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor._model) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: for column in range(self._cursor._model.columnCount()): self._comboBox_1.addItem(self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem(self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect(self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded) def __getattr__(self, name): return DefFun(self, name) def loaded(self): # Es necesario pasar a modo interactivo lo antes posible # Sino, creamos un bug en el cierre de ventana: se recarga toda la tabla para saber el tamaño print("FLTableDB: setting columns in interactive mode") self._tableView._h_header.setResizeMode(QtGui.QHeaderView.Interactive) def cursor(self): assert self._cursor return self._cursor def obj(self): return self def comboBox_putFirstCol(self): self.putFirstCol(str(self._comboBox_1.currentText())) def comboBox_putSecondCol(self): self.putSecondCol(str(self._comboBox_2.currentText())) def putFirstCol(self, fN): _oldPos= None _oldFirst = self._tableView._h_header.logicalIndex(0) for column in range(self._cursor._model.columnCount()): if self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) if not self._comboBox_1.currentText() == fN: self._comboBox_1.setCurrentIndex(column) return False break if not _oldPos or fN == "*": return False else: self._tableView._h_header.swapSections(_oldPos, 0) self._comboBox_2.setCurrentIndex(_oldFirst) return True def putSecondCol(self, fN): _oldPos= None _oldSecond = self._tableView._h_header.logicalIndex(1) for column in range(self._cursor._model.columnCount()): if self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) break if not _oldPos or fN == "*": return False if not self._comboBox_1.currentText() == fN: self._tableView._h_header.swapSections(_oldPos, 1) else: self._comboBox_1.setCurrentIndex(_oldSecond) return True def setTableName(self, tableName): self._tableName = tableName if self.showed: if self.topWidget: self.initCursor() else: self.initFakeEditor() def setForeignField(self, foreingField): self._foreingField = foreingField if self.showed: if self.topWidget: self.initCursor() else: self.initFakeEditor() def setFieldRelation(self, fieldRelation): self._fieldRelation = fieldRelation if self.showed: if self.topWidget: self.initCursor() else: self.initFakeEditor() @decorators.NotImplementedWarn def initCursor(self): # si no existe crea la tabla if not self._cursor: return False if not self._cursor._model: return False self._tMD = 0 if not self._sortField: self._tMD = self._cursor._model.name() if self._tMD: self.sortField_ = self._tMD.value(self._cursor._currentregister, self._tMD.primaryKey()) ownTMD = False if not self._tableName: #if not cursor_->db()->manager()->existsTable(tableName_)) { ownTMD = True #tMD = cursor_->db()->manager()->createTable(tableName_); else: ownTMD = True self._tMD = self._cursor._model._table.name if not self._tMD: return if not self._foreignField or not self._fieldRelation: if not self._cursor._model: if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return if not self._cursor._model.name() == self._tableName: ctxt = self._cursor.context(); self._cursor = FLSqlCursor(self._tableName) if self._cursor: self._cursor.setContext(ctxt) cursorAux = 0 if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return else: cursorTopWidget = self.topWidget._cursor() # ::qt_cast<FLFormDB *>(topWidget)->cursor() if cursorTopWidget and not cursorTopWidget._model.name() == self._tableName: self._cursor = cursorTopWidget if not self._tableName or not self._foreignField or not self._fieldRelation or cursorAux: if ownTMD and self._tMD and not self._tMD.inCache(): tMD = None return cursorAux = self._cursor curName = self._cursor._model.name() rMD = self._cursor._model.relation(self._foreignField,self._fieldRelation,self._tableName) testM1 = self._tMD.relation(self._fieldRelation, self._foreignField, curName) checkIntegrity = bool(False) if not rMD: if testM1: checkIntegrity = (testM1.cardinality() == FLRelationMetaData.RELATION_M1) fMD = FLTableMetaData(self._cursor._model.field(self._foreignField)) if (fMD): tmdAux = self._cursor._model(self._tableName); if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): # mirar inCache() tmdAux = None rMD = FLRelationMetaData(self._tableName,self._fieldRelation, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity) fMD.addRelationMD(rMD) print("FLTableDB : La relación entre la tabla del formulario %r y esta tabla %r de este campo no existe, pero sin embargo se han indicado los campos de relación( %r, %r )" % (curName, self._tableName, self._fieldRelation, self._foreignField)) print("FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (curName, self._foreignField, self._tableName, self._fieldRelation)) else: print("FLTableDB : El campo ( %r ) indicado en la propiedad foreignField no se encuentra en la tabla ( %r )" % (self._foreignField, curName)) rMD = testM1 if not rMD: fMD = FLFieldMetaData(tMD.field(self._fieldRelation)) if (fMD): rMD = FLRelationMetaData(curName,self._foreignField, FLRelationMetaData.RELATION_1M, False, False, False) fMD.addRelationMD(rMD) print("FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (self._tableName, self._fieldRelation, curName, self._foreignField)) else: print("FLTableDB : El campo ( %r ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %r )" % (self._fieldRelation, self._tableName)) self._cursor = FLSqlCursor(self._tableName, True, self._cursor.db().connectionName(), cursorAux, rMD, self); if not self._cursor: self._cursor = cursorAux cursorAux = 0 else: self._cursor.setContext(cursorAux.context()) if self.showed: self.disconnect(cursorAux, QtCore.SIGNAL('newBuffer()'), self.refresh()) self.connect(cursorAux,QtCore.SIGNAL('newBuffer()'), self.refresh()) if cursorAux and self.topWidget.isA("FLFormSearchDB"): self.topWidget.setCaption(self._cursor._model.alias()) self.topWidget.setCursor(self._cursor) #::qt_cast<FLFormSearchDB *>(topWidget)->setCursor(cursor_); if ownTMD and tMD and not tMD.inCache(): tMD = None @QtCore.pyqtSlot() def close(self): print("FLTableDB: close()") @QtCore.pyqtSlot() def refresh(self): print("FLTableDB: refresh()", self.parent().parent().parent()) self._cursor.refresh() @QtCore.pyqtSlot() def show(self): print("FLTableDB: show event") super(FLTableDB, self).show() @QtCore.pyqtSlot() def insertRecord(self): self._cursor.insertRecord() @QtCore.pyqtSlot() def editRecord(self): self._cursor.editRecord() @QtCore.pyqtSlot() def deleteRecord(self): self._cursor.deleteRecord() @QtCore.pyqtSlot() def browseRecord(self): self._cursor.browseRecord() @QtCore.pyqtSlot() def copyRecord(self): self._cursor.copyRecord()
def __init__(self, parent = None, action_or_cursor = None, *args): print("FLTableDB:", parent, action_or_cursor , args) # TODO: Falta el lineeditsearch y el combo, que los QS lo piden super(FLTableDB,self).__init__(parent,*args) # TODO: LA inicialización final hay que hacerla más tarde, en el primer # show(), porque sino obligas a tenerlo todo preparado en el constructor. self._tableView = QtGui.QTableView() self._lineEdit = QtGui.QLineEdit() _label1 = QtGui.QLabel() _label2 = QtGui.QLabel() self._comboBox_1 = QtGui.QComboBox() self._comboBox_2 = QtGui.QComboBox() _label1.setText("Buscar") _label2.setText("en") self._vlayout = QtGui.QVBoxLayout() _hlayout = QtGui.QHBoxLayout() self._tableView._v_header = self._tableView.verticalHeader() self._tableView._v_header.setDefaultSectionSize(18) self._tableView._h_header = self._tableView.horizontalHeader() self._tableView._h_header.setDefaultSectionSize(70) _hlayout.addWidget(_label1) _hlayout.addWidget(self._lineEdit) _hlayout.addWidget(_label2) _hlayout.addWidget(self._comboBox_1) _hlayout.addWidget(self._comboBox_2) self._vlayout.addLayout(_hlayout) self._vlayout.addWidget(self._tableView) self.setLayout(self._vlayout) self._parent = parent while True: parent_cursor = getattr(self._parent,"_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent print(self._parent) self._tableView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self._tableView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self._tableView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self._tableView.setAlternatingRowColors(True) if action_or_cursor is None and parent_cursor: action_or_cursor = parent_cursor if isinstance(action_or_cursor,FLSqlCursor): self._cursor = action_or_cursor elif isinstance(action_or_cursor,str): self._cursor = FLSqlCursor(action_or_cursor) else: self._cursor = None if self._cursor: self._tableView._h_header.setResizeMode(QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor._model) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: for column in range(self._cursor._model.columnCount()): self._comboBox_1.addItem(self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem(self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect(self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded)
class FLTableDB(QtGui.QWidget): """ PLUGIN que contiene una tabla de la base de datos. Este objeto contiene todo lo necesario para manejar los datos de una tabla. Además de la funcionalidad de busqueda en la tabla por un campo, mediante filtros. Este plugin para que sea funcional debe tener como uno de sus padres o antecesor a un objeto FLFormDB. @author InfoSiAL S.L. """ """ Tipos de condiciones para el filtro """ All = None Contains = None Starts = None End = None Equal = None Dist = None Greater = None Less = None FromTo = None Null = None NotNull = None _parent = None _name = None loadLater_ = None comboBoxFieldToSearch = None comboBoxFieldToSearch2 = None tableRecords_ = None lineEditSearch = None tabDataLayout = None tabControlLayout = None _initCursorWhenLoad = None _initTableRecordWhenLoad = None _controlsInit = None """ constructor """ def __init__(self, parent, name=None): super(FLTableDB, self).__init__(parent) self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(0, self.loaded) self.topWidget = parent def __getattr__(self, name): return DefFun(self, name) def loaded(self): # Es necesario pasar a modo interactivo lo antes posible # Sino, creamos un bug en el cierre de ventana: se recarga toda la tabla para saber el tamaño # print("FLTableDB(%s): setting columns in interactive mode" % self._tableName) self._loaded = True while True: # Ahora podemos buscar el cursor ... porque ya estamos añadidos al formulario parent_cursor = getattr(self.topWidget, "cursor_", None) if parent_cursor: break new_parent = self.topWidget.parentWidget() if new_parent is None: break self.topWidget = new_parent if getattr(self.topWidget.parentWidget(), "cursor_", None): self.topWidget = self.topWidget.parentWidget() if not parent_cursor: print( "FLTableDB : Uno de los padres o antecesores de FLTableDB deber ser de la clase FLFormDB o heredar de ella" ) return self.cursor_ = self.topWidget.cursor_ self.setFont(QtGui.qApp.font()) if not self._name: self.setName("FLTableDB") self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.refreshDelayed) self.showWidget() self.initCursor() def setName(self, name): self._name = name """ Para obtener el cursor utilizado por el componente. return Objeto FLSqlCursor con el cursor que contiene los registros para ser utilizados en el formulario """ def cursor(self): if not self.cursor_.d.buffer_: self.cursor_.refreshBuffer() return self.cursor_ """ Para obtener el nombre de la tabla asociada. @return Nombre de la tabla asociado """ def tableName(self): return self.tableName_ """ Para establecer el nombre de la tabla asociada. @param fT Nombre de la tabla asociada """ def setTableName(self, fT): self.tableName_ = fT if self.showed: if self.topwidget: self.initCursor() else: self.initFakeEditor() else: self._initCursorWhenLoad = True self._initTableRecordWhenLoad = True """ Para obtener el nombre del campo foráneo. @return Nombre del campo """ def foreignField(self): return self.foreignField_ """ Para establecer el nombre del campo foráneo. @param fN Nombre del campo """ def setForeignField(self, fN): self.foreignField_ = fN if self.showed: if self.topwidget: self.initCursor() else: self.initFakeEditor() else: self._initCursorWhenLoad = True self._initTableRecordWhenLoad = True """ Para obtener el nombre del campo relacionado. @return Nombre del campo """ def fieldRelation(self): return self.fieldRelation_ """ Para establecer el nombre del campo relacionado. @param fN Nombre del campo """ def setFieldRelation(self, fN): self.fieldRelation_ = fN if self.showed: if self.topwidget: self.initCursor() else: self.initFakeEditor() else: self._initCursorWhenLoad = True self._initTableRecordWhenLoad = True """ Establece si el componente esta en modo solo lectura o no. """ def setReadOnly(self, mode): if self.tableRecords_: self.readonly = mode self.tableRecords_.setFLReadOnly(mode) # self.readOnlyChanged(mode).emit() FIXME self.reqReadOnly_ = mode def readOnly(self): return self.reqReadOnly_ """ Establece si el componente esta en modo solo edición o no. """ def setEditOnly(self, mode): if self.tableRecords_: self.editonly_ = mode self.tableRecords_.setEditOnly(mode) # self.editOnlyChanged(mode).emit() #FIXME self.reqEditOnly_ = mode def editOnly(self): return self.reqEditOnly_ """ Establece el componente a sólo inserción o no. """ def setInsertOnly(self, mode): if self.tableRecords_: self.insertonly_ = mode self.tableRecords_.setInsertOnly(mode) self.insertOnlyChanged(mode).emit() self.reqInsertOnly = mode def insertOnly(self): return self.reqInsertOnly_ """ Establece el filtro inicial de búsqueda """ def setInitSearch(self, iS): self.initSearch_ = iS """ Establece el orden de las columnas de la tabla. @param fields Lista de los nombres de los campos ordenada según se desea que aparezcan en la tabla de izquierda a derecha """ @decorators.NotImplementedWarn def setOrderCols(self, fields): pass """ Devuelve la lista de los campos ordenada por sus columnas en la tabla de izquierda a derecha """ @decorators.NotImplementedWarn def orderCols(self): return None """ Establece el filtro de la tabla @param f Sentencia Where que establece el filtro """ @decorators.NotImplementedWarn def setFilter(self, f): pass """ Devuelve el filtro de la tabla @return Filtro """ @decorators.NotImplementedWarn def filter(self): return None """ Devuelve el filtro de la tabla impuesto en el Find @return Filtro """ @decorators.NotImplementedWarn def findFilter(self): return None """ Obtiene si la columna de selección está activada """ @decorators.NotImplementedWarn def checkColumnEnabled(self): return None """ Establece el estado de activación de la columna de selección El cambio de estado no será efectivo hasta el siguiente refresh. """ @decorators.NotImplementedWarn def setCheckColumnEnabled(self, b): pass """ Obiente el texto de la etiqueta de encabezado para la columna de selección """ @decorators.NotImplementedWarn def aliasCheckColumn(self): pass """ Establece el texto de la etiqueta de encabezado para la columna de selección El cambio del texto de la etiqueta no será efectivo hasta el próximo refresh """ @decorators.NotImplementedWarn def setAliasCheckColumn(self, t): pass """ Obtiene si el marco de búsqueda está oculto """ @decorators.NotImplementedWarn def findHidden(self): return None """ Oculta o muestra el marco de búsqueda @param h TRUE lo oculta, FALSE lo muestra """ @decorators.NotImplementedWarn def setFindHidden(self, h): pass """ Obtiene si el marco para conmutar entre datos y filtro está oculto """ @decorators.NotImplementedWarn def filterHidden(self): return None """ Oculta o muestra el marco para conmutar entre datos y filtro @param h TRUE lo oculta, FALSE lo muestra """ @decorators.NotImplementedWarn def setFilterHidden(self, h): pass """ Ver FLTableDB::showAllPixmaps_ """ @decorators.NotImplementedWarn def showAllPixmaps(self): return None """ Ver FLTableDB::showAllPixmaps_ """ @decorators.NotImplementedWarn def setShowAllPixmaps(self, s): pass """ Ver FLTableDB::functionGetColor_ """ @decorators.NotImplementedWarn def functionGetColor(self): pass """ Ver FLTableDB::functionGetColor_ """ @decorators.NotImplementedWarn def setFunctionGetColor(self, f): pass """ Asigna el nombre de función a llamar cuando cambia el filtro. """ def setFilterRecordsFunction(self, fn): self.tableDB_filterRecords_functionName_ = fn """ Ver FLTableDB::onlyTable_ """ @decorators.NotImplementedWarn def setOnlyTable(self, on=True): pass def onlyTable(self): return self.reqOnlyTable_ """ Ver FLTableDB::autoSortColumn_ """ @decorators.NotImplementedWarn def setAutoSortColumn(self, on=True): self.autoSortColumn_ = on def autoSortColumn(self): return self.autoSortColumn_ """ Filtro de eventos """ def eventFilter(self, obj, ev): if ( not self.tableRecords_ or not self.lineEditSearch or not self.comboBoxFieldToSearch or not self.comboBoxFieldToSearch2 or not self.cursor_ ): return super(FLTableDB, self).eventFilter(obj, ev) if ev.type() == QtCore.QEvent.KeyPress and isinstance(obj, FLDataTable): k = ev if k.key() == QtCore.Qt.Key_F2: self.comboBoxFieldToSearch.popup() return True if ev.type() == QtCore.QEvent.KeyPress and isinstance(obj, QtGui.QLineEdit): k = ev if k.key() == QtCore.Qt.Key_Enter or k.key() == QtCore.Qt.Key_Return: self.tableRecords_.setFocus() return True if k.key() == QtCore.Qt.Key_Up: self.comboBoxFieldToSearch.setFocus() return True if k.key() == QtCore.Qt.Key_Down: self.tableRecords_.setFocus() return True if k.key() == QtCore.Qt.Key_F2: self.comboBoxFieldToSearch.popup() return True if k.text() == "'" or k.text() == "\\": return True if isinstance(obj, FLDataTable) or isinstance(obj, QtGui.QLineEdit): return False else: return super(FLTableDB, self).eventFilter(obj, ev) """ Captura evento mostrar """ def showEvent(self, e): super(FLTableDB, self).showEvent(e) self.showWidget() """ Redefinida por conveniencia """ def showWidget(self): if not self._loaded: # Esperamos a que la carga se realice timer = QtCore.QTimer(self) timer.singleShot(30, self.showWidget) return else: if not self.showed and not self._initCursorWhenLoad and self.cursor_ and self.tableRecords_: if not self.topWidget: self.initFakeEditor() self.showed = True return tMD = None ownTMD = None if self.tableName_: if not self.cursor_.db().manager().existsTable(self.tableName_): ownTMD = True tMD = self.cursor_.db().manager().createTable(self.tableName_) else: ownTMD = True tMD = self.cursor_.db().manager().metadata(self.tableName_) if not tMD: return if not self.cursorAux: if self.initSearch_: self.refresh(True, True) QtCore.QTimer.singleShot(0, self.tableRecords_.ensureRowSelectedVisible) else: self.refresh(True) if self.tableRecords_.numRows() <= 0: self.refresh(False, True) else: self.refreshDelayed() if not isinstance(self.topWidget, FLFormRecordDB): self.lineEditSearch.setFocus() if self.cursorAux: if isinstance(self.topWidget, FLFormRecordDB) and self.cursorAux.modeAccess() == FLSqlCursor.Browse: self.cursor_.setEdition(False) self.setReadOnly(True) if self.initSearch_: self.refresh(True, True) QtCore.QTimer.singleShot(0, self.tableRecords_.ensureRowSelectedVisible) else: self.refresh(True) if self.tableRecords_.numRows() <= 0: self.refresh(False, True) else: self.refreshDelayed() elif ( isinstance(self.topWidget, FLFormRecordDB) and self.cursor_.modeAccess() == FLSqlCursor.Browse and (tMD and not tMD.isQuery()) ): self.cursor_.setEdition(False) self.setReadOnly(True) if ownTMD and tMD and not tMD.inCache(): del tMD if self._initCursorWhenLoad: self._initCursorWhenLoad = False self.initCursor() self.showWidget() if not self.tableRecords_: if not self.tableName_: if not self.cursor_: self.initCursor() QtCore.QTimer.singleShot(50, self.showWidget) return self.tableRecords() self.setTableRecordsCursor() self.showWidget() elif self.tableName_: if not self.cursor_: self.initCursor() QtCore.QTimer.singleShot(50, self.showWidget) return if self.tableName_ == self.cursor_.curName(): self.tableRecords() if self.cursor_.model(): self.setTableRecordsCursor() self.showWidget() """ Obtiene el componente tabla de registros """ def tableRecords(self): self.tabDataLayout = QtGui.QVBoxLayout() self.comboBoxFieldToSearch = QtGui.QComboBox() self.comboBoxFieldToSearch2 = QtGui.QComboBox() self.lineEditSearch = QtGui.QLineEdit() label1 = QtGui.QLabel() label2 = QtGui.QLabel() label1.setText("Buscar") label2.setText("en") self.tabControlLayout = QtGui.QHBoxLayout() self.tabControlLayout.addWidget(label1) self.tabControlLayout.addWidget(self.lineEditSearch) self.tabControlLayout.addWidget(label2) self.tabControlLayout.addWidget(self.comboBoxFieldToSearch) self.tabControlLayout.addWidget(self.comboBoxFieldToSearch2) self.tabDataLayout.addLayout(self.tabControlLayout) if not self.tableRecords_: self.tableRecords_ = FLDataTable(self, "tableRecords") self.tableRecords_.setFocusPolicy(QtCore.Qt.StrongFocus) self.setFocusProxy(self.tableRecords_) self.tabDataLayout.addWidget(self.tableRecords_) self.lineEditSearch.installEventFilter(self) self.tableRecords_.installEventFilter(self) self.setLayout(self.tabDataLayout) self.setTabOrder(self.tableRecords_, self.lineEditSearch) self.setTabOrder(self.lineEditSearch, self.comboBoxFieldToSearch) self.setTabOrder(self.comboBoxFieldToSearch, self.comboBoxFieldToSearch2) self.lineEditSearch.textChanged.connect(self.filterRecords) model = self.cursor_.model() if model: for column in range(model.columnCount()): field = model.metadata().indexFieldObject(column) if not field.visibleGrid(): self.tableRecords_.setColumnHidden(column, True) else: self.comboBoxFieldToSearch.addItem( model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole) ) self.comboBoxFieldToSearch2.addItem( model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole) ) self.comboBoxFieldToSearch.addItem("*") self.comboBoxFieldToSearch2.addItem("*") self.comboBoxFieldToSearch.setCurrentIndex(0) self.comboBoxFieldToSearch2.setCurrentIndex(1) self.comboBoxFieldToSearch.currentIndexChanged.connect(self.putFirstCol) self.comboBoxFieldToSearch2.currentIndexChanged.connect(self.putSecondCol) self._controlsInit = True else: self.comboBoxFieldToSearch.addItem("*") self.comboBoxFieldToSearch2.addItem("*") return self.tableRecords_ """ Asigna el cursor actual del componente a la tabla de registros """ def setTableRecordsCursor(self): self.tableRecords_.setFLSqlCursor(self.cursor_) try: self.tableRecords_.doubleClicked.disconnect(self.chooseRecord) except: pass self.tableRecords_.doubleClicked.connect(self.chooseRecord) """ Refresca la pestaña datos aplicando el filtro """ @decorators.NotImplementedWarn def refreshTabData(self): pass """ Refresca la pestaña del filtro """ @decorators.NotImplementedWarn def refreshTabFilter(self): pass """ Para obtener la enumeración correspondiente a una condición para el filtro a partir de su literal """ @decorators.NotImplementedWarn def decodeCondType(self, strCondType): pass """ Construye la claúsula de filtro en SQL a partir del contenido de los valores definidos en la pestaña de filtro """ @decorators.NotImplementedWarn def tdbFilterBuildWhere(self): pass """ Inicializa un editor falso y no funcional. Esto se utiliza cuando se está editando el formulario con el diseñador y no se puede mostrar el editor real por no tener conexión a la base de datos. Crea una previsualización muy esquemática del editor, pero suficiente para ver la posisicón y el tamaño aproximado que tendrá el editor real. """ @decorators.NotImplementedWarn def initFakeEditor(self): pass """ Componente para visualizar los registros """ tableRecords_ = None """ Nombre de la tabla a la que esta asociado este componente. """ tableName_ = None """ Nombre del campo foráneo """ foreignField_ = None """ Nombre del campo de la relación """ fieldRelation_ = None """ Cursor con los datos de origen para el componente """ cursor_ = None """ Cursor auxiliar de uso interno para almacenar los registros de la tabla relacionada con la de origen """ cursorAux = None """ Matiene la ventana padre """ topWidget = None """ Indica que la ventana ya ha sido mostrada una vez """ showed = None """ Mantiene el filtro de la tabla """ filter_ = None """ Almacena si el componente está en modo sólo lectura """ readonly_ = None reqReadOnly_ = None """ Almacena si el componente está en modo sólo edición """ editonly_ = None reqEditOnly_ = None """ Indica si el componente está en modo sólo permitir añadir registros """ insertonly_ = None reqInsertOnly_ = None """ Almacena los metadatos del campo por el que está actualmente ordenada la tabla """ sortField_ = None """ Almacena los metadatos del campo por el que está actualmente ordenada la tabla en segunda instancia @author Silix - dpinelo """ sortField2_ = None """ Crónometro interno """ timer = None """ Filtro inicial de búsqueda """ initSearch_ = None """ Indica que la columna de seleción está activada """ checkColumnEnabled_ = None """ Indica el texto de la etiqueta de encabezado para la columna de selección """ aliasCheckColumn_ = None """ Indica el nombre para crear un pseudocampo en el cursor para la columna de selección """ fieldNameCheckColumn_ = None """ Indica que la columna de selección está visible """ checkColumnVisible_ = None """ Indica el número de columna por la que ordenar los registros """ sortColumn_ = None """ Indica el número de columna por la que ordenar los registros @author Silix - dpinelo """ sortColumn2_ = None """ Indica el número de columna por la que ordenar los registros @author Silix """ sortColumn3_ = None """ Indica el sentido ascendente o descendente del la ordenacion actual de los registros """ orderAsc_ = None """ Indica el sentido ascendente o descendente del la ordenacion actual de los registros @author Silix - dpinelo """ orderAsc2_ = None """ Indica el sentido ascendente o descendente del la ordenacion actual de los registros @author Silix """ orderAsc3_ = None """ Indica si se debe establecer automáticamente la primera columna como de ordenación """ autoSortColumn_ = None """ Almacena la última claúsula de filtro aplicada en el refresco """ tdbFilterLastWhere_ = None """ Diccionario que relaciona literales descriptivos de una condición de filtro con su enumeración """ mapCondType = [] """ Indica si el marco de búsqueda está oculto """ findHidden_ = None """ Indica si el marco para conmutar entre datos y filtro está oculto """ filterHidden_ = None """ Indica si se deben mostrar los campos tipo pixmap en todas las filas """ showAllPixmaps_ = None """ Nombre de la función de script a invocar para obtener el color y estilo de las filas y celdas El nombre de la función debe tener la forma 'objeto.nombre_funcion' o 'nombre_funcion', en el segundo caso donde no se especifica 'objeto' automáticamente se añadirá como prefijo el nombre del formulario donde se inicializa el componente FLTableDB seguido de un punto. De esta forma si utilizamos un mismo formulario para varias acciones, p.e. master.ui, podemos controlar si usamos distintas funciones de obtener color para cada acción (distintos nombres de formularios) o una única función común para todas las acciones. Ej. Estableciendo 'tdbGetColor' si el componente se inicializa en el formulario maestro de clientes, se utilizará 'formclientes.tdbGetColor', si se inicializa en el fomulario maestro de proveedores, se utilizará 'formproveedores.tdbGetColor', etc... Si establecemos 'flfactppal.tdbGetColor' siempre se llama a esa función independientemente del formulario en el que se inicialize el componente. Cuando se está pintando una celda se llamará a esa función pasándole cinco parámentros: - Nombre del campo correspondiente a la celda - Valor del campo de la celda - Cursor de la tabla posicionado en el registro correspondiente a la fila que está pintando. AVISO: En este punto los valores del buffer son indefinidos, no se hace refreshBuffer por motivos de eficiencia - Tipo del campo, ver FLUtilInterface::Type en FLObjectFactory.h - Seleccionado. Si es TRUE indica que la celda a pintar está en la fila resaltada/seleccionada. Generalmente las celdas en la fila seleccionada se colorean de forma distinta al resto. La función debe devolver una array con cuatro cadenas de caracteres; [ "color_de_fondo", "color_lapiz", "estilo_fondo", "estilo_lapiz" ] En los dos primeros, el color, se puede utilizar cualquier valor aceptado por QColor::setNamedColor, ejemplos; "green" "#44ADDB" En los dos últimos, el estilo, se pueden utilizar los valores aceptados por QBrush::setStyle y QPen::setStyle, ver en FLDataTable.cpp las funciones nametoBrushStyle y nametoPenStyle, ejemplos; "SolidPattern" "DiagCrossPattern" "DotLine" "SolidLine" Si alguno de los valores del array es vacio "", entonces se utilizarán los colores o estilos establecidos por defecto. """ functionGetColor_ = None """ Indica que no se realicen operaciones con la base de datos (abrir formularios). Modo "sólo tabla". """ onlyTable_ = None reqOnlyTable_ = None """ Editor falso """ fakeEditor_ = None tableDB_filterRecords_functionName_ = None """ Actualiza el conjunto de registros. """ @decorators.BetaImplementation @QtCore.pyqtSlot() @QtCore.pyqtSlot(bool) @QtCore.pyqtSlot(bool, bool) def refresh(self, refreshHead=False, refreshData=False): if not self.cursor_ or not self.tableRecords_: return tMD = self.cursor_.metadata() if not tMD: return if not self.tableName_: self.tableName_ = tMD.name() if refreshHead: if not self.tableRecords_.isHidden(): self.tableRecords_.hide() model = self.cursor_.model() for column in range(model.columnCount()): field = model.metadata().indexFieldObject(column) if not field.visibleGrid(): self.tableRecords_.setColumnHidden(column, True) else: self.tableRecords_.setColumnHidden(column, False) # FIXME: Este proceso es MUY LENTO. No deberíamos hacer esto. # Hay que buscar alguna forma manual de iterar las primeras N filas, o calcular un # valor por defecto rápidamente. self.tableRecords_._h_header.setResizeMode(QtGui.QHeaderView.ResizeToContents) if model.rows * model.cols > 500 * 10: # Esto evitará que se calcule para las que tienen más de 500*10 celdas. self.tableRecords_._h_header.setResizeMode(0) # ... de todos modos tendríamos que, con un timer o algo para desactivar el modo. Una vez # ... ya redimensionadas inicialmente, lo único que hace es lastrar Pineboo mucho. if refreshData or self.sender(): finalFilter = self.filter_ if self.tdbFilterBuildWhere_: if not finalFilter: finalFilter = self.tdbFilterLastWhere_ else: finalFilter = "%s and %s" % (finalFilter, self.tdbFilterLastWhere_) self.tableRecords_.setPersistentFilter(finalFilter) self.tableRecords_.refresh() if self.initSearch_: try: self.lineEditSearch.textChanged.disconnect(self.filterRecords) except: pass self.lineEditSearch.setText(self.initSearch_) self.lineEditSearch.textChanged.connect(self.filterRecords) self.lineEditSearch.selectAll() self.initSearch_ = None self.seekCursor() if not self.readonly_ == self.reqReadOnly_ or ( self.tableRecords_ and not self.readonly_ == self.tableRecords_.flReadOnly() ): self.setReadOnly(self.reqReadOnly_) if not self.editonly_ == self.reqEditOnly_ or ( self.tableRecords_ and not self.editonly_ == self.tableRecords_.editOnly() ): self.setEditOnly(self.reqEditOnly_) if not self.insertonly_ == self.reqInsertOnly_ or ( self.tableRecords_ and not self.insertonly_ == self.tableRecords_.insertOnly() ): self.setInsetOnly(self.reqInsertOnly_) if not self.onlyTable_ == self.reqOnlyTable_ or ( self.tableRecords_ and not self.onlyTable_ == self.tableRecords_.onlyTable() ): self.setOnlyTable(self.reqOnlyTable_) if self.tableRecords_ and self.tableRecords_.isHidden(): self.tableRecords_.show() """ Actualiza el conjunto de registros con un retraso. Acepta un lapsus de tiempo en milisegundos, activando el cronómetro interno para que realize el refresh definitivo al cumplirse dicho lapsus. @param msec Cantidad de tiempo del lapsus, en milisegundos. """ def refreshDelayed(self, msec=50, refreshData=True): if not self.cursor_.modeAccess() == FLSqlCursor.Browse: return if refreshData: self._refreshData = True else: self._refreshData = False QtCore.QTimer.singleShot(msec, self.refreshDelayed2) self.seekCursor() def refreshDelayed2(self): self.refresh(False, self._refreshData) self._refreshData = None """ Invoca al método FLSqlCursor::insertRecord() """ @QtCore.pyqtSlot() def insertRecord(self): w = self.sender() if w and ( not self.cursor_ or self.reqReadOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked()) ): w.setDisabled(True) return if self.cursor_: self.cursor_.insertRecord() """ Invoca al método FLSqlCursor::editRecord() """ @QtCore.pyqtSlot() def editRecord(self): w = self.sender() if w and ( not self.cursor_ or self.reqReadOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked()) ): w.setDisabled(True) return if self.cursor_: self.cursor_.editRecord() """ Invoca al método FLSqlCursor::browseRecord() """ @QtCore.pyqtSlot() def browseRecord(self): w = self.sender() if w and (not self.cursor_ or self.reqOnlyTable_): w.setDisaBled(True) return if self.cursor_: self.cursor_.browseRecord() """ Invoca al método FLSqlCursor::deleteRecord() """ @QtCore.pyqtSlot() def deleteRecord(self): w = self.sender() if w and ( not self.cursor_ or self.reqReadOnly_ or self.reqInsertOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked()) ): w.setDisabled(True) return if self.cursor_: self.cursor_.deleteRecord() """ Invoca al método FLSqlCursor::copyRecord() """ @QtCore.pyqtSlot() def copyRecord(self): w = self.sender() if w and ( not self.cursor_ or self.reqReadOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked()) ): w.setDisabled(True) return if self.cursor_: self._cursor.copyRecord() """ Coloca la columna como primera pasando el nombre del campo. Este slot está conectado al cuadro combinado de busqueda del componente. Cuando seleccionamos un campo este se coloca como primera columna y se reordena la tabla con esta columna. De esta manera siempre tendremos la tabla ordenada mediante el campo en el que queremos buscar. @param c Nombre del campo, esta columna intercambia su posion con la primera columna @return Falso si no existe el campo @author [email protected] @author InfoSiAL, S.L. """ @QtCore.pyqtSlot(int) @QtCore.pyqtSlot(str) def putFirstCol(self, c): _index = c if isinstance(c, str): _index = self.tableRecords_.realColumnIndex(c) if _index < 0: return False self.moveCol(_index, 0) return True """ Coloca la columna como segunda pasando el nombre del campo. @author Silix - dpinelo """ @QtCore.pyqtSlot(int) @QtCore.pyqtSlot(str) def putSecondCol(self, c): _index = c if isinstance(c, str): _index = self.tableRecords_.realColumnIndex(c) if _index < 0: return False self.moveCol(_index, 1) return True """ Mueve una columna de un campo origen a la columna de otro campo destino @param from Nombre del campo de la columna de origen @param to Nombre del campo de la columna de destino @param firstSearch dpinelo: Indica si se mueven columnas teniendo en cuenta que esta función se ha llamado o no, desde el combo principal de búsqueda y filtrado """ @decorators.BetaImplementation def moveCol(self, from_, to, firstSearch=True): _oldFirst = None if from_ < 0 or to < 0: return tMD = self.cursor_.metadata() if not tMD: return self.tableRecords_.hide() textSearch = self.lineEditSearch.text() field = self.cursor_.metadata().indexFieldObject(to) if to == 0: # Si ha cambiado la primera columna try: self.comboBoxFieldToSearch.currentIndexChanged.disconnect(self.putFirstCol) except: pass self.comboBoxFieldToSearch.setCurrentIndex(from_) self.comboBoxFieldToSearch.currentIndexChanged.connect(self.putFirstCol) # Actializamos el segundo combo try: self.comboBoxFieldToSearch2.currentIndexChanged.disconnect(self.putSecondCol) except: pass # Falta mejorar if self.comboBoxFieldToSearch.currentIndex() == self.comboBoxFieldToSearch2.currentIndex(): self.comboBoxFieldToSearch2.setCurrentIndex(self.tableRecords_._h_header.logicalIndex(0)) self.comboBoxFieldToSearch2.currentIndexChanged.connect(self.putSecondCol) if to == 1: # Si es la segunda columna ... try: self.comboBoxFieldToSearch2.currentIndexChanged.disconnect(self.putSecondCol) except: pass self.comboBoxFieldToSearch2.setCurrentIndex(from_) self.comboBoxFieldToSearch2.currentIndexChanged.connect(self.putSecondCol) if self.comboBoxFieldToSearch.currentIndex() == self.comboBoxFieldToSearch2.currentIndex(): try: self.comboBoxFieldToSearch.currentIndexChanged.disconnect(self.putFirstCol) except: pass if self.comboBoxFieldToSearch.currentIndex() == self.comboBoxFieldToSearch2.currentIndex(): self.comboBoxFieldToSearch.setCurrentIndex(self.tableRecords_._h_header.logicalIndex(1)) self.comboBoxFieldToSearch.currentIndexChanged.connect(self.putFirstCol) if not textSearch: textSearch = self.cursor_.value(field.name()) self.refresh(True) if textSearch: self.refresh(False, True) try: self.lineEditSearch.textChanged.disconnect(self.filterRecords) except: pass self.lineEditSearch.setText(textSearch) self.lineEditSearch.textChanged.connect(self.filterRecords) self.lineEditSearch.selectAll() self.seekCursor() QtCore.QTimer.singleShot(0, self.tableRecords_.ensureRowSelectedVisible()) else: self.refreshDelayed() from_ = self.tableRecords_.visualIndexToRealIndex(from_) self.tableRecords_._h_header.swapSections(from_, to) self.refresh(True) """ if textSearch: self.refresh(False, True) if firstSearch: self.lineEditSearch.textChanged.disconnect(self.filterRecords) self.lineEditSearch.setText(textSearch) self.lineEditSearch.textChanged.connect(self.filterRecords) self.lineEditSearch.selectAll() self.seekCursor() QtCore.QTimer.singleShot(0,self.tableRecords_.ensureRowSelectedVisible) else: self.refreshDelayed() if not self.sender(): self.lineEditSearch.setFocus() """ # self.tableRecords_.show() """ Inicia el cursor segun este campo sea de la tabla origen o de una tabla relacionada """ def initCursor(self): if not self.topWidget or not self.cursor_: return if not self.cursor_.metadata(): return tMD = None if not self.sortField_: tMD = self.cursor_.metadata() if tMD: self.sortField_ = tMD.field(tMD.primaryKey()) ownTMD = None if self.tableName_: if not self.cursor_.db().manager().existsTable(self.tableName_): ownTMD = True tMD = self.cursor_.db().manager().createTable(self.tableName_) else: ownTMD = True tMD = self.cursor_.db().manager().metadata(self.tableName_) if not tMD: return if not self.foreignField_ or not self.fieldRelation_: if not self.cursor_.metadata(): if ownTMD and tMD and not tMD.inCache(): del tMD return if not self.cursor_.metadata().name() == self.tableName_: ctxt = self.cursor_.context() self.cursor_ = FLSqlCursor( self.tableName_, True, self.cursor_.db().connectionName(), None, None, self ) if self.cursor_: self.cursor_.setContext(ctxt) self.cursorAux = None if ownTMD and tMD and not tMD.inCache(): del tMD return else: cursorTopWidget = self.topWidget.cursor() if cursorTopWidget and not cursorTopWidget.metadata().name() == self.tableName_: self.cursor_ = cursorTopWidget if not self.tableName_ or not self.foreignField_ or not self.fieldRelation_ or self.cursorAux: if ownTMD and tMD and not tMD.inCache(): del tMD return self.cursorAux = self.cursor_ curName = self.cursor_.metadata().name() rMD = self.cursor_.metadata().relation(self.foreignField_, self.fieldRelation_, self.tableName_) testM1 = tMD.relation(self.fieldRelation_, self.foreignField_, curName) checkIntegrity = False if not rMD: if testM1: if testM1.cardinality() == FLRelationMetaData.RELATION_M1: checkIntegrity = True fMD = self.cursor_.metadata().field(self.foreignField_) if fMD: tmdAux = self.cursor_.db().manager().metadata(self.tableName_) if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): del tmdAux rMD = FLRelationMetaData( self.tableName_, self.fieldRelation_, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity ) fMD.addRelationMD(rMD) # print("FLTableDB : La relación entre la tabla del formulario %s y esta tabla %s de este campo no existe, pero sin embargo se han indicado los campos de relación( %s, %s )" % ( curName, self.tableName_, self.fieldRelation_, self.foreignField_)) # print("FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (curName, self.foreignField_, self.tableName_, self.fieldRelation_)) else: # print("FLTableDB : El campo ( %s ) indicado en la propiedad foreignField no se encuentra en la tabla ( %s )" % (self.foreignField_, curName)) pass rMD = testM1 if not rMD: fMD = tMD.field(self.fieldRelation_) if fMD: rMD = FLRelationMetaData( curName, self.foreignField_, FLRelationMetaData.RELATION_1M, False, False, False ) fMD.addRelationMD(rMD) print( "FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (self.tableName_, self.fieldRelation_, curName, self.foreignField_) ) else: print( "FLTableDB : El campo ( %s ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %s )" % (self.fieldRelation_, self.tableName_) ) self.cursor_ = FLSqlCursor(self.tableName_, True, self.cursor_.db().connectionName(), self.cursorAux, rMD, self) if not self.cursor_: self.cursor_ = self.cursorAux self.cursorAux = None else: self.cursor_.setContext(self.cursorAux.context()) if self.showed: try: self.cursorAux.newBuffer.disconnect(self.refresh) except: pass self.cursorAux.newBuffer.connect(self.refresh) if self.cursorAux and isinstance(self.topWidget, FLFormSearchDB): self.topWidget.setCaption(self.cursor_.metadata().alias()) self.topWidget_.setCursor(self.cursor_) if ownTMD or tMD and not tMD.inCache(): del tMD """ Posiciona el cursor en un registro valido """ @decorators.NotImplementedWarn def seekCursor(self): return textSearch = self.lineEditSearch.text() if not textSearch: return if not self.cursor_: return fN = self.sortField_.name() textSearch.replace("%", "") if not "'" in textSearch and not "\\" in textSearch: sql = self.cursor_.executedQuery() + " LIMIT 1" """ #QSqlQuery qry(sql, cursor_->db()->db()); #FIXME if (qry.first()) { QString v(qry.value(0).toString()); int pos = -1; if (!v.upper().startsWith(textSearch.upper())) pos = cursor_->atFromBinarySearch(fN, textSearch, orderAsc_); if (pos == -1) pos = cursor_->atFromBinarySearch(fN, v, orderAsc_); cursor_->seek(pos, false, true); """ """ Redefinida por conveniencia """ @decorators.NotImplementedWarn def setEnabled(self, b): pass """ Establece el ancho de una columna @param field Nombre del campo de la base de datos correspondiente a la columna @param w Ancho de la columna """ @decorators.NotImplementedWarn def setColumnWidth(self, field, w): pass """ @return Ancho de la columna """ @decorators.NotImplementedWarn def columnWidth(self, c): pass """ Establece el alto de una fila @param row Número de orden de la fila, empezando en 0 @param h Alto de la fila """ @decorators.NotImplementedWarn def setRowHeight(self, row, h): pass """ @return Alto de la fila """ @decorators.NotImplementedWarn def rowHeight(self, row): pass """ Exporta a una hoja de cálculo ODS y la visualiza """ @decorators.NotImplementedWarn def exportToOds(self): pass """ Conmuta el sentido de la ordenación de los registros de la tabla, de ascendente a descendente y viceversa. Los registros siempre se ordenan por la primera columna. Si la propiedad autoSortColumn es TRUE. """ @decorators.NotImplementedWarn def switchSortOrder(self, col=0): pass """ Filtra los registros de la tabla utilizando el primer campo, según el patrón dado. Este slot está conectado al cuadro de texto de busqueda del componente, tomando el contenido de este como patrón para el filtrado. @param p Cadena de caracteres con el patrón de filtrado """ @QtCore.pyqtSlot(str) def filterRecords(self, p): if not self.cursor_.model(): return bFilter = None p = str(p) refreshData = None if "%" in p: refreshData = True msec_refresh = 400 column = self.tableRecords_._h_header.logicalIndex(0) field = self.cursor_.model().metadata().indexFieldObject(column) bFilter = self.cursor_.db().manager().formatAssignValue(field, p, True) idMod = self.cursor_.db().managerModules().idModuleOfFile(self.cursor_.metadata().name() + ".mtd") functionQSA = idMod + ".tableDB_filterRecords_" + self.cursor_.metadata().name() vargs = [] vargs.append(self.cursor_.metadata().name()) vargs.append(p) vargs.append(field.name()) vargs.append(bFilter) if functionQSA: msec_refresh = 800 ret = self.cursor_._prj.call(functionQSA, vargs, None) if ret: bFilter = ret print("functionQSA:%s:" % functionQSA) else: if p == "": bFilter = None self.refreshDelayed(msec_refresh, (bFilter or refreshData)) self.filter_ = bFilter @decorators.NotImplementedWarn def setSortOrder(self, ascending): pass @decorators.NotImplementedWarn def isSortOrderAscending(self): pass """ Activa la tabla de datos """ @decorators.NotImplementedWarn def activeTabData(self, b): pass """ Activa la tabla de filtro """ @decorators.NotImplementedWarn def activeTabFilter(self, b): pass """ Limpia e inicializa el filtro """ @decorators.NotImplementedWarn def tdbFilterClear(self): pass """ Señal emitida cuando se refresca por cambio de filtro """ refreshed = QtCore.pyqtSignal() """ Señal emitida cuando se establece si el componente es o no de solo lectura. """ readOnlyChanged = QtCore.pyqtSignal(bool) """ Señal emitida cuando se establece si el componente es o no de solo edición. """ editOnlyChanged = QtCore.pyqtSignal(bool) """ Señal emitida cuando se establece si el componente es o no de solo inserción. """ insertOnlyChanged = QtCore.pyqtSignal(bool) """ Señal emitida cuando se establece cambia el registro seleccionado. """ # currentChanged = QtCore.pyqtSignal() @QtCore.pyqtSlot() @decorators.BetaImplementation def chooseRecord(self): if isinstance(self.topWidget, FLFormSearchDB): if self.topWidget.inExec_: self.topWidget.accept() return if self.cursor().isLocked(): print("FLTable(%s):Registro bloqueado. Modo Solo lectura" % self.cursor().curName()) self.browseRecord() else: self.editRecord()
def insert(table_or_cursor, fields, values, where="", conn=None): if isinstance(table_or_cursor, str): cur = FLSqlCursor(table_or_cursor, conn) else: cur = table_or_cursor if cur is None: return False if not cur.metadata(): return False fieldsCount = len(fields) cur.setModeAccess(cur.Insert) cur.refreshBuffer() for i in range(0, fieldsCount - 1): cur.setValueBuffer(fields[i], values[i]) msgCheck = cur.msgCheckIntegrity() if msgCheck != "": ok = False raise Exception(msgCheck) ok = False actCheck = cur.activatedCheckIntegrity() cur.setActivatedCheckIntegrity(False) ok = cur.commitBuffer() cur.setActivatedCheckIntegrity(actCheck) return ok
class FLTableDB(QtGui.QWidget): _tableView = None _vlayout = None _lineEdit = None _comboBox_1 = None _comboBox_2 = None topWidget = QtGui.QWidget showed = False def __init__(self, parent=None, action_or_cursor=None, *args): print("FLTableDB:", parent, action_or_cursor, args) # TODO: Falta el lineeditsearch y el combo, que los QS lo piden super(FLTableDB, self).__init__(parent, *args) # TODO: LA inicialización final hay que hacerla más tarde, en el primer # show(), porque sino obligas a tenerlo todo preparado en el constructor. self._tableView = QtGui.QTableView() self._lineEdit = QtGui.QLineEdit() _label1 = QtGui.QLabel() _label2 = QtGui.QLabel() self._comboBox_1 = QtGui.QComboBox() self._comboBox_2 = QtGui.QComboBox() _label1.setText("Buscar") _label2.setText("en") self._vlayout = QtGui.QVBoxLayout() _hlayout = QtGui.QHBoxLayout() self._tableView._v_header = self._tableView.verticalHeader() self._tableView._v_header.setDefaultSectionSize(18) self._tableView._h_header = self._tableView.horizontalHeader() self._tableView._h_header.setDefaultSectionSize(70) _hlayout.addWidget(_label1) _hlayout.addWidget(self._lineEdit) _hlayout.addWidget(_label2) _hlayout.addWidget(self._comboBox_1) _hlayout.addWidget(self._comboBox_2) self._vlayout.addLayout(_hlayout) self._vlayout.addWidget(self._tableView) self.setLayout(self._vlayout) self._parent = parent while True: parent_cursor = getattr(self._parent, "_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent print(self._parent) self._tableView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self._tableView.setSelectionMode( QtGui.QAbstractItemView.SingleSelection) self._tableView.setSelectionBehavior( QtGui.QAbstractItemView.SelectRows) self._tableView.setAlternatingRowColors(True) if action_or_cursor is None and parent_cursor: action_or_cursor = parent_cursor if isinstance(action_or_cursor, FLSqlCursor): self._cursor = action_or_cursor elif isinstance(action_or_cursor, str): self._cursor = FLSqlCursor(action_or_cursor) else: self._cursor = None if self._cursor: self._tableView._h_header.setResizeMode( QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor._model) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: for column in range(self._cursor._model.columnCount()): self._comboBox_1.addItem( self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem( self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect( self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded) def __getattr__(self, name): return DefFun(self, name) def loaded(self): # Es necesario pasar a modo interactivo lo antes posible # Sino, creamos un bug en el cierre de ventana: se recarga toda la tabla para saber el tamaño print("FLTableDB: setting columns in interactive mode") self._tableView._h_header.setResizeMode(QtGui.QHeaderView.Interactive) def cursor(self): assert self._cursor return self._cursor def obj(self): return self def comboBox_putFirstCol(self): self.putFirstCol(str(self._comboBox_1.currentText())) def comboBox_putSecondCol(self): self.putSecondCol(str(self._comboBox_2.currentText())) def putFirstCol(self, fN): _oldPos = None _oldFirst = self._tableView._h_header.logicalIndex(0) for column in range(self._cursor._model.columnCount()): if self._cursor._model.headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) if not self._comboBox_1.currentText() == fN: self._comboBox_1.setCurrentIndex(column) return False break if not _oldPos or fN == "*": return False else: self._tableView._h_header.swapSections(_oldPos, 0) self._comboBox_2.setCurrentIndex(_oldFirst) return True def putSecondCol(self, fN): _oldPos = None _oldSecond = self._tableView._h_header.logicalIndex(1) for column in range(self._cursor._model.columnCount()): if self._cursor._model.headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) break if not _oldPos or fN == "*": return False if not self._comboBox_1.currentText() == fN: self._tableView._h_header.swapSections(_oldPos, 1) else: self._comboBox_1.setCurrentIndex(_oldSecond) return True def setTableName(self, tableName): self._tableName = tableName if self.showed: if self.topWidget: self.initCursor() else: self.initFakeEditor() def setForeignField(self, foreingField): self._foreingField = foreingField if self.showed: if self.topWidget: self.initCursor() else: self.initFakeEditor() def setFieldRelation(self, fieldRelation): self._fieldRelation = fieldRelation if self.showed: if self.topWidget: self.initCursor() else: self.initFakeEditor() @decorators.NotImplementedWarn def initCursor(self): # si no existe crea la tabla if not self._cursor: return False if not self._cursor._model: return False self._tMD = 0 if not self._sortField: self._tMD = self._cursor._model.name() if self._tMD: self.sortField_ = self._tMD.value(self._cursor._currentregister, self._tMD.primaryKey()) ownTMD = False if not self._tableName: #if not cursor_->db()->manager()->existsTable(tableName_)) { ownTMD = True #tMD = cursor_->db()->manager()->createTable(tableName_); else: ownTMD = True self._tMD = self._cursor._model._table.name if not self._tMD: return if not self._foreignField or not self._fieldRelation: if not self._cursor._model: if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return if not self._cursor._model.name() == self._tableName: ctxt = self._cursor.context() self._cursor = FLSqlCursor(self._tableName) if self._cursor: self._cursor.setContext(ctxt) cursorAux = 0 if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return else: cursorTopWidget = self.topWidget._cursor( ) # ::qt_cast<FLFormDB *>(topWidget)->cursor() if cursorTopWidget and not cursorTopWidget._model.name( ) == self._tableName: self._cursor = cursorTopWidget if not self._tableName or not self._foreignField or not self._fieldRelation or cursorAux: if ownTMD and self._tMD and not self._tMD.inCache(): tMD = None return cursorAux = self._cursor curName = self._cursor._model.name() rMD = self._cursor._model.relation(self._foreignField, self._fieldRelation, self._tableName) testM1 = self._tMD.relation(self._fieldRelation, self._foreignField, curName) checkIntegrity = bool(False) if not rMD: if testM1: checkIntegrity = ( testM1.cardinality() == FLRelationMetaData.RELATION_M1) fMD = FLTableMetaData(self._cursor._model.field( self._foreignField)) if (fMD): tmdAux = self._cursor._model(self._tableName) if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): # mirar inCache() tmdAux = None rMD = FLRelationMetaData(self._tableName, self._fieldRelation, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity) fMD.addRelationMD(rMD) print( "FLTableDB : La relación entre la tabla del formulario %r y esta tabla %r de este campo no existe, pero sin embargo se han indicado los campos de relación( %r, %r )" % (curName, self._tableName, self._fieldRelation, self._foreignField)) print( "FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (curName, self._foreignField, self._tableName, self._fieldRelation)) else: print( "FLTableDB : El campo ( %r ) indicado en la propiedad foreignField no se encuentra en la tabla ( %r )" % (self._foreignField, curName)) rMD = testM1 if not rMD: fMD = FLFieldMetaData(tMD.field(self._fieldRelation)) if (fMD): rMD = FLRelationMetaData(curName, self._foreignField, FLRelationMetaData.RELATION_1M, False, False, False) fMD.addRelationMD(rMD) print( "FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (self._tableName, self._fieldRelation, curName, self._foreignField)) else: print( "FLTableDB : El campo ( %r ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %r )" % (self._fieldRelation, self._tableName)) self._cursor = FLSqlCursor(self._tableName, True, self._cursor.db().connectionName(), cursorAux, rMD, self) if not self._cursor: self._cursor = cursorAux cursorAux = 0 else: self._cursor.setContext(cursorAux.context()) if self.showed: self.disconnect(cursorAux, QtCore.SIGNAL('newBuffer()'), self.refresh()) self.connect(cursorAux, QtCore.SIGNAL('newBuffer()'), self.refresh()) if cursorAux and self.topWidget.isA("FLFormSearchDB"): self.topWidget.setCaption(self._cursor._model.alias()) self.topWidget.setCursor( self._cursor ) #::qt_cast<FLFormSearchDB *>(topWidget)->setCursor(cursor_); if ownTMD and tMD and not tMD.inCache(): tMD = None @QtCore.pyqtSlot() def close(self): print("FLTableDB: close()") @QtCore.pyqtSlot() def refresh(self): print("FLTableDB: refresh()", self.parent().parent().parent()) self._cursor.refresh() @QtCore.pyqtSlot() def show(self): print("FLTableDB: show event") super(FLTableDB, self).show() @QtCore.pyqtSlot() def insertRecord(self): self._cursor.insertRecord() @QtCore.pyqtSlot() def editRecord(self): self._cursor.editRecord() @QtCore.pyqtSlot() def deleteRecord(self): self._cursor.deleteRecord() @QtCore.pyqtSlot() def browseRecord(self): self._cursor.browseRecord() @QtCore.pyqtSlot() def copyRecord(self): self._cursor.copyRecord()
def sqlDelete(self, t, w, connName="default"): """ Borra uno o más registros en una tabla mediante un objeto FLSqlCursor @param t Nombre de la tabla @param w Sentencia where para identificar los registros a borrar. @param connName Nombre de la conexion @return Verdadero en caso de realizar la inserción con éxito, falso en cualquier otro caso """ from pineboolib.fllegacy.FLSqlCursor import FLSqlCursor c = FLSqlCursor(t, True, connName) # if not c.select(w): # return False c.select(w) c.setForwardOnly(True) while c.next(): c.setModeAccess(FLSqlCursor.Del) c.refreshBuffer() if not c.commitBuffer(): return False return True
def initCursor(self): if not self.topWidget or not self.cursor_: return if not self.cursor_.metadata(): return tMD = self.cursor_.metadata() if not self.sortField_: if tMD: self.sortField_ = tMD.field(tMD.primaryKey()) ownTMD = None if self.tableName_: if DEBUG: print("**FLTableDB::name: %r tableName: %r" % (self.objectName(), self.tableName_)) if not self.cursor_.db().manager().existsTable(self.tableName_): ownTMD = True tMD = self.cursor_.db().manager().createTable(self.tableName_) else: ownTMD = True tMD = self.cursor_.db().manager().metadata(self.tableName_) if not tMD or isinstance(tMD,bool): return if not self.foreignField_ or not self.fieldRelation_: if not self.cursor_.metadata(): if ownTMD and tMD and not tMD.inCache(): del tMD return if not self.cursor_.metadata().name() == self.tableName_: ctxt = self.cursor_.context() self.cursor_ = FLSqlCursor(self.tableName_, True, self.cursor_.db().connectionName(), None, None , self) if self.cursor_: self.cursor_.setContext(ctxt) self.cursorAux = None if ownTMD and tMD and not tMD.inCache(): del tMD return else: cursorTopWidget = self.topWidget.cursor() if cursorTopWidget and not cursorTopWidget.metadata().name() == self.tableName_: self.cursor_ = cursorTopWidget if not self.tableName_ or not self.foreignField_ or not self.fieldRelation_ or self.cursorAux: if ownTMD and tMD and not tMD.inCache(): del tMD return self.cursorAux = self.cursor_ curName = self.cursor_.metadata().name() rMD = self.cursor_.metadata().relation(self.foreignField_, self.fieldRelation_, self.tableName_) testM1 = tMD.relation(self.fieldRelation_, self.foreignField_, curName) checkIntegrity = False if not rMD: if testM1: if testM1.cardinality() == FLRelationMetaData.RELATION_M1: checkIntegrity = True fMD = self.cursor_.metadata().field(self.foreignField_) if fMD: tmdAux = self.cursor_.db().manager().metadata(self.tableName_) if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): del tmdAux rMD = FLRelationMetaData(self.tableName_, self.fieldRelation_, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity) fMD.addRelationMD(rMD) #print("FLTableDB : La relación entre la tabla del formulario %s y esta tabla %s de este campo no existe, pero sin embargo se han indicado los campos de relación( %s, %s )" % ( curName, self.tableName_, self.fieldRelation_, self.foreignField_)) #print("FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (curName, self.foreignField_, self.tableName_, self.fieldRelation_)) else: #print("FLTableDB : El campo ( %s ) indicado en la propiedad foreignField no se encuentra en la tabla ( %s )" % (self.foreignField_, curName)) pass rMD = testM1 if not rMD: fMD = tMD.field(self.fieldRelation_) if fMD: rMD = FLRelationMetaData(curName, self.foreignField_, FLRelationMetaData.RELATION_1M, False, False, False) fMD.addRelationMD(rMD) if DEBUG: print("FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (self.tableName_, self.fieldRelation_, curName, self.foreignField_)) else: if DEBUG: print("FLTableDB : El campo ( %s ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %s )" % (self.fieldRelation_, self.tableName_)) self.cursor_ = FLSqlCursor(self.tableName_, True, self.cursor_.db().connectionName(), self.cursorAux, rMD, self) if not self.cursor_: self.cursor_ = self.cursorAux self.cursorAux = None else: self.cursor_.setContext(self.cursorAux.context()) if self.showed: try: self.cursorAux.newBuffer.disconnect(self.refresh) except: pass self.cursorAux.newBuffer.connect(self.refresh) if self.cursorAux and isinstance(self.topWidget, FLFormSearchDB): self.topWidget.setCaption(self.cursor_.metadata().alias()) self.topWidget_.setCursor(self.cursor_) if ownTMD or tMD and not tMD.inCache(): del tMD
class FLTableDB(QtGui.QWidget): """ PLUGIN que contiene una tabla de la base de datos. Este objeto contiene todo lo necesario para manejar los datos de una tabla. Además de la funcionalidad de busqueda en la tabla por un campo, mediante filtros. Este plugin para que sea funcional debe tener como uno de sus padres o antecesor a un objeto FLFormDB. @author InfoSiAL S.L. """ """ Tipos de condiciones para el filtro """ All = None Contains = None Starts = None End = None Equal = None Dist = None Greater = None Less = None FromTo = None Null = None NotNull = None _parent = None _name = None loadLater_ = None comboBoxFieldToSearch = None comboBoxFieldToSearch2 = None tableRecords_ = None lineEditSearch = None tabDataLayout = None tabControlLayout = None _initCursorWhenLoad = None _initTableRecordWhenLoad = None _controlsInit = None """ constructor """ def __init__(self, parent, name = None): super(FLTableDB, self).__init__(parent) self.topWidget = parent self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(0, self.loaded) def __getattr__(self, name): return DefFun(self, name) def loaded(self): # Es necesario pasar a modo interactivo lo antes posible # Sino, creamos un bug en el cierre de ventana: se recarga toda la tabla para saber el tamaño #print("FLTableDB(%s): setting columns in interactive mode" % self._tableName) while True: #Ahora podemos buscar el cursor ... porque ya estamos añadidos al formulario parent_cursor = getattr(self.topWidget,"cursor_", None) if parent_cursor: break new_parent = self.topWidget.parentWidget() if new_parent is None: break self.topWidget = new_parent if getattr(self.topWidget.parentWidget(), "cursor_", None): self.topWidget = self.topWidget.parentWidget() if not parent_cursor: print("FLTableDB : Uno de los padres o antecesores de FLTableDB deber ser de la clase FLFormDB o heredar de ella") return self.cursor_ = self.topWidget.cursor_ self.setFont(QtGui.qApp.font()) if not self._name: self.setName("FLTableDB") self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.refreshDelayed) # FIXME: El problema de que aparezca al editar un registro que no es, es por carga doble de initCursor() # ...... Cuando se lanza showWidget, y tiene _initCursorWhenLoad, lanza initCursor y luego otra vez. # ...... esta doble carga provoca el error y deja en el formulario el cursor original. self._initCursorWhenLoad = False self.showWidget() self._loaded = True self.initCursor() if DEBUG: print("**FLTableDB::name: %r cursor: %r" % (self.objectName(), self.cursor_.d.nameCursor_)) def setName(self, name): self._name = name """ Inicia el cursor segun este campo sea de la tabla origen o de una tabla relacionada """ def initCursor(self): if not self.topWidget or not self.cursor_: return if not self.cursor_.metadata(): return tMD = self.cursor_.metadata() if not self.sortField_: if tMD: self.sortField_ = tMD.field(tMD.primaryKey()) ownTMD = None if self.tableName_: if DEBUG: print("**FLTableDB::name: %r tableName: %r" % (self.objectName(), self.tableName_)) if not self.cursor_.db().manager().existsTable(self.tableName_): ownTMD = True tMD = self.cursor_.db().manager().createTable(self.tableName_) else: ownTMD = True tMD = self.cursor_.db().manager().metadata(self.tableName_) if not tMD or isinstance(tMD,bool): return if not self.foreignField_ or not self.fieldRelation_: if not self.cursor_.metadata(): if ownTMD and tMD and not tMD.inCache(): del tMD return if not self.cursor_.metadata().name() == self.tableName_: ctxt = self.cursor_.context() self.cursor_ = FLSqlCursor(self.tableName_, True, self.cursor_.db().connectionName(), None, None , self) if self.cursor_: self.cursor_.setContext(ctxt) self.cursorAux = None if ownTMD and tMD and not tMD.inCache(): del tMD return else: cursorTopWidget = self.topWidget.cursor() if cursorTopWidget and not cursorTopWidget.metadata().name() == self.tableName_: self.cursor_ = cursorTopWidget if not self.tableName_ or not self.foreignField_ or not self.fieldRelation_ or self.cursorAux: if ownTMD and tMD and not tMD.inCache(): del tMD return self.cursorAux = self.cursor_ curName = self.cursor_.metadata().name() rMD = self.cursor_.metadata().relation(self.foreignField_, self.fieldRelation_, self.tableName_) testM1 = tMD.relation(self.fieldRelation_, self.foreignField_, curName) checkIntegrity = False if not rMD: if testM1: if testM1.cardinality() == FLRelationMetaData.RELATION_M1: checkIntegrity = True fMD = self.cursor_.metadata().field(self.foreignField_) if fMD: tmdAux = self.cursor_.db().manager().metadata(self.tableName_) if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): del tmdAux rMD = FLRelationMetaData(self.tableName_, self.fieldRelation_, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity) fMD.addRelationMD(rMD) #print("FLTableDB : La relación entre la tabla del formulario %s y esta tabla %s de este campo no existe, pero sin embargo se han indicado los campos de relación( %s, %s )" % ( curName, self.tableName_, self.fieldRelation_, self.foreignField_)) #print("FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (curName, self.foreignField_, self.tableName_, self.fieldRelation_)) else: #print("FLTableDB : El campo ( %s ) indicado en la propiedad foreignField no se encuentra en la tabla ( %s )" % (self.foreignField_, curName)) pass rMD = testM1 if not rMD: fMD = tMD.field(self.fieldRelation_) if fMD: rMD = FLRelationMetaData(curName, self.foreignField_, FLRelationMetaData.RELATION_1M, False, False, False) fMD.addRelationMD(rMD) if DEBUG: print("FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (self.tableName_, self.fieldRelation_, curName, self.foreignField_)) else: if DEBUG: print("FLTableDB : El campo ( %s ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %s )" % (self.fieldRelation_, self.tableName_)) self.cursor_ = FLSqlCursor(self.tableName_, True, self.cursor_.db().connectionName(), self.cursorAux, rMD, self) if not self.cursor_: self.cursor_ = self.cursorAux self.cursorAux = None else: self.cursor_.setContext(self.cursorAux.context()) if self.showed: try: self.cursorAux.newBuffer.disconnect(self.refresh) except: pass self.cursorAux.newBuffer.connect(self.refresh) if self.cursorAux and isinstance(self.topWidget, FLFormSearchDB): self.topWidget.setCaption(self.cursor_.metadata().alias()) self.topWidget_.setCursor(self.cursor_) if ownTMD or tMD and not tMD.inCache(): del tMD """ Para obtener el cursor utilizado por el componente. return Objeto FLSqlCursor con el cursor que contiene los registros para ser utilizados en el formulario """ def cursor(self): if not self.cursor_.d.buffer_: self.cursor_.refreshBuffer() return self.cursor_ """ Para obtener el nombre de la tabla asociada. @return Nombre de la tabla asociado """ def tableName(self): return self.tableName_ """ Para establecer el nombre de la tabla asociada. @param fT Nombre de la tabla asociada """ def setTableName(self, fT): self.tableName_ = fT if self.showed: if self.topwidget: self.initCursor() else: self.initFakeEditor() else: self._initCursorWhenLoad = True self._initTableRecordWhenLoad = True """ Para obtener el nombre del campo foráneo. @return Nombre del campo """ def foreignField(self): return self.foreignField_ """ Para establecer el nombre del campo foráneo. @param fN Nombre del campo """ def setForeignField(self, fN): self.foreignField_ = fN if self.showed: if self.topwidget: self.initCursor() else: self.initFakeEditor() else: self._initCursorWhenLoad = True self._initTableRecordWhenLoad = True """ Para obtener el nombre del campo relacionado. @return Nombre del campo """ def fieldRelation(self): return self.fieldRelation_ """ Para establecer el nombre del campo relacionado. @param fN Nombre del campo """ def setFieldRelation(self, fN): self.fieldRelation_ = fN if self.showed: if self.topwidget: self.initCursor() else: self.initFakeEditor() else: self._initCursorWhenLoad = True self._initTableRecordWhenLoad = True """ Establece si el componente esta en modo solo lectura o no. """ def setReadOnly(self, mode): if self.tableRecords_: self.readonly = mode self.tableRecords_.setFLReadOnly(mode) #self.readOnlyChanged(mode).emit() FIXME self.reqReadOnly_ = mode def readOnly(self): return self.reqReadOnly_ """ Establece si el componente esta en modo solo edición o no. """ def setEditOnly(self, mode): if self.tableRecords_: self.editonly_ = mode self.tableRecords_.setEditOnly(mode) #self.editOnlyChanged(mode).emit() #FIXME self.reqEditOnly_ = mode def editOnly(self): return self.reqEditOnly_ """ Establece el componente a sólo inserción o no. """ def setInsertOnly(self, mode): if self.tableRecords_: self.insertonly_ = mode self.tableRecords_.setInsertOnly(mode) self.insertOnlyChanged(mode).emit() self.reqInsertOnly = mode def insertOnly(self): return self.reqInsertOnly_ """ Establece el filtro inicial de búsqueda """ def setInitSearch(self, iS): self.initSearch_ = iS """ Establece el orden de las columnas de la tabla. @param fields Lista de los nombres de los campos ordenada según se desea que aparezcan en la tabla de izquierda a derecha """ @decorators.NotImplementedWarn def setOrderCols(self, fields): pass """ Devuelve la lista de los campos ordenada por sus columnas en la tabla de izquierda a derecha """ @decorators.NotImplementedWarn def orderCols(self): return None """ Establece el filtro de la tabla @param f Sentencia Where que establece el filtro """ @decorators.NotImplementedWarn def setFilter(self, f): pass """ Devuelve el filtro de la tabla @return Filtro """ @decorators.NotImplementedWarn def filter(self): return None """ Devuelve el filtro de la tabla impuesto en el Find @return Filtro """ @decorators.NotImplementedWarn def findFilter(self): return None """ Obtiene si la columna de selección está activada """ @decorators.NotImplementedWarn def checkColumnEnabled(self): return None """ Establece el estado de activación de la columna de selección El cambio de estado no será efectivo hasta el siguiente refresh. """ @decorators.NotImplementedWarn def setCheckColumnEnabled(self, b): pass """ Obiente el texto de la etiqueta de encabezado para la columna de selección """ @decorators.NotImplementedWarn def aliasCheckColumn(self): pass """ Establece el texto de la etiqueta de encabezado para la columna de selección El cambio del texto de la etiqueta no será efectivo hasta el próximo refresh """ @decorators.NotImplementedWarn def setAliasCheckColumn(self, t): pass """ Obtiene si el marco de búsqueda está oculto """ @decorators.NotImplementedWarn def findHidden(self): return None """ Oculta o muestra el marco de búsqueda @param h TRUE lo oculta, FALSE lo muestra """ @decorators.NotImplementedWarn def setFindHidden(self, h): pass """ Obtiene si el marco para conmutar entre datos y filtro está oculto """ @decorators.NotImplementedWarn def filterHidden(self): return None """ Oculta o muestra el marco para conmutar entre datos y filtro @param h TRUE lo oculta, FALSE lo muestra """ @decorators.NotImplementedWarn def setFilterHidden(self, h): pass """ Ver FLTableDB::showAllPixmaps_ """ @decorators.NotImplementedWarn def showAllPixmaps(self): return None """ Ver FLTableDB::showAllPixmaps_ """ @decorators.NotImplementedWarn def setShowAllPixmaps(self, s): pass """ Ver FLTableDB::functionGetColor_ """ @decorators.NotImplementedWarn def functionGetColor(self): pass """ Ver FLTableDB::functionGetColor_ """ @decorators.NotImplementedWarn def setFunctionGetColor(self, f): pass """ Asigna el nombre de función a llamar cuando cambia el filtro. """ def setFilterRecordsFunction(self, fn): self.tableDB_filterRecords_functionName_ = fn """ Ver FLTableDB::onlyTable_ """ @decorators.NotImplementedWarn def setOnlyTable(self, on = True): pass def onlyTable(self): return self.reqOnlyTable_ """ Ver FLTableDB::autoSortColumn_ """ @decorators.NotImplementedWarn def setAutoSortColumn(self, on = True): self.autoSortColumn_ = on def autoSortColumn(self): return self.autoSortColumn_ """ Filtro de eventos """ def eventFilter(self, obj, ev): if not self.tableRecords_ or not self.lineEditSearch or not self.comboBoxFieldToSearch or not self.comboBoxFieldToSearch2 or not self.cursor_: return super(FLTableDB, self).eventFilter(obj, ev) if ev.type() == QtCore.QEvent.KeyPress and isinstance(obj, FLDataTable): k = ev if k.key() == QtCore.Qt.Key_F2: self.comboBoxFieldToSearch.popup() return True if ev.type() == QtCore.QEvent.KeyPress and isinstance(obj, QtGui.QLineEdit): k = ev if k.key() == QtCore.Qt.Key_Enter or k.key() == QtCore.Qt.Key_Return: self.tableRecords_.setFocus() return True if k.key() == QtCore.Qt.Key_Up: self.comboBoxFieldToSearch.setFocus() return True if k.key() == QtCore.Qt.Key_Down: self.tableRecords_.setFocus() return True if k.key() == QtCore.Qt.Key_F2: self.comboBoxFieldToSearch.popup() return True if k.text() == "'" or k.text() == "\\": return True if isinstance(obj, FLDataTable) or isinstance(obj, QtGui.QLineEdit): return False else: return super(FLTableDB, self).eventFilter(obj, ev) """ Captura evento mostrar """ def showEvent(self, e): super(FLTableDB, self).showEvent(e) self.showWidget() """ Redefinida por conveniencia """ def showWidget(self): if not self._loaded: #Esperamos a que la carga se realice timer = QtCore.QTimer(self) timer.singleShot(30, self.showWidget) return else: if not self.showed and not self._initCursorWhenLoad and self.cursor_ and self.tableRecords_: if not self.topWidget: self.initFakeEditor() self.showed = True return tMD = None ownTMD = None if self.tableName_: if not self.cursor_.db().manager().existsTable(self.tableName_): ownTMD = True tMD = self.cursor_.db().manager().createTable(self.tableName_) else: ownTMD = True tMD = self.cursor_.db().manager().metadata(self.tableName_) if not tMD: return if not self.cursorAux: if self.initSearch_: self.refresh(True, True) QtCore.QTimer.singleShot(0, self.tableRecords_.ensureRowSelectedVisible) else: self.refresh(True) if self.tableRecords_.numRows() <= 0: self.refresh(False, True) else: self.refreshDelayed() if not isinstance(self.topWidget, FLFormRecordDB): self.lineEditSearch.setFocus() if self.cursorAux: if isinstance(self.topWidget, FLFormRecordDB) and self.cursorAux.modeAccess() == FLSqlCursor.Browse: self.cursor_.setEdition(False) self.setReadOnly(True) if self.initSearch_: self.refresh(True, True) QtCore.QTimer.singleShot(0, self.tableRecords_.ensureRowSelectedVisible) else: self.refresh(True) if self.tableRecords_.numRows() <= 0: self.refresh(False, True) else: self.refreshDelayed() elif isinstance(self.topWidget, FLFormRecordDB) and self.cursor_.modeAccess() == FLSqlCursor.Browse and (tMD and not tMD.isQuery()): self.cursor_.setEdition(False) self.setReadOnly(True) if ownTMD and tMD and not tMD.inCache(): del tMD if self._initCursorWhenLoad: self._initCursorWhenLoad = False self.initCursor() self.showWidget() if not self.tableRecords_: if not self.tableName_: if not self.cursor_: self.initCursor() QtCore.QTimer.singleShot(50, self.showWidget) return self.tableRecords() self.setTableRecordsCursor() self.showWidget() elif self.tableName_: if not self.cursor_: self.initCursor() QtCore.QTimer.singleShot(50, self.showWidget) return if self.tableName_ == self.cursor_.curName(): self.tableRecords() if self.cursor_.model(): self.setTableRecordsCursor() self.showWidget() """ Obtiene el componente tabla de registros """ def tableRecords(self): if self.tableRecords_: print("ERROR: tableRecords - llamada doble") return self.tabDataLayout = QtGui.QVBoxLayout() self.comboBoxFieldToSearch = QtGui.QComboBox() self.comboBoxFieldToSearch2 = QtGui.QComboBox() self.lineEditSearch = QtGui.QLineEdit() label1 = QtGui.QLabel() label2 = QtGui.QLabel() label1.setText("Buscar") label2.setText("en") self.tabControlLayout = QtGui.QHBoxLayout() self.tabControlLayout.addWidget(label1) self.tabControlLayout.addWidget(self.lineEditSearch) self.tabControlLayout.addWidget(label2) self.tabControlLayout.addWidget(self.comboBoxFieldToSearch) self.tabControlLayout.addWidget(self.comboBoxFieldToSearch2) self.tabDataLayout.addLayout(self.tabControlLayout) if not self.tableRecords_: self.tableRecords_ = FLDataTable(self, "tableRecords") self.tableRecords_.setFocusPolicy(QtCore.Qt.StrongFocus) self.setFocusProxy(self.tableRecords_) self.tabDataLayout.addWidget(self.tableRecords_) self.lineEditSearch.installEventFilter(self) self.tableRecords_.installEventFilter(self) self.setLayout(self.tabDataLayout) self.setTabOrder(self.tableRecords_, self.lineEditSearch) self.setTabOrder(self.lineEditSearch, self.comboBoxFieldToSearch) self.setTabOrder(self.comboBoxFieldToSearch, self.comboBoxFieldToSearch2) self.tableRecords_.recordChoosed.connect(self.currentChanged) self.lineEditSearch.textChanged.connect(self.filterRecords) model = self.cursor_.model() if model: for column in range(model.columnCount()): field = model.metadata().indexFieldObject(column) if not field.visibleGrid(): self.tableRecords_.setColumnHidden(column, True) else: self.comboBoxFieldToSearch.addItem(model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self.comboBoxFieldToSearch2.addItem(model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self.comboBoxFieldToSearch.addItem("*") self.comboBoxFieldToSearch2.addItem("*") self.comboBoxFieldToSearch.setCurrentIndex(0) self.comboBoxFieldToSearch2.setCurrentIndex(1) self.comboBoxFieldToSearch.currentIndexChanged.connect(self.putFirstCol) self.comboBoxFieldToSearch2.currentIndexChanged.connect(self.putSecondCol) self._controlsInit = True else: self.comboBoxFieldToSearch.addItem("*") self.comboBoxFieldToSearch2.addItem("*") return self.tableRecords_ """ Asigna el cursor actual del componente a la tabla de registros """ def setTableRecordsCursor(self): self.tableRecords_.setFLSqlCursor(self.cursor_) try: self.tableRecords_.doubleClicked.disconnect(self.chooseRecord) except: pass self.tableRecords_.doubleClicked.connect(self.chooseRecord) """ Refresca la pestaña datos aplicando el filtro """ @decorators.NotImplementedWarn def refreshTabData(self): pass """ Refresca la pestaña del filtro """ @decorators.NotImplementedWarn def refreshTabFilter(self): pass """ Para obtener la enumeración correspondiente a una condición para el filtro a partir de su literal """ @decorators.NotImplementedWarn def decodeCondType(self, strCondType): pass """ Construye la claúsula de filtro en SQL a partir del contenido de los valores definidos en la pestaña de filtro """ @decorators.NotImplementedWarn def tdbFilterBuildWhere(self): pass """ Inicializa un editor falso y no funcional. Esto se utiliza cuando se está editando el formulario con el diseñador y no se puede mostrar el editor real por no tener conexión a la base de datos. Crea una previsualización muy esquemática del editor, pero suficiente para ver la posisicón y el tamaño aproximado que tendrá el editor real. """ @decorators.NotImplementedWarn def initFakeEditor(self): pass """ Componente para visualizar los registros """ tableRecords_ = None """ Nombre de la tabla a la que esta asociado este componente. """ tableName_ = None """ Nombre del campo foráneo """ foreignField_ = None """ Nombre del campo de la relación """ fieldRelation_ = None """ Cursor con los datos de origen para el componente """ cursor_ = None """ Cursor auxiliar de uso interno para almacenar los registros de la tabla relacionada con la de origen """ cursorAux = None """ Matiene la ventana padre """ topWidget = None """ Indica que la ventana ya ha sido mostrada una vez """ showed = None """ Mantiene el filtro de la tabla """ filter_ = None """ Almacena si el componente está en modo sólo lectura """ readonly_ = None reqReadOnly_ = None """ Almacena si el componente está en modo sólo edición """ editonly_ = None reqEditOnly_ = None """ Indica si el componente está en modo sólo permitir añadir registros """ insertonly_ = None reqInsertOnly_ = None """ Almacena los metadatos del campo por el que está actualmente ordenada la tabla """ sortField_ = None """ Almacena los metadatos del campo por el que está actualmente ordenada la tabla en segunda instancia @author Silix - dpinelo """ sortField2_ = None """ Crónometro interno """ timer = None """ Filtro inicial de búsqueda """ initSearch_ = None """ Indica que la columna de seleción está activada """ checkColumnEnabled_ = None """ Indica el texto de la etiqueta de encabezado para la columna de selección """ aliasCheckColumn_ = None """ Indica el nombre para crear un pseudocampo en el cursor para la columna de selección """ fieldNameCheckColumn_ = None """ Indica que la columna de selección está visible """ checkColumnVisible_ = None """ Indica el número de columna por la que ordenar los registros """ sortColumn_ = None """ Indica el número de columna por la que ordenar los registros @author Silix - dpinelo """ sortColumn2_ = None """ Indica el número de columna por la que ordenar los registros @author Silix """ sortColumn3_ = None """ Indica el sentido ascendente o descendente del la ordenacion actual de los registros """ orderAsc_ = None """ Indica el sentido ascendente o descendente del la ordenacion actual de los registros @author Silix - dpinelo """ orderAsc2_ = None """ Indica el sentido ascendente o descendente del la ordenacion actual de los registros @author Silix """ orderAsc3_ = None """ Indica si se debe establecer automáticamente la primera columna como de ordenación """ autoSortColumn_ = None """ Almacena la última claúsula de filtro aplicada en el refresco """ tdbFilterLastWhere_ = None """ Diccionario que relaciona literales descriptivos de una condición de filtro con su enumeración """ mapCondType = [] """ Indica si el marco de búsqueda está oculto """ findHidden_ = None """ Indica si el marco para conmutar entre datos y filtro está oculto """ filterHidden_ = None """ Indica si se deben mostrar los campos tipo pixmap en todas las filas """ showAllPixmaps_ = None """ Nombre de la función de script a invocar para obtener el color y estilo de las filas y celdas El nombre de la función debe tener la forma 'objeto.nombre_funcion' o 'nombre_funcion', en el segundo caso donde no se especifica 'objeto' automáticamente se añadirá como prefijo el nombre del formulario donde se inicializa el componente FLTableDB seguido de un punto. De esta forma si utilizamos un mismo formulario para varias acciones, p.e. master.ui, podemos controlar si usamos distintas funciones de obtener color para cada acción (distintos nombres de formularios) o una única función común para todas las acciones. Ej. Estableciendo 'tdbGetColor' si el componente se inicializa en el formulario maestro de clientes, se utilizará 'formclientes.tdbGetColor', si se inicializa en el fomulario maestro de proveedores, se utilizará 'formproveedores.tdbGetColor', etc... Si establecemos 'flfactppal.tdbGetColor' siempre se llama a esa función independientemente del formulario en el que se inicialize el componente. Cuando se está pintando una celda se llamará a esa función pasándole cinco parámentros: - Nombre del campo correspondiente a la celda - Valor del campo de la celda - Cursor de la tabla posicionado en el registro correspondiente a la fila que está pintando. AVISO: En este punto los valores del buffer son indefinidos, no se hace refreshBuffer por motivos de eficiencia - Tipo del campo, ver FLUtilInterface::Type en FLObjectFactory.h - Seleccionado. Si es TRUE indica que la celda a pintar está en la fila resaltada/seleccionada. Generalmente las celdas en la fila seleccionada se colorean de forma distinta al resto. La función debe devolver una array con cuatro cadenas de caracteres; [ "color_de_fondo", "color_lapiz", "estilo_fondo", "estilo_lapiz" ] En los dos primeros, el color, se puede utilizar cualquier valor aceptado por QColor::setNamedColor, ejemplos; "green" "#44ADDB" En los dos últimos, el estilo, se pueden utilizar los valores aceptados por QBrush::setStyle y QPen::setStyle, ver en FLDataTable.cpp las funciones nametoBrushStyle y nametoPenStyle, ejemplos; "SolidPattern" "DiagCrossPattern" "DotLine" "SolidLine" Si alguno de los valores del array es vacio "", entonces se utilizarán los colores o estilos establecidos por defecto. """ functionGetColor_ = None """ Indica que no se realicen operaciones con la base de datos (abrir formularios). Modo "sólo tabla". """ onlyTable_ = None reqOnlyTable_ = None """ Editor falso """ fakeEditor_ = None tableDB_filterRecords_functionName_ = None """ Actualiza el conjunto de registros. """ @QtCore.pyqtSlot() @QtCore.pyqtSlot(bool) @QtCore.pyqtSlot(bool, bool) def refresh(self, refreshHead = False, refreshData = False): if not self.cursor_ or not self.tableRecords_: return tMD = self.cursor_.metadata() if not tMD: return if not self.tableName_: self.tableName_ = tMD.name() if refreshHead: if not self.tableRecords_.isHidden(): self.tableRecords_.hide() model = self.cursor_.model() for column in range(model.columnCount()): field = model.metadata().indexFieldObject(column) if not field.visibleGrid(): self.tableRecords_.setColumnHidden(column, True) else: self.tableRecords_.setColumnHidden(column, False) # FIXME FIX: Esto lo he implementado en otro lado manualmente. A elminar, o mover algo de aquel código aquí. # FIXME: Este proceso es MUY LENTO. No deberíamos hacer esto. # Hay que buscar alguna forma manual de iterar las primeras N filas, o calcular un # valor por defecto rápidamente. #self.tableRecords_._h_header.setResizeMode(QtGui.QHeaderView.ResizeToContents) #if model.rows * model.cols > 500*10: # # Esto evitará que se calcule para las que tienen más de 500*10 celdas. # self.tableRecords_._h_header.setResizeMode(0) # ... de todos modos tendríamos que, con un timer o algo para desactivar el modo. Una vez # ... ya redimensionadas inicialmente, lo único que hace es lastrar Pineboo mucho. if refreshData or self.sender(): finalFilter = self.filter_ if self.tdbFilterBuildWhere_: if not finalFilter: finalFilter = self.tdbFilterLastWhere_ else: finalFilter = "%s and %s" % (finalFilter, self.tdbFilterLastWhere_) self.tableRecords_.setPersistentFilter(finalFilter) self.tableRecords_.refresh() if self.initSearch_: try: self.lineEditSearch.textChanged.disconnect(self.filterRecords) except: pass self.lineEditSearch.setText(self.initSearch_) self.lineEditSearch.textChanged.connect(self.filterRecords) self.lineEditSearch.selectAll() self.initSearch_ = None self.seekCursor() if not self.readonly_ == self.reqReadOnly_ or (self.tableRecords_ and not self.readonly_ == self.tableRecords_.flReadOnly()): self.setReadOnly(self.reqReadOnly_) if not self.editonly_ == self.reqEditOnly_ or (self.tableRecords_ and not self.editonly_ == self.tableRecords_.editOnly()): self.setEditOnly(self.reqEditOnly_) if not self.insertonly_ == self.reqInsertOnly_ or (self.tableRecords_ and not self.insertonly_ == self.tableRecords_.insertOnly()): self.setInsetOnly(self.reqInsertOnly_) if not self.onlyTable_ == self.reqOnlyTable_ or (self.tableRecords_ and not self.onlyTable_ == self.tableRecords_.onlyTable()): self.setOnlyTable(self.reqOnlyTable_) if self.tableRecords_ and self.tableRecords_.isHidden(): self.tableRecords_.show() """ Actualiza el conjunto de registros con un retraso. Acepta un lapsus de tiempo en milisegundos, activando el cronómetro interno para que realize el refresh definitivo al cumplirse dicho lapsus. @param msec Cantidad de tiempo del lapsus, en milisegundos. """ def refreshDelayed(self, msec = 50, refreshData = True): if not self.cursor_.modeAccess() == FLSqlCursor.Browse: return if refreshData: self._refreshData = True else: self._refreshData = False QtCore.QTimer.singleShot(msec, self.refreshDelayed2) self.seekCursor() def refreshDelayed2(self): self.refresh(False, self._refreshData) self._refreshData = None """ Invoca al método FLSqlCursor::insertRecord() """ @QtCore.pyqtSlot() def insertRecord(self): w = self.sender() if w and (not self.cursor_ or self.reqReadOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked())): w.setDisabled(True) return if self.cursor_: self.cursor_.insertRecord() """ Invoca al método FLSqlCursor::editRecord() """ @QtCore.pyqtSlot() def editRecord(self): w = self.sender() if w and (not self.cursor_ or self.reqReadOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked())): w.setDisabled(True) return if self.cursor_: self.cursor_.editRecord() """ Invoca al método FLSqlCursor::browseRecord() """ @QtCore.pyqtSlot() def browseRecord(self): w = self.sender() if w and (not self.cursor_ or self.reqOnlyTable_): w.setDisabled(True) return if self.cursor_: self.cursor_.browseRecord() """ Invoca al método FLSqlCursor::deleteRecord() """ @QtCore.pyqtSlot() def deleteRecord(self): w = self.sender() if w and (not self.cursor_ or self.reqReadOnly_ or self.reqInsertOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked())): w.setDisabled(True) return if self.cursor_: self.cursor_.deleteRecord() """ Invoca al método FLSqlCursor::copyRecord() """ @QtCore.pyqtSlot() def copyRecord(self): w = self.sender() if w and (not self.cursor_ or self.reqReadOnly_ or self.reqEditOnly_ or self.reqOnlyTable_ or (self.cursor_.cursorRelation() and self.cursor_.cursorRelation().isLocked())): w.setDisabled(True) return if self.cursor_: self._cursor.copyRecord() """ Coloca la columna como primera pasando el nombre del campo. Este slot está conectado al cuadro combinado de busqueda del componente. Cuando seleccionamos un campo este se coloca como primera columna y se reordena la tabla con esta columna. De esta manera siempre tendremos la tabla ordenada mediante el campo en el que queremos buscar. @param c Nombre del campo, esta columna intercambia su posion con la primera columna @return Falso si no existe el campo @author [email protected] @author InfoSiAL, S.L. """ @QtCore.pyqtSlot(int) @QtCore.pyqtSlot(str) def putFirstCol(self, c ): _index = c if isinstance(c, str): _index = self.tableRecords_.realColumnIndex(c) if _index < 0: return False self.moveCol(_index, 0) return True """ Coloca la columna como segunda pasando el nombre del campo. @author Silix - dpinelo """ @QtCore.pyqtSlot(int) @QtCore.pyqtSlot(str) def putSecondCol(self, c): _index = c if isinstance(c, str): _index = self.tableRecords_.realColumnIndex(c) if _index < 0: return False self.moveCol(_index, 1) return True """ Mueve una columna de un campo origen a la columna de otro campo destino @param from Nombre del campo de la columna de origen @param to Nombre del campo de la columna de destino @param firstSearch dpinelo: Indica si se mueven columnas teniendo en cuenta que esta función se ha llamado o no, desde el combo principal de búsqueda y filtrado """ @decorators.BetaImplementation def moveCol(self, from_, to, firstSearch = True ): _oldFirst = None if from_ < 0 or to < 0: return tMD = self.cursor_.metadata() if not tMD: return self.tableRecords_.hide() textSearch = self.lineEditSearch.text() field = self.cursor_.metadata().indexFieldObject(to) if to == 0: # Si ha cambiado la primera columna try: self.comboBoxFieldToSearch.currentIndexChanged.disconnect(self.putFirstCol) except: pass self.comboBoxFieldToSearch.setCurrentIndex(from_) self.comboBoxFieldToSearch.currentIndexChanged.connect(self.putFirstCol) #Actializamos el segundo combo try: self.comboBoxFieldToSearch2.currentIndexChanged.disconnect(self.putSecondCol) except: pass #Falta mejorar if self.comboBoxFieldToSearch.currentIndex() == self.comboBoxFieldToSearch2.currentIndex(): self.comboBoxFieldToSearch2.setCurrentIndex(self.tableRecords_._h_header.logicalIndex(0)) self.comboBoxFieldToSearch2.currentIndexChanged.connect(self.putSecondCol) if (to == 1): #Si es la segunda columna ... try: self.comboBoxFieldToSearch2.currentIndexChanged.disconnect(self.putSecondCol) except: pass self.comboBoxFieldToSearch2.setCurrentIndex(from_) self.comboBoxFieldToSearch2.currentIndexChanged.connect(self.putSecondCol) if self.comboBoxFieldToSearch.currentIndex() == self.comboBoxFieldToSearch2.currentIndex(): try: self.comboBoxFieldToSearch.currentIndexChanged.disconnect(self.putFirstCol) except: pass if self.comboBoxFieldToSearch.currentIndex() == self.comboBoxFieldToSearch2.currentIndex(): self.comboBoxFieldToSearch.setCurrentIndex(self.tableRecords_._h_header.logicalIndex(1)) self.comboBoxFieldToSearch.currentIndexChanged.connect(self.putFirstCol) if not textSearch: textSearch = self.cursor_.value(field.name()) self.refresh(True) if textSearch: self.refresh(False, True) try: self.lineEditSearch.textChanged.disconnect(self.filterRecords) except: pass self.lineEditSearch.setText(textSearch) self.lineEditSearch.textChanged.connect(self.filterRecords) self.lineEditSearch.selectAll() self.seekCursor() QtCore.QTimer.singleShot(0, self.tableRecords_.ensureRowSelectedVisible()) else: self.refreshDelayed() from_ = self.tableRecords_.visualIndexToRealIndex(from_) self.tableRecords_._h_header.swapSections(from_, to) self.refresh(True) """ if textSearch: self.refresh(False, True) if firstSearch: self.lineEditSearch.textChanged.disconnect(self.filterRecords) self.lineEditSearch.setText(textSearch) self.lineEditSearch.textChanged.connect(self.filterRecords) self.lineEditSearch.selectAll() self.seekCursor() QtCore.QTimer.singleShot(0,self.tableRecords_.ensureRowSelectedVisible) else: self.refreshDelayed() if not self.sender(): self.lineEditSearch.setFocus() """ #self.tableRecords_.show() """ Posiciona el cursor en un registro valido """ @decorators.BetaImplementation def seekCursor(self): return textSearch = self.lineEditSearch.text() if not textSearch: return if not self.cursor_: return fN = self.sortField_.name() textSearch.replace("%", "") if not "'" in textSearch and not "\\" in textSearch: sql = self.cursor_.executedQuery() + " LIMIT 1" """ #QSqlQuery qry(sql, cursor_->db()->db()); #FIXME if (qry.first()) { QString v(qry.value(0).toString()); int pos = -1; if (!v.upper().startsWith(textSearch.upper())) pos = cursor_->atFromBinarySearch(fN, textSearch, orderAsc_); if (pos == -1) pos = cursor_->atFromBinarySearch(fN, v, orderAsc_); cursor_->seek(pos, false, true); """ """ Redefinida por conveniencia """ @decorators.NotImplementedWarn def setEnabled(self, b): pass """ Establece el ancho de una columna @param field Nombre del campo de la base de datos correspondiente a la columna @param w Ancho de la columna """ @decorators.NotImplementedWarn def setColumnWidth(self, field, w): pass """ @return Ancho de la columna """ @decorators.NotImplementedWarn def columnWidth(self, c): pass """ Establece el alto de una fila @param row Número de orden de la fila, empezando en 0 @param h Alto de la fila """ @decorators.NotImplementedWarn def setRowHeight(self, row, h): pass """ @return Alto de la fila """ @decorators.NotImplementedWarn def rowHeight(self, row): pass """ Exporta a una hoja de cálculo ODS y la visualiza """ @decorators.NotImplementedWarn def exportToOds(self): pass """ Conmuta el sentido de la ordenación de los registros de la tabla, de ascendente a descendente y viceversa. Los registros siempre se ordenan por la primera columna. Si la propiedad autoSortColumn es TRUE. """ @decorators.NotImplementedWarn def switchSortOrder(self, col = 0): pass """ Filtra los registros de la tabla utilizando el primer campo, según el patrón dado. Este slot está conectado al cuadro de texto de busqueda del componente, tomando el contenido de este como patrón para el filtrado. @param p Cadena de caracteres con el patrón de filtrado """ @QtCore.pyqtSlot(str) def filterRecords(self, p): if not self.cursor_.model(): return bFilter = None p = str(p) refreshData = None if "%" in p: refreshData = True msec_refresh = 400 column = self.tableRecords_._h_header.logicalIndex(0) field = self.cursor_.model().metadata().indexFieldObject(column) bFilter = self.cursor_.db().manager().formatAssignValue(field, p, True) idMod = self.cursor_.db().managerModules().idModuleOfFile(self.cursor_.metadata().name() + ".mtd") functionQSA = idMod + ".tableDB_filterRecords_" + self.cursor_.metadata().name() vargs = [] vargs.append(self.cursor_.metadata().name()) vargs.append(p) vargs.append(field.name()) vargs.append(bFilter) if functionQSA: msec_refresh = 800 ret = self.cursor_._prj.call(functionQSA, vargs, None) if ret: bFilter = ret print("functionQSA:%s:" % functionQSA) else: if p == "": bFilter = None self.refreshDelayed(msec_refresh, (bFilter or refreshData)) self.filter_ = bFilter @decorators.NotImplementedWarn def setSortOrder(self, ascending): pass @decorators.NotImplementedWarn def isSortOrderAscending(self): pass """ Activa la tabla de datos """ @decorators.NotImplementedWarn def activeTabData(self, b): pass """ Activa la tabla de filtro """ @decorators.NotImplementedWarn def activeTabFilter(self, b): pass """ Limpia e inicializa el filtro """ @decorators.NotImplementedWarn def tdbFilterClear(self): pass """ Señal emitida cuando se refresca por cambio de filtro """ refreshed = QtCore.pyqtSignal() """ Señal emitida cuando se establece si el componente es o no de solo lectura. """ readOnlyChanged = QtCore.pyqtSignal(bool) """ Señal emitida cuando se establece si el componente es o no de solo edición. """ editOnlyChanged = QtCore.pyqtSignal(bool) """ Señal emitida cuando se establece si el componente es o no de solo inserción. """ insertOnlyChanged = QtCore.pyqtSignal(bool) """ Señal emitida cuando se establece cambia el registro seleccionado. """ currentChanged = QtCore.pyqtSignal() @QtCore.pyqtSlot() @decorators.BetaImplementation def chooseRecord(self): if isinstance(self.topWidget, FLFormSearchDB): if self.topWidget.inExec_: self.topWidget.accept() return if self.cursor().isLocked(): print("FLTable(%s):Registro bloqueado. Modo Solo lectura" % self.cursor().curName()) self.browseRecord() else: self.editRecord()
def alterTable2(self, mtd1, mtd2, key, force=False): util = FLUtil() oldMTD = None newMTD = None doc = QDomDocument("doc") docElem = None if not util.docDocumentSetContect(doc, mtd1): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) else: docElem = doc.documentElement() oldMTD = self.db_.manager().metadata(docElem, True) if oldMTD and oldMTD.isQuery(): return True if not util.docDocumentSetContect(doc, mtd2): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) return False else: docElem = doc.documentElement() newMTD = self.db_.manager().metadata(docElem, True) if not oldMTD: oldMTD = newMTD if not oldMTD.name() == newMTD.name(): print("FLManager::alterTable : " + qApp.tr("Los nombres de las tablas nueva y vieja difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False oldPK = oldMTD.primaryKey() newPK = newMTD.primaryKey() if not oldPK == newPK: print("FLManager::alterTable : " + qApp.tr("Los nombres de las claves primarias difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().checkMetaData(oldMTD, newMTD): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return True if not self.db_.manager().existsTable(oldMTD.name()): print("FLManager::alterTable : " + qApp.tr( "La tabla %1 antigua de donde importar los registros no existe." ).arg(oldMTD.name())) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False fieldList = oldMTD.fieldList() oldField = None if not fieldList: print("FLManager::alterTable : " + qApp.tr("Los antiguos metadatos no tienen campos.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False renameOld = "%salteredtable%s" % (oldMTD.name()[0:5], QDateTime( ).currentDateTime().toString("ddhhssz")) if not self.db_.dbAux(): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False self.db_.dbAux().transaction() if key and len(key) == 40: c = FLSqlCursor("flfiles", True, self.db_.dbAux()) c.setForwardOnly(True) c.setFilter("nombre = '%s.mtd'" % renameOld) c.select() if not c.next(): buffer = c.primeInsert() buffer.setValue("nombre", "%s.mtd" % renameOld) buffer.setValue("contenido", mtd1) buffer.setValue("sha", key) c.insert() q = FLSqlQuery("", self.db_.dbAux()) constraintName = "%s_pkey" % oldMTD.name() if self.constraintExists(constraintName) and not q.exec_( "ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): print("FLManager : " + qApp.tr( "En método alterTable, no se ha podido borrar el índice %1_pkey de la tabla antigua." ).arg(oldMTD.name())) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False fieldsNamesOld = [] for it in fieldList: if newMTD.field(it.name()): fieldsNamesOld.append(it.name()) if it.isUnique(): constraintName = "%s_%s_key" % (oldMTD.name(), it.name()) if self.constraintExists(constraintName) and not q.exec_( "ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): print("FLManager : " + qApp.tr( "En método alterTable, no se ha podido borrar el índice %1_%2_key de la tabla antigua." ).arg(oldMTD.name(), oldField.name())) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not q.exec_("ALTER TABLE %s RENAME TO %s" % (oldMTD.name(), renameOld)): print("FLManager::alterTable : " + qApp.tr("No se ha podido renombrar la tabla antigua.")) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().createTable(newMTD): self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False v = None ok = False if not force and not fieldsNamesOld: self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return self.alterTable2(mtd1, mtd2, key, True) oldCursor = FLSqlCursor(renameOld, True, self.db_.dbAux()) oldCursor.setModeAccess(oldCursor.Browse) newCursor = FLSqlCursor(newMTD.name(), True, self.db_.dbAux()) newCursor.setMode(newCursor.Insert) oldCursor.select() totalSteps = oldCursor.size() progress = QProgressDialog( qApp.tr("Reestructurando registros para %1...").arg( newMTD.alias()), qApp.tr("Cancelar"), 0, totalSteps) progress.setLabelText(qApp.tr("Tabla modificada")) step = 0 newBuffer = None newField = None listRecords = [] newBufferInfo = self.recordInfo2(newMTD.name()) oldFieldsList = {} newFieldsList = {} defValues = {} v = None for newField in fieldList: oldField = oldMTD.field(newField.name()) defValues[str(step)] = None if not oldField or not oldCursor.field(oldField.name()): if not oldField: oldField = newField if not newField.type() == "serial": v = newField.defaultValue() defValues[str(step)] = v newFieldsList[str(step)] = newField oldFieldsList[str(step)] = oldField step = step + 1 step = 0 ok = True while oldCursor.next(): newBuffer = newBufferInfo for reg in defValues.keys(): newField = newFieldsList[reg] oldField = oldFieldsList[reg] if defValues[reg]: v = defValues[reg] else: v = oldCursor.value(newField.name()) if (not oldField.allowNull or not newField.allowNull() ) and not v and not newField.type() == "serial": defVal = newField.defaultValue() if defVal is not None: v = defVal if v is not None and not newBuffer.field( newField.name()).type() == newField.type(): print("FLManager::alterTable : " + qApp.tr( "Los tipos del campo %1 no son compatibles. Se introducirá un valor nulo." ).arg(newField.name())) if v is not None and newField.type( ) == "string" and newField.length() > 0: v = str(v)[0:newField.length()] if (not oldField.allowNull() or not newField.allowNull()) and v is None: if oldField.type() == "serial": v = int( self.nextSerialVal(newMTD.name(), newField.name())) elif oldField.type() in ("int", "uint", "bool", "unlock"): v = 0 elif oldField.type() == "double": v = 0.0 elif oldField.type() == "time": v = QTime().currentTime() elif oldField.type() == "date": v = QDate().currentDate() else: v = "NULL"[0:newField.length()] newBuffer.setValue(newField.name(), v) listRecords.append(newBuffer) if not self.insertMulti(newMTD.name(), listRecords): ok = False listRecords.clear() break listRecords.clear() if len(listRecords) > 0: if not self.insertMulti(newMTD.name(), listRecords): ok = False listRecords.clear() progress.setProgress(totalSteps) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD if ok: self.db_.dbAux().commit() else: self.db_.dbAux().rollback() return False if force and ok: q.exec_("DROP TABLE %s CASCADE" % renameOld) return True
def alterTable3(self, newMTD): if self.hasCheckColumn(newMTD): return False oldMTD = newMTD fieldList = oldMTD.fieldList() renameOld = "%salteredtable%s" % (oldMTD.name()[0:5], QDateTime( ).currentDateTime().toString("ddhhssz")) self.db_.dbAux().transaction() q = FLSqlQuery(None, self.db_.dbAux()) constraintName = "%s_key" % oldMTD.name() if self.constraintExists(constraintName) and not q.exec_( "ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): self.db_.dbAux().rollback() return False for oldField in fieldList: if oldField.isCheck(): return False if oldField.isUnique(): constraintName = "%s_%s_key" % (oldMTD.name(), oldField.name()) if self.constraintExists(constraintName) and not q.exec_( "ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): self.db_.dbAux().rollback() return False if not q.exec_("ALTER TABLE %s RENAME TO %s" % (oldMTD.name(), renameOld)): self.db_.dbAux().rollback() return False if not self.db_.manager().createTable(newMTD): self.db_.dbAux().rollback() return False oldCursor = FLSqlCursor(renameOld, True, self.db_.dbAux()) oldCursor.setModeAccess(oldCursor.Browse) oldCursor.select() fieldList = newMTD.fieldList() if not fieldList: self.db_.dbAux().rollback() return False oldCursor.select() totalSteps = oldCursor.size() progress = QProgressDialog( qApp.tr("Reestructurando registros para %1...").arg( newMTD.alias()), qApp.tr("Cancelar"), 0, totalSteps) progress.setLabelText(qApp.tr("Tabla modificada")) step = 0 newBuffer = None newField = None listRecords = [] newBufferInfo = self.recordInfo2(newMTD.name()) oldFieldsList = {} newFieldsList = {} defValues = {} v = None for newField in fieldList: oldField = oldMTD.field(newField.name()) defValues[str(step)] = None if not oldField or not oldCursor.field(oldField.name()): if not oldField: oldField = newField if not newField.type() == "serial": v = newField.defaultValue() defValues[str(step)] = v newFieldsList[str(step)] = newField oldFieldsList[str(step)] = oldField step = step + 1 ok = True while oldCursor.next(): newBuffer = newBufferInfo for reg in defValues.keys(): newField = newFieldsList[reg] oldField = oldFieldsList[reg] if defValues[reg]: v = defValues[reg] else: v = oldCursor.value(newField.name()) if (not oldField.allowNull or not newField.allowNull() ) and not v and not newField.type() == "serial": defVal = newField.defaultValue() if defVal is not None: v = defVal if v is not None and not newBuffer.field( newField.name()).type() == newField.type(): print("FLManager::alterTable : " + qApp.tr( "Los tipos del campo %1 no son compatibles. Se introducirá un valor nulo." ).arg(newField.name())) if v is not None and newField.type( ) == "string" and newField.length() > 0: v = str(v)[0:newField.length()] if (not oldField.allowNull() or not newField.allowNull()) and v is None: if oldField.type() == "serial": v = int( self.nextSerialVal(newMTD.name(), newField.name())) elif oldField.type() in ("int", "uint", "bool", "unlock"): v = 0 elif oldField.type() == "double": v = 0.0 elif oldField.type() == "time": v = QTime().currentTime() elif oldField.type() == "date": v = QDate().currentDate() else: v = "NULL"[0:newField.length()] newBuffer.setValue(newField.name(), v) listRecords.append(newBuffer) # if not self.insertMulti(newMTD.name(), listRecords): # ok = False # listRecords.clear() # break # listRecords.clear() if len(listRecords) > 0: if not self.insertMulti(newMTD.name(), listRecords): ok = False listRecords.clear() if ok: self.db_.dbAux().commit() else: self.db_.dbAux().rollback() return False force = False # FIXME if force and ok: q.exec_("DROP TABLE %s CASCADE" % renameOld) return True
def Mr_Proper(self): util = FLUtil() self.db_.dbAux().transaction() qry = FLSqlQuery(None, self.db_.dbAux()) qry2 = FLSqlQuery(None, self.db_.dbAux()) steps = 0 rx = QRegExp("^.*\\d{6,9}$") listOldBks = rx in self.tables("") qry.exec_( "select nombre from flfiles where nombre similar to" "'%[[:digit:]][[:digit:]][[:digit:]][[:digit:]]-[[:digit:]][[:digit:]]%:[[:digit:]][[:digit:]]%' or nombre similar to" "'%alteredtable[[:digit:]][[:digit:]][[:digit:]][[:digit:]]%' or (bloqueo='f' and nombre like '%.mtd')" ) util.createProgressDialog(util.tr("Borrando backups"), len(listOldBks) + qry.size() + 2) while qry.next(): item = qry.value(0) util.setLabelText(util.tr("Borrando registro %1").arg(item)) qry2.exec_("DELETE FROM flfiles WERE nombre ='%s'" % item) if item.find("alteredtable") > -1: if self.existsTable(item.replace(".mtd", "")): util.setLabelText(util.tr("Borrando tabla %1").arg(item)) qry2.exec_("DROP TABLE %s CASCADE" % item.replace(".mtd", "")) steps = steps + 1 util.setProgress(steps) for item in listOldBks: if self.existsTable(item): util.setLabelText(util.tr("Borrando tabla %1").arg(item)) qry2.exec_("DROP TABLE %s CASCADE" % item) steps = steps + 1 util.setProgress(steps) util.setLabelText(util.tr("Inicializando cachés")) steps = steps + 1 util.setProgress(steps) qry.exec_("DELETE FROM flmetadata") qry.exec_("DELETE FROM flvar") self.db_.manager().cleanupMetaData() self.db_.commit() util.destroyProgressDialog() steps = 0 qry.exec_("select tablename from pg_tables where schemaname='public'") util.createProgressDialog(util.tr("Comprobando base de datos"), qry.size()) while qry.next(): item = qry.value(0) util.setLabelText(util.tr("Comprobando tabla %1").arg(item)) mustAlter = self.mismatchedTable(item, item) if mustAlter: conte = self.db_.managerModules().content("%s.mtd" % item) if conte: msg = util.tr( "La estructura de los metadatos de la tabla '%1' y su " "estructura interna en la base de datos no coinciden. " "Intentando regenerarla.").arg(item) print(msg) self.alterTable2(conte, conte, None, True) steps = steps + 1 util.setProgress(steps) self.db_.dbAux().transaction() steps = 0 sqlCursor = FLSqlCursor(None, True, self.db_.dbAux()) sqlQuery = FLSqlQuery(None, self.db_.dbAux()) if sqlQuery.exec_( "select relname from pg_class where ( relkind = 'r' ) " "and ( relname !~ '^Inv' ) " "and ( relname !~ '^pg_' ) and ( relname !~ '^sql_' )"): util.setTotalSteps(sqlQuery.size()) while sqlQuery.next(): item = sqlQuery.value(0) steps = steps + 1 util.setProgress(steps) util.setLabelText(util.tr("Creando índices para %1").arg(item)) mtd = self.db_.manager().metadata(item) fL = mtd.fieldList() if not mtd or not fL: continue for it in fL: if not it or not it.type() == "pixmap": continue cur = FLSqlCursor(item, True, self.db_.dbAux()) cur.select("%s not like 'RK@%'" % it.name()) while cur.next(): v = cur.value(it.name()) if v is None: continue v = self.db_.manager().storeLargeValue(mtd, v) if v: buf = cur.primeUpdate() buf.setValue(it.name(), v) cur.update(False) sqlCursor.setName(item, True) self.db_.dbAux().commit() steps = 0 qry.exec_("select tablename from pg_tables where schemaname='public'") util.createProgressDialog(util.tr("Analizando base de datos"), qry.size()) while qry.next(): item = qry.value(0) util.setLabelText(util.tr("Analizando tabla %1").arg(item)) qry2.exec_("vacuum analyze %s" % item) steps = steps + 1 util.setProgress(steps) util.destroyProgressDialog()
def run(self): value = 0 cursor = FLSqlCursor("paises") try: cursor.setModeAccess(cursor.Insert) cursor.refreshBuffer() except Exception: print(traceback.format_exc()) else: value = value + 10 try: cursor.setValueBuffer("codpais", "TEST") cursor.setValueBuffer("nombre", "test name") cursor.setValueBuffer("codiso", "TS") except Exception: print(traceback.format_exc()) else: value = value + 10 try: cursor.commitBuffer() except Exception: print(traceback.format_exc()) else: value = value + 10 try: val1 = cursor.valueBuffer("codpais") except Exception: print(traceback.format_exc()) else: if val1 == "TEST": value = value + 10 try: cursor.select("codpais = 'TEST'") while cursor.next(): cursor.setModeAccess(cursor.Del) cursor.refreshBuffer() cursor.commitBuffer() except Exception: print(traceback.format_exc()) else: value = value + 10 return value
def initCursor(self): # si no existe crea la tabla if not self._cursor: return False if not self._cursor._model: return False self._tMD = 0 if not self._sortField: self._tMD = self._cursor._model.name() if self._tMD: self.sortField_ = self._tMD.value(self._cursor._currentregister, self._tMD.primaryKey()) ownTMD = False if not self._tableName: #if not cursor_->db()->manager()->existsTable(tableName_)) { ownTMD = True #tMD = cursor_->db()->manager()->createTable(tableName_); else: ownTMD = True self._tMD = self._cursor._model._table.name if not self._tMD: return if not self._foreignField or not self._fieldRelation: if not self._cursor._model: if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return if not self._cursor._model.name() == self._tableName: ctxt = self._cursor.context() self._cursor = FLSqlCursor(self._tableName) if self._cursor: self._cursor.setContext(ctxt) cursorAux = 0 if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return else: cursorTopWidget = self.topWidget._cursor( ) # ::qt_cast<FLFormDB *>(topWidget)->cursor() if cursorTopWidget and not cursorTopWidget._model.name( ) == self._tableName: self._cursor = cursorTopWidget if not self._tableName or not self._foreignField or not self._fieldRelation or cursorAux: if ownTMD and self._tMD and not self._tMD.inCache(): tMD = None return cursorAux = self._cursor curName = self._cursor._model.name() rMD = self._cursor._model.relation(self._foreignField, self._fieldRelation, self._tableName) testM1 = self._tMD.relation(self._fieldRelation, self._foreignField, curName) checkIntegrity = bool(False) if not rMD: if testM1: checkIntegrity = ( testM1.cardinality() == FLRelationMetaData.RELATION_M1) fMD = FLTableMetaData(self._cursor._model.field( self._foreignField)) if (fMD): tmdAux = self._cursor._model(self._tableName) if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): # mirar inCache() tmdAux = None rMD = FLRelationMetaData(self._tableName, self._fieldRelation, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity) fMD.addRelationMD(rMD) print( "FLTableDB : La relación entre la tabla del formulario %r y esta tabla %r de este campo no existe, pero sin embargo se han indicado los campos de relación( %r, %r )" % (curName, self._tableName, self._fieldRelation, self._foreignField)) print( "FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (curName, self._foreignField, self._tableName, self._fieldRelation)) else: print( "FLTableDB : El campo ( %r ) indicado en la propiedad foreignField no se encuentra en la tabla ( %r )" % (self._foreignField, curName)) rMD = testM1 if not rMD: fMD = FLFieldMetaData(tMD.field(self._fieldRelation)) if (fMD): rMD = FLRelationMetaData(curName, self._foreignField, FLRelationMetaData.RELATION_1M, False, False, False) fMD.addRelationMD(rMD) print( "FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (self._tableName, self._fieldRelation, curName, self._foreignField)) else: print( "FLTableDB : El campo ( %r ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %r )" % (self._fieldRelation, self._tableName)) self._cursor = FLSqlCursor(self._tableName, True, self._cursor.db().connectionName(), cursorAux, rMD, self) if not self._cursor: self._cursor = cursorAux cursorAux = 0 else: self._cursor.setContext(cursorAux.context()) if self.showed: self.disconnect(cursorAux, QtCore.SIGNAL('newBuffer()'), self.refresh()) self.connect(cursorAux, QtCore.SIGNAL('newBuffer()'), self.refresh()) if cursorAux and self.topWidget.isA("FLFormSearchDB"): self.topWidget.setCaption(self._cursor._model.alias()) self.topWidget.setCursor( self._cursor ) #::qt_cast<FLFormSearchDB *>(topWidget)->setCursor(cursor_); if ownTMD and tMD and not tMD.inCache(): tMD = None
def sqlUpdate(self, t, fL, vL, w, connName="default"): """ Realiza la modificación de uno o más registros en una tabla mediante un objeto FLSqlCursor @param t Nombre de la tabla @param fL Lista separada con comas de los nombres de los campos @param vL Lista separada con comas de los valores correspondientes @param w Sentencia where para identificar los registros a editar. @param connName Nombre de la conexion @return Verdadero en caso de realizar la inserción con éxito, falso en cualquier otro caso """ from pineboolib.fllegacy.FLSqlCursor import FLSqlCursor c = FLSqlCursor(t, True, connName) c.select(w) c.setForwardOnly(True) while c.next(): c.setModeAccess(FLSqlCursor.Edit) c.refreshBuffer() if isinstance(fL, list): i = 0 for f in fL: c.setValueBuffer(f, vL[i]) i = i + 1 else: c.setValueBuffer(fL, vL) if not c.commitBuffer(): return False return True
def __init__(self, parent=None, action_or_cursor=None, *args): print("FLTableDB:", parent, action_or_cursor, args) # TODO: Falta el lineeditsearch y el combo, que los QS lo piden super(FLTableDB, self).__init__(parent, *args) # TODO: LA inicialización final hay que hacerla más tarde, en el primer # show(), porque sino obligas a tenerlo todo preparado en el constructor. self._tableView = QtGui.QTableView() self._lineEdit = QtGui.QLineEdit() _label1 = QtGui.QLabel() _label2 = QtGui.QLabel() self._comboBox_1 = QtGui.QComboBox() self._comboBox_2 = QtGui.QComboBox() _label1.setText("Buscar") _label2.setText("en") self._vlayout = QtGui.QVBoxLayout() _hlayout = QtGui.QHBoxLayout() self._tableView._v_header = self._tableView.verticalHeader() self._tableView._v_header.setDefaultSectionSize(18) self._tableView._h_header = self._tableView.horizontalHeader() self._tableView._h_header.setDefaultSectionSize(70) _hlayout.addWidget(_label1) _hlayout.addWidget(self._lineEdit) _hlayout.addWidget(_label2) _hlayout.addWidget(self._comboBox_1) _hlayout.addWidget(self._comboBox_2) self._vlayout.addLayout(_hlayout) self._vlayout.addWidget(self._tableView) self.setLayout(self._vlayout) self._parent = parent while True: parent_cursor = getattr(self._parent, "_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent print(self._parent) self._tableView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self._tableView.setSelectionMode( QtGui.QAbstractItemView.SingleSelection) self._tableView.setSelectionBehavior( QtGui.QAbstractItemView.SelectRows) self._tableView.setAlternatingRowColors(True) if action_or_cursor is None and parent_cursor: action_or_cursor = parent_cursor if isinstance(action_or_cursor, FLSqlCursor): self._cursor = action_or_cursor elif isinstance(action_or_cursor, str): self._cursor = FLSqlCursor(action_or_cursor) else: self._cursor = None if self._cursor: self._tableView._h_header.setResizeMode( QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor._model) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: for column in range(self._cursor._model.columnCount()): self._comboBox_1.addItem( self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem( self._cursor._model.headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect( self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded)
def alterTable2(self, mtd1, mtd2, key, force=False): util = FLUtil() oldMTD = None newMTD = None doc = QDomDocument("doc") docElem = None if not util.docDocumentSetContect(doc, mtd1): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) else: docElem = doc.documentElement() oldMTD = self.db_.manager().metadata(docElem, True) if oldMTD and oldMTD.isQuery(): return True if not util.docDocumentSetContect(doc, mtd2): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) return False else: docElem = doc.documentElement() newMTD = self.db_.manager().metadata(docElem, True) if not oldMTD: oldMTD = newMTD if not oldMTD.name() == newMTD.name(): print("FLManager::alterTable : " + qApp.tr("Los nombres de las tablas nueva y vieja difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False oldPK = oldMTD.primaryKey() newPK = newMTD.primaryKey() if not oldPK == newPK: print("FLManager::alterTable : " + qApp.tr("Los nombres de las claves primarias difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().checkMetaData(oldMTD, newMTD): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return True if not self.db_.manager().existsTable(oldMTD.name()): print("FLManager::alterTable : " + qApp.tr( "La tabla %1 antigua de donde importar los registros no existe.").arg(oldMTD.name())) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False fieldList = oldMTD.fieldList() oldField = None if not fieldList: print("FLManager::alterTable : " + qApp.tr("Los antiguos metadatos no tienen campos.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False renameOld = "%salteredtable%s" % ( oldMTD.name()[0:5], QDateTime().currentDateTime().toString("ddhhssz")) if not self.db_.dbAux(): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False self.db_.dbAux().transaction() if key and len(key) == 40: c = FLSqlCursor("flfiles", True, self.db_.dbAux()) c.setForwardOnly(True) c.setFilter("nombre = '%s.mtd'" % renameOld) c.select() if not c.next(): buffer = c.primeInsert() buffer.setValue("nombre", "%s.mtd" % renameOld) buffer.setValue("contenido", mtd1) buffer.setValue("sha", key) c.insert() q = FLSqlQuery("", self.db_.dbAux()) constraintName = "%s_pkey" % oldMTD.name() if self.constraintExists(constraintName) and not q.exec_("ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): print("FLManager : " + qApp.tr("En método alterTable, no se ha podido borrar el índice %1_pkey de la tabla antigua.").arg(oldMTD.name())) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False fieldsNamesOld = [] for it in fieldList: if newMTD.field(it.name()): fieldsNamesOld.append(it.name()) if it.isUnique(): constraintName = "%s_%s_key" % (oldMTD.name(), it.name()) if self.constraintExists(constraintName) and not q.exec_("ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): print("FLManager : " + qApp.tr("En método alterTable, no se ha podido borrar el índice %1_%2_key de la tabla antigua.") .arg(oldMTD.name(), oldField.name())) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not q.exec_("ALTER TABLE %s RENAME TO %s" % (oldMTD.name(), renameOld)): print("FLManager::alterTable : " + qApp.tr("No se ha podido renombrar la tabla antigua.")) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().createTable(newMTD): self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False v = None ok = False if not force and not fieldsNamesOld: self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return self.alterTable2(mtd1, mtd2, key, True) oldCursor = FLSqlCursor(renameOld, True, self.db_.dbAux()) oldCursor.setModeAccess(oldCursor.Browse) newCursor = FLSqlCursor(newMTD.name(), True, self.db_.dbAux()) newCursor.setMode(newCursor.Insert) oldCursor.select() totalSteps = oldCursor.size() progress = QProgressDialog(qApp.tr("Reestructurando registros para %1...").arg( newMTD.alias()), qApp.tr("Cancelar"), 0, totalSteps) progress.setLabelText(qApp.tr("Tabla modificada")) step = 0 newBuffer = None newField = None listRecords = [] newBufferInfo = self.recordInfo2(newMTD.name()) oldFieldsList = {} newFieldsList = {} defValues = {} v = None for newField in fieldList: oldField = oldMTD.field(newField.name()) defValues[str(step)] = None if not oldField or not oldCursor.field(oldField.name()): if not oldField: oldField = newField if not newField.type() == "serial": v = newField.defaultValue() defValues[str(step)] = v newFieldsList[str(step)] = newField oldFieldsList[str(step)] = oldField step = step + 1 step = 0 ok = True while oldCursor.next(): newBuffer = newBufferInfo for reg in defValues.keys(): newField = newFieldsList[reg] oldField = oldFieldsList[reg] if defValues[reg]: v = defValues[reg] else: v = oldCursor.value(newField.name()) if (not oldField.allowNull or not newField.allowNull()) and not v and not newField.type() == "serial": defVal = newField.defaultValue() if defVal is not None: v = defVal if v is not None and not newBuffer.field(newField.name()).type() == newField.type(): print("FLManager::alterTable : " + qApp.tr( "Los tipos del campo %1 no son compatibles. Se introducirá un valor nulo.").arg(newField.name())) if v is not None and newField.type() == "string" and newField.length() > 0: v = str(v)[0:newField.length()] if (not oldField.allowNull() or not newField.allowNull()) and v is None: if oldField.type() == "serial": v = int(self.nextSerialVal( newMTD.name(), newField.name())) elif oldField.type() in ("int", "uint", "bool", "unlock"): v = 0 elif oldField.type() == "double": v = 0.0 elif oldField.type() == "time": v = QTime().currentTime() elif oldField.type() == "date": v = QDate().currentDate() else: v = "NULL"[0:newField.length()] newBuffer.setValue(newField.name(), v) listRecords.append(newBuffer) if not self.insertMulti(newMTD.name(), listRecords): ok = False listRecords.clear() break listRecords.clear() if len(listRecords) > 0: if not self.insertMulti(newMTD.name(), listRecords): ok = False listRecords.clear() progress.setProgress(totalSteps) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD if ok: self.db_.dbAux().commit() else: self.db_.dbAux().rollback() return False if force and ok: q.exec_("DROP TABLE %s CASCADE" % renameOld) return True
def alterTable(self, mtd1, mtd2, key): util = FLUtil() oldMTD = None newMTD = None doc = QDomDocument("doc") docElem = None if not util.docDocumentSetContect(doc, mtd1): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) else: docElem = doc.documentElement() oldMTD = self.db_.manager().metadata(docElem, True) if oldMTD and oldMTD.isQuery(): return True if not util.docDocumentSetContect(doc, mtd2): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) return False else: docElem = doc.documentElement() newMTD = self.db_.manager().metadata(docElem, True) if not oldMTD: oldMTD = newMTD if not oldMTD.name() == newMTD.name(): print("FLManager::alterTable : " + qApp.tr("Los nombres de las tablas nueva y vieja difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False oldPK = oldMTD.primaryKey() newPK = newMTD.primaryKey() if not oldPK == newPK: print("FLManager::alterTable : " + qApp.tr("Los nombres de las claves primarias difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().checkMetaData(oldMTD, newMTD): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return True if not self.db_.manager().existsTable(oldMTD.name()): print("FLManager::alterTable : " + qApp.tr( "La tabla %1 antigua de donde importar los registros no existe.").arg(oldMTD.name())) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False fieldList = oldMTD.fieldList() oldField = None if not fieldList: print("FLManager::alterTable : " + qApp.tr("Los antiguos metadatos no tienen campos.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False renameOld = "%salteredtable%s" % ( oldMTD.name()[0:5], QDateTime().currentDateTime().toString("ddhhssz")) if not self.db_.dbAux(): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False self.db_.dbAux().transaction() if key and len(key) == 40: c = FLSqlCursor("flfiles", True, self.db_.dbAux()) c.setForwardOnly(True) c.setFilter("nombre = '%s.mtd'" % renameOld) c.select() if not c.next(): buffer = c.primeInsert() buffer.setValue("nombre", "%s.mtd" % renameOld) buffer.setValue("contenido", mtd1) buffer.setValue("sha", key) c.insert() q = FLSqlQuery("", self.db_.dbAux()) if not q.exec_("CREATE TABLE %s AS SELECT * FROM %s;" % (renameOld, oldMTD.name())) or not q.exec_("DROP TABLE %s;" % oldMTD.name()): print("FLManager::alterTable : " + qApp.tr("No se ha podido renombrar la tabla antigua.")) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().createTable(newMTD): self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False oldCursor = FLSqlCursor(renameOld, True, self.db_.dbAux()) oldCursor.setModeAccess(oldCursor.Browse) newCursor = FLSqlCursor(newMTD.name(), True, self.db_.dbAux()) newCursor.setMode(newCursor.Insert) oldCursor.select() totalSteps = oldCursor.size() progress = QProgressDialog(qApp.tr("Reestructurando registros para %1...").arg( newMTD.alias()), qApp.tr("Cancelar"), 0, totalSteps) progress.setLabelText(qApp.tr("Tabla modificada")) step = 0 newBuffer = None # sequence = "" fieldList = newMTD.fieldList() newField = None if not fieldList: print("FLManager::alterTable : " + qApp.tr("Los nuevos metadatos no tienen campos.")) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False v = None ok = True while oldCursor.next(): v = None newBuffer = newCursor.primeInsert() for it in fieldList: oldField = oldMTD.field(newField.name()) if not oldField or not oldCursor.field(oldField.name()): if not oldField: oldField = newField v = newField.defaultValue() else: v = oldCursor.value(newField.name()) if (not oldField.allowNull() or not newField.allowNull()) and (v is None): defVal = newField.defaultValue() if defVal is not None: v = defVal if not newBuffer.field(newField.name()).type() == newField.type(): print("FLManager::alterTable : " + qApp.tr("Los tipos del campo %1 no son compatibles. Se introducirá un valor nulo.") .arg(newField.name())) if not oldField.allowNull() or not newField.allowNull() and v is not None: if oldField.type() in ("int", "serial", "uint", "bool", "unlock"): v = 0 elif oldField.type() == "double": v = 0.0 elif oldField.type() == "time": v = QTime().currentTime() elif oldField.type() == "date": v = QDate().currentDate() else: v = "NULL"[0:newField.length()] newBuffer.setValue(newField.name(), v) if not newCursor.insert(): ok = False break step = step + 1 progress.setProgress(step) progress.setProgress(totalSteps) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD if ok: self.db_.dbAux().commit() else: self.db_.dbAux().rollback() return False return True
def initCursor(self): if not self.topWidget or not self.cursor_: return if not self.cursor_.metadata(): return tMD = None if not self.sortField_: tMD = self.cursor_.metadata() if tMD: self.sortField_ = tMD.field(tMD.primaryKey()) ownTMD = None if self.tableName_: if not self.cursor_.db().manager().existsTable(self.tableName_): ownTMD = True tMD = self.cursor_.db().manager().createTable(self.tableName_) else: ownTMD = True tMD = self.cursor_.db().manager().metadata(self.tableName_) if not tMD: return if not self.foreignField_ or not self.fieldRelation_: if not self.cursor_.metadata(): if ownTMD and tMD and not tMD.inCache(): del tMD return if not self.cursor_.metadata().name() == self.tableName_: ctxt = self.cursor_.context() self.cursor_ = FLSqlCursor( self.tableName_, True, self.cursor_.db().connectionName(), None, None, self ) if self.cursor_: self.cursor_.setContext(ctxt) self.cursorAux = None if ownTMD and tMD and not tMD.inCache(): del tMD return else: cursorTopWidget = self.topWidget.cursor() if cursorTopWidget and not cursorTopWidget.metadata().name() == self.tableName_: self.cursor_ = cursorTopWidget if not self.tableName_ or not self.foreignField_ or not self.fieldRelation_ or self.cursorAux: if ownTMD and tMD and not tMD.inCache(): del tMD return self.cursorAux = self.cursor_ curName = self.cursor_.metadata().name() rMD = self.cursor_.metadata().relation(self.foreignField_, self.fieldRelation_, self.tableName_) testM1 = tMD.relation(self.fieldRelation_, self.foreignField_, curName) checkIntegrity = False if not rMD: if testM1: if testM1.cardinality() == FLRelationMetaData.RELATION_M1: checkIntegrity = True fMD = self.cursor_.metadata().field(self.foreignField_) if fMD: tmdAux = self.cursor_.db().manager().metadata(self.tableName_) if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): del tmdAux rMD = FLRelationMetaData( self.tableName_, self.fieldRelation_, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity ) fMD.addRelationMD(rMD) # print("FLTableDB : La relación entre la tabla del formulario %s y esta tabla %s de este campo no existe, pero sin embargo se han indicado los campos de relación( %s, %s )" % ( curName, self.tableName_, self.fieldRelation_, self.foreignField_)) # print("FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (curName, self.foreignField_, self.tableName_, self.fieldRelation_)) else: # print("FLTableDB : El campo ( %s ) indicado en la propiedad foreignField no se encuentra en la tabla ( %s )" % (self.foreignField_, curName)) pass rMD = testM1 if not rMD: fMD = tMD.field(self.fieldRelation_) if fMD: rMD = FLRelationMetaData( curName, self.foreignField_, FLRelationMetaData.RELATION_1M, False, False, False ) fMD.addRelationMD(rMD) print( "FLTableDB : Creando automáticamente %s.%s --1M--> %s.%s" % (self.tableName_, self.fieldRelation_, curName, self.foreignField_) ) else: print( "FLTableDB : El campo ( %s ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %s )" % (self.fieldRelation_, self.tableName_) ) self.cursor_ = FLSqlCursor(self.tableName_, True, self.cursor_.db().connectionName(), self.cursorAux, rMD, self) if not self.cursor_: self.cursor_ = self.cursorAux self.cursorAux = None else: self.cursor_.setContext(self.cursorAux.context()) if self.showed: try: self.cursorAux.newBuffer.disconnect(self.refresh) except: pass self.cursorAux.newBuffer.connect(self.refresh) if self.cursorAux and isinstance(self.topWidget, FLFormSearchDB): self.topWidget.setCaption(self.cursor_.metadata().alias()) self.topWidget_.setCursor(self.cursor_) if ownTMD or tMD and not tMD.inCache(): del tMD
class FLTableDB(QtGui.QWidget): _tableView = None _vlayout = None _lineEdit = None _comboBox_1 = None _comboBox_2 = None _topWidget = None _cursor = None _loaded = False _cursorLoaded = False _tableName = None _foreignField = None _fieldRelation = None _action = None _foreignFilter = None def __init__(self, parent=None, action_or_cursor=None, *args): #print("FLTableDB:", parent, action_or_cursor , args) # TODO: Falta el lineeditsearch y el combo, que los QS lo piden super(FLTableDB, self).__init__(parent, *args) # TODO: LA inicialización final hay que hacerla más tarde, en el primer # show(), porque sino obligas a tenerlo todo preparado en el constructor. self._tableView = QtGui.QTableView() self._lineEdit = QtGui.QLineEdit() _label1 = QtGui.QLabel() _label2 = QtGui.QLabel() self._comboBox_1 = QtGui.QComboBox() self._comboBox_2 = QtGui.QComboBox() _label1.setText("Buscar") _label2.setText("en") self._vlayout = QtGui.QVBoxLayout() _hlayout = QtGui.QHBoxLayout() self._tableView._v_header = self._tableView.verticalHeader() self._tableView._v_header.setDefaultSectionSize(18) self._tableView._h_header = self._tableView.horizontalHeader() self._tableView._h_header.setDefaultSectionSize(70) _hlayout.addWidget(_label1) _hlayout.addWidget(self._lineEdit) _hlayout.addWidget(_label2) _hlayout.addWidget(self._comboBox_1) _hlayout.addWidget(self._comboBox_2) self._vlayout.addLayout(_hlayout) self._vlayout.addWidget(self._tableView) self.setLayout(self._vlayout) self._parent = parent while True: parent_cursor = getattr(self._parent, "_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent print(self._parent) self._tableView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self._tableView.setSelectionMode( QtGui.QAbstractItemView.SingleSelection) self._tableView.setSelectionBehavior( QtGui.QAbstractItemView.SelectRows) self._tableView.setAlternatingRowColors(True) if action_or_cursor is None and parent_cursor: action_or_cursor = parent_cursor if isinstance(action_or_cursor, FLSqlCursor): self._cursor = action_or_cursor elif isinstance(action_or_cursor, str): self._action = action_or_cursor else: self._cursor = None if self._cursor: self._tableView._h_header.setResizeMode( QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor.model()) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: i = 0 for column in range(self._cursor.model().columnCount()): #print("Columna ", i) self._comboBox_1.addItem(self._cursor.model().headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem(self._cursor.model().headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect( self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded) self._topWidget = parent def __getattr__(self, name): return DefFun(self, name) def loaded(self): # Es necesario pasar a modo interactivo lo antes posible # Sino, creamos un bug en el cierre de ventana: se recarga toda la tabla para saber el tamaño #print("FLTableDB(%s): setting columns in interactive mode" % self._tableName) self._tableView._h_header.setResizeMode(QtGui.QHeaderView.Interactive) self._loaded = True while True: #Ahora podemos buscar el cursor ... porque ya estamos añadidos al formulario parent_cursor = getattr(self._parent, "_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent self.initCursor() def cursor(self): if not self._cursorLoaded: self.timer_cursor = QtCore.QTimer(self) self.timer_cursor.singleShot(100, self.cursor) else: if not self._cursor: self._cursor = None print("WARN: FLTableDB.cursor(): Cursor Inválido a", self._tableName) return self._cursor def obj(self): return self def comboBox_putFirstCol(self): self.putFirstCol(str(self._comboBox_1.currentText())) def comboBox_putSecondCol(self): self.putSecondCol(str(self._comboBox_2.currentText())) def putFirstCol(self, fN): _oldPos = None _oldFirst = self._tableView._h_header.logicalIndex(0) for column in range(self._cursor.model().columnCount()): if self._cursor.model().headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) if not self._comboBox_1.currentText() == fN: self._comboBox_1.setCurrentIndex(column) return False break if not _oldPos or fN == "*": return False else: self._tableView._h_header.swapSections(_oldPos, 0) self._comboBox_2.setCurrentIndex(_oldFirst) return True def putSecondCol(self, fN): if self._cursor is None: return _oldPos = None _oldSecond = self._tableView._h_header.logicalIndex(1) for column in range(self._cursor.model().columnCount()): if self._cursor.model().headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) break if not _oldPos or fN == "*": return False if not self._comboBox_1.currentText() == fN: self._tableView._h_header.swapSections(_oldPos, 1) else: self._comboBox_1.setCurrentIndex(_oldSecond) return True def setTableName(self, tableName): self._tableName = tableName self.initCursor() return True def tableName(self): return self._tableName def foreignField(self): return self._foreignField def fieldRelation(self): return self._fieldRelation def setForeignField(self, foreignField): self._foreignField = foreignField self.initCursor() return True def setFieldRelation(self, fieldRelation): self._fieldRelation = fieldRelation self.initCursor() return True def setActionName(self, action): self._action = action def showAlias(self, b): self._showAlias = b def initCursor(self): filtro = None self._cursorLoaded = True if not self._foreignField: return if not self._fieldRelation: return if not self._tableName: return if self._loaded: tipo = self._cursor.model().fieldType(self._fieldRelation) foranea = self._parent.parentWidget().cursor().valueBuffer( self._foreignField) if foranea is None: #print("FLTable(%s): campo foraneo \"%s.%s\" no encontrado." % (self._tableName,self._parent.parentWidget()._cursor.table(), self._foreignField)) return if tipo is "uint": self._foreignFilter = "%s = %s" % ( self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer( self._foreignField)) else: self._foreignFilter = "%s = '%s'" % ( self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer( self._foreignField)) #print("Filtro:%s" % filtro) self._cursor.setMainFilter(self._foreignFilter) self._cursor.refresh() else: self._cursor = FLSqlCursor(self._tableName) #self._cursor.setMainFilter("%s = ") @QtCore.pyqtSlot() def close(self): print("FLTableDB: close()") @QtCore.pyqtSlot() def refresh(self): print("FLTableDB: refresh()", self.parent().parent().parent()) self._cursor.setMainFilter(self._foreignFilter) @QtCore.pyqtSlot() def show(self): print("FLTableDB: show event") #super(FLTableDB, self).show() if self._cursor: self._tableView._h_header.setResizeMode( QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor.model()) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: for column in range(self._cursor.model().columnCount()): self._comboBox_1.addItem(self._cursor.model().headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem(self._cursor.model().headerData( column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect( self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded) @QtCore.pyqtSlot() def insertRecord(self): self._cursor.insertRecord() @QtCore.pyqtSlot() def editRecord(self): self._cursor.editRecord() @QtCore.pyqtSlot() def deleteRecord(self): self._cursor.deleteRecord() @QtCore.pyqtSlot() def browseRecord(self): self._cursor.browseRecord() @QtCore.pyqtSlot() def copyRecord(self): self._cursor.copyRecord() @decorators.WorkingOnThis def setEditOnly(self, value): return True @decorators.WorkingOnThis def setReadOnly(self, value): return True
def alterTable(self, mtd1, mtd2, key): util = FLUtil() oldMTD = None newMTD = None doc = QDomDocument("doc") docElem = None if not util.docDocumentSetContect(doc, mtd1): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) else: docElem = doc.documentElement() oldMTD = self.db_.manager().metadata(docElem, True) if oldMTD and oldMTD.isQuery(): return True if not util.docDocumentSetContect(doc, mtd2): print("FLManager::alterTable : " + qApp.tr("Error al cargar los metadatos.")) return False else: docElem = doc.documentElement() newMTD = self.db_.manager().metadata(docElem, True) if not oldMTD: oldMTD = newMTD if not oldMTD.name() == newMTD.name(): print("FLManager::alterTable : " + qApp.tr("Los nombres de las tablas nueva y vieja difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False oldPK = oldMTD.primaryKey() newPK = newMTD.primaryKey() if not oldPK == newPK: print("FLManager::alterTable : " + qApp.tr("Los nombres de las claves primarias difieren.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().checkMetaData(oldMTD, newMTD): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return True if not self.db_.manager().existsTable(oldMTD.name()): print("FLManager::alterTable : " + qApp.tr( "La tabla %1 antigua de donde importar los registros no existe." ).arg(oldMTD.name())) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False fieldList = oldMTD.fieldList() oldField = None if not fieldList: print("FLManager::alterTable : " + qApp.tr("Los antiguos metadatos no tienen campos.")) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False renameOld = "%salteredtable%s" % (oldMTD.name()[0:5], QDateTime( ).currentDateTime().toString("ddhhssz")) if not self.db_.dbAux(): if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False self.db_.dbAux().transaction() if key and len(key) == 40: c = FLSqlCursor("flfiles", True, self.db_.dbAux()) c.setForwardOnly(True) c.setFilter("nombre = '%s.mtd'" % renameOld) c.select() if not c.next(): buffer = c.primeInsert() buffer.setValue("nombre", "%s.mtd" % renameOld) buffer.setValue("contenido", mtd1) buffer.setValue("sha", key) c.insert() q = FLSqlQuery("", self.db_.dbAux()) if not q.exec_("CREATE TABLE %s AS SELECT * FROM %s;" % (renameOld, oldMTD.name())) or not q.exec_( "DROP TABLE %s;" % oldMTD.name()): print("FLManager::alterTable : " + qApp.tr("No se ha podido renombrar la tabla antigua.")) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False if not self.db_.manager().createTable(newMTD): self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False oldCursor = FLSqlCursor(renameOld, True, self.db_.dbAux()) oldCursor.setModeAccess(oldCursor.Browse) newCursor = FLSqlCursor(newMTD.name(), True, self.db_.dbAux()) newCursor.setMode(newCursor.Insert) oldCursor.select() totalSteps = oldCursor.size() progress = QProgressDialog( qApp.tr("Reestructurando registros para %1...").arg( newMTD.alias()), qApp.tr("Cancelar"), 0, totalSteps) progress.setLabelText(qApp.tr("Tabla modificada")) step = 0 newBuffer = None # sequence = "" fieldList = newMTD.fieldList() newField = None if not fieldList: print("FLManager::alterTable : " + qApp.tr("Los nuevos metadatos no tienen campos.")) self.db_.dbAux().rollback() if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD return False v = None ok = True while oldCursor.next(): v = None newBuffer = newCursor.primeInsert() for it in fieldList: oldField = oldMTD.field(newField.name()) if not oldField or not oldCursor.field(oldField.name()): if not oldField: oldField = newField v = newField.defaultValue() else: v = oldCursor.value(newField.name()) if (not oldField.allowNull() or not newField.allowNull()) and (v is None): defVal = newField.defaultValue() if defVal is not None: v = defVal if not newBuffer.field( newField.name()).type() == newField.type(): print("FLManager::alterTable : " + qApp.tr( "Los tipos del campo %1 no son compatibles. Se introducirá un valor nulo." ).arg(newField.name())) if not oldField.allowNull( ) or not newField.allowNull() and v is not None: if oldField.type() in ("int", "serial", "uint", "bool", "unlock"): v = 0 elif oldField.type() == "double": v = 0.0 elif oldField.type() == "time": v = QTime().currentTime() elif oldField.type() == "date": v = QDate().currentDate() else: v = "NULL"[0:newField.length()] newBuffer.setValue(newField.name(), v) if not newCursor.insert(): ok = False break step = step + 1 progress.setProgress(step) progress.setProgress(totalSteps) if oldMTD and not oldMTD == newMTD: del oldMTD if newMTD: del newMTD if ok: self.db_.dbAux().commit() else: self.db_.dbAux().rollback() return False return True
def sqlUpdate(self, t, fL, vL, w, connName="default"): """ Realiza la modificación de uno o más registros en una tabla mediante un objeto FLSqlCursor @param t Nombre de la tabla @param fL Lista separada con comas de los nombres de los campos @param vL Lista separada con comas de los valores correspondientes @param w Sentencia where para identificar los registros a editar. @param connName Nombre de la conexion @return Verdadero en caso de realizar la inserción con éxito, falso en cualquier otro caso """ from pineboolib.fllegacy.FLSqlCursor import FLSqlCursor c = FLSqlCursor(t, True, connName) c.setForwardOnly(True) # if not c.select(w): # return False c.select(w) while c.next(): c.setModeAccess(FLSqlCursor.Edit) c.refreshBuffer() if isinstance(fL, list): i = 0 for f in fL: c.setValueBuffer(f, vL[i]) i = i + 1 else: c.setValueBuffer(fL, vL) if not c.commitBuffer(): return False return True
def initCursor(self): # si no existe crea la tabla if not self._cursor: return False if not self._cursor._model: return False self._tMD = 0 if not self._sortField: self._tMD = self._cursor._model.name() if self._tMD: self.sortField_ = self._tMD.value(self._cursor._currentregister, self._tMD.primaryKey()) ownTMD = False if not self._tableName: #if not cursor_->db()->manager()->existsTable(tableName_)) { ownTMD = True #tMD = cursor_->db()->manager()->createTable(tableName_); else: ownTMD = True self._tMD = self._cursor._model._table.name if not self._tMD: return if not self._foreignField or not self._fieldRelation: if not self._cursor._model: if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return if not self._cursor._model.name() == self._tableName: ctxt = self._cursor.context(); self._cursor = FLSqlCursor(self._tableName) if self._cursor: self._cursor.setContext(ctxt) cursorAux = 0 if ownTMD and self._tMD and not self._tMD.inCache(): self._tMD = None return else: cursorTopWidget = self.topWidget._cursor() # ::qt_cast<FLFormDB *>(topWidget)->cursor() if cursorTopWidget and not cursorTopWidget._model.name() == self._tableName: self._cursor = cursorTopWidget if not self._tableName or not self._foreignField or not self._fieldRelation or cursorAux: if ownTMD and self._tMD and not self._tMD.inCache(): tMD = None return cursorAux = self._cursor curName = self._cursor._model.name() rMD = self._cursor._model.relation(self._foreignField,self._fieldRelation,self._tableName) testM1 = self._tMD.relation(self._fieldRelation, self._foreignField, curName) checkIntegrity = bool(False) if not rMD: if testM1: checkIntegrity = (testM1.cardinality() == FLRelationMetaData.RELATION_M1) fMD = FLTableMetaData(self._cursor._model.field(self._foreignField)) if (fMD): tmdAux = self._cursor._model(self._tableName); if not tmdAux or tmdAux.isQuery(): checkIntegrity = False if tmdAux and not tmdAux.inCache(): # mirar inCache() tmdAux = None rMD = FLRelationMetaData(self._tableName,self._fieldRelation, FLRelationMetaData.RELATION_1M, False, False, checkIntegrity) fMD.addRelationMD(rMD) print("FLTableDB : La relación entre la tabla del formulario %r y esta tabla %r de este campo no existe, pero sin embargo se han indicado los campos de relación( %r, %r )" % (curName, self._tableName, self._fieldRelation, self._foreignField)) print("FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (curName, self._foreignField, self._tableName, self._fieldRelation)) else: print("FLTableDB : El campo ( %r ) indicado en la propiedad foreignField no se encuentra en la tabla ( %r )" % (self._foreignField, curName)) rMD = testM1 if not rMD: fMD = FLFieldMetaData(tMD.field(self._fieldRelation)) if (fMD): rMD = FLRelationMetaData(curName,self._foreignField, FLRelationMetaData.RELATION_1M, False, False, False) fMD.addRelationMD(rMD) print("FLTableDB : Creando automáticamente %r.%r --1M--> %r.%r" % (self._tableName, self._fieldRelation, curName, self._foreignField)) else: print("FLTableDB : El campo ( %r ) indicado en la propiedad fieldRelation no se encuentra en la tabla ( %r )" % (self._fieldRelation, self._tableName)) self._cursor = FLSqlCursor(self._tableName, True, self._cursor.db().connectionName(), cursorAux, rMD, self); if not self._cursor: self._cursor = cursorAux cursorAux = 0 else: self._cursor.setContext(cursorAux.context()) if self.showed: self.disconnect(cursorAux, QtCore.SIGNAL('newBuffer()'), self.refresh()) self.connect(cursorAux,QtCore.SIGNAL('newBuffer()'), self.refresh()) if cursorAux and self.topWidget.isA("FLFormSearchDB"): self.topWidget.setCaption(self._cursor._model.alias()) self.topWidget.setCursor(self._cursor) #::qt_cast<FLFormSearchDB *>(topWidget)->setCursor(cursor_); if ownTMD and tMD and not tMD.inCache(): tMD = None
class FLFormSearchDB(FLFormDB): """ Subclase de la clase FLFormDB, pensada para buscar un registro en una tabla. El comportamiento de elegir un registro se modifica para solamente cerrar el formulario y así el objeto que lo invoca pueda obtener del cursor dicho registro. También añade botones Aceptar y Cancelar. Aceptar indica que se ha elegido el registro activo (igual que hacer doble clic sobre él o pulsar la tecla Intro) y Cancelar aborta la operación. @author InfoSiAL S.L. """ """ Boton Aceptar """ pushButtonAccept = None """ Almacena si se ha abierto el formulario con el método FLFormSearchDB::exec() """ loop = None acceptingRejecting_ = None inExec_ = None accepted_ = None cursor_ = None eventloop = None """ constructor. """ def __init__(self, *args, **kwargs): parent = None name = None action = None if isinstance(args[0], str): #@param actionName Nombre de la acción asociada al formulario if len(args) == 2: parent = args[1] name = args[0] self.cursor_ = FLSqlCursor(name, True, "default", None, None, self) action = self.cursor_.action() self.accepted_ = False elif isinstance(args[0], FLSqlCursor): #@param cursor Objeto FLSqlCursor para asignar a este formulario #@param actionName Nombre de la acción asociada al formulario if len(args) > 2: action = args[1] name = action.name if len(args) == 3: parent = args[2] self.cursor_ = args[0] super(FLFormSearchDB,self).__init__(parent, action) self.setFocusPolicy(QtCore.Qt.NoFocus) if not name: print("FLFormSearchDB : Nombre de acción vacío") return if not action: print("FLFormSearchDB : No existe la acción", name) return self.initForm() """ destructor """ def __delattr__(self, *args, **kwargs): if self.cursor_: self.cursor_.restoreEditionFlag(self) self.cursor_.restoreBrowseFlag(self) FLFormDB.__delattr__(self, *args, **kwargs) """ formReady = QtCore.pyqtSignal() """ def initForm(self): super(FLFormSearchDB, self).initForm() def loadControls(self): self.bottomToolbar = QtGui.QFrame() self.bottomToolbar.setMaximumHeight(64) self.bottomToolbar.setMinimumHeight(16) self.bottomToolbar.layout = QtGui.QHBoxLayout() self.bottomToolbar.setLayout(self.bottomToolbar.layout) self.bottomToolbar.layout.setMargin(0) self.bottomToolbar.layout.setSpacing(0) self.bottomToolbar.layout.addStretch() self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus) self.layout.addWidget(self.bottomToolbar) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(0) ,QtGui.QSizePolicy.Policy(0)) sizePolicy.setHeightForWidth(True) pbSize = QtCore.QSize(22,22) if not self.pushButtonAccept: self.pushButtonAccept = QtGui.QToolButton() self.pushButtonAccept.clicked.connect(self.accept) self.pushButtonAccept.setSizePolicy(sizePolicy) self.pushButtonAccept.setMaximumSize(pbSize) self.pushButtonAccept.setMinimumSize(pbSize) self.pushButtonAccept.setIcon(QtGui.QIcon(filedir("icons","gtk-save.png"))) #pushButtonAccept->setAccel(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 = QtGui.QToolButton() self.pushButtonCancel.clicked.connect(self.reject) self.pushButtonCancel.setSizePolicy(sizePolicy) self.pushButtonCancel.setMaximumSize(pbSize) self.pushButtonCancel.setMinimumSize(pbSize) self.pushButtonCancel.setIcon(QtGui.QIcon(filedir("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() self.cursor_.setEdition(False) self.cursor_.setBrowse(False) self.cursor_.recordChoosed.connect(self.accept) def __getattr__(self, name): return DefFun(self, name) """ Muestra el formulario y entra en un nuevo bucle de eventos para esperar, a seleccionar registro. Se espera el nombre de un campo del cursor devolviendo el valor de dicho campo si se acepta el formulario y un QVariant::Invalid si se cancela. @param n Nombre del un campo del cursor del formulario @return El valor del campo si se acepta, o QVariant::Invalid si se cancela """ @decorators.BetaImplementation def exec_(self, valor): if not self.cursor_: return None if not self.cursor_.isLocked(): self.cursor_.setModeAccess(FLSqlCursor.Edit) if self.loop or self.inExec_: print("FLFormSearchDB::exec(): Se ha detectado una llamada recursiva") super(FLFormDB,self).show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() return None self.load() #Extra self.inExec_ = True self.acceptingRejecting_ = False super(FLFormDB,self).show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() if self.iface: try: timer1 = QtCore.QTimer(self) timer1.singleShot(300, self.iface.init) except Exception: pass if not self.isClosing_: timer2 = QtCore.QTimer(self) timer2.singleShot(0, self.emitFormReady) self.accepted_ = False self.loop = True self.eventloop = QtCore.QEventLoop() self.eventloop.exec_() #if not self.isClosing_ and not self.acceptingRejecting_: #QtCore.QEventLoop().enterLoop() FIXME self.loop = False #self.clearWFlags(WShowModal) FIXME v = None if self.accepted_ and valor: v = self.cursor_.valueBuffer(valor) else: v = None self.inExec_ = False return v """ Aplica un filtro al cursor """ def setFilter(self, f): if not self.cursor_: return previousF = self.cursor_.mainFilter() newF = None if not previousF: newF = f elif previousF.contains(f): return else: newF = "%s AND %s" % (previousF, f) self.cursor_.setMainFilter(newF) """ Devuelve el nombre de la clase del formulario en tiempo de ejecución """ def formClassName(self): return "FormSearchDB" """ Nombre interno del formulario """ def geoName(self): return "formSearch%s" % self.idMDI_ """ Captura evento cerrar """ def closeEvent(self, e): self.frameGeometry() if self.focusWidget(): fdb = self.focusWidget().parentWidget() if fdb and fdb.autoComFrame_ and fdb.autoComFrame_.isvisible(): fdb.autoComFrame_.hide() return if self.cursor_ and self.pushButtonCancel: if not self.pushButtonCancel.isEnabled(): return self.isClosing_ = True self.setCursor(None) else: self.isClosing_ = True if self.isShown(): self.reject() if self.isHidden(): self.closed.emit() QtGui.QWidget.closeEvent(e) self.deleteLater() """ Invoca a la función "init()" del script asociado al formulario """ @QtCore.pyqtSlot() def initScript(self): return False """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def hide(self): if self.isHidden(): return super(FLFormSearchDB, self).hide() if self.loop: self.loop = False self.eventloop.exit() """ Se activa al pulsar el boton aceptar """ @QtCore.pyqtSlot() def accept(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: try: self.cursor_.recordChoosed.disconnect(self.accept) except: pass self.acceptingRejecting_ = True self.accepted_ = True self.hide() """ Se activa al pulsar el botón cancelar """ @QtCore.pyqtSlot() def reject(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: try: self.cursor_.recordChoosed.disconnect(self.accept) except: pass self.acceptingRejecting_ = True self.hide() """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def show(self): self.exec_() def accepted(self): return self.accepted_ def setMainWidget(self, w=None): if not self.cursor_: return if w: w.hide() self.mainWidget_ = w
class FLFormDB(QtGui.QWidget): """ Representa un formulario que enlaza con una tabla. Se utiliza como contenedor de componentes que quieran enlazar con la base de datos y acceder a los registros del cursor. Esta estructura simplifica en gran medida el acceso a los datos ya que muchas tareas son automáticamente gestionadas por este formulario contenedor. En un principio el formulario se crea vacío y debemos invocar el metodo FLFormDB::setMainWidget(), pasándole como parámetro otro widget (generalmente un formulario creado con QtDesigner), el cual contiene distintos componentes, este widget se visualizará dentro de este contenedor, autofonfigurándose todos los componentes que contiene, con los datos y metadatos del cursor. Generalmente los componentes serán plugins, como FLFieldDB o FLTableDB. @author InfoSiAL S.L. """ """ Cursor, con los registros, utilizado por el formulario """ cursor_ = None """ Nombre de la tabla, contiene un valor no vacío cuando la clase es propietaria del cursor """ name_ = None """ Capa principal del formulario """ layout = None """ Widget principal del formulario """ mainWidget_ = None """ Acción asociada al formulario """ action_ = None """ Identificador de ventana MDI. Generalmente es el nombre de la acción que abre el formulario """ idMDI_ = None """ Capa para botones """ layoutButtons = None """ Boton Cancelar """ pushButtonCancel = None """ Indica que la ventana ya ha sido mostrada una vez """ showed = None """ Guarda el contexto anterior que tenia el cursor """ oldCursorCtxt = None """ Indica que el formulario se está cerrando """ isClosing_ = None """ Componente con el foco inicial """ initFocusWidget_ = None """ Guarda el último objeto de formulario unido a la interfaz de script (con bindIface()) """ oldFormObj = None #ifdef QSDEBUGGER """ Boton Debug Script """ pushButtonDebug = None #endif """ Almacena que se aceptado, es decir NO se ha pulsado, botón cancelar """ accepted_ = None """ Interface para scripts """ iface = None parent_= None @decorators.BetaImplementation def __init__(self, *args, **kwargs): if isinstance(args[0],FLSqlCursor): QtGui.QWidget.__init__(self, args[2]) self.inicialize3(args, kwargs) elif isinstance(args[0], QtGui.QWidget): QtGui.QWidget.__init__(self, args[0]) self.inicialize1(args,kwargs) else: QtGui.QWidget.__init__(self, args[1]) self.inicialize2(args,kwargs) """ constructor """ @decorators.BetaImplementation def inicialize1(self, *args, **kwargs): parent = args[0][0] name = args[0][1] f = args[1] if parent: self.parent_ = parent else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), name, f) self.cursor_ = None self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False self.loaded = False """ constructor. @param actionName Nombre de la acción asociada al formulario """ @decorators.BetaImplementation def inicialize2(self,*args, **kwargs): actionName = str(args[0][0]) parent = args[0][1] f = args[1] if parent: self.parent_ = parent else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), actionName, f) self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = None print(FLUtil.translate("sys","FLFormDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action(actionName) if not self.action_: print(FLUtil.translate("sys","FLFormDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True, "default", 0, 0, self) self.name_ = self.action_.name() self.initForm() """ constructor sobrecargado. @param cursor Objeto FLSqlCursor para asignar a este formulario @param actionName Nombre de la acción asociada al formulario """ @decorators.BetaImplementation def inicialize3(self, *args, **kwargs): cursor = args[0] actionName = args[1] parent = args[2] f = args[3] self.cursor_ = cursor self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False if parent: self.parent_ = QtGui.QWidget(parent) else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), actionName, f) self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = None elif cursor: self.action_ = cursor.db().manager().action(actionName) else: self.action = FLSqlConnections.database().manager().action(actionName) if self.action_: self.name_ = self.action_.name() """ destructor """ @decorators.BetaImplementation def __del__(self): self.unbindIface() """ Establece el cursor que debe utilizar el formulario. @param c Cursor con el que trabajar """ @decorators.BetaImplementation def setCursor(self, *c): if not c == self.cursor_ and self.cursor_ and self.oldCursorCtxt: self.cursor_.setContext(self.oldCursorCtxt) if not c: return if self.cursor_: self.cursor_.destroyed.disconnect(self.cursorDestroyed) self.cursor_ = c self.cursor_.destroyed.connect(self.cursorDestroyed) if self.iface and self.cursor_: self.oldCursorCtxt = self.cursor_.context() self.cursor_.setContext(self.iface) """ Para obtener el cursor utilizado por el formulario. return Objeto FLSqlCursor con el cursor que contiene los registros para ser utilizados en el formulario """ @decorators.BetaImplementation def cursor(self): return self.cursor_ """ Para obtener el widget principal del formulario. return Objeto QWidget que corresponde con el widget principal del formulario """ @decorators.BetaImplementation def mainWidget(self): return self.mainWidget_ """ Establece el identificador MDI """ @decorators.BetaImplementation def setIdMDI(self, _id): self.idMDI_ = _id """ Obtiene el identificador MDI """ @decorators.BetaImplementation def idMDI(self): return self.idMDI_ @decorators.BetaImplementation def setMainWidget(self, *args, **kwarg): if isinstance(args[0], QtGui.QWidget): self.setMainWidgetQWidget(args[0]) elif isinstance(args[0], str): self.setMainWidgetString(args[0]) else: self.setMainWidgetEmpty() """ Establece widget como principal del formulario. Este widget contendrá componentes que quieran enlazar con la base de datos, por lo que esperan estar contenidos en una clase FLFormDB, la cual les proporciona el cursor (registros) a los que enlazar. Si ya existiera otro widget como principal, este será borrado. Si existe un widget principal establecido con anterioridad será borrado @param w Widget principal para el formulario """ @decorators.BetaImplementation def setMainWidgetQWidget(self, *w): if not self.cursor_ and not w: return if self.showed: if self.mainWidget_ and not self.mainWidget_ == w: self.initMainWidget(w) else: w.hide() if self.layout: del self.Layout #w.setFont(qApp.font()) #FIXME self.layout = QtGui.QVBoxLayout(self, 2,3,"vlay" + self.name_) self.layout.add(w) self.layoutButtons = QtGui.QHBoxLayout(self.layout , 3, "hlay" + self.name_) self.layoutButtons.addItem(QtGui.QSpacerItem()) self.pushButtonCancel = QtGui.QPushButton(self, "pushButtonCancel") #self.pushButtonCancel.set_size(QtGui.QSizePolicy) #FIXME self.pushButtonCancel.setMinimumSize(22, 22) self.pushButtonCancel.setMaximumSize(22, 22) self.pushButtonCancel.setIcon(QtGui.QIcon(filedir("icons","gtk-cancel.png"))) #pushButtonCancel->setFocusPolicy(QWidget::NoFocus); #pushButtonCancel->setAccel(QKeySequence(tr("Esc"))); #QToolTip::add(pushButtonCancel, tr("Cerrar formulario (Esc)")); #QWhatsThis::add(pushButtonCancel, tr("Cerrar formulario (Esc)")); self.layoutButtons.addWidget(self.pushButtonCancel) self.pushButtonCancel.clicked.connect(self.close) self.pushButtonCancel.show() self.mainWidget_ = w """ Sobrecargado de setMainWidget. Aqui toma el nombre de un formulario de la acción asociada y construye el Widget principal, a partir de él. """ @decorators.BetaImplementation def setMainWidgetEmpty(self): if not self.action_: return if self.cursor_: self.setMainWidgetQWidget(self.cursor_.db().managerModules.createUI(self.action_, self, self)) else: self.setMainWidget(FLSqlConnections.database().managerModules().createUI(self.action_, self, self)) """ Sobrecargado de setMainWidget. Aqui construye el Widget principal a partir del nombre de un fichero de interfaz .ui. @param uiFileName Nombre del fichero de descripción de interfaz, incluyendo la extension .ui, p.e. clientes.ui """ @decorators.BetaImplementation def setMainWidgetString(self, uiFileName): if self.cursor_: self.setMainWidgetQWidget(self.cursor_.db().managerModules.createUI(uiFileName, self, self)) else: self.setMainWidget(FLSqlConnections.database().managerModules().createUI(uiFileName, self, self)) """ Obtiene la imagen o captura de pantalla del formulario. """ @decorators.BetaImplementation def snapShot(self): pix = QtGui.QPixmap.grabWidget(self) return QtGui.QImage(pix) """ Salva en un fichero con formato PNG la imagen o captura de pantalla del formulario. @param pathFile Ruta y nombre del fichero donde guardar la imagen """ @decorators.BetaImplementation def saveSnapShot(self, pathFile): fi = QtCore.QFile(pathFile) if not fi.open(QtCore.QFile.WriteOnly): print("FLFormDB : " + FLUtil.translate("sys", "Error I/O al intentar escribir el fichero %s" % pathFile)) return self.snapShot().save(fi, "PNG") """ Establece el título de la ventana. @param text Texto a establecer como título de la ventana @author Silix """ @decorators.BetaImplementation def setCaptionWidget(self, text): if text.isEmpty(): return self.setCaption(text) """ Devuelve si se ha aceptado el formulario """ @decorators.BetaImplementation def accepted(self): return self.accepted_ """ Devuelve el nombre de la clase del formulario en tiempo de ejecución """ @decorators.BetaImplementation def formClassName(self): return "FormDB" """ Sólo para compatibilizar con FLFormSearchDB. Por defecto sólo llama QWidget::show """ @decorators.BetaImplementation def exec_(self): QtGui.QWidget.show() return QtCore.QVariant() #public slots: """ Cierra el formulario """ @decorators.BetaImplementation def close(self): if self.isClosing_: return True self.isClosing_ = True self.isClosing_ = QtGui.QWidget.close() """ Invoca a la función "init" del script "masterprocess" asociado al formulario """ @decorators.NotImplementedWarn def initScript(self): if self.iface: #pineboolib.project.call("init", QtCore.QSArgumentList(), self.iface) #FIXME return True else: return False """ Se activa al pulsar el boton aceptar """ @decorators.BetaImplementation def accept(self): return """ Se activa al pulsar el botón cancelar """ @decorators.BetaImplementation def reject(self): return """ Redefinida por conveniencia """ @decorators.BetaImplementation def show(self): QtGui.QWidget.show() """ Muestra el formulario sin llamar al script "init". Utilizado en documentación para evitar conflictos al capturar los formularios """ @decorators.BetaImplementation def showForDocument(self): self.showed = True self.mainWidget_.show() self.resize(self.size().expandedTo(self.mainWidget_.size())) QtGui.QWidget.show() """ Maximiza el formulario """ @decorators.BetaImplementation def setMaximized(self): self.setWindowState(self.windowState() | QtCore.Qt.WindowMaximized) """ Muestra el script asociado al formulario en el Workbench para depurar """ @decorators.BetaImplementation def debugScript(self): return """ Devuelve el script asociado al formulario """ @decorators.BetaImplementation def script(self): return #private slots: @decorators.BetaImplementation def callInitScript(self): if not self.initScript(): return if not self.isClosing_: self.emitFormReady.emit() #protected: """ Inicialización """ @decorators.BetaImplementation def initForm(self): if self.cursor_ and self.cursor_.metadata(): caption = None if self.action_: self.cursor_.setAction(self.action_) caption = self.action_.caption() if not self.action_.description().isEmpty(): self.QtGui.QWhatsThis.add(self, self.action_.description()) self.idMDI_ = self.action_.name() if caption.isEmpty(): caption = self.cursor_.metadata().alias() self.setCaption(caption) self.bindIface() self.setCursor(self.cursor_) else: self.setCaption(FLUtil.translate("sys" ,"No hay metadatos")) """ Nombre interno del formulario """ @decorators.BetaImplementation def formName(self): return ("form%s" % self.idMDI_) @decorators.BetaImplementation def geoName(self): return self.formName() """ Une la interfaz de script al objeto del formulario """ @decorators.BetaImplementation def bindIface(self): p = pineboolib.project if not p: return self.setName(self.formName()) o = p.object(self.name()) if not o == self.iface and self.iface and self.oldFormObj: self.iface.setObj(self.oldFormObj) self.iface = o ifc = self.iface if not ifc: return if not ifc.obj() == self: if self.oldFormObj: self.oldFormObj.destroyed.disconnect(self.oldFormObjDestroyed()) self.oldFormObj = ifc.obj() if self.oldFormObj: self.oldFormObj.destroyed.connect(self.oldFormObjDestroyed()) ifc.setObj(self) """ Desune la interfaz de script al objeto del formulario """ @decorators.BetaImplementation def unbindIface(self): ifc = self.iface if not ifc: return if ifc.obj() == self: ifc.setObj(self.oldFormObj) """ Indica si la interfaz de script está unida al objeto formulario """ @decorators.BetaImplementation def isIfaceBind(self): ifc = self.iface if not ifc: return return (ifc.obj() == self) """ Captura evento cerrar """ @decorators.BetaImplementation def closeEvent(self, *e): self.frameGeometry() if self.focusWidget(): fdb = self.focusWidget().parentWidget() if fdb and fdb.autoComFrame_ and fdb.autoComFrame_.isVisible(): fdb.autoComFrame_.hide() return """ Captura evento mostrar """ @decorators.NotImplementedWarn def showEvent(self, *e): if not self.showed and self.mainWidget_: self.showed = True if self.cursor_ and self.iface: #v = pineboolib.project.call("preloadMainFilter", QSArgumentList(), self.iface).variant()) if v and isinstance(v.type(), str): self.cursor_.setMainFilter(str(v), False) self.initMainWidget() self.callInitScript() if not self.isIfaceBind(): self.bindIface() """ Captura evento ocultar """ @decorators.NotImplementedWarn def hideEvent(self, *h): return """ { QWidget *pW = parentWidget(); if (pW && pW->isA("QWorkspaceChild")) { QRect geo(pW->x(), pW->y(), pW->width(), pW->height()); if (isMinimized()) { geo.setWidth(1); aqApp->saveGeometryForm(geoName(), geo); } else if (isMaximized()) { geo.setWidth(9999); aqApp->saveGeometryForm(geoName(), geo); } else aqApp->saveGeometryForm(geoName(), geo); } else { QRect geo(x(), y(), width(), height()); aqApp->saveGeometryForm(geoName(), geo); } } """ """ Captura evento de entrar foco """ @decorators.BetaImplementation def focusInEvent(self, *f): self.focusInEvent(f) if self.isIfaceBind(): self.bindIface() """ Inicializa componenentes del widget principal @param w Widget a inicializar. Si no se establece utiliza por defecto el widget principal actual """ @decorators.NotImplementedWarn def initMainWidget(self, *w): return """ { QWidget *mWidget = w ? w : mainWidget_; if (mWidget) { QObjectList *l = static_cast<QObject *>(mWidget)->queryList("FLTableDB"); QObjectListIt itt(*l); FLTableDB *tdb; while ((tdb = static_cast<FLTableDB *>(itt.current())) != 0) { ++itt; tdb->initCursor(); } delete l; l = static_cast<QObject *>(mWidget)->queryList("FLFieldDB"); QObjectListIt itf(*l); FLFieldDB *fdb; while ((fdb = static_cast<FLFieldDB *>(itf.current())) != 0) { ++itf; fdb->initCursor(); fdb->initEditor(); if (fdb->aqFirstTabStop == 1) initFocusWidget_ = fdb; } while (mWidget->parentWidget() && mWidget->parentWidget() != this) mWidget = mWidget->parentWidget(); mWidget->show(); FLAccessControlLists *acl = aqApp->acl(); if (acl) acl->process(this); QWidget *pW = parentWidget(); QRect desk; bool parentIsDesktop = true; if (!(pW && pW->isA("QWorkspaceChild"))) { desk = QApplication::desktop()->availableGeometry(this); pW = this; } else { desk = pW->parentWidget()->rect(); parentIsDesktop = false; } QRect geo(aqApp->geometryForm(QObject::name())); pW->show(); QSize oSz = mWidget->size(); mWidget->updateGeometry(); QSize bSz = mWidget->baseSize(); QSize SzH = mWidget->sizeHint(); int border = 5, border_b = 48; /* qDebug("geo: " + QString::number(geo.width()) + "x" + QString::number(geo.height())); qDebug("oSz: " + QString::number(oSz.width()) + "x" + QString::number(oSz.height())); qDebug("bSz: " + QString::number(bSz.width()) + "x" + QString::number(bSz.height())); qDebug("SzH: " + QString::number(SzH.width()) + "x" + QString::number(SzH.height())); */ if (geo.width() < 100 || geo.width()>9000) { // qDebug(" -- reset Form Size and position -- "); geo.setWidth(oSz.width()); geo.setHeight(oSz.height()); geo.moveCenter(desk.center()); if (!parentIsDesktop) { geo.moveTop(desk.top() + border - geo.top()+1); } } if (geo.width() < SzH.width()) { // qDebug(" -- geo width too small -- "); geo.setWidth(SzH.width()); } if (geo.height() < SzH.height()) { // qDebug(" -- geo height too small -- "); geo.setHeight(SzH.height()); } // Exceeds available horizontal area: if (geo.width() > desk.width() - border * 2) { // qDebug(" -- geo width too big -- "); geo.setWidth(desk.width() - border * 2 - 5); } // Exceeds available vertical area: if (geo.height() > desk.height() - border - border_b) { // qDebug(" -- geo height too big -- "); geo.setHeight(desk.height() - border - border_b - 5); } if (parentIsDesktop) { // Invalid position values, re-center if ( geo.right() > 9000 || geo.left() < 1 || geo.bottom() > 9000 || geo.top() < 1 ) { // qDebug(" -- geo invalid position -- "); geo.moveCenter(desk.center()); } if ( geo.top() < desk.top() + border) { // qDebug(" -- geo position too high -- "); geo.moveTop(desk.top() + border - geo.top()+1); } if ( geo.left() < desk.left() + border) { // qDebug(" -- geo position too left -- "); geo.moveLeft(desk.left() + border - geo.left()+1); } if ( geo.bottom() > desk.bottom() - border_b ) { int diff = geo.bottom() - desk.bottom() - border_b; // qDebug(" -- geo position too low -- "); geo.moveTop(-diff-1); } if ( geo.right() > desk.right() - border) { int diff = geo.right() - desk.right() - border; // qDebug(" -- geo position too right -- "); geo.moveLeft(-diff-1); } // Outside of screen, re-center: if ( geo.right() > desk.right() - border || geo.left() < desk.left() + border || geo.bottom() > desk.bottom() - border_b || geo.top() < desk.top() + border ) { // qDebug(" -- geo position out of screen -- "); geo.moveCenter(desk.center()); } } mWidget->resize(geo.size()); pW->updateGeometry(); QSize tSz= pW->size(); QSize tSzH = pW->sizeHint(); if (tSz.width() < tSzH.width()) { tSz.setWidth(tSzH.width()); } if (tSz.height() < tSzH.height()) { tSz.setHeight(tSzH.height()); } pW->resize(tSz.expandedTo(mWidget->size())); pW->move(geo.topLeft()); if (!initFocusWidget_) { itf.toFirst(); while ((fdb = static_cast<FLFieldDB *>(itf.current())) != 0) { ++itf; if (fdb->isEnabled()) { initFocusWidget_ = fdb; break; } } if (!initFocusWidget_) initFocusWidget_ = static_cast<QWidget *>(mWidget->focusWidget()); if (initFocusWidget_) initFocusWidget_->setFocus(); } delete l; QWidget *focWid = qApp->focusWidget(); if (focWid) { QWidget *topWidget = focWid->topLevelWidget(); if (topWidget && !topWidget->inherits("FLFormDB")) { QWidget *topWid = focWid->parentWidget(); while (topWid && !topWid->inherits("FLFormDB")) topWid = topWid->parentWidget(); topWidget = topWid; } if (topWidget != this) setFocus(); } else setFocus(); } } """ #protected slots: """ Emite señal formulari listo. Ver FLFormDB::formReady() """ emitFormReady = QtCore.pyqtSignal() """ Uso interno """ @QtCore.pyqtSlot() def oldFormObjDestroyed(self): print("oldFormObjDestroyed") self.oldFormObj = None return None @QtCore.pyqtSlot(QtCore.QObject) def cursorDestroyed(self, *obj): print("cursorDestroyed") if not obj or not obj == self.cursor_: return self.cursor_ = None return None #signals: """ Señal emitida cuando se cierra el formulario """ closed = QtCore.pyqtSignal() """ Señal emitida cuando el formulario ya ha sido inicializado y está listo para usarse """ formReady = QtCore.pyqtSignal()
class FLFormSearchDB(FLFormDB): """ Subclase de la clase FLFormDB, pensada para buscar un registro en una tabla. El comportamiento de elegir un registro se modifica para solamente cerrar el formulario y así el objeto que lo invoca pueda obtener del cursor dicho registro. También añade botones Aceptar y Cancelar. Aceptar indica que se ha elegido el registro activo (igual que hacer doble clic sobre él o pulsar la tecla Intro) y Cancelar aborta la operación. @author InfoSiAL S.L. """ """ Boton Aceptar """ pushButtonAccept = None """ Almacena si se ha abierto el formulario con el método FLFormSearchDB::exec() """ loop = None acceptingRejecting_ = None inExec_ = None accepted_ = None cursor_ = None eventloop = None """ constructor. """ def __init__(self, *args, **kwargs): parent = None name = None action = None if isinstance(args[0], str): #@param actionName Nombre de la acción asociada al formulario if len(args) == 2: parent = args[1] name = args[0] self.cursor_ = FLSqlCursor(name, True, "default", None, None, self) action = self.cursor_.action() self.accepted_ = False elif isinstance(args[0], FLSqlCursor): #@param cursor Objeto FLSqlCursor para asignar a este formulario #@param actionName Nombre de la acción asociada al formulario if len(args) > 2: action = args[1] name = action.name if len(args) == 3: parent = args[2] self.cursor_ = args[0] super(FLFormSearchDB, self).__init__(parent, action) self.setFocusPolicy(QtCore.Qt.NoFocus) if not name: print("FLFormSearchDB : Nombre de acción vacío") return if not action: print("FLFormSearchDB : No existe la acción", name) return self.initForm() """ destructor """ def __delattr__(self, *args, **kwargs): if self.cursor_: self.cursor_.restoreEditionFlag(self) self.cursor_.restoreBrowseFlag(self) FLFormDB.__delattr__(self, *args, **kwargs) """ formReady = QtCore.pyqtSignal() """ def initForm(self): super(FLFormSearchDB, self).initForm() def loadControls(self): self.bottomToolbar = QtGui.QFrame() self.bottomToolbar.setMaximumHeight(64) self.bottomToolbar.setMinimumHeight(16) self.bottomToolbar.layout = QtGui.QHBoxLayout() self.bottomToolbar.setLayout(self.bottomToolbar.layout) self.bottomToolbar.layout.setMargin(0) self.bottomToolbar.layout.setSpacing(0) self.bottomToolbar.layout.addStretch() self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus) self.layout.addWidget(self.bottomToolbar) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(0), QtGui.QSizePolicy.Policy(0)) sizePolicy.setHeightForWidth(True) pbSize = QtCore.QSize(22, 22) if not self.pushButtonAccept: self.pushButtonAccept = QtGui.QToolButton() self.pushButtonAccept.clicked.connect(self.accept) self.pushButtonAccept.setSizePolicy(sizePolicy) self.pushButtonAccept.setMaximumSize(pbSize) self.pushButtonAccept.setMinimumSize(pbSize) self.pushButtonAccept.setIcon( QtGui.QIcon(filedir("icons", "gtk-save.png"))) #pushButtonAccept->setAccel(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 = QtGui.QToolButton() self.pushButtonCancel.clicked.connect(self.reject) self.pushButtonCancel.setSizePolicy(sizePolicy) self.pushButtonCancel.setMaximumSize(pbSize) self.pushButtonCancel.setMinimumSize(pbSize) self.pushButtonCancel.setIcon( QtGui.QIcon(filedir("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() self.cursor_.setEdition(False) self.cursor_.setBrowse(False) self.cursor_.recordChoosed.connect(self.accept) def __getattr__(self, name): return DefFun(self, name) """ Muestra el formulario y entra en un nuevo bucle de eventos para esperar, a seleccionar registro. Se espera el nombre de un campo del cursor devolviendo el valor de dicho campo si se acepta el formulario y un QVariant::Invalid si se cancela. @param n Nombre del un campo del cursor del formulario @return El valor del campo si se acepta, o QVariant::Invalid si se cancela """ @decorators.BetaImplementation def exec_(self, valor): if not self.cursor_: return None if not self.cursor_.isLocked(): self.cursor_.setModeAccess(FLSqlCursor.Edit) if self.loop or self.inExec_: print( "FLFormSearchDB::exec(): Se ha detectado una llamada recursiva" ) super(FLFormDB, self).show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() return None self.load() #Extra self.inExec_ = True self.acceptingRejecting_ = False super(FLFormDB, self).show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() if self.iface: try: timer1 = QtCore.QTimer(self) timer1.singleShot(300, self.iface.init) except Exception: pass if not self.isClosing_: timer2 = QtCore.QTimer(self) timer2.singleShot(0, self.emitFormReady) self.accepted_ = False self.loop = True self.eventloop = QtCore.QEventLoop() self.eventloop.exec_() #if not self.isClosing_ and not self.acceptingRejecting_: #QtCore.QEventLoop().enterLoop() FIXME self.loop = False #self.clearWFlags(WShowModal) FIXME v = None if self.accepted_ and valor: v = self.cursor_.valueBuffer(valor) else: v = None self.inExec_ = False return v """ Aplica un filtro al cursor """ def setFilter(self, f): if not self.cursor_: return previousF = self.cursor_.mainFilter() newF = None if not previousF: newF = f elif previousF.contains(f): return else: newF = "%s AND %s" % (previousF, f) self.cursor_.setMainFilter(newF) """ Devuelve el nombre de la clase del formulario en tiempo de ejecución """ def formClassName(self): return "FormSearchDB" """ Nombre interno del formulario """ def geoName(self): return "formSearch%s" % self.idMDI_ """ Captura evento cerrar """ def closeEvent(self, e): self.frameGeometry() if self.focusWidget(): fdb = self.focusWidget().parentWidget() if fdb and fdb.autoComFrame_ and fdb.autoComFrame_.isvisible(): fdb.autoComFrame_.hide() return if self.cursor_ and self.pushButtonCancel: if not self.pushButtonCancel.isEnabled(): return self.isClosing_ = True self.setCursor(None) else: self.isClosing_ = True if self.isShown(): self.reject() if self.isHidden(): self.closed.emit() super(FLFormSearchDB, self).closeEvent(e) self.deleteLater() """ Invoca a la función "init()" del script asociado al formulario """ @QtCore.pyqtSlot() def initScript(self): return False """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def hide(self): if self.isHidden(): return super(FLFormSearchDB, self).hide() if self.loop: self.loop = False self.eventloop.exit() """ Se activa al pulsar el boton aceptar """ @QtCore.pyqtSlot() def accept(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: try: self.cursor_.recordChoosed.disconnect(self.accept) except: pass self.acceptingRejecting_ = True self.accepted_ = True self.hide() """ Se activa al pulsar el botón cancelar """ @QtCore.pyqtSlot() def reject(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: try: self.cursor_.recordChoosed.disconnect(self.accept) except: pass self.acceptingRejecting_ = True self.hide() """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def show(self): self.exec_() def accepted(self): return self.accepted_ def setMainWidget(self, w=None): if not self.cursor_: return if w: w.hide() self.mainWidget_ = w
def sqlDelete(self, t, w, connName="default"): from pineboolib.fllegacy.FLSqlCursor import FLSqlCursor c = FLSqlCursor(t, True, connName) c.setForwardOnly(True) # if not c.select(w): # return False c.select(w) while c.next(): c.setModeAccess(FLSqlCursor.DEL) c.refreshBuffer() if not c.commitBuffer(): return False return True
class FLFormSearchDB(FLFormDB): """ Subclase de la clase FLFormDB, pensada para buscar un registro en una tabla. El comportamiento de elegir un registro se modifica para solamente cerrar el formulario y así el objeto que lo invoca pueda obtener del cursor dicho registro. También añade botones Aceptar y Cancelar. Aceptar indica que se ha elegido el registro activo (igual que hacer doble clic sobre él o pulsar la tecla Intro) y Cancelar aborta la operación. @author InfoSiAL S.L. """ """ Uso interno """ acceptingRejecting_ = False inExec_ = False """ Boton Aceptar """ pushButtonAccept = None """ Almacena si se ha abierto el formulario con el método FLFormSearchDB::exec() """ loop = None def __init__(self, *args, **kwargs): if isinstance(args[0], QString): super(FLFormSearchDB, self).__init( args[0], args[1], (Qt.WStyle_Customize, Qt.WStyle_Maximize, Qt.WStyle_Title, Qt.WStyle_NormalBorder, Qt.WType_Dialog, Qt.WShowModal, Qt.WStyle_SysMenu)) self.init1(args[0], args[1]) else: super(FLFormSearchDB, self).__init( args[1], args[2], (Qt.WStyle_Customize, Qt.WStyle_Maximize, Qt.WStyle_Title, Qt.WStyle_NormalBorder, Qt.WType_Dialog, Qt.WShowModal, Qt.WStyle_SysMenu)) self.init2(args[0], args[1], args[2]) """ constructor. @param actionName Nombre de la acción asociada al formulario """ def init1(self, actionName, parent=None): self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = False print( FLUtil.translate("app", "FLFormSearchDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action( actionName) if not self.action_: print( FLUtil.translate( "app", "FLFormSearchDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True, "default", 0, 0, self) self.name_ = self.action_.name() self.initForm() """ constructor sobrecargado. @param cursor Objeto FLSqlCursor para asignar a este formulario @param actionName Nombre de la acción asociada al formulario """ def init2(self, cursor, actionName=QString.null, parent=None): self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = False elif cursor: self.action_ = FLSqlConnections.database().manager().action( actionName) self.cursor_ = cursor if self.action_: self.name_ = self.action_.name() else: self.name_ = QString.null """ destructor """ def __del__(self): if self.cursor_ and not self.cursor_.aqWasDeleted(): self.cursor_.restoreEditionFlag(self) self.cursor_.restoreBrowseFlag(self) """ Establece el cursor que debe utilizar el formulario. @param c Cursor con el que trabajar """ def setCursor(self, c): if not c == self.cursor_ and self.cursor_ and self.oldCursorCtxt: self.cursor_.setContext(self.oldCursorCtxt) if not c: return if self.cursor_: self.cursor_.recordChoosed.disconnect(self.accept()) self.cursor_.destroyed.disconnect(self.cursorDestroyed()) if self.cursor_ and not c == self.cursor_: self.cursor_.restoreEditionFlag(self) self.cursor_.restoreBrowseFlag(self) self.cursor_ = c self.cursor_.setEdition(False, self) self.cursor_.setBrowse(False, self) self.cursor_.recordChoosed.connect(self.accept()) self.cursor_.destroyed.connect(self.cursorDestroyed()) if self.iface and self.cursor_: self.oldCursorCtxt = self.cursor_.context() self.cursor_.setContext(self.iface) """ Sobrecargado de setMainWidget. Aqui toma el nombre de un formulario de la acción asociada y construye el Widget principal, a partir de él. """ """ Reimplementado, añade un widget como principal del formulario """ def setMainWidget(self, *args, **kwargs): if len(args) == 0: super(FLFormSearchDB, self).setMainWidget() else: self.setMainWidgetFLFormSearhDB(args[0]) def setMainWidgetFLFormSearchDB(self, w): if not self.cursor_ or not w: return if self.showed: if self.mainWidget_ and not self.mainWidget_ == w: self.initMainWidget(w) else: w.hide() if self.layoutButtons: del self.layoutButtons if self.layout: del self.layout w.setFont(QtGui.qApp.font()) desk = QtGui.QApplication.desktop.availableGeometry(self) geo = w.geometry() tooLarge = False if geo.width() > desk.width() or geo.height() > desk.heigh(): sv = QtGui.QScrollArea(self) #sv->setResizePolicy(QScrollView::AutoOneFit) FIXME sv.hide() sv.addChild(w) self.layout = QtGui.QVBoxLayout(self, 5, 5, "vlay" + self.name_) self.Layout.add(sv) sv.resize(self.size().expand(desk.size())) self.layoutButtons = QtGui.QHBoxLayout(self.layout, 3, "hlay" + self.name_) self.formReady.connect(sv.show()) tooLarge = True else: self.layout = QtGui.QVBoxLayout(self, 2, 3, "vlay" + self.name_) self.layout.add(w) self.layoutButtons = QtGui.QHBoxLayout(self.layout, 3, "hlay" + self.name_) pbSize = Qt.qsize(22, 22) """ QToolButton *wt = QWhatsThis::whatsThisButton(this); wt->setIconSet(QPixmap::fromMimeSource("about.png")); layoutButtons->addWidget(wt); wt->show() """ self.layoutButtons.addItem( QtGui.QSpacerItem(20, 20, Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum)) self.pushButtonAccept = QtGui.QPushButton(self, "pushButtonAccept") self.pushButtonAccept.sizePolicy( Qt.QSizePolicy( 0, 0, 0, 0, self.pushButtonAccept.sizePolicy().hasHeightForWidth())) self.pushButtonAccept.setMinimumSize(pbSize) self.pushButtonAccept.setMaximumSize(pbSize) ok = QtGui.QIcon(FLUtil.filedir("icons", "button_ok.png")) self.pushButtonAccept.setIcon(ok) self.pushButtonAccept.setFocusPolicy(QtGui.QWidget.NoFocus) #pushButtonAccept->setAccel(QKeySequence(Qt::Key_F10)); FIXME self.pushButtonAccept.setDefault(True) #QToolTip::add(pushButtonAccept, tr("Seleccionar registro actual y cerrar formulario (F10)")); FIXME #QWhatsThis::add(pushButtonAccept, tr("Seleccionar registro actual y cerrar formulario (F10)")); FIXME self.layoutButtons.addWidget(self.pushButtonAccept) self.pushButtonAccept.clicked.connect(self.accept()) self.pushButtonCancel = QtGui.QPushButton(self, "pushButtonCancel") self.pushButtonCancel.sizePolicy( Qt.QSizePolicy( 0, 0, 0, 0, self.pushButtonAccept.sizePolicy().hasHeightForWidth())) self.pushButtonCancel.setMinimumSize(pbSize) self.pushButtonCancel.setMaximumSize(pbSize) cancel = QtGui.QIcon(FLUtil.filedir("icons", "button_cancel.png")) self.pushButtonAccept.setIcon(cancel) self.pushButtonCancel.setFocusPolicy(QtGui.QWidget.NoFocus) #pushButtonCancel->setAccel(QKeySequence(tr("Esc"))); #FIXME #QToolTip::add(pushButtonCancel, tr("Cerrar formulario sin seleccionar registro (Esc)")); #FIXME #QWhatsThis::add(pushButtonCancel, tr("Cerrar formulario sin seleccionar registro (Esc)")); #FIXME self.layoutButtons.addItem( QtGui.QSpacerItem(20, 20, Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Fixed)) self.layoutButtons.addWidget(self.pushButtonCancel) self.pushButtonCancel.clicked.connect(self.reject()) self.mainWidget_ = w self.cursor_.setEdition(False) self.cursor_.setBrowse(False) self.cursor_.recordChoosed.connect(self.accept()) if not tooLarge: mWidth = self.mainWidget_.width() mHeight = self.mainWidget_.height() actWin = QtGui.qApp.activeWindow() if actWin: screen = actWin.geometry() else: screen = QtGui.qApp.mainWidget().geometry() p = screen.center() - Qt.QPoint(mWidth / 2, mHeight / 2) if p.x() + mWidth > desk.width(): p.setx(desk.width() - mWidth) if p.y() + mHeight > desk.height(): p.sety(desk.height() - mHeight) if p.x() < 0: p.setx(0) if p.y() < 0: p.sety(0) self.move(p) """ Muestra el formulario y entra en un nuevo bucle de eventos para esperar, a seleccionar registro. Se espera el nombre de un campo del cursor devolviendo el valor de dicho campo si se acepta el formulario y un QVariant::Invalid si se cancela. @param n Nombre del un campo del cursor del formulario @return El valor del campo si se acepta, o QVariant::Invalid si se cancela """ def exec(self, n=QString.null): if not self.cursor_: return QVariant() if self.loop and self.inExec_: print( FLUtil.translate( "app", "FLFormSearchDB::exec(): Se ha detectado una llamada recursiva" )) self.QWidget.show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() return QVariant() self.inExec_ = True self.acceptingRejecting_ = False self.QWidget.show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() if self.iface: aqApp.call("init", self.QSArgumentList(), self.iface) #if (!isClosing_ && !aqApp->project()->interpreter()->hadError()) #FIXME # QTimer::singleShot(0, this, SLOT(emitFormReady())); #FIXME self.accepted_ = False self.loop = True if not self.isClosing_ and not self.acceptingRejecting_: QtGui.QApplication.eventLoop().enterLoop() self.loop = False self.clearWFlags(Qt.WShowModal) v = None if self.accepted_ and not n.isEmpty(): v = self.cursor_.valueBuffer(n) else: v = QVariant() self.inExec_ = False return v """ Aplica un filtro al cursor """ def setFilter(self, f): if not self.cursor_: return previousF = QString(self.cursor_.mainFilter()) newF = QString(None) if previousF.isEmpty(): newF = f elif previousF.contains(f): return else: newF = previousF + " AND " + f self.cursor_.setMainFilter(newF) """ Devuelve el nombre de la clase del formulario en tiempo de ejecución """ def formClassName(self): return "FormSearhDB" """ Establece el título de la ventana. @param text Texto a establecer como título de la ventana @author Silix """ def setCaptionWidget(self, text): if text.isEmpty(): return self.setCaption(text) """ Nombre interno del formulario """ def geoName(self): return QString("formSearch") + self.idMDI_ """ Captura evento cerrar """ def closeEvent(self, e): self.frameGeometry() if self.focusWidget(): fdb = self.focusWidget().parentWidget() if fdb and fdb.autoComFrame_ and fdb.autoComFrame_.isvisible(): fdb.autoComFrame_.hide() return if self.cursor_ and self.pushButtonCancel: if not self.pushButtonCancel.isEnabled(): return self.isClosing_ = True self.setCursor(None) else: self.isClosing_ = True if self.isShown(): self.reject() if self.isHidden(): self.closed() self.QWidget.closeEvent(e) self.deleteLater() """ Invoca a la función "init()" del script asociado al formulario """ @QtCore.pyqtSlot() def initScript(self): return False """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def hide(self): if self.isHidden(): return self.QWidget.hide() if self.loop: self.loop = False QtGui.QApplication.eventLoop().exitLoop() """ Se activa al pulsar el boton aceptar """ @QtCore.pyqtSlot() def accept(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: self.cursor_.recordChoosed.disconnect(self.accept()) self.accepted_ = True self.acceptingRejecting_ = True self.hide() """ Se activa al pulsar el botón cancelar """ @QtCore.pyqtSlot() def reject(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: self.cursor_.recordChoosed.disconnect(self.accept()) self.acceptingRejecting_ = True self.hide() """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def show(self): self.exec()
def sqlInsert(self, t, fL, vL, connName="default"): if not fL.len == vL: return False c = FLSqlCursor(t, True, connName) c.setModeAccess(FLSqlCursor.Insert) c.refreshBuffer() for f, v in (fL, vL): if v == "NULL": c.bufferSetNull(f) else: c.setValueBuffer(f, v) return c.commitBuffer()
def sqlUpdate(self, t, fL, vL, w, connName="default"): from pineboolib.fllegacy.FLSqlCursor import FLSqlCursor c = FLSqlCursor(t, True, connName) c.setForwardOnly(True) # if not c.select(w): # return False c.select(w) while c.next(): c.setModeAccess(FLSqlCursor.Edit) c.refreshBuffer() if isinstance(fL, list): i = 0 for f in fL: c.setValueBuffer(f, vL[i]) i = i + 1 else: c.setValueBuffer(fL, vL) if not c.commitBuffer(): return False return True
class FLFormDB(QtGui.QWidget): """ Representa un formulario que enlaza con una tabla. Se utiliza como contenedor de componentes que quieran enlazar con la base de datos y acceder a los registros del cursor. Esta estructura simplifica en gran medida el acceso a los datos ya que muchas tareas son automáticamente gestionadas por este formulario contenedor. En un principio el formulario se crea vacío y debemos invocar el metodo FLFormDB::setMainWidget(), pasándole como parámetro otro widget (generalmente un formulario creado con QtDesigner), el cual contiene distintos componentes, este widget se visualizará dentro de este contenedor, autofonfigurándose todos los componentes que contiene, con los datos y metadatos del cursor. Generalmente los componentes serán plugins, como FLFieldDB o FLTableDB. @author InfoSiAL S.L. """ """ Cursor, con los registros, utilizado por el formulario """ cursor_ = None """ Nombre de la tabla, contiene un valor no vacío cuando la clase es propietaria del cursor """ name_ = None """ Capa principal del formulario """ layout = None """ Widget principal del formulario """ mainWidget_ = None """ Acción asociada al formulario """ action_ = None """ Identificador de ventana MDI. Generalmente es el nombre de la acción que abre el formulario """ idMDI_ = None """ Capa para botones """ layoutButtons = None """ Boton Cancelar """ pushButtonCancel = None """ Indica que la ventana ya ha sido mostrada una vez """ showed = None """ Guarda el contexto anterior que tenia el cursor """ oldCursorCtxt = None """ Indica que el formulario se está cerrando """ isClosing_ = None """ Componente con el foco inicial """ initFocusWidget_ = None """ Guarda el último objeto de formulario unido a la interfaz de script (con bindIface()) """ oldFormObj = None #ifdef QSDEBUGGER """ Boton Debug Script """ pushButtonDebug = None #endif """ Almacena que se aceptado, es decir NO se ha pulsado, botón cancelar """ accepted_ = None """ Interface para scripts """ iface = None parent_ = None @decorators.BetaImplementation def __init__(self, *args, **kwargs): if isinstance(args[0], FLSqlCursor): QtGui.QWidget.__init__(self, args[2]) self.inicialize3(args, kwargs) elif isinstance(args[0], QtGui.QWidget): QtGui.QWidget.__init__(self, args[0]) self.inicialize1(args, kwargs) else: QtGui.QWidget.__init__(self, args[1]) self.inicialize2(args, kwargs) """ constructor """ @decorators.BetaImplementation def inicialize1(self, *args, **kwargs): parent = args[0][0] name = args[0][1] f = args[1] if parent: self.parent_ = parent else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), name, f) self.cursor_ = None self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False self.loaded = False """ constructor. @param actionName Nombre de la acción asociada al formulario """ @decorators.BetaImplementation def inicialize2(self, *args, **kwargs): actionName = str(args[0][0]) parent = args[0][1] f = args[1] if parent: self.parent_ = parent else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), actionName, f) self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = None print(FLUtil.translate("sys", "FLFormDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action( actionName) if not self.action_: print( FLUtil.translate( "sys", "FLFormDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True, "default", 0, 0, self) self.name_ = self.action_.name() self.initForm() """ constructor sobrecargado. @param cursor Objeto FLSqlCursor para asignar a este formulario @param actionName Nombre de la acción asociada al formulario """ @decorators.BetaImplementation def inicialize3(self, *args, **kwargs): cursor = args[0] actionName = args[1] parent = args[2] f = args[3] self.cursor_ = cursor self.layout = None self.mainWidget_ = None self.layoutButtons = None self.pushButtonCancel = None self.showed = False self.iface = None self.oldCursorCtxt = None self.isClosing_ = False self.initFocusWidget_ = None self.oldFormObj = None self.accepted_ = False if parent: self.parent_ = QtGui.QWidget(parent) else: self.parent_ = QtGui.QWidget(pineboolib.project.mainWidget(), actionName, f) self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = None elif cursor: self.action_ = cursor.db().manager().action(actionName) else: self.action = FLSqlConnections.database().manager().action( actionName) if self.action_: self.name_ = self.action_.name() """ destructor """ @decorators.BetaImplementation def __del__(self): self.unbindIface() """ Establece el cursor que debe utilizar el formulario. @param c Cursor con el que trabajar """ @decorators.BetaImplementation def setCursor(self, *c): if not c == self.cursor_ and self.cursor_ and self.oldCursorCtxt: self.cursor_.setContext(self.oldCursorCtxt) if not c: return if self.cursor_: self.cursor_.destroyed.disconnect(self.cursorDestroyed) self.cursor_ = c self.cursor_.destroyed.connect(self.cursorDestroyed) if self.iface and self.cursor_: self.oldCursorCtxt = self.cursor_.context() self.cursor_.setContext(self.iface) """ Para obtener el cursor utilizado por el formulario. return Objeto FLSqlCursor con el cursor que contiene los registros para ser utilizados en el formulario """ @decorators.BetaImplementation def cursor(self): return self.cursor_ """ Para obtener el widget principal del formulario. return Objeto QWidget que corresponde con el widget principal del formulario """ @decorators.BetaImplementation def mainWidget(self): return self.mainWidget_ """ Establece el identificador MDI """ @decorators.BetaImplementation def setIdMDI(self, _id): self.idMDI_ = _id """ Obtiene el identificador MDI """ @decorators.BetaImplementation def idMDI(self): return self.idMDI_ @decorators.BetaImplementation def setMainWidget(self, *args, **kwarg): if isinstance(args[0], QtGui.QWidget): self.setMainWidgetQWidget(args[0]) elif isinstance(args[0], str): self.setMainWidgetString(args[0]) else: self.setMainWidgetEmpty() """ Establece widget como principal del formulario. Este widget contendrá componentes que quieran enlazar con la base de datos, por lo que esperan estar contenidos en una clase FLFormDB, la cual les proporciona el cursor (registros) a los que enlazar. Si ya existiera otro widget como principal, este será borrado. Si existe un widget principal establecido con anterioridad será borrado @param w Widget principal para el formulario """ @decorators.BetaImplementation def setMainWidgetQWidget(self, *w): if not self.cursor_ and not w: return if self.showed: if self.mainWidget_ and not self.mainWidget_ == w: self.initMainWidget(w) else: w.hide() if self.layout: del self.Layout #w.setFont(qApp.font()) #FIXME self.layout = QtGui.QVBoxLayout(self, 2, 3, "vlay" + self.name_) self.layout.add(w) self.layoutButtons = QtGui.QHBoxLayout(self.layout, 3, "hlay" + self.name_) self.layoutButtons.addItem(QtGui.QSpacerItem()) self.pushButtonCancel = QtGui.QPushButton(self, "pushButtonCancel") #self.pushButtonCancel.set_size(QtGui.QSizePolicy) #FIXME self.pushButtonCancel.setMinimumSize(22, 22) self.pushButtonCancel.setMaximumSize(22, 22) self.pushButtonCancel.setIcon( QtGui.QIcon(filedir("icons", "gtk-cancel.png"))) #pushButtonCancel->setFocusPolicy(QWidget::NoFocus); #pushButtonCancel->setAccel(QKeySequence(tr("Esc"))); #QToolTip::add(pushButtonCancel, tr("Cerrar formulario (Esc)")); #QWhatsThis::add(pushButtonCancel, tr("Cerrar formulario (Esc)")); self.layoutButtons.addWidget(self.pushButtonCancel) self.pushButtonCancel.clicked.connect(self.close) self.pushButtonCancel.show() self.mainWidget_ = w """ Sobrecargado de setMainWidget. Aqui toma el nombre de un formulario de la acción asociada y construye el Widget principal, a partir de él. """ @decorators.BetaImplementation def setMainWidgetEmpty(self): if not self.action_: return if self.cursor_: self.setMainWidgetQWidget( self.cursor_.db().managerModules.createUI( self.action_, self, self)) else: self.setMainWidget( FLSqlConnections.database().managerModules().createUI( self.action_, self, self)) """ Sobrecargado de setMainWidget. Aqui construye el Widget principal a partir del nombre de un fichero de interfaz .ui. @param uiFileName Nombre del fichero de descripción de interfaz, incluyendo la extension .ui, p.e. clientes.ui """ @decorators.BetaImplementation def setMainWidgetString(self, uiFileName): if self.cursor_: self.setMainWidgetQWidget( self.cursor_.db().managerModules.createUI( uiFileName, self, self)) else: self.setMainWidget( FLSqlConnections.database().managerModules().createUI( uiFileName, self, self)) """ Obtiene la imagen o captura de pantalla del formulario. """ @decorators.BetaImplementation def snapShot(self): pix = QtGui.QPixmap.grabWidget(self) return QtGui.QImage(pix) """ Salva en un fichero con formato PNG la imagen o captura de pantalla del formulario. @param pathFile Ruta y nombre del fichero donde guardar la imagen """ @decorators.BetaImplementation def saveSnapShot(self, pathFile): fi = QtCore.QFile(pathFile) if not fi.open(QtCore.QFile.WriteOnly): print("FLFormDB : " + FLUtil.translate( "sys", "Error I/O al intentar escribir el fichero %s" % pathFile)) return self.snapShot().save(fi, "PNG") """ Establece el título de la ventana. @param text Texto a establecer como título de la ventana @author Silix """ @decorators.BetaImplementation def setCaptionWidget(self, text): if text.isEmpty(): return self.setCaption(text) """ Devuelve si se ha aceptado el formulario """ @decorators.BetaImplementation def accepted(self): return self.accepted_ """ Devuelve el nombre de la clase del formulario en tiempo de ejecución """ @decorators.BetaImplementation def formClassName(self): return "FormDB" """ Sólo para compatibilizar con FLFormSearchDB. Por defecto sólo llama QWidget::show """ @decorators.BetaImplementation def exec_(self): QtGui.QWidget.show() return QtCore.QVariant() #public slots: """ Cierra el formulario """ @decorators.BetaImplementation def close(self): if self.isClosing_: return True self.isClosing_ = True self.isClosing_ = QtGui.QWidget.close() """ Invoca a la función "init" del script "masterprocess" asociado al formulario """ @decorators.NotImplementedWarn def initScript(self): if self.iface: #pineboolib.project.call("init", QtCore.QSArgumentList(), self.iface) #FIXME return True else: return False """ Se activa al pulsar el boton aceptar """ @decorators.BetaImplementation def accept(self): return """ Se activa al pulsar el botón cancelar """ @decorators.BetaImplementation def reject(self): return """ Redefinida por conveniencia """ @decorators.BetaImplementation def show(self): QtGui.QWidget.show() """ Muestra el formulario sin llamar al script "init". Utilizado en documentación para evitar conflictos al capturar los formularios """ @decorators.BetaImplementation def showForDocument(self): self.showed = True self.mainWidget_.show() self.resize(self.size().expandedTo(self.mainWidget_.size())) QtGui.QWidget.show() """ Maximiza el formulario """ @decorators.BetaImplementation def setMaximized(self): self.setWindowState(self.windowState() | QtCore.Qt.WindowMaximized) """ Muestra el script asociado al formulario en el Workbench para depurar """ @decorators.BetaImplementation def debugScript(self): return """ Devuelve el script asociado al formulario """ @decorators.BetaImplementation def script(self): return #private slots: @decorators.BetaImplementation def callInitScript(self): if not self.initScript(): return if not self.isClosing_: self.emitFormReady.emit() #protected: """ Inicialización """ @decorators.BetaImplementation def initForm(self): if self.cursor_ and self.cursor_.metadata(): caption = None if self.action_: self.cursor_.setAction(self.action_) caption = self.action_.caption() if not self.action_.description().isEmpty(): self.QtGui.QWhatsThis.add(self, self.action_.description()) self.idMDI_ = self.action_.name() if caption.isEmpty(): caption = self.cursor_.metadata().alias() self.setCaption(caption) self.bindIface() self.setCursor(self.cursor_) else: self.setCaption(FLUtil.translate("sys", "No hay metadatos")) """ Nombre interno del formulario """ @decorators.BetaImplementation def formName(self): return ("form%s" % self.idMDI_) @decorators.BetaImplementation def geoName(self): return self.formName() """ Une la interfaz de script al objeto del formulario """ @decorators.BetaImplementation def bindIface(self): p = pineboolib.project if not p: return self.setName(self.formName()) o = p.object(self.name()) if not o == self.iface and self.iface and self.oldFormObj: self.iface.setObj(self.oldFormObj) self.iface = o ifc = self.iface if not ifc: return if not ifc.obj() == self: if self.oldFormObj: self.oldFormObj.destroyed.disconnect( self.oldFormObjDestroyed()) self.oldFormObj = ifc.obj() if self.oldFormObj: self.oldFormObj.destroyed.connect(self.oldFormObjDestroyed()) ifc.setObj(self) """ Desune la interfaz de script al objeto del formulario """ @decorators.BetaImplementation def unbindIface(self): ifc = self.iface if not ifc: return if ifc.obj() == self: ifc.setObj(self.oldFormObj) """ Indica si la interfaz de script está unida al objeto formulario """ @decorators.BetaImplementation def isIfaceBind(self): ifc = self.iface if not ifc: return return (ifc.obj() == self) """ Captura evento cerrar """ @decorators.BetaImplementation def closeEvent(self, *e): self.frameGeometry() if self.focusWidget(): fdb = self.focusWidget().parentWidget() if fdb and fdb.autoComFrame_ and fdb.autoComFrame_.isVisible(): fdb.autoComFrame_.hide() return """ Captura evento mostrar """ @decorators.NotImplementedWarn def showEvent(self, *e): if not self.showed and self.mainWidget_: self.showed = True if self.cursor_ and self.iface: #v = pineboolib.project.call("preloadMainFilter", QSArgumentList(), self.iface).variant()) if v and isinstance(v.type(), str): self.cursor_.setMainFilter(str(v), False) self.initMainWidget() self.callInitScript() if not self.isIfaceBind(): self.bindIface() """ Captura evento ocultar """ @decorators.NotImplementedWarn def hideEvent(self, *h): return """ { QWidget *pW = parentWidget(); if (pW && pW->isA("QWorkspaceChild")) { QRect geo(pW->x(), pW->y(), pW->width(), pW->height()); if (isMinimized()) { geo.setWidth(1); aqApp->saveGeometryForm(geoName(), geo); } else if (isMaximized()) { geo.setWidth(9999); aqApp->saveGeometryForm(geoName(), geo); } else aqApp->saveGeometryForm(geoName(), geo); } else { QRect geo(x(), y(), width(), height()); aqApp->saveGeometryForm(geoName(), geo); } } """ """ Captura evento de entrar foco """ @decorators.BetaImplementation def focusInEvent(self, *f): self.focusInEvent(f) if self.isIfaceBind(): self.bindIface() """ Inicializa componenentes del widget principal @param w Widget a inicializar. Si no se establece utiliza por defecto el widget principal actual """ @decorators.NotImplementedWarn def initMainWidget(self, *w): return """ { QWidget *mWidget = w ? w : mainWidget_; if (mWidget) { QObjectList *l = static_cast<QObject *>(mWidget)->queryList("FLTableDB"); QObjectListIt itt(*l); FLTableDB *tdb; while ((tdb = static_cast<FLTableDB *>(itt.current())) != 0) { ++itt; tdb->initCursor(); } delete l; l = static_cast<QObject *>(mWidget)->queryList("FLFieldDB"); QObjectListIt itf(*l); FLFieldDB *fdb; while ((fdb = static_cast<FLFieldDB *>(itf.current())) != 0) { ++itf; fdb->initCursor(); fdb->initEditor(); if (fdb->aqFirstTabStop == 1) initFocusWidget_ = fdb; } while (mWidget->parentWidget() && mWidget->parentWidget() != this) mWidget = mWidget->parentWidget(); mWidget->show(); FLAccessControlLists *acl = aqApp->acl(); if (acl) acl->process(this); QWidget *pW = parentWidget(); QRect desk; bool parentIsDesktop = true; if (!(pW && pW->isA("QWorkspaceChild"))) { desk = QApplication::desktop()->availableGeometry(this); pW = this; } else { desk = pW->parentWidget()->rect(); parentIsDesktop = false; } QRect geo(aqApp->geometryForm(QObject::name())); pW->show(); QSize oSz = mWidget->size(); mWidget->updateGeometry(); QSize bSz = mWidget->baseSize(); QSize SzH = mWidget->sizeHint(); int border = 5, border_b = 48; /* qDebug("geo: " + QString::number(geo.width()) + "x" + QString::number(geo.height())); qDebug("oSz: " + QString::number(oSz.width()) + "x" + QString::number(oSz.height())); qDebug("bSz: " + QString::number(bSz.width()) + "x" + QString::number(bSz.height())); qDebug("SzH: " + QString::number(SzH.width()) + "x" + QString::number(SzH.height())); */ if (geo.width() < 100 || geo.width()>9000) { // qDebug(" -- reset Form Size and position -- "); geo.setWidth(oSz.width()); geo.setHeight(oSz.height()); geo.moveCenter(desk.center()); if (!parentIsDesktop) { geo.moveTop(desk.top() + border - geo.top()+1); } } if (geo.width() < SzH.width()) { // qDebug(" -- geo width too small -- "); geo.setWidth(SzH.width()); } if (geo.height() < SzH.height()) { // qDebug(" -- geo height too small -- "); geo.setHeight(SzH.height()); } // Exceeds available horizontal area: if (geo.width() > desk.width() - border * 2) { // qDebug(" -- geo width too big -- "); geo.setWidth(desk.width() - border * 2 - 5); } // Exceeds available vertical area: if (geo.height() > desk.height() - border - border_b) { // qDebug(" -- geo height too big -- "); geo.setHeight(desk.height() - border - border_b - 5); } if (parentIsDesktop) { // Invalid position values, re-center if ( geo.right() > 9000 || geo.left() < 1 || geo.bottom() > 9000 || geo.top() < 1 ) { // qDebug(" -- geo invalid position -- "); geo.moveCenter(desk.center()); } if ( geo.top() < desk.top() + border) { // qDebug(" -- geo position too high -- "); geo.moveTop(desk.top() + border - geo.top()+1); } if ( geo.left() < desk.left() + border) { // qDebug(" -- geo position too left -- "); geo.moveLeft(desk.left() + border - geo.left()+1); } if ( geo.bottom() > desk.bottom() - border_b ) { int diff = geo.bottom() - desk.bottom() - border_b; // qDebug(" -- geo position too low -- "); geo.moveTop(-diff-1); } if ( geo.right() > desk.right() - border) { int diff = geo.right() - desk.right() - border; // qDebug(" -- geo position too right -- "); geo.moveLeft(-diff-1); } // Outside of screen, re-center: if ( geo.right() > desk.right() - border || geo.left() < desk.left() + border || geo.bottom() > desk.bottom() - border_b || geo.top() < desk.top() + border ) { // qDebug(" -- geo position out of screen -- "); geo.moveCenter(desk.center()); } } mWidget->resize(geo.size()); pW->updateGeometry(); QSize tSz= pW->size(); QSize tSzH = pW->sizeHint(); if (tSz.width() < tSzH.width()) { tSz.setWidth(tSzH.width()); } if (tSz.height() < tSzH.height()) { tSz.setHeight(tSzH.height()); } pW->resize(tSz.expandedTo(mWidget->size())); pW->move(geo.topLeft()); if (!initFocusWidget_) { itf.toFirst(); while ((fdb = static_cast<FLFieldDB *>(itf.current())) != 0) { ++itf; if (fdb->isEnabled()) { initFocusWidget_ = fdb; break; } } if (!initFocusWidget_) initFocusWidget_ = static_cast<QWidget *>(mWidget->focusWidget()); if (initFocusWidget_) initFocusWidget_->setFocus(); } delete l; QWidget *focWid = qApp->focusWidget(); if (focWid) { QWidget *topWidget = focWid->topLevelWidget(); if (topWidget && !topWidget->inherits("FLFormDB")) { QWidget *topWid = focWid->parentWidget(); while (topWid && !topWid->inherits("FLFormDB")) topWid = topWid->parentWidget(); topWidget = topWid; } if (topWidget != this) setFocus(); } else setFocus(); } } """ #protected slots: """ Emite señal formulari listo. Ver FLFormDB::formReady() """ emitFormReady = QtCore.pyqtSignal() """ Uso interno """ @QtCore.pyqtSlot() def oldFormObjDestroyed(self): print("oldFormObjDestroyed") self.oldFormObj = None return None @QtCore.pyqtSlot(QtCore.QObject) def cursorDestroyed(self, *obj): print("cursorDestroyed") if not obj or not obj == self.cursor_: return self.cursor_ = None return None #signals: """ Señal emitida cuando se cierra el formulario """ closed = QtCore.pyqtSignal() """ Señal emitida cuando el formulario ya ha sido inicializado y está listo para usarse """ formReady = QtCore.pyqtSignal()
def Mr_Proper(self): util = FLUtil() self.db_.dbAux().transaction() qry = FLSqlQuery(None, self.db_.dbAux()) qry2 = FLSqlQuery(None, self.db_.dbAux()) steps = 0 rx = QRegExp("^.*\\d{6,9}$") if rx in self.tables() is not False: listOldBks = rx in self.tables() else: listOldBks = [] qry.exec_("select nombre from flfiles where nombre similar to" "'%[[:digit:]][[:digit:]][[:digit:]][[:digit:]]-[[:digit:]][[:digit:]]%:[[:digit:]][[:digit:]]%' or nombre similar to" "'%alteredtable[[:digit:]][[:digit:]][[:digit:]][[:digit:]]%' or (bloqueo='f' and nombre like '%.mtd')") util.createProgressDialog( util.tr("Borrando backups"), len(listOldBks) + qry.size() + 2) while qry.next(): item = qry.value(0) util.setLabelText(util.tr("Borrando registro %1").arg(item)) qry2.exec_("DELETE FROM flfiles WERE nombre ='%s'" % item) if item.find("alteredtable") > -1: if self.existsTable(item.replace(".mtd", "")): util.setLabelText(util.tr("Borrando tabla %1").arg(item)) qry2.exec_("DROP TABLE %s CASCADE" % item.replace(".mtd", "")) steps = steps + 1 util.setProgress(steps) for item in listOldBks: if self.existsTable(item): util.setLabelText(util.tr("Borrando tabla %s" % item)) qry2.exec_("DROP TABLE %s CASCADE" % item) steps = steps + 1 util.setProgress(steps) util.setLabelText(util.tr("Inicializando cachés")) steps = steps + 1 util.setProgress(steps) qry.exec_("DELETE FROM flmetadata") qry.exec_("DELETE FROM flvar") self.db_.manager().cleanupMetaData() # self.db_.driver().commit() util.destroyProgressDialog() steps = 0 qry.exec_("select tablename from pg_tables where schemaname='public'") util.createProgressDialog( util.tr("Comprobando base de datos"), qry.size()) while qry.next(): item = qry.value(0) util.setLabelText(util.tr("Comprobando tabla %s" % item)) mustAlter = self.mismatchedTable(item, item) if mustAlter: conte = self.db_.managerModules().content("%s.mtd" % item) if conte: msg = util.tr("La estructura de los metadatos de la tabla '%s' y su " "estructura interna en la base de datos no coinciden. " "Intentando regenerarla." % item) print(msg) self.alterTable2(conte, conte, None, True) steps = steps + 1 util.setProgress(steps) self.db_.dbAux().driver().transaction() steps = 0 sqlCursor = FLSqlCursor(None, True, self.db_.dbAux()) sqlQuery = FLSqlQuery(None, self.db_.dbAux()) if sqlQuery.exec_("select relname from pg_class where ( relkind = 'r' ) " "and ( relname !~ '^Inv' ) " "and ( relname !~ '^pg_' ) and ( relname !~ '^sql_' )"): util.setTotalSteps(sqlQuery.size()) while sqlQuery.next(): item = sqlQuery.value(0) steps = steps + 1 util.setProgress(steps) util.setLabelText(util.tr("Creando índices para %s" % item)) mtd = self.db_.manager().metadata(item) fL = mtd.fieldList() if not mtd or not fL: continue for it in fL: if not it or not it.type() == "pixmap": continue cur = FLSqlCursor(item, True, self.db_.dbAux()) cur.select(it.name() + " not like 'RK@%'") while cur.next(): v = cur.value(it.name()) if v is None: continue v = self.db_.manager().storeLargeValue(mtd, v) if v: buf = cur.primeUpdate() buf.setValue(it.name(), v) cur.update(False) sqlCursor.setName(item, True) # self.db_.dbAux().driver().commit() steps = 0 qry.exec_("select tablename from pg_tables where schemaname='public'") util.createProgressDialog( util.tr("Analizando base de datos"), qry.size()) while qry.next(): item = qry.value(0) util.setLabelText(util.tr("Analizando tabla %s" % item)) qry2.exec_("vacuum analyze %s" % item) steps = steps + 1 util.setProgress(steps) util.destroyProgressDialog()
class FLTableDB(QtGui.QWidget): _tableView = None _vlayout = None _lineEdit = None _comboBox_1 = None _comboBox_2 = None _topWidget = None _cursor = None _loaded = False _cursorLoaded = False _tableName = None _foreignField = None _fieldRelation = None _action = None _foreignFilter = None def __init__(self, parent = None, action_or_cursor = None, *args): #print("FLTableDB:", parent, action_or_cursor , args) # TODO: Falta el lineeditsearch y el combo, que los QS lo piden super(FLTableDB,self).__init__(parent,*args) # TODO: LA inicialización final hay que hacerla más tarde, en el primer # show(), porque sino obligas a tenerlo todo preparado en el constructor. self._tableView = QtGui.QTableView() self._lineEdit = QtGui.QLineEdit() _label1 = QtGui.QLabel() _label2 = QtGui.QLabel() self._comboBox_1 = QtGui.QComboBox() self._comboBox_2 = QtGui.QComboBox() _label1.setText("Buscar") _label2.setText("en") self._vlayout = QtGui.QVBoxLayout() _hlayout = QtGui.QHBoxLayout() self._tableView._v_header = self._tableView.verticalHeader() self._tableView._v_header.setDefaultSectionSize(18) self._tableView._h_header = self._tableView.horizontalHeader() self._tableView._h_header.setDefaultSectionSize(70) _hlayout.addWidget(_label1) _hlayout.addWidget(self._lineEdit) _hlayout.addWidget(_label2) _hlayout.addWidget(self._comboBox_1) _hlayout.addWidget(self._comboBox_2) self._vlayout.addLayout(_hlayout) self._vlayout.addWidget(self._tableView) self.setLayout(self._vlayout) self._parent = parent while True: parent_cursor = getattr(self._parent,"_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent print(self._parent) self._tableView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self._tableView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self._tableView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self._tableView.setAlternatingRowColors(True) if action_or_cursor is None and parent_cursor: action_or_cursor = parent_cursor if isinstance(action_or_cursor,FLSqlCursor): self._cursor = action_or_cursor elif isinstance(action_or_cursor,str): self._action = action_or_cursor else: self._cursor = None if self._cursor: self._tableView._h_header.setResizeMode(QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor.model()) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: i = 0 for column in range(self._cursor.model().columnCount()): #print("Columna ", i) self._comboBox_1.addItem(self._cursor.model().headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem(self._cursor.model().headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect(self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded) self._topWidget = parent def __getattr__(self, name): return DefFun(self, name) def loaded(self): # Es necesario pasar a modo interactivo lo antes posible # Sino, creamos un bug en el cierre de ventana: se recarga toda la tabla para saber el tamaño #print("FLTableDB(%s): setting columns in interactive mode" % self._tableName) self._tableView._h_header.setResizeMode(QtGui.QHeaderView.Interactive) self._loaded = True while True: #Ahora podemos buscar el cursor ... porque ya estamos añadidos al formulario parent_cursor = getattr(self._parent,"_cursor", None) if parent_cursor: break new_parent = self._parent.parentWidget() if new_parent is None: break self._parent = new_parent self.initCursor() def cursor(self): if not self._cursorLoaded: self.timer_cursor = QtCore.QTimer(self) self.timer_cursor.singleShot(100, self.cursor) else: if not self._cursor: self._cursor = None print("WARN: FLTableDB.cursor(): Cursor Inválido a", self._tableName) return self._cursor def obj(self): return self def comboBox_putFirstCol(self): self.putFirstCol(str(self._comboBox_1.currentText())) def comboBox_putSecondCol(self): self.putSecondCol(str(self._comboBox_2.currentText())) def putFirstCol(self, fN): _oldPos= None _oldFirst = self._tableView._h_header.logicalIndex(0) for column in range(self._cursor.model().columnCount()): if self._cursor.model().headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) if not self._comboBox_1.currentText() == fN: self._comboBox_1.setCurrentIndex(column) return False break if not _oldPos or fN == "*": return False else: self._tableView._h_header.swapSections(_oldPos, 0) self._comboBox_2.setCurrentIndex(_oldFirst) return True def putSecondCol(self, fN): if self._cursor is None: return _oldPos= None _oldSecond = self._tableView._h_header.logicalIndex(1) for column in range(self._cursor.model().columnCount()): if self._cursor.model().headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole).lower() == fN.lower(): _oldPos = self._tableView._h_header.visualIndex(column) break if not _oldPos or fN == "*": return False if not self._comboBox_1.currentText() == fN: self._tableView._h_header.swapSections(_oldPos, 1) else: self._comboBox_1.setCurrentIndex(_oldSecond) return True def setTableName(self, tableName): self._tableName = tableName self.initCursor() return True def tableName(self): return self._tableName def foreignField(self): return self._foreignField def fieldRelation(self): return self._fieldRelation def setForeignField(self, foreignField): self._foreignField = foreignField self.initCursor() return True def setFieldRelation(self, fieldRelation): self._fieldRelation = fieldRelation self.initCursor() return True def setActionName(self, action): self._action = action def showAlias(self, b): self._showAlias = b def initCursor(self): filtro = None self._cursorLoaded = True if not self._foreignField: return if not self._fieldRelation: return if not self._tableName: return if self._loaded: tipo = self._cursor.model().fieldType(self._fieldRelation) foranea = self._parent.parentWidget().cursor().valueBuffer(self._foreignField) if foranea is None: #print("FLTable(%s): campo foraneo \"%s.%s\" no encontrado." % (self._tableName,self._parent.parentWidget()._cursor.table(), self._foreignField)) return if tipo is "uint": self._foreignFilter = "%s = %s" % (self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer(self._foreignField)) else: self._foreignFilter = "%s = '%s'" % (self._fieldRelation, self._parent.parentWidget().cursor().valueBuffer(self._foreignField)) #print("Filtro:%s" % filtro) self._cursor.setMainFilter(self._foreignFilter) self._cursor.refresh() else: self._cursor = FLSqlCursor(self._tableName) #self._cursor.setMainFilter("%s = ") @QtCore.pyqtSlot() def close(self): print("FLTableDB: close()") @QtCore.pyqtSlot() def refresh(self): print("FLTableDB: refresh()", self.parent().parent().parent()) self._cursor.setMainFilter(self._foreignFilter) @QtCore.pyqtSlot() def show(self): print("FLTableDB: show event") #super(FLTableDB, self).show() if self._cursor: self._tableView._h_header.setResizeMode(QtGui.QHeaderView.ResizeToContents) self._tableView.setModel(self._cursor.model()) self._tableView.setSelectionModel(self._cursor.selection()) self.tableRecords = self # control de tabla interno #Carga de comboBoxs y connects .- posiblemente a mejorar if self._cursor: for column in range(self._cursor.model().columnCount()): self._comboBox_1.addItem(self._cursor.model().headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_2.addItem(self._cursor.model().headerData(column, QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)) self._comboBox_1.addItem("*") self._comboBox_2.addItem("*") self._comboBox_1.setCurrentIndex(0) self._comboBox_2.setCurrentIndex(1) self._comboBox_1.currentIndexChanged.connect(self.comboBox_putFirstCol) self._comboBox_2.currentIndexChanged.connect(self.comboBox_putSecondCol) self.sort = [] self.timer_1 = QtCore.QTimer(self) self.timer_1.singleShot(100, self.loaded) @QtCore.pyqtSlot() def insertRecord(self): self._cursor.insertRecord() @QtCore.pyqtSlot() def editRecord(self): self._cursor.editRecord() @QtCore.pyqtSlot() def deleteRecord(self): self._cursor.deleteRecord() @QtCore.pyqtSlot() def browseRecord(self): self._cursor.browseRecord() @QtCore.pyqtSlot() def copyRecord(self): self._cursor.copyRecord() @decorators.WorkingOnThis def setEditOnly(self, value): return True @decorators.WorkingOnThis def setReadOnly(self, value): return True
def alterTable3(self, newMTD): if self.hasCheckColumn(newMTD): return False oldMTD = newMTD fieldList = oldMTD.fieldList() renameOld = "%salteredtable%s" % ( oldMTD.name()[0:5], QDateTime().currentDateTime().toString("ddhhssz")) self.db_.dbAux().transaction() q = FLSqlQuery(None, self.db_.dbAux()) constraintName = "%s_key" % oldMTD.name() if self.constraintExists(constraintName) and not q.exec_("ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): self.db_.dbAux().rollback() return False for oldField in fieldList: if oldField.isCheck(): return False if oldField.isUnique(): constraintName = "%s_%s_key" % (oldMTD.name(), oldField.name()) if self.constraintExists(constraintName) and not q.exec_("ALTER TABLE %s DROP CONSTRAINT %s" % (oldMTD.name(), constraintName)): self.db_.dbAux().rollback() return False if not q.exec_("ALTER TABLE %s RENAME TO %s" % (oldMTD.name(), renameOld)): self.db_.dbAux().rollback() return False if not self.db_.manager().createTable(newMTD): self.db_.dbAux().rollback() return False oldCursor = FLSqlCursor(renameOld, True, self.db_.dbAux()) oldCursor.setModeAccess(oldCursor.Browse) oldCursor.select() fieldList = newMTD.fieldList() if not fieldList: self.db_.dbAux().rollback() return False oldCursor.select() totalSteps = oldCursor.size() progress = QProgressDialog(qApp.tr("Reestructurando registros para %1...").arg( newMTD.alias()), qApp.tr("Cancelar"), 0, totalSteps) progress.setLabelText(qApp.tr("Tabla modificada")) step = 0 newBuffer = None newField = None listRecords = [] newBufferInfo = self.recordInfo2(newMTD.name()) oldFieldsList = {} newFieldsList = {} defValues = {} v = None for newField in fieldList: oldField = oldMTD.field(newField.name()) defValues[str(step)] = None if not oldField or not oldCursor.field(oldField.name()): if not oldField: oldField = newField if not newField.type() == "serial": v = newField.defaultValue() defValues[str(step)] = v newFieldsList[str(step)] = newField oldFieldsList[str(step)] = oldField step = step + 1 ok = True while oldCursor.next(): newBuffer = newBufferInfo for reg in defValues.keys(): newField = newFieldsList[reg] oldField = oldFieldsList[reg] if defValues[reg]: v = defValues[reg] else: v = oldCursor.value(newField.name()) if (not oldField.allowNull or not newField.allowNull()) and not v and not newField.type() == "serial": defVal = newField.defaultValue() if defVal is not None: v = defVal if v is not None and not newBuffer.field(newField.name()).type() == newField.type(): print("FLManager::alterTable : " + qApp.tr( "Los tipos del campo %1 no son compatibles. Se introducirá un valor nulo.").arg(newField.name())) if v is not None and newField.type() == "string" and newField.length() > 0: v = str(v)[0:newField.length()] if (not oldField.allowNull() or not newField.allowNull()) and v is None: if oldField.type() == "serial": v = int(self.nextSerialVal( newMTD.name(), newField.name())) elif oldField.type() in ("int", "uint", "bool", "unlock"): v = 0 elif oldField.type() == "double": v = 0.0 elif oldField.type() == "time": v = QTime().currentTime() elif oldField.type() == "date": v = QDate().currentDate() else: v = "NULL"[0:newField.length()] newBuffer.setValue(newField.name(), v) listRecords.append(newBuffer) # if not self.insertMulti(newMTD.name(), listRecords): # ok = False # listRecords.clear() # break # listRecords.clear() if len(listRecords) > 0: if not self.insertMulti(newMTD.name(), listRecords): ok = False listRecords.clear() if ok: self.db_.dbAux().commit() else: self.db_.dbAux().rollback() return False force = False # FIXME if force and ok: q.exec_("DROP TABLE %s CASCADE" % renameOld) return True
class FLFormSearchDB(FLFormDB): """ Subclase de la clase FLFormDB, pensada para buscar un registro en una tabla. El comportamiento de elegir un registro se modifica para solamente cerrar el formulario y así el objeto que lo invoca pueda obtener del cursor dicho registro. También añade botones Aceptar y Cancelar. Aceptar indica que se ha elegido el registro activo (igual que hacer doble clic sobre él o pulsar la tecla Intro) y Cancelar aborta la operación. @author InfoSiAL S.L. """ """ Uso interno """ acceptingRejecting_ = False inExec_ = False """ Boton Aceptar """ pushButtonAccept = None """ Almacena si se ha abierto el formulario con el método FLFormSearchDB::exec() """ loop = None def __init__(self,*args, **kwargs): if isinstance(args[0],QString): super(FLFormSearchDB,self).__init(args[0], args[1],(Qt.WStyle_Customize, Qt.WStyle_Maximize, Qt.WStyle_Title, Qt.WStyle_NormalBorder, Qt.WType_Dialog, Qt.WShowModal, Qt.WStyle_SysMenu)) self.init1(args[0],args[1]) else: super(FLFormSearchDB,self).__init(args[1], args[2],(Qt.WStyle_Customize, Qt.WStyle_Maximize, Qt.WStyle_Title, Qt.WStyle_NormalBorder, Qt.WType_Dialog, Qt.WShowModal, Qt.WStyle_SysMenu)) self.init2(args[0],args[1],args[2]) """ constructor. @param actionName Nombre de la acción asociada al formulario """ def init1(self, actionName, parent = None): self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = False print(FLUtil.translate("app","FLFormSearchDB : Nombre de acción vacío")) return else: self.action_ = FLSqlConnections.database().manager().action(actionName) if not self.action_: print(FLUtil.translate("app","FLFormSearchDB : No existe la acción %s" % actionName)) return self.cursor_ = FLSqlCursor(self.action_.table(), True,"default", 0, 0, self) self.name_ = self.action_.name() self.initForm() """ constructor sobrecargado. @param cursor Objeto FLSqlCursor para asignar a este formulario @param actionName Nombre de la acción asociada al formulario """ def init2(self, cursor,actionName = QString.null, parent = None): self.setFocusPolicy(QtGui.QWidget.NoFocus) if actionName.isEmpty(): self.action_ = False elif cursor: self.action_ = FLSqlConnections.database().manager().action(actionName) self.cursor_ = cursor if self.action_: self.name_ = self.action_.name() else: self.name_ = QString.null """ destructor """ def __del__(self): if self.cursor_ and not self.cursor_.aqWasDeleted(): self.cursor_.restoreEditionFlag(self) self.cursor_.restoreBrowseFlag(self) """ Establece el cursor que debe utilizar el formulario. @param c Cursor con el que trabajar """ def setCursor(self, c): if not c == self.cursor_ and self.cursor_ and self.oldCursorCtxt: self.cursor_.setContext(self.oldCursorCtxt) if not c: return if self.cursor_: self.cursor_.recordChoosed.disconnect(self.accept()) self.cursor_.destroyed.disconnect(self.cursorDestroyed()) if self.cursor_ and not c == self.cursor_: self.cursor_.restoreEditionFlag(self) self.cursor_.restoreBrowseFlag(self) self.cursor_ = c self.cursor_.setEdition(False, self) self.cursor_.setBrowse(False, self) self.cursor_.recordChoosed.connect(self.accept()) self.cursor_.destroyed.connect(self.cursorDestroyed()) if self.iface and self.cursor_: self.oldCursorCtxt = self.cursor_.context() self.cursor_.setContext(self.iface) """ Sobrecargado de setMainWidget. Aqui toma el nombre de un formulario de la acción asociada y construye el Widget principal, a partir de él. """ """ Reimplementado, añade un widget como principal del formulario """ def setMainWidget(self, *args, **kwargs): if len(args) == 0: super(FLFormSearchDB,self).setMainWidget() else: self.setMainWidgetFLFormSearhDB(args[0]) def setMainWidgetFLFormSearchDB(self, w): if not self.cursor_ or not w: return if self.showed: if self.mainWidget_ and not self.mainWidget_ == w: self.initMainWidget(w) else: w.hide() if self.layoutButtons: del self.layoutButtons if self.layout: del self.layout w.setFont(QtGui.qApp.font()) desk = QtGui.QApplication.desktop.availableGeometry(self) geo = w.geometry() tooLarge = False if geo.width() > desk.width() or geo.height() > desk.heigh(): sv = QtGui.QScrollArea(self) #sv->setResizePolicy(QScrollView::AutoOneFit) FIXME sv.hide() sv.addChild(w) self.layout = QtGui.QVBoxLayout(self, 5,5,"vlay" + self.name_) self.Layout.add(sv) sv.resize(self.size().expand(desk.size())) self.layoutButtons = QtGui.QHBoxLayout(self.layout, 3, "hlay" + self.name_) self.formReady.connect(sv.show()) tooLarge = True else: self.layout = QtGui.QVBoxLayout(self, 2, 3, "vlay" + self.name_) self.layout.add(w) self.layoutButtons = QtGui.QHBoxLayout(self.layout, 3, "hlay" + self.name_) pbSize = Qt.qsize(22,22) """ QToolButton *wt = QWhatsThis::whatsThisButton(this); wt->setIconSet(QPixmap::fromMimeSource("about.png")); layoutButtons->addWidget(wt); wt->show() """ self.layoutButtons.addItem(QtGui.QSpacerItem(20,20, Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Minimum)) self.pushButtonAccept = QtGui.QPushButton(self,"pushButtonAccept") self.pushButtonAccept.sizePolicy(Qt.QSizePolicy(0,0,0,0, self.pushButtonAccept.sizePolicy().hasHeightForWidth())) self.pushButtonAccept.setMinimumSize(pbSize) self.pushButtonAccept.setMaximumSize(pbSize) ok = QtGui.QIcon(FLUtil.filedir("icons","button_ok.png")) self.pushButtonAccept.setIcon(ok) self.pushButtonAccept.setFocusPolicy(QtGui.QWidget.NoFocus) #pushButtonAccept->setAccel(QKeySequence(Qt::Key_F10)); FIXME self.pushButtonAccept.setDefault(True) #QToolTip::add(pushButtonAccept, tr("Seleccionar registro actual y cerrar formulario (F10)")); FIXME #QWhatsThis::add(pushButtonAccept, tr("Seleccionar registro actual y cerrar formulario (F10)")); FIXME self.layoutButtons.addWidget(self.pushButtonAccept) self.pushButtonAccept.clicked.connect(self.accept()) self.pushButtonCancel = QtGui.QPushButton(self, "pushButtonCancel") self.pushButtonCancel.sizePolicy(Qt.QSizePolicy(0,0,0,0, self.pushButtonAccept.sizePolicy().hasHeightForWidth())) self.pushButtonCancel.setMinimumSize(pbSize) self.pushButtonCancel.setMaximumSize(pbSize) cancel = QtGui.QIcon(FLUtil.filedir("icons","button_cancel.png")) self.pushButtonAccept.setIcon(cancel) self.pushButtonCancel.setFocusPolicy(QtGui.QWidget.NoFocus) #pushButtonCancel->setAccel(QKeySequence(tr("Esc"))); #FIXME #QToolTip::add(pushButtonCancel, tr("Cerrar formulario sin seleccionar registro (Esc)")); #FIXME #QWhatsThis::add(pushButtonCancel, tr("Cerrar formulario sin seleccionar registro (Esc)")); #FIXME self.layoutButtons.addItem(QtGui.QSpacerItem(20,20, Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Fixed)) self.layoutButtons.addWidget(self.pushButtonCancel) self.pushButtonCancel.clicked.connect(self.reject()) self.mainWidget_ = w self.cursor_.setEdition(False) self.cursor_.setBrowse(False) self.cursor_.recordChoosed.connect(self.accept()) if not tooLarge: mWidth = self.mainWidget_.width() mHeight = self.mainWidget_.height() actWin = QtGui.qApp.activeWindow() if actWin: screen = actWin.geometry() else: screen = QtGui.qApp.mainWidget().geometry() p = screen.center() - Qt.QPoint(mWidth / 2, mHeight / 2) if p.x() + mWidth > desk.width(): p.setx(desk.width() - mWidth) if p.y() + mHeight > desk.height(): p.sety(desk.height() - mHeight) if p.x() < 0: p.setx(0) if p.y() < 0: p.sety(0) self.move(p) """ Muestra el formulario y entra en un nuevo bucle de eventos para esperar, a seleccionar registro. Se espera el nombre de un campo del cursor devolviendo el valor de dicho campo si se acepta el formulario y un QVariant::Invalid si se cancela. @param n Nombre del un campo del cursor del formulario @return El valor del campo si se acepta, o QVariant::Invalid si se cancela """ def exec(self, n = QString.null): if not self.cursor_: return QVariant() if self.loop and self.inExec_: print(FLUtil.translate("app","FLFormSearchDB::exec(): Se ha detectado una llamada recursiva")) self.QWidget.show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() return QVariant() self.inExec_ = True self.acceptingRejecting_ = False self.QWidget.show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() if self.iface: aqApp.call("init", self.QSArgumentList(), self.iface) #if (!isClosing_ && !aqApp->project()->interpreter()->hadError()) #FIXME # QTimer::singleShot(0, this, SLOT(emitFormReady())); #FIXME self.accepted_ = False self.loop = True if not self.isClosing_ and not self.acceptingRejecting_: QtGui.QApplication.eventLoop().enterLoop() self.loop = False self.clearWFlags(Qt.WShowModal) v = None if self.accepted_ and not n.isEmpty(): v = self.cursor_.valueBuffer(n) else: v = QVariant() self.inExec_ = False return v """ Aplica un filtro al cursor """ def setFilter(self, f): if not self.cursor_: return previousF = QString(self.cursor_.mainFilter()) newF = QString(None) if previousF.isEmpty(): newF = f elif previousF.contains(f): return else: newF = previousF + " AND " + f self.cursor_.setMainFilter(newF) """ Devuelve el nombre de la clase del formulario en tiempo de ejecución """ def formClassName(self): return "FormSearhDB" """ Establece el título de la ventana. @param text Texto a establecer como título de la ventana @author Silix """ def setCaptionWidget(self, text): if text.isEmpty(): return self.setCaption(text) """ Nombre interno del formulario """ def geoName(self): return QString("formSearch") + self.idMDI_ """ Captura evento cerrar """ def closeEvent(self, e): self.frameGeometry() if self.focusWidget(): fdb = self.focusWidget().parentWidget() if fdb and fdb.autoComFrame_ and fdb.autoComFrame_.isvisible(): fdb.autoComFrame_.hide() return if self.cursor_ and self.pushButtonCancel: if not self.pushButtonCancel.isEnabled(): return self.isClosing_ = True self.setCursor(None) else: self.isClosing_ = True if self.isShown(): self.reject() if self.isHidden(): self.closed() self.QWidget.closeEvent(e) self.deleteLater() """ Invoca a la función "init()" del script asociado al formulario """ @QtCore.pyqtSlot() def initScript(self): return False """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def hide(self): if self.isHidden(): return self.QWidget.hide() if self.loop: self.loop = False QtGui.QApplication.eventLoop().exitLoop() """ Se activa al pulsar el boton aceptar """ @QtCore.pyqtSlot() def accept(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: self.cursor_.recordChoosed.disconnect(self.accept()) self.accepted_ = True self.acceptingRejecting_ = True self.hide() """ Se activa al pulsar el botón cancelar """ @QtCore.pyqtSlot() def reject(self): if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: self.cursor_.recordChoosed.disconnect(self.accept()) self.acceptingRejecting_ = True self.hide() """ Redefinida por conveniencia """ @QtCore.pyqtSlot() def show(self): self.exec()