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. """ """ 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()
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()
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 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()
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()