def a_imagen(self, de_muestra=False, svg=False): """Devuelve la imagen para imprimir el apertura.""" titulo = _("titulo_apertura") try: presidente = self.autoridades[0] except IndexError: presidente = "" suplentes = self.autoridades[1:] mesa = self.mesa datos = { 'presidente': presidente, 'suplentes': suplentes, 'cantidad_suplentes': len(suplentes), 'mesa': mesa.numero, 'escuela': mesa.escuela, 'municipio': mesa.municipio, 'departamento': mesa.departamento, 'horas': "%02d" % self.hora['horas'], 'minutos': "%02d" % self.hora['minutos'], 'mostrar_texto': True, 'leyenda': None, 'pie': "|".join([mesa.codigo, str(mesa.id_planilla), mesa.escuela]), "cod_datos": self.mesa.cod_datos, } config = Config(["imaging"], mesa.cod_datos) usar_qr = config.val("usar_qr") qr_img = self.a_qr_b64_encoded() if usar_qr and not de_muestra else None imagen = ImagenActa(titulo, datos, de_muestra=de_muestra, qr=qr_img) if svg: rendered = imagen.render_svg() else: rendered = imagen.render_image() return rendered
class Imagen(object): """Clase base para las imagenes del modulo.""" def generate_data(self): """Genera la data para enviar al template.""" raise NotImplementedError("You must implement on subclass") def render_template(self): self.rendered_template = jinja_env.get_template(self.template) def render_svg(self): """Renderiza el SVG.""" data = self.generate_data() xml = self.rendered_template.render(**data) return xml def render_image(self): """Renderiza la imagen.""" xml = self.render_svg() return xml2pil(xml, self.data['width'], self.data['height']) def _get_img_b64(self, img_path): """Devuelve la imagen en base64 formato browser.""" image = open(img_path, 'rb') img_data = image.read() img_data = encodestring(img_data) image.close() img_link = "data:image/png;base64,%s" % img_data.decode() return img_link def config(self, key, id_ubicacion=None): self._config = Config(["imaging"], id_ubicacion) value, file_ = self._config.data(key) logger.debug("Trayendo config {}: {} desde {}".format( key, value, file_)) return value
def a_imagen(self, de_muestra=False, svg=False): """Devuelve la imagen para imprimir el apertura.""" titulo = _("titulo_apertura") try: presidente = self.autoridades[0] except IndexError: presidente = "" suplentes = self.autoridades[1:] mesa = self.mesa datos = { 'presidente': presidente, 'suplentes': suplentes, 'cantidad_suplentes': len(suplentes), 'mesa': mesa.numero, 'escuela': mesa.escuela, 'municipio': mesa.municipio, 'departamento': mesa.departamento, 'horas': "%02d" % self.hora['horas'], 'minutos': "%02d" % self.hora['minutos'], 'mostrar_texto': True, 'leyenda': None, 'pie': "|".join([mesa.codigo, str(mesa.id_planilla), mesa.escuela]), "cod_datos": self.mesa.cod_datos, } config = Config(["imaging"], mesa.cod_datos) usar_qr = config.val("usar_qr") qr_img = self.a_qr_b64_encoded( ) if usar_qr and not de_muestra else None imagen = ImagenActa(titulo, datos, de_muestra=de_muestra, qr=qr_img) if svg: rendered = imagen.render_svg() else: rendered = imagen.render_image() return rendered
class Imagen(object): """Clase base para las imagenes del modulo.""" def generate_data(self): """Genera la data para enviar al template.""" raise NotImplementedError("You must implement on subclass") def render_template(self): self.rendered_template = jinja_env.get_template(self.template) def render_svg(self): """Renderiza el SVG.""" data = self.generate_data() xml = self.rendered_template.render(**data) return xml def render_image(self): """Renderiza la imagen.""" xml = self.render_svg() return xml2pil(xml, self.data['width'], self.data['height']) def _get_img_b64(self, img_path): """Devuelve la imagen en base64 formato browser.""" image = open(img_path, 'rb') img_data = image.read() img_data = encodestring(img_data) image.close() img_link = "data:image/png;base64,%s" % img_data.decode() return img_link def config(self, key, id_ubicacion=None): self._config = Config(["imaging"], id_ubicacion) value, file_ = self._config.data(key) logger.debug("Trayendo config {}: {} desde {}".format(key, value, file_)) return value
def a_imagen(self, tipo=None, de_muestra=False, svg=False): """Devuelve la imagen para imprimir recuento. Argumentos: tipo -- una tupla con el tipo de acta y el id_de grupo de categorias. Puede ser None si no no queremos agrupar. de_muestra -- es la imagen que no se imprime, que se muestra en pantalla. svg -- Devuelve un svg si True, en caso contrario un objeto PIL.Image """ if tipo is None: tipo = (CIERRE_RECUENTO, None) # Muestra el icono del verificador en la boleta. Si no tiene chip en el # documento en el que imprimimos no imprimirmos el verificador. verif = True # Por defecto no tenemos titulo, a menos que el tipo de acta tenga # titulo. titulo = "" leyenda = None # Internamente todas las actas son iguales, lo que cambia es el texto # que se imprime, pero el acta una vez serializada no sabe cual es. if tipo[0] == CIERRE_RECUENTO: # El acta de cierre. titulo = _("titulo_recuento") leyenda = _("no_insertar_en_urna") elif tipo[0] == CIERRE_TRANSMISION: # El acta de transmision. titulo = _("titulo_transmision") leyenda = _("no_insertar_en_urna") elif tipo[0] == CIERRE_CERTIFICADO or tipo[0] == CIERRE_ESCRUTINIO: # El certificado de escrutinio. titulo = _("titulo_certificado") verif = False elif tipo[0] == CIERRE_COPIA_FIEL: # Una copia fiel del certificado. (Certificado sin datos desc_mesa # autoridades) titulo = _("titulo_copia_fiel") verif = False grupo_cat = tipo[1] # Establecemos las autoridades para los templates del texto del acta, # los cuales hacen diferencia entre el presidente y los suplentes. try: presidente = self.autoridades[0] except IndexError: presidente = "" suplentes = [sup for sup in self.autoridades[1:] if sup.nro_documento != 0] mesa = self.mesa # Armamos los datos para el texto. datos = { 'presidente': presidente, 'suplentes': suplentes, 'cantidad_suplentes': len(suplentes), 'mesa': mesa.numero, 'escuela': mesa.escuela, 'municipio': mesa.municipio, 'departamento': mesa.departamento, 'horas': "%02d" % self.hora.get('horas', "") \ if self.hora is not None else "", 'minutos': "%02d" % self.hora.get('minutos', "") if self.hora is not None else "", 'mostrar_texto': self.hora is not None, 'leyenda': leyenda, 'pie': "|".join([mesa.codigo, str(mesa.id_planilla), mesa.escuela]), "cod_datos": self.mesa.cod_datos, } config = Config(["imaging"], mesa.cod_datos) usar_qr = config.val("usar_qr") # Generamos el QR que va a ir en el acta. qr_img = self.a_qr_b64_encoded(grupo_cat) if usar_qr else None # Y armamos la imagen. imagen = ImagenActa(titulo, datos, qr=qr_img, recuento=self, grupo_cat=grupo_cat, de_muestra=de_muestra, verificador=verif) if svg: rendered = imagen.render_svg() else: rendered = imagen.render_image() # Devolvemos la imagen en el formato solicitado. return rendered
class ModuloBase(object): """Modulo base. Implementa una pantalla y la funcionalidad basica.""" def __init__(self, nombre): """ Constructor.""" self.sesion = get_sesion() self.config_files = [COMMON_SETTINGS, nombre] self._load_config() self.nombre = nombre self.logger = self.sesion.logger self.pantalla = None self.ret_code = '' self.signal = None self.player = None self.plugin_manager = PluginManager self.plugin_manager.autoregister() self.ventana = self._inicializa_ventana() self._cargar_ui_web() sleep(0.2) self.ventana.show_all() def cambiar_po(self, nombre_po): """Cambia la localización.""" cambiar_po(nombre_po) def _inicializa_ventana(self): """Inicializa la ventana básica, tamaño, layout básico y títulos.""" ventana = Gtk.Window(Gtk.WindowType.TOPLEVEL) ventana.set_position(Gtk.WindowPosition.CENTER_ALWAYS) ventana.set_size_request(*SCREEN_SIZE) ventana.set_resizable(False) ventana.set_support_multidevice(False) ventana.set_title(APP_TITLE) ventana.set_border_width(WINDOW_BORDER_WIDTH) ventana.connect('destroy', self.quit) root_wnd = ventana.get_root_window() if MOSTRAR_CURSOR: cursor_type = Gdk.CursorType.LEFT_PTR else: cursor_type = Gdk.CursorType.BLANK_CURSOR cursor = Gdk.Cursor(cursor_type) root_wnd.set_cursor(cursor) if FULLSCREEN: ventana.fullscreen() self.logger.debug("Fin de inicializacion ventana") return ventana def _get_uri(self): html_name = '{}.html'.format(self.web_template) file_ = join(PATH_TEMPLATES_MODULOS, html_name) uri = 'file://' + pathname2url(file_) return uri def get_browser(self, uri): debug_callback = print_zaguan_input if DEBUG_ZAGUAN else None return self.controlador.get_browser(uri, debug=DEBUG_ZAGUAN, webkit_version=WEBKIT_VERSION, debug_callback=debug_callback) def _webkit2_touch(self, widget, event): """ Webkitgtk 2 no lanza el evento del DOM touchend y touchmove por un bug https://bugs.webkit.org/show_bug.cgi?id=158531 Por lo tanto muchos clicks no son capturados correctamente. Esta funcion intenta parchear el comportamiento y emitir el click cuando la persona hace algo con el dedo que no sea "el tipoco click con la punta" la mayoría de los clicks con la llema entran en esta funcion. """ # Agarro el evento de inicio del touch y guardo x, y timestamp if event.touch.type == Gdk.EventType.TOUCH_BEGIN: self.last_start = (event.x, event.y, event.get_time()) elif event.touch.type == Gdk.EventType.TOUCH_END: # Establezco la diferencia para los dos ejes dx = abs(self.last_start[0] - event.x) dy = abs(self.last_start[1] - event.y) # si hubo algun evento de touch start (que debería siempre haber) y # los dedos se movieron menos de 20 pixeles en ambas direcciones if self.last_start is not None and dx < 20 and dy < 20: # en alguno de los dos ejes el dedo de tiene que haber movido # al menos dos pixeles dist_diff = dx > 2 or dy > 2 time_diff = event.get_time() - self.last_start[2] # y el tiempo de click tiene que ser mayor a 250 milisegundos if dist_diff and time_diff > 250: data = { "x": event.x, "y": event.y, "dx": dx, "dy": dy } # Lanzo un click en la posicion del final del click self.controlador.send_command("lanzar_click", data) def _cargar_ui_web(self, agregar=True): """Carga el browser y lo mete en la ventana contenedora.""" uri = self._get_uri() self.browser = self.get_browser(uri) self.last_start = None self.browser.connect('touch-event', self._webkit2_touch) self.ventana.set_border_width(0) if agregar and self.browser is not None: self._agregar_browser() def _agregar_browser(self): """Agrega el browser a la ventana.""" self.ventana.add(self.browser) def _descargar_ui_web(self): """Descarga la UI web.""" if self.browser is not None: self.ventana.remove(self.browser) def set_pantalla(self, pantalla): """ Establece y muestra la pantalla en el panel principal del modulo Argumentos: pantalla -- la pantalla a mostrar. En realidad se muestra el atributo panel de esta pantalla """ if hasattr(self, 'pantalla') and self.pantalla is not None and \ len(self.panel.get_children()) > 0: self.panel.remove(self.pantalla) self.pantalla.destroy() self.pantalla = None self.pantalla = pantalla self.panel.add(self.pantalla) self.ventana.show_all() def main(self, titulo=None): """ Ejecuta el sistema """ Gdk.threads_init() # Habilito el modo touchscreen, que desactiva el hover del cursor #settings = Gtk.Settings.get_default() #settings.set_property('gtk-long-press-time', 5000) self.loop = GObject.MainLoop() if titulo is not None: self.ventana.set_title(titulo) self.loop.run() return self.ret_code def quit(self, w=None): """ Ejecuta Gtk.main_quit() y termina la ejecucion. """ if hasattr(self, "signal") and self.signal is not None: self.signal.remove() if hasattr(self, "signal_papel") and self.signal_papel is not None: self.signal_papel.remove() if self.sesion.lector is not None: self.sesion.lector.remover_consultar_lector() if self.sesion.impresora is not None: self.sesion.impresora.remover_consultar_tarjeta() if hasattr(self, "rampa"): self.rampa.desregistrar_eventos() if hasattr(self, 'pantalla') and self.pantalla is not None: self.pantalla.destroy() if hasattr(self, "browser") and self.browser is not None: if hasattr(self, "ventana"): self.ventana.remove(self.browser) self.browser.destroy() if hasattr(self, "ventana"): self.ventana.destroy() if hasattr(self, "loop"): self.loop.quit() return False def admin(self): """Levanta el modulo menu.""" self.salir_a_modulo(MODULO_MENU) def salir_a_modulo(self, modulo): self.logger.debug("Saliendo a modulo {}".format(modulo)) self.ret_code = modulo self.quit() def hide_dialogo(self): """Esconde el dialogo.""" self.controlador.hide_dialogo() def _start_audio(self): global _audio_player if _audio_player is None or not _audio_player.is_alive(): _audio_player = WavPlayer() _audio_player.start() self._player = _audio_player def _stop_audio(self): """Para el audioplayer.""" global _audio_player if _audio_player is not None: _audio_player.stop() def _play(self, nombre_sonido): self._start_audio() sonido = join(PATH_SONIDOS_VOTO, '{}.wav'.format(nombre_sonido)) self._player.play(sonido) def play_sonido_ok(self): self._play("ok") def play_sonido_warning(self): self._play("warning") def play_sonido_error(self): self._play("error") def play_sonido_tecla(self): self._play("tecla") def _load_config(self): id_ubicacion = None if self.sesion.mesa is not None: id_ubicacion = self.sesion.mesa.codigo self._config = Config(self.config_files, id_ubicacion) def config(self, key): value, file_ = self._config.data(key) self.logger.debug("Trayendo config {}: {} desde {}".format(key, value, file_)) return value
def _load_config(self): id_ubicacion = None if self.sesion.mesa is not None: id_ubicacion = self.sesion.mesa.codigo self._config = Config(self.config_files, id_ubicacion)
def a_imagen(self, tipo=None, de_muestra=False, svg=False): """Devuelve la imagen para imprimir recuento. Argumentos: tipo -- una tupla con el tipo de acta y el id_de grupo de categorias. Puede ser None si no no queremos agrupar. de_muestra -- es la imagen que no se imprime, que se muestra en pantalla. svg -- Devuelve un svg si True, en caso contrario un objeto PIL.Image """ if tipo is None: tipo = (CIERRE_RECUENTO, None) # Muestra el icono del verificador en la boleta. Si no tiene chip en el # documento en el que imprimimos no imprimirmos el verificador. verif = True # Por defecto no tenemos titulo, a menos que el tipo de acta tenga # titulo. titulo = "" leyenda = None # Internamente todas las actas son iguales, lo que cambia es el texto # que se imprime, pero el acta una vez serializada no sabe cual es. if tipo[0] == CIERRE_RECUENTO: # El acta de cierre. titulo = _("titulo_recuento") leyenda = _("no_insertar_en_urna") elif tipo[0] == CIERRE_TRANSMISION: # El acta de transmision. titulo = _("titulo_transmision") leyenda = _("no_insertar_en_urna") elif tipo[0] == CIERRE_CERTIFICADO or tipo[0] == CIERRE_ESCRUTINIO: # El certificado de escrutinio. titulo = _("titulo_certificado") verif = False elif tipo[0] == CIERRE_COPIA_FIEL: # Una copia fiel del certificado. (Certificado sin datos desc_mesa # autoridades) titulo = _("titulo_copia_fiel") verif = False grupo_cat = tipo[1] # Establecemos las autoridades para los templates del texto del acta, # los cuales hacen diferencia entre el presidente y los suplentes. try: presidente = self.autoridades[0] except IndexError: presidente = "" suplentes = [ sup for sup in self.autoridades[1:] if sup.nro_documento != 0 ] mesa = self.mesa # Armamos los datos para el texto. datos = { 'presidente': presidente, 'suplentes': suplentes, 'cantidad_suplentes': len(suplentes), 'mesa': mesa.numero, 'escuela': mesa.escuela, 'municipio': mesa.municipio, 'departamento': mesa.departamento, 'horas': "%02d" % self.hora.get('horas', "") \ if self.hora is not None else "", 'minutos': "%02d" % self.hora.get('minutos', "") if self.hora is not None else "", 'mostrar_texto': self.hora is not None, 'leyenda': leyenda, 'pie': "|".join([mesa.codigo, str(mesa.id_planilla), mesa.escuela]), "cod_datos": self.mesa.cod_datos, } config = Config(["imaging"], mesa.cod_datos) usar_qr = config.val("usar_qr") # Generamos el QR que va a ir en el acta. qr_img = self.a_qr_b64_encoded(grupo_cat) if usar_qr else None # Y armamos la imagen. imagen = ImagenActa(titulo, datos, qr=qr_img, recuento=self, grupo_cat=grupo_cat, de_muestra=de_muestra, verificador=verif) if svg: rendered = imagen.render_svg() else: rendered = imagen.render_image() # Devolvemos la imagen en el formato solicitado. return rendered
def config(self, key, id_ubicacion=None): self._config = Config(["imaging"], id_ubicacion) value, file_ = self._config.data(key) logger.debug("Trayendo config {}: {} desde {}".format(key, value, file_)) return value
class ModuloBase(object): """Modulo base. Implementa una pantalla y la funcionalidad basica.""" def __init__(self, nombre): """ Constructor.""" self.sesion = get_sesion() self.config_files = [COMMON_SETTINGS, nombre] self._load_config() self.nombre = nombre self.logger = self.sesion.logger self.pantalla = None self.ret_code = '' self.signal = None self.player = None self.plugin_manager = PluginManager self.plugin_manager.autoregister() self.ventana = self._inicializa_ventana() self._cargar_ui_web() sleep(0.2) self.ventana.show_all() def cambiar_po(self, nombre_po): """Cambia la localización.""" cambiar_po(nombre_po) def _inicializa_ventana(self): """Inicializa la ventana básica, tamaño, layout básico y títulos.""" ventana = Gtk.Window(Gtk.WindowType.TOPLEVEL) ventana.set_position(Gtk.WindowPosition.CENTER_ALWAYS) ventana.set_size_request(*SCREEN_SIZE) ventana.set_resizable(False) ventana.set_support_multidevice(False) ventana.set_title(APP_TITLE) ventana.set_border_width(WINDOW_BORDER_WIDTH) ventana.connect('destroy', self.quit) root_wnd = ventana.get_root_window() if MOSTRAR_CURSOR: cursor_type = Gdk.CursorType.LEFT_PTR else: cursor_type = Gdk.CursorType.BLANK_CURSOR cursor = Gdk.Cursor(cursor_type) root_wnd.set_cursor(cursor) if FULLSCREEN: ventana.fullscreen() self.logger.debug("Fin de inicializacion ventana") return ventana def _get_uri(self): html_name = '{}.html'.format(self.web_template) file_ = join(PATH_TEMPLATES_MODULOS, html_name) uri = 'file://' + pathname2url(file_) return uri def get_browser(self, uri): debug_callback = print_zaguan_input if DEBUG_ZAGUAN else None return self.controlador.get_browser(uri, debug=DEBUG_ZAGUAN, webkit_version=WEBKIT_VERSION, debug_callback=debug_callback) def _webkit2_touch(self, widget, event): """ Webkitgtk 2 no lanza el evento del DOM touchend y touchmove por un bug https://bugs.webkit.org/show_bug.cgi?id=158531 Por lo tanto muchos clicks no son capturados correctamente. Esta funcion intenta parchear el comportamiento y emitir el click cuando la persona hace algo con el dedo que no sea "el tipoco click con la punta" la mayoría de los clicks con la llema entran en esta funcion. """ # Agarro el evento de inicio del touch y guardo x, y timestamp if event.touch.type == Gdk.EventType.TOUCH_BEGIN: self.last_start = (event.x, event.y, event.get_time()) elif event.touch.type == Gdk.EventType.TOUCH_END: # Establezco la diferencia para los dos ejes dx = abs(self.last_start[0] - event.x) dy = abs(self.last_start[1] - event.y) # si hubo algun evento de touch start (que debería siempre haber) y # los dedos se movieron menos de 20 pixeles en ambas direcciones if self.last_start is not None and dx < 20 and dy < 20: # en alguno de los dos ejes el dedo de tiene que haber movido # al menos dos pixeles dist_diff = dx > 2 or dy > 2 time_diff = event.get_time() - self.last_start[2] # y el tiempo de click tiene que ser mayor a 250 milisegundos if dist_diff and time_diff > 250: data = {"x": event.x, "y": event.y, "dx": dx, "dy": dy} # Lanzo un click en la posicion del final del click self.controlador.send_command("lanzar_click", data) def _cargar_ui_web(self, agregar=True): """Carga el browser y lo mete en la ventana contenedora.""" uri = self._get_uri() self.browser = self.get_browser(uri) self.last_start = None self.browser.connect('touch-event', self._webkit2_touch) self.ventana.set_border_width(0) if agregar and self.browser is not None: self._agregar_browser() def _agregar_browser(self): """Agrega el browser a la ventana.""" self.ventana.add(self.browser) def _descargar_ui_web(self): """Descarga la UI web.""" if self.browser is not None: self.ventana.remove(self.browser) def set_pantalla(self, pantalla): """ Establece y muestra la pantalla en el panel principal del modulo Argumentos: pantalla -- la pantalla a mostrar. En realidad se muestra el atributo panel de esta pantalla """ if hasattr(self, 'pantalla') and self.pantalla is not None and \ len(self.panel.get_children()) > 0: self.panel.remove(self.pantalla) self.pantalla.destroy() self.pantalla = None self.pantalla = pantalla self.panel.add(self.pantalla) self.ventana.show_all() def main(self, titulo=None): """ Ejecuta el sistema """ Gdk.threads_init() # Habilito el modo touchscreen, que desactiva el hover del cursor #settings = Gtk.Settings.get_default() #settings.set_property('gtk-long-press-time', 5000) self.loop = GObject.MainLoop() if titulo is not None: self.ventana.set_title(titulo) self.loop.run() return self.ret_code def quit(self, w=None): """ Ejecuta Gtk.main_quit() y termina la ejecucion. """ if hasattr(self, "signal") and self.signal is not None: self.signal.remove() if hasattr(self, "signal_papel") and self.signal_papel is not None: self.signal_papel.remove() if self.sesion.lector is not None: self.sesion.lector.remover_consultar_lector() if self.sesion.impresora is not None: self.sesion.impresora.remover_consultar_tarjeta() if hasattr(self, "rampa"): self.rampa.desregistrar_eventos() if hasattr(self, 'pantalla') and self.pantalla is not None: self.pantalla.destroy() if hasattr(self, "browser") and self.browser is not None: if hasattr(self, "ventana"): self.ventana.remove(self.browser) self.browser.destroy() if hasattr(self, "ventana"): self.ventana.destroy() if hasattr(self, "loop"): self.loop.quit() return False def admin(self): """Levanta el modulo menu.""" self.salir_a_modulo(MODULO_MENU) def salir_a_modulo(self, modulo): self.logger.debug("Saliendo a modulo {}".format(modulo)) self.ret_code = modulo self.quit() def hide_dialogo(self): """Esconde el dialogo.""" self.controlador.hide_dialogo() def _start_audio(self): global _audio_player if _audio_player is None or not _audio_player.is_alive(): _audio_player = WavPlayer() _audio_player.start() self._player = _audio_player def _stop_audio(self): """Para el audioplayer.""" global _audio_player if _audio_player is not None: _audio_player.stop() def _play(self, nombre_sonido): self._start_audio() sonido = join(PATH_SONIDOS_VOTO, '{}.wav'.format(nombre_sonido)) self._player.play(sonido) def play_sonido_ok(self): self._play("ok") def play_sonido_warning(self): self._play("warning") def play_sonido_error(self): self._play("error") def play_sonido_tecla(self): self._play("tecla") def _load_config(self): id_ubicacion = None if self.sesion.mesa is not None: id_ubicacion = self.sesion.mesa.codigo self._config = Config(self.config_files, id_ubicacion) def config(self, key): value, file_ = self._config.data(key) self.logger.debug("Trayendo config {}: {} desde {}".format( key, value, file_)) return value
def config(self, key, id_ubicacion=None): self._config = Config(["imaging"], id_ubicacion) value, file_ = self._config.data(key) logger.debug("Trayendo config {}: {} desde {}".format( key, value, file_)) return value