def init_logging(loglevel: int = logging.INFO, logtime: bool = False, trace_loggers: List[str] = []) -> None: """Initialize pineboo logging.""" # ---- LOGGING ----- log_format = "%(levelname)s: %(name)s: %(message)s" if logtime: log_format = "%(asctime)s - %(levelname)s: %(name)s: %(message)s" app_loglevel = logging.TRACE if trace_loggers else loglevel if trace_loggers: logging.Logger.set_pineboo_default_level(loglevel) logging.basicConfig(format=log_format, level=app_loglevel) # LOGGER.info("LOG LEVEL: %s", loglevel) disable_loggers = [ "PyQt5.uic.uiparser", "PyQt5.uic.properties", "blib2to3.pgen2.driver" ] for loggername in disable_loggers: modlogger = logging.getLogger(loggername) modlogger.setLevel(logging.WARN) for loggername in trace_loggers: modlogger = logging.getLogger(loggername) modlogger.setLevel(logging.TRACE)
def __init__( self, parent: Optional[QtWidgets.QWidget] = None, name: Optional[str] = None, embedInParent: bool = False, rptEngine: Optional[FLReportEngine] = None, ) -> None: """Inicialize.""" super(FLReportViewer, self).__init__(parent) self.logger = logging.getLogger("FLReportViewer") self.loop_ = False self.eventloop = QtCore.QEventLoop() self.reportPrinted_ = False self.rptEngine_: Optional[Any] = None self.report_ = [] self.slotsPrintDisabled_ = False self.slotsExportedDisabled_ = False self.printing_ = False self.embedInParent_ = True if parent and embedInParent else False self.ui_: Dict[str, QtCore.QObject] = {} self.Display = 1 self.Append = 1 self.PageBreak = 1 self.rptViewer_ = internalReportViewer(self) self.setReportEngine(FLReportEngine(self) if rptEngine is None else rptEngine) if self.rptViewer_ is None: raise Exception("self.rptViewer_ is empty!") self.report_ = self.rptViewer_.reportPages()
def __init__(self, parent: Optional[QtWidgets.QWidget] = None) -> None: """Inicialize.""" super().__init__(parent) self.d_ = FLReportEngine.FLReportEnginePrivate(self) self.relDpi_ = 78.0 self.report_ = None self.rt = "" self.rd: Optional[QtXml.QDomDocument] = None self.logger = logging.getLogger("FLReportEngine") from pineboolib.application.parsers.kugarparser.kut2fpdf import Kut2FPDF self.parser_: Kut2FPDF = Kut2FPDF()
def __init__( self, parent: Optional["QtWidgets.QWidget"] = None, name: Optional[str] = None, multiLang: bool = False, sysTrans: bool = False, ) -> None: """Inicialize.""" super(FLTranslator, self).__init__() self.logger = logging.getLogger("FLTranslator") self._prj = parent if not name: raise Exception("Name is mandatory") self._id_module = name[:name.rfind("_")] self._lang = name[name.rfind("_") + 1:] self._multi_lang = multiLang self._sys_trans = sysTrans self._ts_translation_contexts = {} self._translation_from_qm = config.value( "ebcomportamiento/translations_from_qm", False)
class FormDBWidget(QtWidgets.QWidget): """FormDBWidget class.""" closed = QtCore.pyqtSignal() cursor_: Optional["isqlcursor.ISqlCursor"] form: Any iface: Optional[object] signal_test = QtCore.pyqtSignal(str, QtCore.QObject) logger = logging.getLogger("q3widgets.formdbwidget.FormDBWidget") def __init__(self, action: Optional["xmlaction.XMLAction"] = None): """Inicialize.""" super().__init__() self._module = sys.modules[self.__module__] self._action = action self.iface = None self.cursor_ = None # self.parent_ = parent or QtWidgets.QWidget() # if parent and hasattr(parent, "parentWidget"): # self.parent_ = parent.parentWidget() self.form = None # Limpiar self.form al inicializar... Luego flformdb se asigna.. # from pineboolib.fllegacy import flformdb # if isinstance(parent, flformdb.FLFormDB): # self.form = parent self._formconnections: Set[Tuple] = set([]) self._class_init() def module_connect(self, sender: Any, signal: str, receiver: Any, slot: str) -> None: """Connect two objects.""" # print(" > > > connect:", sender, " signal ", str(signal)) from pineboolib.application import connections signal_slot = connections.connect(sender, signal, receiver, slot, caller=self) if not signal_slot: return self._formconnections.add(signal_slot) def module_disconnect(self, sender: Any, signal: str, receiver: Any, slot: str) -> None: """Disconnect two objects.""" # print(" > > > disconnect:", self) from pineboolib.application import connections signal_slot = connections.disconnect(sender, signal, receiver, slot, caller=self) if not signal_slot: return for sl in self._formconnections: # PyQt5-Stubs misses signal.signal if (sl[0].signal == getattr(signal_slot[0], "signal") and sl[1].__name__ == signal_slot[1].__name__): self._formconnections.remove(sl) break def obj(self) -> "FormDBWidget": """Return self.""" return self def parent(self) -> QtWidgets.QWidget: """Return parent widget.""" return self.parentWidget() def _class_init(self) -> None: """Initialize the class.""" pass # def init(self): # """Evento init del motor. Llama a interna_init en el QS""" # pass def closeEvent(self, event: QtCore.QEvent) -> None: """Close event.""" if self._action is None: self._action = getattr(self.parent(), "_action") if self._action is not None: self.logger.debug("closeEvent para accion %r", self._action.name) self.closed.emit() event.accept() # let the window close self.doCleanUp() def doCleanUp(self) -> None: """Cleanup gabange and connections.""" self.clear_connections() iface = getattr(self, "iface", None) if iface is not None and self._action is not None: from pineboolib.core.garbage_collector import check_gc_referrers check_gc_referrers( "FormDBWidget.iface:" + iface.__class__.__name__, weakref.ref(self.iface), self._action.name, ) delattr(self.iface, "ctx") del self._action.formrecord_widget self.iface = None self._action.formrecord_widget = None def clear_connections(self) -> None: """Clear al conecctions established on the module.""" # Limpiar todas las conexiones hechas en el script for signal, slot in self._formconnections: try: signal.disconnect(slot) self.logger.debug("Señal desconectada al limpiar: %s %s" % (signal, slot)) except Exception: # self.logger.exception("Error al limpiar una señal: %s %s" % (signal, slot)) pass self._formconnections.clear() def child(self, child_name: str) -> Any: """Return child from name.""" ret = None if self.form: ret = self.form.child(child_name) if ret is None: if child_name == super().objectName(): return self.form else: ret = getattr(self.form, child_name, None) if ret is None: parent = self.parent() if parent is not None: ret = getattr(parent, child_name, None) if ret is None: raise Exception("control %s not found!" % child_name) return ret def cursor( self ) -> "isqlcursor.ISqlCursor": # type: ignore [override] # noqa F821 """Return cursor associated.""" if not self.cursor_: if self.form is not None: self.cursor_ = self.form.cursor_ if not self.cursor_: if self._action: action = application.PROJECT.conn_manager.manager().action( self._action.name) self.cursor_ = pnsqlcursor.PNSqlCursor(action.name()) else: raise Exception("_action is empty!.") return self.cursor_ def __getattr__(self, name: str) -> QtWidgets.QWidget: """Guess if attribute can be found in other related objects.""" ret_ = getattr(self.cursor_, name, None) if ret_ is None and self.parent(): parent_ = self.parent() ret_ = getattr(parent_, name, None) if ret_ is None: script = getattr(parent_, "script", None) if script is not None: ret_ = getattr(script, name, None) if ret_ is None and not TYPE_CHECKING: # FIXME: q3widgets should not interact with fllegacy from pineboolib.fllegacy import flapplication ret_ = getattr(flapplication.aqApp, name, None) if ret_ is not None: self.logger.warning( "FormDBWidget: Coearcing attribute %r from aqApp (should be avoided)" % name) if ret_ is None: raise AttributeError("FormDBWidget: Attribute does not exist: %r" % name) return ret_
"""Fllistview module.""" # -*- coding: utf-8 -*- from PyQt5 import Qt # type: ignore from pineboolib.core import decorators from pineboolib import logging from pineboolib.q3widgets import qlistview from typing import Any, Optional, cast, TYPE_CHECKING if TYPE_CHECKING: from PyQt5 import QtWidgets # noqa: F401 logger = logging.getLogger("FLListViewItem") class FLListViewItem(Qt.QStandardItem): """FLListView class.""" _expandable: bool _key: str _open: bool _root: bool _index_child: int def __init__(self, parent: Optional["QtWidgets.QWidget"] = None) -> None: """Inicialize.""" super().__init__() self._root = False self.setOpen(False) self.setExpandable(False)
"""Qgroupbox module.""" # -*- coding: utf-8 -*- from PyQt5 import QtWidgets, QtCore # type: ignore from pineboolib.core import decorators from pineboolib.core import settings from pineboolib import logging from typing import Any logger = logging.getLogger("QGroupBox") class QGroupBox(QtWidgets.QGroupBox): """QGroupBox class.""" # style_str: str # _line_width: int presset = QtCore.pyqtSignal(int) selectedId: int line_width: int = 1 def __init__(self, *args, **kwargs) -> None: """Inicialize.""" super(QGroupBox, self).__init__(*args, **kwargs) if not settings.config.value("ebcomportamiento/spacerLegacy", False): self.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
Generate .ods files (Opendocument Spreadsheet) """ from typing import Union, List, Any, Tuple, Optional, TYPE_CHECKING import odf # type: ignore from odf import table, style # type: ignore from pineboolib import logging from pineboolib.core import decorators if TYPE_CHECKING: from odf.opendocument import OpenDocumentSpreadsheet # type: ignore logger = logging.getLogger("AQOds") """ Generador de ficheros ODS """ class OdsStyleFlags(object): """OdsStyleFlags.""" ODS_NONE = 0 ODS_BORDER_BOTTOM = 10 ODS_BORDER_LEFT = 11 ODS_BORDER_RIGHT = 12 ODS_BORDER_TOP = 13 ODS_ALIGN_LEFT = 14
from pineboolib import application from pineboolib.application import database from pineboolib.application.qsatypes import sysbasetype from pineboolib.application.acls import pnaccesscontrollists from . import fltranslator from typing import Any, Optional, List, cast, TYPE_CHECKING if TYPE_CHECKING: from pineboolib.application.database import pnsqlcursor # noqa: F401 from pineboolib.application.database import pnsqlquery # noqa: F401 from PyQt5 import QtXml # noqa: F401 logger = logging.getLogger("FLApplication") class FLPopupWarn(QtCore.QObject): """FLPoppupWarn Class.""" # FIXME: Incomplete class! def __init__(self, mainwindow) -> None: """Inicialize.""" self.mainWindow = mainwindow class FLApplication(QtCore.QObject): """FLApplication Class."""
"""Manage cached xpm.""" import os import os.path from pineboolib.core.settings import config from pineboolib import logging, application LOGGER = logging.getLogger("xpm") def cache_xpm(value: str) -> str: """ Return a path to a file with the content of the specified string. @param value. text string with the xpm or path to this. @return file path contains Xpm """ if not value: LOGGER.warning("the value is empty!") return "" xpm_name = value[:value.find("[]")] xpm_name = xpm_name[xpm_name.rfind(" ") + 1:] conn = application.PROJECT.conn_manager.mainConn() if conn is None: raise Exception("Project is not connected yet") cache_dir = "%s/cache/%s/cacheXPM" % (application.PROJECT.tmpdir,
"""Dgi_schema module.""" # -*- coding: utf-8 -*- from importlib import import_module from typing import List, cast, Optional, Any from PyQt5 import QtCore, QtWidgets from pineboolib.application.utils.mobilemode import is_mobile_mode from pineboolib import logging logger = logging.getLogger(__name__) class dgi_schema(object): """dgi_schema class.""" _desktopEnabled: bool _mLDefault: bool _name: str _alias: str _localDesktop: bool _mobile: bool _clean_no_python: bool # FIXME: Guess this is because there is conditional code we don't want to run on certain DGI # .... this is really obscure. Please avoid at all costs. Having __NO_PYTHON__ is bad enough. _alternative_content_cached: bool def __init__(self) -> None: """Inicialize.""" # FIXME: This init is intended to be called only on certain conditions. # ... Worse than it seems: looks like this class is prepared to be constructed without
from pineboolib.core import settings from pineboolib.application.acls import pnaccesscontrollists from pineboolib.fllegacy.aqsobjects import aqs from pineboolib.fllegacy import flapplication, flworkspace, flformdb from pineboolib.application import pncore from pineboolib import application from pineboolib import logging from typing import Any, cast, List, Optional, Dict, TYPE_CHECKING if TYPE_CHECKING: from pineboolib.application.database import pnconnectionmanager logger = logging.getLogger("mainForm_%s" % __name__) class MainForm(QtWidgets.QMainWindow): """MainForm class.""" acl_: pnaccesscontrollists.PNAccessControlLists is_closing_: bool mdi_enable_: bool container_: Optional[QtWidgets.QMainWindow] w_: QtWidgets.QMainWindow exit_button: QtWidgets.QPushButton _p_work_space: Any mdi_toolbuttons: List[QtWidgets.QToolButton] _dict_main_widgets: Dict[str, QtWidgets.QWidget] debugLevel: int
class FLFormSearchDB(flformdb.FLFormDB): """ Subclass of the FLFormDB class, designed to search for a record in a table. The behavior of choosing a record is modified for only close the form and so the object that invokes it can get of the cursor said record. It also adds OK and Cancel buttons. Accept indicates that it has been chosen the active record (same as double clicking on it or press the Enter key) and Cancel abort the operation. @author InfoSiAL S.L. """ """ Boton Aceptar """ pushButtonAccept: Optional[QtWidgets.QToolButton] """ Almacena si se ha abierto el formulario con el método FLFormSearchDB::exec() """ acceptingRejecting_: bool logger = logging.getLogger("FLFormSearchDB") def __init__(self, *args) -> None: """ Initialize. """ action: "pnaction.PNAction" parent: Optional["QtWidgets.QWidget"] = None cursor: "pnsqlcursor.PNSqlCursor" if isinstance(args[0], str): action = application.PROJECT.conn_manager.manager().action(args[0]) cursor = pnsqlcursor.PNSqlCursor(action.table()) if len(args) > 1 and args[1]: parent = args[1] elif isinstance(args[1], str): action = application.PROJECT.conn_manager.manager().action(args[1]) cursor = args[0] if len(args) > 2 and args[2]: parent = args[2] else: raise Exception("Wrong size of arguments") if not parent: parent = QtWidgets.QApplication.activeModalWidget() if cursor is None: self.logger.warning( "Se ha llamado a FLFormSearchDB sin nombre de action o cursor") return if application.PROJECT.conn_manager is None: raise Exception("Project is not connected yet") super().__init__(action, parent, load=False) self.setWindowModality(QtCore.Qt.ApplicationModal) self.setCursor(cursor) self.accepted_ = False self.inExec_ = False self.loop = False self.acceptingRejecting_ = False self.pushButtonAccept = None self.load() self.initForm() self.setFocusPolicy(QtCore.Qt.NoFocus) def setAction(self, a: "pnaction.PNAction") -> None: """Set a action.""" if self.cursor_: self.cursor_.setAction(a) # def __delattr__(self, *args, **kwargs) -> None: # """Delete attributes.""" # if self.cursor_: # self.cursor_.restoreEditionFlag(self) # self.cursor_.restoreBrowseFlag(self) # super().__delattr__(self, *args, **kwargs) """ formReady = QtCore.pyqtSignal() """ def loadControls(self) -> None: """Load form controls.""" self.bottomToolbar = QtWidgets.QFrame() if self.bottomToolbar: self.bottomToolbar.setMaximumHeight(64) self.bottomToolbar.setMinimumHeight(16) hblay = QtWidgets.QHBoxLayout() hblay.setContentsMargins(0, 0, 0, 0) hblay.setSpacing(0) hblay.addStretch() self.bottomToolbar.setLayout(hblay) self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus) self.layout_.addWidget(self.bottomToolbar) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy(0), QtWidgets.QSizePolicy.Policy(0)) sizePolicy.setHeightForWidth(True) pbSize = self.iconSize if settings.config.value("application/isDebuggerMode", False): pushButtonExport = QtWidgets.QToolButton(self) pushButtonExport.setObjectName("pushButtonExport") pushButtonExport.setSizePolicy(sizePolicy) pushButtonExport.setMinimumSize(pbSize) pushButtonExport.setMaximumSize(pbSize) pushButtonExport.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-properties.png"))) pushButtonExport.setShortcut(Qt.QKeySequence(self.tr("F3"))) pushButtonExport.setWhatsThis("Exportar a XML(F3)") pushButtonExport.setToolTip("Exportar a XML(F3)") pushButtonExport.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(pushButtonExport) pushButtonExport.clicked.connect(self.exportToXml) if settings.config.value("ebcomportamiento/show_snaptshop_button", False): push_button_snapshot = QtWidgets.QToolButton(self) push_button_snapshot.setObjectName("pushButtonSnapshot") push_button_snapshot.setSizePolicy(sizePolicy) push_button_snapshot.setMinimumSize(pbSize) push_button_snapshot.setMaximumSize(pbSize) push_button_snapshot.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-paste.png"))) push_button_snapshot.setShortcut(Qt.QKeySequence( self.tr("F8"))) push_button_snapshot.setWhatsThis("Capturar pantalla(F8)") push_button_snapshot.setToolTip("Capturar pantalla(F8)") push_button_snapshot.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(push_button_snapshot) push_button_snapshot.clicked.connect(self.saveSnapShot) spacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) self.bottomToolbar.layout().addItem(spacer) if not self.pushButtonAccept: self.pushButtonAccept = QtWidgets.QToolButton(self) self.pushButtonAccept.setObjectName("pushButtonAccept") self.pushButtonAccept.clicked.connect(self.accept) self.pushButtonAccept.setSizePolicy(sizePolicy) self.pushButtonAccept.setMaximumSize(pbSize) self.pushButtonAccept.setMinimumSize(pbSize) self.pushButtonAccept.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-save.png"))) # pushButtonAccept->setAccel(Qt.QKeySequence(Qt::Key_F10)); FIXME self.pushButtonAccept.setFocus() self.pushButtonAccept.setWhatsThis( "Seleccionar registro actual y cerrar formulario (F10)") self.pushButtonAccept.setToolTip( "Seleccionar registro actual y cerrar formulario (F10)") self.pushButtonAccept.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(self.pushButtonAccept) self.pushButtonAccept.show() if not self.pushButtonCancel: self.pushButtonCancel = QtWidgets.QToolButton(self) self.pushButtonCancel.setObjectName("pushButtonCancel") self.pushButtonCancel.clicked.connect(self.reject) self.pushButtonCancel.setSizePolicy(sizePolicy) self.pushButtonCancel.setMaximumSize(pbSize) self.pushButtonCancel.setMinimumSize(pbSize) self.pushButtonCancel.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-stop.png"))) self.pushButtonCancel.setFocusPolicy(QtCore.Qt.NoFocus) # pushButtonCancel->setAccel(Esc); FIXME self.pushButtonCancel.setWhatsThis( "Cerrar formulario sin seleccionar registro (Esc)") self.pushButtonCancel.setToolTip( "Cerrar formulario sin seleccionar registro (Esc)") self.bottomToolbar.layout().addWidget(self.pushButtonCancel) self.pushButtonCancel.show() if self.cursor_ is None: raise Exception("Cursor is empty!.") self.cursor_.setEdition(False) self.cursor_.setBrowse(False) self.cursor_.recordChoosed.connect(self.accept) def exec_(self, valor: Optional[str] = None) -> bool: """ Show the form and enter a new event loop to wait, to select record. The name of a cursor field is expected returning the value of that field if the form is accepted and a QVariant :: Invalid if canceled. @param valor Name of a form cursor field @return The value of the field if accepted, or False if canceled """ if not self.cursor_: return False if self.cursor_.isLocked(): self.cursor_.setModeAccess(pnsqlcursor.PNSqlCursor.Browse) if self.loop or self.inExec_: print( "FLFormSearchDB::exec(): Se ha detectado una llamada recursiva" ) if self.isHidden(): super().show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() return False self.inExec_ = True self.acceptingRejecting_ = False self.accepted_ = False super().show() if self.initFocusWidget_: self.initFocusWidget_.setFocus() if self.iface: try: QtCore.QTimer.singleShot(50, self.iface.init) except Exception: pass if not self.isClosing_: QtCore.QTimer.singleShot(0, self.emitFormReady) self.loop = True if self.eventloop: self.eventloop.exec_() self.loop = False self.inExec_ = False if self.accepted_ and valor: return self.cursor_.valueBuffer(valor) else: self.close() return False def setFilter(self, f: str) -> None: """Apply a filter to the cursor.""" if not self.cursor_: return previousF = self.cursor_.mainFilter() newF = None if previousF == "": newF = f elif f is None or previousF.find(f) > -1: return else: newF = "%s AND %s" % (previousF, f) self.cursor_.setMainFilter(newF) def formClassName(self) -> str: """Return the class name of the form at runtime.""" return "FormSearchDB" def formName(self) -> str: """ Return internal form name. """ return "formSearch%s" % self.idMDI_ def closeEvent(self, e: QtCore.QEvent) -> None: """Capture event close.""" self.frameGeometry() # if self.focusWidget(): # fdb = self.focusWidget().parentWidget() # try: # if fdb and fdb.autoComFrame_ and fdb.autoComFrame_.isvisible(): # fdb.autoComFrame_.hide() # return # except Exception: # pass if self.cursor_ and self.pushButtonCancel: if not self.pushButtonCancel.isEnabled(): return self.isClosing_ = True self.setCursor(None) else: self.isClosing_ = True if self.isHidden(): # self.saveGeometry() # self.closed.emit() super().closeEvent(e) # self.deleteLater() else: self.reject() @decorators.pyqtSlot() def callInitScript(self) -> None: """Call the "init" function of the "masterprocess" script associated with the form.""" pass @decorators.pyqtSlot() def hide(self) -> None: """Redefined for convenience.""" if self.loop: self.loop = False self.eventloop.exit() if self.isHidden(): return super().hide() @decorators.pyqtSlot() def accept(self) -> None: """Activate pressing the accept button.""" if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: try: self.cursor_.recordChoosed.disconnect(self.accept) except Exception: pass self.acceptingRejecting_ = True self.accepted_ = True self.saveGeometry() self.hide() parent = self.parent() if isinstance(parent, QtWidgets.QMdiSubWindow): parent.hide() @decorators.pyqtSlot() def reject(self) -> None: """Activate pressing the accept button.""" if self.acceptingRejecting_: return self.frameGeometry() if self.cursor_: try: self.cursor_.recordChoosed.disconnect(self.accept) except Exception: pass self.acceptingRejecting_ = True self.hide() @decorators.pyqtSlot() def show(self) -> None: """Redefined for convenience.""" self.exec_() def setMainWidget(self, w: QtWidgets.QWidget = None) -> None: """ Set widget as the main form. """ if not self.cursor_: return if w: w.hide() self.mainWidget_ = w
class DelayedObjectProxyLoader(object): """ Delay load of an object until its first accessed. This is used to create entities such "formclientes" or "flfactppal" ahead of time and publish them in pineboolib.qsa.qsa so the code can freely call flfactppal.iface.XXX. Once the first attribute is called, the object is loaded. QSA Code should avoid calling directly "formclientes" and instead use QSADictModules or SafeQSA """ logger = logging.getLogger("application.DelayedObjectProxyLoader") def __init__(self, obj: Callable[..., "FLFormDB"], name: Optional[str] = None, *args: str, **kwargs: str) -> None: """ Constructor. """ self.logger.trace("obj: %r", obj) self._name: str = name or "unnamed-loader" self._obj = obj self._args = args self._kwargs = kwargs self.loaded_obj: Optional["FLFormDB"] = None def __load(self) -> "FLFormDB": """ Load a new object. @return objeto nuevo o si ya existe , cacheado """ if (self.loaded_obj is not None and self.loaded_obj._loaded ): # Si no está _loaded lo sobrecarga también return self.loaded_obj self.logger.debug( "DelayedObjectProxyLoader: loading %s %s( *%s **%s)", self._name, self._obj, self._args, self._kwargs, ) self.loaded_obj = self._obj(*self._args, **self._kwargs) self.logger.trace("loaded object: %r", self.loaded_obj) if self.loaded_obj is None: raise Exception("Failed to load object") return self.loaded_obj def __getattr__( self, name: str) -> Any: # Solo se lanza si no existe la propiedad. """ Return attribute or method from internal object. @param name. Nombre del la función buscada @return el objecto del XMLAction afectado """ obj_ = self.__load() return getattr(obj_, name, getattr(obj_.widget, name, None))
"""Preload Module.""" from pineboolib import logging from typing import Container, Any LOGGER = logging.getLogger("loader.preload_actions") def preload_actions(project: Any, forceload: Container = None) -> None: """ Preload actions for warming up the pythonizer cache. forceload: When passed an string, it filters and loads all actions that match "*forceload*". If None, all actions are loaded. """ LOGGER.info("Precarga ...") for action in project.actions: if forceload and action not in forceload: continue LOGGER.debug("* * * Cargando acción %s . . . " % action) try: project.actions[action].load() except Exception: LOGGER.exception("Failure trying to load action %s", action) project.conn_manager.mainConn().rollback( ) # FIXME: Proper transaction handling using with context try: project.actions[action].loadRecord(None) except Exception: LOGGER.exception("Failure trying to loadRecord action %s", action)
""" from pineboolib.core import decorators from pineboolib.interfaces import itablemetadata from pineboolib import logging import copy from typing import Optional, List, Dict, Union, TYPE_CHECKING from . import pnfieldmetadata from . import pncompoundkeymetadata if TYPE_CHECKING: from . import pnrelationmetadata # noqa LOGGER = logging.getLogger("CursorTableModel") class PNTableMetaData(itablemetadata.ITableMetaData): """PNTableMetaData Class.""" private: "PNTableMetaDataPrivate" def __init__( self, name_or_metadata: Union[str, "PNTableMetaData"] = "", alias: Optional[str] = None, query_name: Optional[str] = None, ) -> None: """ Collect the data to start.
def __init__(self) -> None: """Create base class for tools.""" self.logger = logging.getLogger("ParseTools") self.pagina = 0 self._fix_ratio_h = 0.927 # Corrector de altura 0.927 self._fix_ratio_w = 0.92
def __init__(self) -> None: """Initialize.""" super(FLTranslations, self).__init__() self.logger = logging.getLogger("FLTranslations")
class FLFormDB(QtWidgets.QDialog): """ Represents a form that links to a table. It is used as a container of components that want link to the database and access the records of the cursor. This structure greatly simplifies measure access to data since many tasks are Automatically managed by this container form. At first the form is created empty and we must invoke the FLFormDB :: setMainWidget () method, passing it as a parameter another widget (usually a form created with QtDesigner), which contains different components, this widget will be displayed inside this container, self-configuring all the components It contains, with the cursor data and metadata. Generally the Components will be plugins, such as FLFieldDB or FLTableDB """ """ Cursor, con los registros, utilizado por el formulario """ cursor_: Optional["isqlcursor.ISqlCursor"] """ Nombre de la tabla, contiene un valor no vacío cuando la clase es propietaria del cursor """ name_: str """ Capa principal del formulario """ layout_: QtWidgets.QVBoxLayout """ Widget principal del formulario """ mainWidget_: Optional[QtWidgets.QWidget] """ Identificador de ventana MDI. Generalmente es el nombre de la acción que abre el formulario """ idMDI_: str """ Capa para botones """ layoutButtons: QtWidgets.QHBoxLayout """ Boton Cancelar """ pushButtonCancel: Optional[QtWidgets.QToolButton] """ Indica que la ventana ya ha sido mostrada una vez """ showed: bool """ Guarda el contexto anterior que tenia el cursor """ oldCursorCtxt: Any """ Indica que el formulario se está cerrando """ isClosing_: bool """ Componente con el foco inicial """ initFocusWidget_: Optional[QtWidgets.QWidget] """ Guarda el último objeto de formulario unido a la interfaz de script (con bindIface()) """ oldFormObj: Any """ Boton Debug Script """ pushButtonDebug: Optional[QtWidgets.QToolButton] """ Almacena que se aceptado, es decir NO se ha pulsado, botón cancelar """ accepted_: bool """ Nombre del formulario relativo a la acción (form / formRecrd + nombre de la acción) """ actionName_: str """ Interface para scripts """ iface: Any """ Tamaño de icono por defecto """ iconSize: QtCore.QSize # protected slots: """ Uso interno """ oldFormObjDestroyed = QtCore.pyqtSignal() # 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() formClosed = QtCore.pyqtSignal() known_instances: Dict[Tuple[Type["FLFormDB"], str], "FLFormDB"] = {} bottomToolbar: Optional[QtWidgets.QFrame] toolButtonClose: Optional[QtWidgets.QToolButton] _uiName: str _scriptForm: Union[Any, str] loop: bool _action: "pnaction.PNAction" logger = logging.getLogger("FLFormDB") def __init__( self, action_or_name: Union["pnaction.PNAction", str], parent: Optional[Union[QtWidgets.QWidget, int]] = None, load: Union[bool, int] = False, ) -> None: """Create a new FLFormDB for given action.""" # self.tiempo_ini = time.time() parent_widget: QtWidgets.QWidget if isinstance(load, int): load = load == 1 if parent is None or isinstance(parent, int): parent_widget = flapplication.aqApp.mainWidget() else: parent_widget = parent super().__init__(parent_widget) self._loaded = False if isinstance(action_or_name, str): self._action = application.PROJECT.conn_manager.manager().action( action_or_name) else: self._action = action_or_name self.known_instances[(self.__class__, self._action.name())] = self self.actionName_ = script_name = self._action.name() if self._action.table(): if type(self).__name__ == "FLFormRecordDB": self.actionName_ = "formRecord%s" % self.actionName_ script_name = self._action.scriptFormRecord() else: self.actionName_ = "form%s" % self.actionName_ script_name = self._action.scriptForm() # self.mod = self._action.mod self.loop = False self.eventloop = QtCore.QEventLoop() self.layout_ = QtWidgets.QVBoxLayout() self.layout_.setContentsMargins(1, 1, 1, 1) self.layout_.setSpacing(1) self.layout_.setContentsMargins(1, 1, 1, 1) self.layout_.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize) self.setLayout(self.layout_) self._uiName = self._action.form() self.pushButtonCancel = None self.toolButtonClose = None self.bottomToolbar = None self.cursor_ = None self.initFocusWidget_ = None self.showed = False self.isClosing_ = False self.accepted_ = False self.mainWidget_ = None self.iface = None self.oldFormObj = None self.oldCursorCtxt = None self.idMDI_ = self._action.name() self.logger.info("init: Action: %s", self._action) self.script = load_script.load_script( script_name, application.PROJECT.actions[self._action.name()]) self.widget = self.script.form self.widget.form = self if hasattr(self.widget, "iface"): self.iface = self.widget.iface self.iconSize = application.PROJECT.DGI.iconSize() if load: self.load() self.initForm() def load(self) -> None: """Load control.""" if self._loaded: return # self.resize(550,350) if self.layout_ is None: return self.layout_.insertWidget(0, self.widget) self.layout_.setSpacing(1) self.layout_.setContentsMargins(1, 1, 1, 1) self.layout_.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize) if self._uiName: if application.PROJECT.conn_manager is None: raise Exception("Project is not connected yet") application.PROJECT.conn_manager.managerModules().createUI( self._uiName, None, self) self._loaded = True def loaded(self) -> bool: """Return if the control is initialized.""" return self._loaded @decorators.pyqtSlot() def initScript(self) -> bool: """ Call the "init" function of the masterprocess script associated with the form. """ if self._loaded: if not getattr(self.widget, "iface", None): self.iface = ( self.widget ) # Es posible que no tenga ifaceCtx, así hacemos que sea polivalente if self.widget: self.widget.clear_connections() if hasattr(self.iface, "init"): try: self.iface.init() except Exception: from pineboolib.core.error_manager import error_manager flapplication.aqApp.msgBoxWarning( error_manager( traceback.format_exc(limit=-6, chain=False)), application.PROJECT.DGI, ) return False return True return False def __del__(self) -> None: """ Destroyer. """ # TODO: Esto hay que moverlo al closeEvent o al close() # ..... los métodos __del__ de python son muy poco fiables. # ..... Se lanzan o muy tarde, o nunca. # (De todos modos creo que ya hice lo mismo a mano en el closeEvent en commits anteriores) self.unbindIface() def setCursor( self, cursor: "isqlcursor.ISqlCursor" = None) -> None: # type: ignore """Change current cursor binded to this control.""" if cursor is not self.cursor_ and self.cursor_ and self.oldCursorCtxt: self.cursor_.setContext(self.oldCursorCtxt) if not cursor: return if self.cursor_ and self.cursor_ is not cursor: if type(self).__name__ == "FLFormRecodDB": self.cursor_.restoreEditionFlag(self.objectName()) self.cursor_.restoreBrowseFlag(self.objectName()) if self.cursor_: cast(QtCore.pyqtSignal, self.cursor_.destroyed).disconnect(self.cursorDestroyed) self.widget.cursor_ = cursor self.cursor_ = cursor if type(self).__name__ == "FLFormRecodDB": self.cursor_.setEdition(False, self.objectName()) self.cursor_.setBrowse(False, self.objectName()) cast(QtCore.pyqtSignal, self.cursor_.destroyed).connect(self.cursorDestroyed) if self.iface and self.cursor_: self.oldCursorCtxt = self.cursor_.context() self.cursor_.setContext(self.iface) def cursor( self ) -> "isqlcursor.ISqlCursor": # type: ignore [override] # noqa F821 """ To get the cursor used by the form. """ if self.cursor_ is None: raise Exception("cursor_ is empty!.") return self.cursor_ def mainWidget(self) -> Optional[QtWidgets.QWidget]: """ To get the form's main widget. """ return self.mainWidget_ def setIdMDI(self, id_: str) -> None: """ Set the MDI ID. """ self.idMDI_ = id_ def idMDI(self) -> str: """ Return the MDI ID. """ return self.idMDI_ def setMainWidget(self, w: Optional[QtWidgets.QWidget] = None) -> None: """ Set widget as the main form. """ self.mainWidget_ = self def snapShot(self) -> QtGui.QImage: """ Return the image or screenshot of the form. """ pix = self.grab() return pix.toImage() def saveSnapShot(self, path_file: Optional[str] = None) -> None: """ Save the image or screenshot of the form in a PNG format file. """ if not path_file: tmp_file = "%s/snap_shot_%s.png" % ( flapplication.aqApp.tmp_dir(), QtCore.QDateTime.currentDateTime().toString( "ddMMyyyyhhmmsszzz"), ) ret = QtWidgets.QFileDialog.getSaveFileName( QtWidgets.QApplication.activeWindow(), "Pineboo", tmp_file, "PNG(*.png)") path_file = ret[0] if ret else None if path_file: fi = QtCore.QFile(path_file) if not fi.OpenMode(QtCore.QIODevice.WriteOnly): self.tr("Error I/O al intentar escribir el fichero %s" % path_file) return self.snapShot().save(fi, "PNG") def saveGeometry(self) -> QtCore.QByteArray: """Save current window size into settings.""" # pW = self.parentWidget() # if not pW: geo = QtCore.QSize(self.width(), self.height()) if self.isMinimized(): geo.setWidth(1) elif self.isMaximized(): geo.setWidth(9999) # else: # geo = QtCore.QSize(pW.width(), pW.height()) geometry.save_geometry_form(self.geoName(), geo) return super().saveGeometry() def setCaptionWidget(self, text: str) -> None: """ Set the window title. """ if not text: return self.setWindowTitle(text) def accepted(self) -> bool: # type: ignore """ Return if the form has been accepted. """ # FIXME: QtWidgets.QDialog.accepted() is a signal. We're shadowing it. return self.accepted_ def formClassName(self) -> str: """ Return the class name of the form at runtime. """ return "FormDB" def exec_(self) -> bool: """ Only to be compatible with FLFormSearchDB. By default, just call QWidget.show. """ super().show() return True def hide(self) -> None: """Hide control.""" super().hide() @decorators.pyqtSlot() def close(self) -> bool: """ Close the form. """ if self.isClosing_ or not self._loaded: return True self.isClosing_ = True super().close() self.isClosing_ = False return True @decorators.pyqtSlot() def accept(self) -> None: """ Activated by pressing the accept button. """ pass @decorators.pyqtSlot() def reject(self) -> None: """ Activated by pressing the cancel button. """ pass @decorators.pyqtSlot() def showForDocument(self) -> None: """ Show the form without calling the script "init". Used in documentation to avoid conflicts when capturing forms. """ self.showed = True if self.mainWidget_: self.mainWidget_.show() self.resize(self.mainWidget_.size()) super().show() @decorators.pyqtSlot() @decorators.NotImplementedWarn def debugScript(self) -> bool: """ Show the script associated with the form in the Workbench to debug. """ return True @decorators.pyqtSlot() def get_script(self) -> Optional[str]: """ Return the script associated with the form. """ ifc = self.iface if ifc: return str(ifc) return None # private slots: @decorators.pyqtSlot() def callInitScript(self) -> None: """Call QS Script related to this control.""" if not self.initScript(): raise Exception("Error initializing the module.") if not self.isClosing_: QtCore.QTimer.singleShot(0, self.emitFormReady) def emitFormReady(self) -> None: """Emit formReady signal, after the form has been loaded.""" from pineboolib.application.qsatypes.sysbasetype import SysBaseType qsa_sys = SysBaseType() if qsa_sys.isLoadedModule("fltesttest"): flapplication.aqApp.call("fltesttest.iface.recibeEvento", ("formReady", self.actionName_), None) self.formReady.emit() # protected_: def emitFormClosed(self) -> None: """Emit formClosed signal.""" if application.PROJECT.conn_manager is None: raise Exception("Project is not connected yet") if "fltesttest" in application.PROJECT.conn_manager.managerModules( ).listAllIdModules(): application.PROJECT.call("fltesttest.iface.recibeEvento", ["formClosed", self.actionName_], None) self.formClosed.emit() if self.widget: self.widget.closed.emit() def action(self) -> "pnaction.PNAction": """Get form PNAction.""" return self._action def initForm(self) -> None: """ Initialize the associated script. """ from pineboolib.fllegacy import flapplication acl = flapplication.aqApp.acl() if acl: acl.process(self) self.loadControls() if self._action is None: raise Exception("_action is empty!") if self._action.table(): if (not self.cursor_ or not self.cursor_._action or self.cursor_._action.table() is not self._action.table()): cursor = pnsqlcursor.PNSqlCursor(self._action.table()) self.setCursor(cursor) v = None preload_main_filter = getattr(self.iface, "preloadMainFilter", None) if preload_main_filter: v = preload_main_filter() if v is not None and self.cursor_: self.cursor_.setMainFilter(v, False) # if self._loaded and not self.__class__.__name__ == "FLFormRecordDB": # application.PROJECT.conn_manager.managerModules().loadFLTableDBs(self) if self._action.description() not in ("", None): self.setWhatsThis(self._action.description()) caption = self._action.caption() if caption in ("", None) and self.cursor_ and self.cursor_.metadata(): caption = self.cursor_.metadata().alias() if caption in ("", None): caption = QtWidgets.QApplication.translate( "FLFormDB", "No hay metadatos") self.setCaptionWidget(caption) def loadControls(self) -> None: """Load form controls.""" if self.pushButtonCancel: self.pushButtonCancel.hide() if self.bottomToolbar and self.toolButtonClose: self.toolButtonClose.hide() self.bottomToolbar = QtWidgets.QFrame() if self.bottomToolbar is None: raise Exception("bottomToolBar is empty!") if self.iconSize is not None: self.bottomToolbar.setMinimumSize(self.iconSize) hblay = QtWidgets.QHBoxLayout() hblay.setContentsMargins(0, 0, 0, 0) hblay.setSpacing(0) hblay.addStretch() self.bottomToolbar.setLayout(hblay) self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus) if self.layout_ is not None: self.layout_.addWidget(self.bottomToolbar) # if self.layout: # self.layout = None # Limpiamos la toolbar sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy(0), QtWidgets.QSizePolicy.Policy(0)) sizePolicy.setHeightForWidth(True) pbSize = self.iconSize if settings.config.value("application/isDebuggerMode", False): pushButtonExport = QtWidgets.QToolButton() pushButtonExport.setObjectName("pushButtonExport") pushButtonExport.setSizePolicy(sizePolicy) pushButtonExport.setMinimumSize(pbSize) pushButtonExport.setMaximumSize(pbSize) pushButtonExport.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-properties.png"))) pushButtonExport.setShortcut(QtGui.QKeySequence(self.tr("F3"))) pushButtonExport.setWhatsThis( QtWidgets.QApplication.translate("FLFormDB", "Exportar a XML(F3)")) pushButtonExport.setToolTip( QtWidgets.QApplication.translate("FLFormDB", "Exportar a XML(F3)")) pushButtonExport.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(pushButtonExport) pushButtonExport.clicked.connect(self.exportToXml) if settings.config.value("ebcomportamiento/show_snaptshop_button", False): push_button_snapshot = QtWidgets.QToolButton() push_button_snapshot.setObjectName("pushButtonSnapshot") push_button_snapshot.setSizePolicy(sizePolicy) push_button_snapshot.setMinimumSize(pbSize) push_button_snapshot.setMaximumSize(pbSize) push_button_snapshot.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-paste.png"))) push_button_snapshot.setShortcut( QtGui.QKeySequence(self.tr("F8"))) push_button_snapshot.setWhatsThis("Capturar pantalla(F8)") push_button_snapshot.setToolTip("Capturar pantalla(F8)") push_button_snapshot.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(push_button_snapshot) push_button_snapshot.clicked.connect(self.saveSnapShot) spacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) self.bottomToolbar.layout().addItem(spacer) if not self.pushButtonCancel: self.pushButtonCancel = QtWidgets.QToolButton() self.pushButtonCancel.setObjectName("pushButtonCancel") cast(QtCore.pyqtSignal, self.pushButtonCancel.clicked).connect( cast(Callable, self.close)) self.pushButtonCancel.setSizePolicy(sizePolicy) self.pushButtonCancel.setMaximumSize(pbSize) self.pushButtonCancel.setMinimumSize(pbSize) self.pushButtonCancel.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-stop.png"))) # self.pushButtonCancel.setFocusPolicy(QtCore.Qt.StrongFocus) # self.pushButtonCancel.setFocus() self.pushButtonCancel.setShortcut(QtGui.QKeySequence(self.tr("Esc"))) self.pushButtonCancel.setWhatsThis("Cerrar formulario (Esc)") self.pushButtonCancel.setToolTip("Cerrar formulario (Esc)") self.bottomToolbar.layout().addWidget(self.pushButtonCancel) self.setFocusPolicy(QtCore.Qt.NoFocus) def formName(self) -> str: """ Return internal form name. """ return "form%s" % self.idMDI_ def name(self) -> str: """Get name of the form.""" return self.formName() def geoName(self) -> str: """Get name of the form.""" # FIXME: What this should do exactly? return self.formName() def bindIface(self) -> None: """ Join the script interface to the form object. """ if self.iface: self.oldFormObj = self.iface def unbindIface(self) -> None: """ Disconnect the script interface to the form object. """ if not self.iface: return self.iface = self.oldFormObj def isIfaceBind(self) -> bool: """ Indicate if the script interface is attached to the form object. """ if self.iface: return True else: return False def closeEvent(self, e: Any) -> None: """ Capture event close. """ self.frameGeometry() self.saveGeometry() self.setCursor(None) # self.closed.emit() self.hide() self.emitFormClosed() # super().closeEvent(e) # self._action.mainform_widget = None self.deleteLater() self._loaded = False # from PyQt5.QtWidgets import qApp # qApp.processEvents() #Si se habilita pierde mucho tiempo! # self.hide() try: # if hasattr(self.script, "form"): # print("Borrando self.script.form", self.script.form) # self.script.form = None if self.widget is not None and type( self).__name__ != "FLFormSearchDB": self.widget.close() self.widget = None # del self.widget # self.iface = None # del self.iface # if hasattr(self, "widget"): # print("Borrando self.widget", self.widget) # self.widget.close() # del self.widget instance_name = (self.__class__, self._action.name()) if instance_name in self.known_instances.keys(): del self.known_instances[instance_name] # if hasattr(self, "script"): # print("Borrando self.script", self.script) self.script = None except Exception: self.logger.error( "El FLFormDB %s no se cerró correctamente:\n%s", self.formName(), traceback.format_exc(), ) parent = self.parent() if isinstance(parent, QtWidgets.QMdiSubWindow): parent.close() def showEvent(self, e: Any) -> None: """ Capture event show. """ # --> Para mostrar form sin negro previo # QtWidgets.QApplication.processEvents() # <-- if not self.loaded(): return if not self.showed: self.showed = True # self.initMainWidget() self.callInitScript() if not self._loaded: return self.bindIface() size = geometry.load_geometry_form(self.geoName()) if size: self.resize(size) parent = self.parent() if parent and isinstance(parent, QtWidgets.QMdiSubWindow): parent.resize(size) parent.repaint() def cursorDestroyed(self, obj_: Optional[Any] = None) -> None: """Clean up. Called when cursor has been deleted.""" if not obj_: obj_ = self.sender() if not obj_ or obj_ is self.cursor_: return del self.cursor_ """ Captura evento ocultar def hideEvent(self, h): pW = self.parentWidget() if not pW: geo = QtCore.QSize(self.width(), self.height()) if self.isMinimized(): geo.setWidth(1) elif self.isMaximized(): geo.setWidth(9999) else: geo = QtCore.QSize(pW.width(), pW.height()) #geometry.saveGeometryForm(self.geoName(), geo) """ def focusInEvent(self, f: Any) -> None: """ Capture Focus Enter Event. """ super().focusInEvent(f) if not self.isIfaceBind(): self.bindIface() def show(self) -> None: """ Initialize components of the main widget. @param w Widget to initialize. If not set use by default the current main widget. """ if hasattr(application.PROJECT.main_window, "_dict_main_widgets"): module_name = application.PROJECT.conn_manager.managerModules( ).activeIdModule() if (module_name and module_name in application.PROJECT.main_window._dict_main_widgets.keys()): module_window = application.PROJECT.main_window._dict_main_widgets[ module_name] mdi_area = module_window.centralWidget() if isinstance(mdi_area, QtWidgets.QMdiArea): for sub_window in mdi_area.subWindowList(): if cast(FLFormDB, sub_window.widget()).formName( ) == self.formName(): mdi_area.setActiveSubWindow(sub_window) return if type(self).__name__ == "FLFormDB": # if not isinstance(self.parent(), QtWidgets.QMdiSubWindow): # size = self.size() mdi_area.addSubWindow(self) if self.initFocusWidget_ is None: self.initFocusWidget_ = self.focusWidget() if self.initFocusWidget_: self.initFocusWidget_.setFocus() # if not self.tiempo_ini: # self.tiempo_ini = time.time() super().show() # tiempo_fin = time.time() parent_ = self.parent() if parent_ and parent_.parent() is None: qt_rectangle = self.frameGeometry() center_point = QtWidgets.QDesktopWidget().availableGeometry( ).center() qt_rectangle.moveCenter(center_point) self.move(qt_rectangle.topLeft()) # if settings.readBoolEntry("application/isDebuggerMode", False): # self.logger.warning("INFO:: Tiempo de carga de %s: %.3fs %s (iface %s)" % # (self.actionName_, tiempo_fin - self.tiempo_ini, self, self.iface)) # self.tiempo_ini = None def initMainWidget(self, w: Optional[QtWidgets.QWidget] = None) -> None: """Initialize widget.""" if not self.showed: self.show() def child(self, child_name: str) -> QtWidgets.QWidget: """Get child by name.""" ret = cast( QtWidgets.QWidget, self.findChild(QtWidgets.QWidget, child_name, QtCore.Qt.FindChildrenRecursively), ) if ret is not None: from . import flfielddb, fltabledb if isinstance(ret, (flfielddb.FLFieldDB, fltabledb.FLTableDB)): if ret._loaded is False: ret.load() return ret # def __getattr__(self, name): # if getattr(self.script, "form", None): # return getattr(self.script.form, name) # else: # qWarning("%s (%s):No se encuentra el atributo %s" % (self, self.iface, name)) @decorators.NotImplementedWarn def exportToXml(self, b: bool) -> None: """Export this widget into an xml.""" from pineboolib.fllegacy.aqsobjects.aqs import AQS xml = AQS.toXml(self, True, True) print(xml.toString(2)) pass
def __init__(self) -> None: """Initialize a new instance.""" self._logger = logging.getLogger(__name__)
class FLFormRecordDB(flformdb.FLFormDB): """ FLFormRecordDBInterface Class. FLFormDB subclass designed to edit records. Basically this class does the same as its class FLFormDB base, the only thing you add is two buttons Accept and / or Cancel to confirm or cancel the changes that are made to the components of data it contains. This class is suitable for loading forms editing records defined in metadata (FLTableMetaData). @author InfoSiAL S.L. """ logger = logging.getLogger("FLFormRecordDB") """ Boton Aceptar """ pushButtonAccept: Optional[QtWidgets.QToolButton] """ Boton Aceptar y continuar """ pushButtonAcceptContinue: Optional[QtWidgets.QToolButton] """ Boton Primero """ pushButtonFirst: Optional[QtWidgets.QToolButton] """ Boton Anterior """ pushButtonPrevious: Optional[QtWidgets.QToolButton] """ Boton Siguiente """ pushButtonNext: Optional[QtWidgets.QToolButton] """ Boton Ultimo """ pushButtonLast: Optional[QtWidgets.QToolButton] """ Indica si se debe mostrar el botón Aceptar y Continuar """ showAcceptContinue_: bool """ Indica que se está intentando aceptar los cambios """ accepting: bool """ Modo en el que inicialmente está el cursor """ initialModeAccess: int """ Registra el nivel de anidamiento de transacciones en el que se entra al iniciar el formulario """ initTransLevel: int def __init__( self, action: "pnaction.PNAction", parent_or_cursor: Optional[Union[QtWidgets.QWidget, "isqlcursor.ISqlCursor", int]] = None, load: bool = False, ) -> None: """ Inicialize. """ self.logger.trace("__init__: parent_or_cursor=%s, action=%s, load=%s", parent_or_cursor, action, load) cursor: Optional[pnsqlcursor.PNSqlCursor] = None parent: Optional[QtWidgets.QWidget] = None if isinstance(parent_or_cursor, pnsqlcursor.PNSqlCursor): cursor = parent_or_cursor elif isinstance(parent_or_cursor, QtWidgets.QWidget): parent = parent_or_cursor super().__init__(action, parent, load) self.setWindowModality(QtCore.Qt.ApplicationModal) if cursor: self.setCursor(cursor) self.logger.trace("__init__: load formRecord") self._uiName = action.formRecord() self._scriptForm = action.scriptFormRecord() or "emptyscript" self.bottomToolbar = None self.pushButtonAccept = None self.pushButtonAcceptContinue = None self.pushButtonFirst = None self.pushButtonPrevious = None self.pushButtonNext = None self.pushButtonLast = None self.accepting = False self.showAcceptContinue_ = True self.initialModeAccess = pnsqlcursor.PNSqlCursor.Browse if self.cursor_: self.initialModeAccess = self.cursor_.modeAccess() self.logger.trace("__init__: load form") self.load() self.logger.trace("__init__: init form") self.initForm() self.logger.trace("__init__: done") self.loop = False def setCaptionWidget(self, text: Optional[str] = None) -> None: """ Set the window title. """ if not self.cursor_: return if not text: text = self.cursor_.metadata().alias() if self.cursor_.modeAccess() == self.cursor_.Insert: self.setWindowTitle("Insertar %s" % text) elif self.cursor_.modeAccess() == self.cursor_.Edit: self.setWindowTitle("Editar %s" % text) elif self.cursor_.modeAccess() == self.cursor_.Browse: self.setWindowTitle("Visualizar %s" % text) def formClassName(self) -> str: """ Return the class name of the form at runtime. """ return "FormRecordDB" def initForm(self) -> None: """ Initialize the form. """ if self.cursor_ and self.cursor_.metadata(): # caption = None if self._action: self.cursor().setAction(self._action) if self._action.description(): self.setWhatsThis(self._action.description()) self.idMDI_ = self._action.name() # self.bindIface() # self.setCursor(self.cursor_) else: self.setCaptionWidget("No hay metadatos") acl = flapplication.aqApp.acl() if acl: acl.process(self) def loadControls(self) -> None: """Load widgets for this form.""" if self.pushButtonAcceptContinue: self.pushButtonAcceptContinue.hide() if self.pushButtonAccept: self.pushButtonAccept.hide() if self.pushButtonCancel: self.pushButtonCancel.hide() if self.pushButtonFirst: self.pushButtonFirst.hide() if self.pushButtonPrevious: self.pushButtonPrevious.hide() if self.pushButtonNext: self.pushButtonNext.hide() if self.pushButtonLast: self.pushButtonLast.hide() if self.bottomToolbar and self.toolButtonClose: self.toolButtonClose.hide() self.bottomToolbar = QtWidgets.QFrame() if self.bottomToolbar: self.bottomToolbar.setMinimumSize(self.iconSize) hblay = QtWidgets.QHBoxLayout() hblay.setContentsMargins(0, 0, 0, 0) hblay.setSpacing(0) hblay.addStretch() self.bottomToolbar.setLayout(hblay) self.bottomToolbar.setFocusPolicy(QtCore.Qt.NoFocus) self.layout_.addWidget(self.bottomToolbar) else: raise Exception("bottomToolbar is missing!") # if self.layout: # self.layout = None # Limpiamos la toolbar sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy(0), QtWidgets.QSizePolicy.Policy(0)) sizePolicy.setHeightForWidth(True) pbSize = self.iconSize if settings.config.value("application/isDebuggerMode", False): pushButtonExport = QtWidgets.QToolButton() pushButtonExport.setObjectName("pushButtonExport") pushButtonExport.setSizePolicy(sizePolicy) pushButtonExport.setMinimumSize(pbSize) pushButtonExport.setMaximumSize(pbSize) pushButtonExport.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-properties.png"))) pushButtonExport.setShortcut(Qt.QKeySequence(self.tr("F3"))) pushButtonExport.setWhatsThis("Exportar a XML(F3)") pushButtonExport.setToolTip("Exportar a XML(F3)") pushButtonExport.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(pushButtonExport) pushButtonExport.clicked.connect(self.exportToXml) if settings.config.value("ebcomportamiento/show_snaptshop_button", False): push_button_snapshot = QtWidgets.QToolButton() push_button_snapshot.setObjectName("pushButtonSnapshot") push_button_snapshot.setSizePolicy(sizePolicy) push_button_snapshot.setMinimumSize(pbSize) push_button_snapshot.setMaximumSize(pbSize) push_button_snapshot.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-paste.png"))) push_button_snapshot.setShortcut(Qt.QKeySequence( self.tr("F8"))) push_button_snapshot.setWhatsThis("Capturar pantalla(F8)") push_button_snapshot.setToolTip("Capturar pantalla(F8)") push_button_snapshot.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(push_button_snapshot) push_button_snapshot.clicked.connect(self.saveSnapShot) spacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) self.bottomToolbar.layout().addItem(spacer) if self.cursor().modeAccess() in (self.cursor().Edit, self.cursor().Browse): if not self.pushButtonFirst: self.pushButtonFirst = QtWidgets.QToolButton() self.pushButtonFirst.setObjectName("pushButtonFirst") self.pushButtonFirst.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-goto-first-ltr.png"))) self.pushButtonFirst.clicked.connect(self.firstRecord) self.pushButtonFirst.setSizePolicy(sizePolicy) self.pushButtonFirst.setMaximumSize(pbSize) self.pushButtonFirst.setMinimumSize(pbSize) self.pushButtonFirst.setShortcut(Qt.QKeySequence( self.tr("F5"))) self.pushButtonFirst.setWhatsThis( "Aceptar los cambios e ir al primer registro (F5)") self.pushButtonFirst.setToolTip( "Aceptar los cambios e ir al primer registro (F5)") self.pushButtonFirst.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(self.pushButtonFirst) # self.pushButtonFirst.show() if not self.pushButtonPrevious: self.pushButtonPrevious = QtWidgets.QToolButton() self.pushButtonPrevious.setObjectName("pushButtonPrevious") self.pushButtonPrevious.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-go-back-ltr.png"))) self.pushButtonPrevious.clicked.connect(self.previousRecord) self.pushButtonPrevious.setSizePolicy(sizePolicy) self.pushButtonPrevious.setMaximumSize(pbSize) self.pushButtonPrevious.setMinimumSize(pbSize) self.pushButtonPrevious.setShortcut( Qt.QKeySequence(self.tr("F6"))) self.pushButtonPrevious.setWhatsThis( "Aceptar los cambios e ir al registro anterior (F6)") self.pushButtonPrevious.setToolTip( "Aceptar los cambios e ir al registro anterior (F6)") self.pushButtonPrevious.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(self.pushButtonPrevious) # self.pushButtonPrevious.show() if not self.pushButtonNext: self.pushButtonNext = QtWidgets.QToolButton() self.pushButtonNext.setObjectName("pushButtonNext") self.pushButtonNext.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-go-back-rtl.png"))) self.pushButtonNext.clicked.connect(self.nextRecord) self.pushButtonNext.setSizePolicy(sizePolicy) self.pushButtonNext.setMaximumSize(pbSize) self.pushButtonNext.setMinimumSize(pbSize) self.pushButtonNext.setShortcut(Qt.QKeySequence(self.tr("F7"))) self.pushButtonNext.setWhatsThis( "Aceptar los cambios e ir al registro siguiente (F7)") self.pushButtonNext.setToolTip( "Aceptar los cambios e ir al registro siguiente (F7)") self.pushButtonNext.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(self.pushButtonNext) # self.pushButtonNext.show() if not self.pushButtonLast: self.pushButtonLast = QtWidgets.QToolButton() self.pushButtonLast.setObjectName("pushButtonLast") self.pushButtonLast.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-goto-last-ltr.png"))) self.pushButtonLast.clicked.connect(self.lastRecord) self.pushButtonLast.setSizePolicy(sizePolicy) self.pushButtonLast.setMaximumSize(pbSize) self.pushButtonLast.setMinimumSize(pbSize) self.pushButtonLast.setShortcut(Qt.QKeySequence(self.tr("F8"))) self.pushButtonLast.setWhatsThis( "Aceptar los cambios e ir al último registro (F8)") self.pushButtonLast.setToolTip( "Aceptar los cambios e ir al último registro (F8)") self.pushButtonLast.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(self.pushButtonLast) # self.pushButtonLast.show() if not self.cursor().modeAccess() == self.cursor().Browse: self.pushButtonAcceptContinue = QtWidgets.QToolButton() self.pushButtonAcceptContinue.setObjectName( "pushButtonAcceptContinue") self.pushButtonAcceptContinue.clicked.connect(self.acceptContinue) self.pushButtonAcceptContinue.setSizePolicy(sizePolicy) self.pushButtonAcceptContinue.setMaximumSize(pbSize) self.pushButtonAcceptContinue.setMinimumSize(pbSize) self.pushButtonAcceptContinue.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-refresh.png"))) self.pushButtonAcceptContinue.setShortcut( Qt.QKeySequence(self.tr("F9"))) self.pushButtonAcceptContinue.setWhatsThis( "Aceptar los cambios y continuar con la edición de un nuevo registro (F9)" ) self.pushButtonAcceptContinue.setToolTip( "Aceptar los cambios y continuar con la edición de un nuevo registro (F9)" ) self.pushButtonAcceptContinue.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget( self.pushButtonAcceptContinue) if not self.showAcceptContinue_: self.pushButtonAcceptContinue.close() # self.pushButtonAcceptContinue.show() if not self.pushButtonAccept: self.pushButtonAccept = QtWidgets.QToolButton() self.pushButtonAccept.setObjectName("pushButtonAccept") self.pushButtonAccept.clicked.connect(self.accept) self.pushButtonAccept.setSizePolicy(sizePolicy) self.pushButtonAccept.setMaximumSize(pbSize) self.pushButtonAccept.setMinimumSize(pbSize) self.pushButtonAccept.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-save.png"))) self.pushButtonAccept.setShortcut(Qt.QKeySequence(self.tr("F10"))) self.pushButtonAccept.setWhatsThis( "Aceptar los cambios y cerrar formulario (F10)") self.pushButtonAccept.setToolTip( "Aceptar los cambios y cerrar formulario (F10)") self.pushButtonAccept.setFocusPolicy(QtCore.Qt.NoFocus) self.bottomToolbar.layout().addWidget(self.pushButtonAccept) # self.pushButtonAccept.show() if not self.pushButtonCancel: self.pushButtonCancel = QtWidgets.QToolButton() self.pushButtonCancel.setObjectName("pushButtonCancel") try: self.cursor().autoCommit.connect(self.disablePushButtonCancel) except Exception: pass self.pushButtonCancel.clicked.connect(self.reject) self.pushButtonCancel.setSizePolicy(sizePolicy) self.pushButtonCancel.setMaximumSize(pbSize) self.pushButtonCancel.setMinimumSize(pbSize) self.pushButtonCancel.setShortcut(Qt.QKeySequence(self.tr("Esc"))) self.pushButtonCancel.setIcon( QtGui.QIcon( utils_base.filedir("./core/images/icons", "gtk-stop.png"))) if not self.cursor().modeAccess() == self.cursor().Browse: self.pushButtonCancel.setFocusPolicy(QtCore.Qt.NoFocus) self.pushButtonCancel.setWhatsThis( "Cancelar los cambios y cerrar formulario (Esc)") self.pushButtonCancel.setToolTip( "Cancelar los cambios y cerrar formulario (Esc)") else: self.pushButtonCancel.setFocusPolicy(QtCore.Qt.StrongFocus) self.pushButtonCancel.setFocus() # pushButtonCancel->setAccel(4096); FIXME self.pushButtonCancel.setWhatsThis( "Aceptar y cerrar formulario (Esc)") self.pushButtonCancel.setToolTip( "Aceptar y cerrar formulario (Esc)") # pushButtonCancel->setDefault(true); self.bottomToolbar.layout().addItem( QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) self.bottomToolbar.layout().addWidget(self.pushButtonCancel) # self.pushButtonAccept.show() self.setFocusPolicy(QtCore.Qt.NoFocus) # self.toolButtonAccept = QtGui.QToolButton() # self.toolButtonAccept.setIcon(QtGui.QIcon(utils_base.filedir("./core/images/icons","gtk-add.png"))) # self.toolButtonAccept.clicked.connect(self.validateForm) # self.bottomToolbar.layout.addWidget(self.toolButtonAccept) self.inicializeControls() def formName(self) -> str: """ Return internal form name. """ return "formRecord%s" % self.idMDI_ def closeEvent(self, e: QtCore.QEvent) -> None: """ Capture event close. """ self.frameGeometry() if self.focusWidget(): parent = self.focusWidget().parentWidget() if parent: fdb = cast(flfielddb.FLFieldDB, parent) acf_ = getattr(fdb, "autoComFrame_", None) if acf_ and acf_.autoComFrame_.isVisible(): acf_.hide() return if self.cursor_: try: levels = self.cursor_.transactionLevel() - self.initTransLevel if levels > 0: self.cursor_.rollbackOpened( levels, "Se han detectado transacciones no finalizadas en la última operación.\n" "Se van a cancelar las transacciones pendientes.\n" "Los últimos datos introducidos no han sido guardados, por favor\n" "revise sus últimas acciones y repita las operaciones que no\n" "se han guardado.\n" "FLFormRecordDB::closeEvent: %s %s" % (levels, self.name()), ) except Exception: print( "ERROR: FLFormRecordDB @ closeEvent :: las transacciones aún no funcionan." ) if self.accepted_: if not self.cursor_.commit(): return self.afterCommitTransaction() else: if not self.cursor_.rollback(): e.ignore() return # else: # self.cursor_.select() self.closed.emit() self.setCursor(None) else: self.closed.emit() super(FLFormRecordDB, self).closeEvent(e) self.deleteLater() def validateForm(self) -> bool: """ Form validation. Call the "validateForm" function of the associated script when the form and only continue with the commit commit when that function of script returns TRUE. If FLTableMetaData :: concurWarn () is true and two or more sessions / users are. Modifying the same fields will display a warning notice. @return TRUE if the form has been validated correctly. """ if not self.cursor_: return True mtd = self.cursor_.metadata() if not mtd: return True if self.cursor_.modeAccess( ) == pnsqlcursor.PNSqlCursor.Edit and mtd.concurWarn(): colFields = self.cursor_.concurrencyFields() if colFields: pKN = mtd.primaryKey() pKWhere = (self.cursor_.db().connManager().manager(). formatAssignValue(mtd.field(pKN), self.cursor_.valueBuffer(pKN))) q = pnsqlquery.PNSqlQuery(None, self.cursor_.db().connectionName()) q.setTablesList(mtd.name()) q.setSelect(colFields) q.setFrom(mtd.name()) q.setWhere(pKWhere) q.setForwardOnly(True) if q.exec_() and q.next(): i = 0 for field in colFields: # msg = "El campo '%s' con valor '%s' ha sido modificado\npor otro usuario con el valor '%s'" % ( # mtd.fieldNameToAlias(field), self.cursor_.valueBuffer(field), q.value(i)) res = QtWidgets.QMessageBox.warning( QtWidgets.QApplication.focusWidget(), "Aviso de concurrencia", "\n\n ¿ Desea realmente modificar este campo ?\n\n" "Sí : Ignora el cambio del otro usuario y utiliza el valor que acaba de introducir\n" "No : Respeta el cambio del otro usuario e ignora el valor que ha introducido\n" "Cancelar : Cancela el guardado del registro y vuelve a la edición del registro\n\n", cast( QtWidgets.QMessageBox.StandardButtons, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Default, ), cast( QtWidgets.QMessageBox.StandardButton, QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Escape, ), ) if res == QtWidgets.QMessageBox.Cancel: return False if res == QtWidgets.QMessageBox.No: self.cursor_.setValueBuffer(field, q.value(i)) if (self.iface and self.cursor_.modeAccess() == pnsqlcursor.PNSqlCursor.Insert or self.cursor_.modeAccess() == pnsqlcursor.PNSqlCursor.Edit): ret_ = True fun_ = getattr(self.iface, "validateForm", None) if fun_ is not None and fun_ != self.validateForm: try: ret_ = fun_() except Exception: # script_name = self.iface.__module__ from pineboolib.core.error_manager import error_manager from pineboolib import application flapplication.aqApp.msgBoxWarning( error_manager( traceback.format_exc(limit=-6, chain=False)), application.PROJECT.DGI, ) return ret_ if isinstance(ret_, bool) else True return True def acceptedForm(self) -> None: """ Accept of form. Call the "acceptedForm" function of the script associated with the form, when the form is accepted and just before committing the registration. """ if self.iface: try: self.iface.acceptedForm() except Exception: pass def afterCommitBuffer(self) -> None: """ After setting the changes of the current record buffer. Call the "afterCommitBuffer" function of the script associated with the form right after committing the registry buffer. """ if self.iface: try: self.iface.afterCommitBuffer() except Exception: pass def afterCommitTransaction(self) -> None: """ After fixing the transaction. Call the "afterCommitTransaction" function of the script associated with the form, right after finishing the current transaction accepting. """ if self.iface: try: self.iface.afterCommitTransaction() except Exception: pass def canceledForm(self) -> None: """ Form Cancellation. Call the "canceledForm" function of the script associated with the form, when cancel the form. """ if self.iface: try: self.iface.canceledForm() except Exception: pass @decorators.pyqtSlot() def accept(self) -> None: """ Activate pressing the accept button. """ if self.accepting: return self.accepting = True if not self.cursor_: self.close() self.accepting = False return if not self.validateForm(): self.accepting = False return if self.cursor_.checkIntegrity(): self.acceptedForm() self.cursor_.setActivatedCheckIntegrity(False) if not self.cursor_.commitBuffer(): self.accepting = False return else: self.cursor_.setActivatedCheckIntegrity(True) else: self.accepting = False return self.afterCommitBuffer() self.accepted_ = True self.close() self.accepting = False @decorators.pyqtSlot() def acceptContinue(self) -> None: """ Activate pressing the accept and continue button. """ if self.accepting: return self.accepting = True if not self.cursor_: self.close() self.accepting = False return if not self.validateForm(): self.accepting = False return if self.cursor_.checkIntegrity(): self.acceptedForm() self.cursor_.setActivatedCheckIntegrity(False) if self.cursor_.commitBuffer(): self.cursor_.setActivatedCheckIntegrity(True) self.cursor_.commit() self.cursor_.setModeAccess(pnsqlcursor.PNSqlCursor.Insert) self.accepted_ = False caption = None if self._action: caption = self._action.name() if not caption: caption = self.cursor_.metadata().alias() self.cursor_.transaction() self.setCaptionWidget(caption) if self.initFocusWidget_: self.initFocusWidget_.setFocus() self.cursor_.refreshBuffer() self.initScript() self.accepting = False @decorators.pyqtSlot() def reject(self) -> None: """ Activate pressing the cancel button. """ self.accepted_ = False self.canceledForm() self.close() @decorators.pyqtSlot() @decorators.NotImplementedWarn def script(self) -> None: """ Return the script associated with the form. """ pass @decorators.pyqtSlot() def firstRecord(self) -> None: """ Go to the first record. """ if self.cursor_ and not self.cursor_.at() == 0: if not self.validateForm(): return if self.cursor_.checkIntegrity(): self.acceptedForm() self.cursor_.setActivatedCheckIntegrity(False) if self.cursor_.commitBuffer(): self.cursor_.setActivatedCheckIntegrity(True) self.cursor_.commit() self.cursor_.setModeAccess(self.initialModeAccess) self.accepted_ = False self.cursor_.transaction() self.cursor_.first() self.setCaptionWidget() self.initScript() @decorators.pyqtSlot() def previousRecord(self) -> None: """ Go to the previous record. """ if self.cursor_ and self.cursor_.isValid(): if self.cursor_.at() == 0: self.lastRecord() return if not self.validateForm(): return if self.cursor_.checkIntegrity(): self.acceptedForm() self.cursor_.setActivatedCheckIntegrity(False) if self.cursor_.commitBuffer(): self.cursor_.setActivatedCheckIntegrity(True) self.cursor_.commit() self.cursor_.setModeAccess(self.initialModeAccess) self.accepted_ = False self.cursor_.transaction() self.cursor_.prev() self.setCaptionWidget() self.initScript() @decorators.pyqtSlot() def nextRecord(self) -> None: """ Go to the next record. """ if self.cursor_ and self.cursor_.isValid(): if self.cursor_.at() == (self.cursor_.size() - 1): self.firstRecord() return if not self.validateForm(): return if self.cursor_.checkIntegrity(): self.acceptedForm() self.cursor_.setActivatedCheckIntegrity(False) if self.cursor_.commitBuffer(): self.cursor_.setActivatedCheckIntegrity(True) self.cursor_.commit() self.cursor_.setModeAccess(self.initialModeAccess) self.accepted_ = False self.cursor_.transaction() self.cursor_.next() self.setCaptionWidget() self.initScript() @decorators.pyqtSlot() def lastRecord(self) -> None: """ Go to the last record. """ if self.cursor_ and not self.cursor_.at() == (self.cursor_.size() - 1): if not self.validateForm(): return if self.cursor_.checkIntegrity(): self.acceptedForm() self.cursor_.setActivatedCheckIntegrity(False) if self.cursor_.commitBuffer(): self.cursor_.setActivatedCheckIntegrity(True) self.cursor_.commit() self.cursor_.setModeAccess(self.initialModeAccess) self.accepted_ = False self.cursor_.transaction() self.cursor_.last() self.setCaptionWidget() self.initScript() @decorators.pyqtSlot() def disablePushButtonCancel(self) -> None: """ Turn off the cancel button. """ if self.pushButtonCancel: self.pushButtonCancel.setDisabled(True) def show(self) -> None: """Show this widget.""" caption = self._action.caption() if not caption: caption = self.cursor().metadata().alias() cur = self.cursor_ iface = getattr(self.script, "iface", None) if cur: if not cur.isValid(): cur.model().refresh() if cur.modeAccess() in (cur.Insert, cur.Edit, cur.Browse): cur.transaction() self.initTransLevel = cur.transactionLevel() if cur.modeAccess() == pnsqlcursor.PNSqlCursor.Insert: self.showAcceptContinue_ = True else: self.showAcceptContinue_ = False self.loadControls() if iface is not None: cur.setContext(iface) self.setCaptionWidget(caption) super().show() def inicializeControls(self) -> None: """Initialize UI controls for this form.""" from pineboolib.fllegacy.flfielddb import FLFieldDB for child_ in self.findChildren(QtWidgets.QWidget): if isinstance(child_, FLFieldDB): loaded = getattr(child_, "_loaded", None) if loaded is False: QtCore.QTimer.singleShot(0, child_.load) def show_and_wait(self) -> None: """Show this form blocking for exit.""" if self.loop: raise Exception( "show_and_wait(): Se ha detectado una llamada recursiva") self.loop = True self.show() if self.eventloop: self.eventloop.exec_() self.loop = False def hide(self) -> None: """Hide this form.""" if self.loop: self.eventloop.exit()
from pineboolib.application.utils.path import _path from pineboolib.core.utils.utils_base import filedir from pineboolib.core.settings import config from importlib import machinery from sqlalchemy import String # type: ignore import importlib import traceback import sys import os from pineboolib import logging, application from typing import Any LOGGER = logging.getLogger("PNORMModelsFactory") # processed_: List[str] = [] def base_model(name: str) -> Any: """Import and return sqlAlchemy model for given table name.""" # print("Base", name) if application.PROJECT.conn_manager is None: raise Exception("Project is not connected yet") path = _path("%s.mtd" % name, False) if path is None: return None if path.find("system_module/tables") > -1:
"""Test Eneboo module.""" import unittest from PyQt5 import QtWidgets from pineboolib.loader.main import init_testing, finish_testing from pineboolib.core.settings import config from pineboolib import application from . import fixture_path from pineboolib import logging logger = logging.getLogger("eneboo_%s" % __name__) class TestEnebooGUI(unittest.TestCase): """Tes EnebooGUI class.""" prev_main_window_name: str @classmethod def setUpClass(cls) -> None: """Ensure pineboo is initialized for testing.""" config.set_value("application/isDebuggerMode", True) config.set_value("application/dbadmin_enabled", True) cls.prev_main_window_name = config.value( "ebcomportamiento/main_form_name", "eneboo") config.set_value("ebcomportamiento/main_form_name", "eneboo") init_testing()
"""conn_dialog module.""" from pineboolib import logging from PyQt5 import QtWidgets from pineboolib.loader.projectconfig import ProjectConfig from typing import Optional LOGGER = logging.getLogger("loader.conn_dialog") def show_connection_dialog( app: QtWidgets.QApplication) -> Optional[ProjectConfig]: """Show the connection dialog, and configure the project accordingly.""" from .dlgconnect import DlgConnect connection_window = DlgConnect() connection_window.load() connection_window.show() app.exec_() # FIXME: App should be started before this function connection_window.close() return connection_window.selected_project_config
from pineboolib.application.utils import check_dependencies from pineboolib import application, logging from pineboolib.core import settings from . import flmysql_myisam import traceback from typing import Any, Dict, cast, List, TYPE_CHECKING if TYPE_CHECKING: from pineboolib.application.metadata import pntablemetadata # noqa: F401 LOGGER = logging.getLogger(__name__) class FLMYSQL_MYISAM2(flmysql_myisam.FLMYSQL_MYISAM): """MYISAM2 Driver class.""" cursorsArray_: Dict[str, Any] # IApiCursor rowsFetched: Dict[str, List] def __init__(self): """Create empty driver.""" super().__init__() self.name_ = "FLMYSQL_MyISAM2" self.alias_ = "MySQL MyISAM (PyMySQL)" self.cursorsArray_ = {} self.mobile_ = True
""" Finalize pineboo setup and load. """ from pineboolib import logging from typing import Any LOGGER = logging.getLogger("loader.init_project") def init_project(dgi: Any, options: Any, project: Any, main_form: Any, app: Any) -> Any: """Initialize the project and start it.""" # from PyQt5 import QtCore # type: ignore # if dgi.useDesktop() and dgi.localDesktop() and splash: # splash.showMessage("Iniciando proyecto ...", QtCore.Qt.AlignLeft, QtCore.Qt.white) # dgi.processEvents() LOGGER.info("Iniciando proyecto ...") if options.preload: from .preload import preload_actions preload_actions(project, options.forceload) LOGGER.info("Finished preloading") return if options.action: list = options.action.split(":") action_name = list[0].split(".")[0] # FIXME: Why is commented out?