diff options
author | Rogelio Mita <rogeliomita@activitycentral.com> | 2013-06-11 14:23:23 (GMT) |
---|---|---|
committer | Rogelio Mita <rogeliomita@activitycentral.com> | 2013-06-11 14:23:23 (GMT) |
commit | f06e9ae50db5ba76cf910d54462a114f353b54ac (patch) | |
tree | 28d6647817c65b86b61667278d482d9f97713dd5 | |
parent | d8ede5c03e1f20fe57b54c08c94a1ffffe95e54b (diff) |
Gtk2: general poll type behaviour.
-rw-r--r-- | CeibalEncuesta/gtk2/CeibalEncuesta/CeibalEncuesta.py | 33 | ||||
-rw-r--r-- | CeibalEncuesta/gtk2/CeibalEncuesta/Widgets.py | 1307 | ||||
-rw-r--r-- | CeibalEncuesta/gtk2/CeibalEncuesta/__init__.py | 2 | ||||
-rwxr-xr-x | CeibalEncuesta/gtk3/CeibalEncuesta/CeibalEncuesta.py | 376 | ||||
-rwxr-xr-x | CeibalEncuesta/gtk3/CeibalEncuesta/Widgets.py | 9 |
5 files changed, 939 insertions, 788 deletions
diff --git a/CeibalEncuesta/gtk2/CeibalEncuesta/CeibalEncuesta.py b/CeibalEncuesta/gtk2/CeibalEncuesta/CeibalEncuesta.py index 1bfd967..b970681 100644 --- a/CeibalEncuesta/gtk2/CeibalEncuesta/CeibalEncuesta.py +++ b/CeibalEncuesta/gtk2/CeibalEncuesta/CeibalEncuesta.py @@ -101,11 +101,14 @@ class CeibalEncuesta(gtk.Window): self.panel.connect("text_and_change", self.__set_text_and_change) self.panel.connect("new-selection", self.__new_selection) + self.connect("key-press-event", self.__key_press_event) self.connect("destroy", self.__salir) self.connect("expose-event", self.__do_draw) self.__init() + self.fullscreen() + def __init(self, widget = None): """ Abre encuesta y lista a través del asistente. @@ -143,6 +146,34 @@ class CeibalEncuesta(gtk.Window): if reset: self.__init() + def __key_press_event(self, widget, event): + """ + Eventos de Teclas. + """ + + if self.panel.encuesta_tipo == "normal": return + + ### Cuando se presiona escape + if event.keyval == 65307: + from Widgets import Password_Dialog + + dialog = Password_Dialog( + parent_window = self, + title = "Administrar", + label = "Password:") + + response = dialog.run() + + password = 0 + + if gtk.ResponseType(response) == gtk.RESPONSE_ACCEPT: + password = dialog.get_password() + + dialog.destroy() + + if password == "123": + self.panel.show_lista() + def __do_draw(self, widget, event): """ Pinta una imagen si no se ha cargado una lista @@ -267,6 +298,8 @@ class CeibalEncuesta(gtk.Window): self.out_dict[encuestado] = {} self.panel.update({}) + self.infowidget.set_encuestado(encuestado) + def __get_menu(self): """ Crea y devuelve el menú de la aplicación. diff --git a/CeibalEncuesta/gtk2/CeibalEncuesta/Widgets.py b/CeibalEncuesta/gtk2/CeibalEncuesta/Widgets.py index 89210d7..c9ec97f 100644 --- a/CeibalEncuesta/gtk2/CeibalEncuesta/Widgets.py +++ b/CeibalEncuesta/gtk2/CeibalEncuesta/Widgets.py @@ -32,7 +32,7 @@ HOME = os.environ["HOME"] WORKPATH = os.path.join(HOME, "CeibalEncuesta") class Panel(gtk.Paned): - + __gsignals__ = { "new":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, @@ -44,299 +44,302 @@ class Panel(gtk.Paned): gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT))} - + def __init__(self): - + gtk.Paned.__init__(self) - + self.modify_bg(0, gdk.color_parse("#d8eeb1")) - + self.encuestados = None # mantiene csv para guardarlo como tal self.lista = None # Lista() Lista de encuestados self.encuesta = None # Dict Encuesta - + self.encuesta_tipo = None # Tipo de encuesta (general o normal) + # Izquierda box = gtk.VBox() - + self.scroll_list = gtk.ScrolledWindow() - + self.scroll_list.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) # self.scroll_list.add_with_viewport(self.lista) - + box.pack_start(self.scroll_list, True, True, 0) - + self.pack1(box, resize = False, shrink = True) - + # Derecha base_box = gtk.VBox() - + self.box_encuesta = gtk.VBox() scroll = gtk.ScrolledWindow() - + scroll.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - + scroll.add_with_viewport(self.box_encuesta) - + self.toolbar_encuesta = ToolbarEncuesta() - + base_box.pack_start(scroll, True, True, 0) base_box.pack_start(self.toolbar_encuesta, False, False, 0) - + self.pack2(base_box, resize = True, shrink = True) - + self.show_all() - + self.scroll_list.hide() self.box_encuesta.hide() - + self.toolbar_encuesta.connect("accion", self.__accion_encuesta) - + def __check_sensibility_butons(self): """ Habilita y deshabilita los botones para recorrer los grupos de preguntas. """ - + index_visible = 0 - + grupos = self.box_encuesta.get_children() - + for child in grupos: if child.get_visible(): index_visible = grupos.index(child) break - + if index_visible == 0: self.toolbar_encuesta.anterior.set_sensitive(False) - + else: self.toolbar_encuesta.anterior.set_sensitive(True) - + if index_visible == grupos.index(grupos[-1]): self.toolbar_encuesta.siguiente.set_sensitive(False) - + else: self.toolbar_encuesta.siguiente.set_sensitive(True) - + def __accion_encuesta(self, widget, accion): """ Pasa la vista de un grupo de preguntas a otro según valor de accion. """ - + index_visible = 0 - + grupos = self.box_encuesta.get_children() - + for child in grupos: if child.get_visible(): index_visible = grupos.index(child) break - + if accion == "Pag. Anterior": if index_visible > 0: map(self.__hide_groups, grupos) map(self.__show_groups, [grupos[index_visible - 1]]) - + elif accion == "Pag. Siguiente": if index_visible < len(grupos)-1: map(self.__hide_groups, grupos) map(self.__show_groups, [grupos[index_visible + 1]]) - + self.__check_sensibility_butons() - + def load_encuestados(self, encuestados): """ Carga una lista a encuestar. """ - + if not encuestados: return - + self.show() self.scroll_list.show_all() - + if self.lista: self.lista.destroy() - + self.encuestados = encuestados - + if not "NOMBRE" in self.encuestados[0]: ### Encuesta de tipo General. - + self.encuesta_tipo = "general" + id = "ID" in self.encuestados[0] - + if not id: self.encuestados[0].append("ID") - + for encuestado in self.encuestados[1:]: encuestado.append(str(0)) - + self.lista = GeneralWidget(self.encuestados) self.lista.connect("new_encuestado", self.__new_encuestado) - + else: ### Encuesta de tipo normal + self.encuesta_tipo = "normal" self.lista = Lista(self.encuestados) - + self.lista.connect("new-selection", self.__new_selection) self.scroll_list.add_with_viewport(self.lista) - + self.scroll_list.set_size_request(200,-1) - + self.__check_sensitive() - + def load_encuesta(self, encuesta): """ Carga una nueva Encuesta eliminando la anterior. Encuesta es un diccionario. """ - + if not encuesta: return - + self.show() self.box_encuesta.show_all() - + self.encuesta = encuesta.copy() - + # Limpiar la interfaz. for child in self.box_encuesta.get_children(): child.destroy() - + # un grupo es un frame grupos = self.encuesta.keys() grupos.sort() - + for indice in grupos: # indice es el indice del grupo, Encuesta[indice] es el contenido # cada grupo es un diccionario con dos keys (name y fields) # name es el nombre del grupo == text del frame. fields son las preguntas - + grupo = Grupo(indice, self.encuesta[indice]) self.box_encuesta.pack_start(grupo, False, True, 5) - + grupo.connect("new", self.__change) grupo.connect("text_and_change", self.__emit_text_and_change) - + self.__check_sensitive() - + grupos = self.box_encuesta.get_children() map(self.__hide_groups, grupos) map(self.__show_groups, [grupos[0]]) - + self.__check_sensibility_butons() - + def __emit_text_and_change(self, widget_grupo, pregunta, id_opcion, text, activan): """ Cuando el usuario ingresa algún valor en una entrada de texto, se manda guardar los datos y chequear las dependencias. """ - + encuestado = self.__get_encuestado() - + dict_pregunta = dict(pregunta.pregunta.copy()) - + if activan: dict_pregunta["default"] = list(activan) # list(pregunta.widget_obtions.default) if text: dict_pregunta["options"][id_opcion]["newtext"] = text - + self.emit("text_and_change", encuestado, widget_grupo, pregunta, dict_pregunta) - + self.__set_chequeo_dependencias(widget_grupo, pregunta) - + def __change(self, widget_grupo, pregunta, activan): """ Cuando se contesta una pregunta, se manda guardar los datos y chequear las dependencias. """ - + encuestado = self.__get_encuestado() - + grupo_name = widget_grupo.grupo["name"] dict_pregunta = pregunta.pregunta.copy() if activan: dict_pregunta["default"] = list(activan) # list(pregunta.widget_obtions.default) - + indice_grupo = widget_grupo.indice indice_pregunta = pregunta.indice - + ### Guarda la respuesta en archivo de salida self.emit("new", encuestado, indice_grupo, grupo_name, indice_pregunta, dict_pregunta) - + self.__set_chequeo_dependencias(widget_grupo, pregunta) - + def __set_chequeo_dependencias(self, widget_grupo, pregunta): """ Chequear dependencias para todas las preguntas posteriores a la que ha enviado la señal de cambio en ella. """ - + ### Obtener todas las opciones activas opciones_activas = [] - + grupos = self.box_encuesta.get_children() # grupos de preguntas - + for grupo in grupos: preguntas = grupo.box_preguntas.get_children() - + for preg in preguntas: opciones_activas = opciones_activas + preg.widget_obtions.get_active_options() - + almacenar = False # flag preguntas_a_checkear = [] # preguntas posteriores a la modificada - + ### Obtener preguntas posteriores a la que ha lanzado "new". for grupo in grupos[grupos.index(widget_grupo):]: - + for preg in grupo.box_preguntas.get_children(): - + if almacenar: preguntas_a_checkear.append(preg) - + if preg == pregunta: # preguntas posteriores a la que ha lanzado "new" almacenar = True - + self.__chequear_dependencias(opciones_activas, preguntas_a_checkear) - + def __chequear_dependencias(self, opciones_activas, preguntas_a_checkear): """ Chequeo de dependencias propiamente dicho. """ - + preguntas_para_activar = [] preguntas_para_desactivar = [] for pregunta in preguntas_a_checkear: - + dependencia = pregunta.pregunta.get("dependence", False) ### Solo si tienen dependencias if dependencia: - + valor, forma = G.convert(dependencia, opciones_activas) - + ### Si las dependencias de esta pregunta se cumplen if G.evaluar(valor, forma): preguntas_para_activar.append(pregunta) - + ### Si las dependencias no se cumplen else: preguntas_para_desactivar.append(pregunta) - + else: preguntas_para_activar.append(pregunta) - + map(self.__activar, preguntas_para_activar) map(self.__desactivar, preguntas_para_desactivar) - + """ A continuación: Resetear la 1º pregunta desactivada, lo cual ejecutará recurrencia sobre todo el sistema de dependencias. Esto es necesario para evitar que quede contestada una pregunta inactiva. - + Analisis del caso: Se contesta una opción en una 1ª pregunta que activa a una 2ª pregunta. Se contesta la 2ª pregunta. @@ -345,86 +348,103 @@ class Panel(gtk.Paned): """ if preguntas_para_desactivar: gobject.idle_add(preguntas_para_desactivar[0].reset) - + def __get_encuestado(self): """ Devuelve lista con datos del encuestado seleccionado. """ - + modelo, iter = self.lista.get_selected_item() - + encuestado = [] - + for index in range(0, self.lista.get_num_columns()): encuestado.append(modelo.get_value(iter, index)) - + return encuestado - + def __new_selection(self, widget, encuestado): """ Cuando el usuario cambia de Encuestado. """ - + self.emit("new-selection", encuestado) - + def __show_groups(self, widget): - + widget.set_visible(True) - + def __hide_groups(self, widget): - + widget.set_visible(False) - + def __activar(self, widget): """ Recibe una pregunta. - + Cuando se cumplen las dependencias para esta pregunta, la misma se hace visible para de esa forma, permitir ser contestada. """ - + widget.set_visible(True) - + def __desactivar(self, widget): """ Recibe una pregunta. - + Cuando no se cumplen las dependencias para esta pregunta, la misma se hace invisible. """ - + widget.set_visible(False) - + def __check_sensitive(self): - + """ + Habilita y deshabilita - Visibiliza e invisibiliza + widgets y funcionalidad general según condiciones. + """ + if not self.encuesta: self.box_encuesta.hide() - + elif self.encuesta: self.box_encuesta.show_all() - + if not self.lista: self.scroll_list.hide() - + elif self.lista: self.scroll_list.show_all() - + if self.encuesta and self.lista: self.set_sensitive(True) - + else: self.set_sensitive(False) - + + if self.encuesta_tipo == "general": + self.get_children()[0].hide() + + elif self.encuesta_tipo == "normal": + self.get_children()[0].show_all() + + def show_lista(self): + """ + Muestra la lista en encuestas de tipo general. + """ + + self.get_children()[0].show() + def __new_encuestado(self, widget, encuestado): """ Cuando se crea un nuevo encuestado, este debe agregarse a la lista de encuestados del panel. """ - + self.encuestados.append(encuestado) - + def update(self, dict): """ Cuando se selecciona un usuario, se @@ -432,19 +452,19 @@ class Panel(gtk.Paned): respuestas del usuario. (dict == {}, actualiza la interfaz de una encuesta sin responder). """ - + self.load_encuesta(self.encuesta) - + grupos = self.box_encuesta.get_children() # grupos de preguntas - + ### Actualiza Respuestas. for grupo in grupos: if not grupo.indice in dict.keys(): continue - + else: grupo.update(dict[grupo.indice]) - + ### Obtener todas las opciones activas opciones_activas = [] grupos = self.box_encuesta.get_children() # grupos de preguntas @@ -452,266 +472,285 @@ class Panel(gtk.Paned): preguntas = grupo.box_preguntas.get_children() for preg in preguntas: opciones_activas = opciones_activas + preg.widget_obtions.get_active_options() - + ### Actualiza Visibilidad. preguntas_para_activar = [] preguntas_para_desactivar = [] - + for grupo in grupos: preguntas = grupo.box_preguntas.get_children() - + for preg in preguntas: contestada = preg.widget_obtions.get_active_options() con_dependencias = preg.pregunta.get("dependence", False) - + if contestada or not con_dependencias: preguntas_para_activar.append(preg) - + elif not contestada and con_dependencias: dependencia = preg.pregunta.get("dependence", False) ### Solo si tienen dependencias valor, forma = G.convert(dependencia, opciones_activas) - + ### Si las dependencias de esta pregunta se cumplen if G.evaluar(valor, forma): preguntas_para_activar.append(preg) - + ### Si las dependencias no se cumplen else: preguntas_para_desactivar.append(preg) - + map(self.__activar, preguntas_para_activar) map(self.__desactivar, preguntas_para_desactivar) - + gobject.idle_add(self.check_text_inputs) - + def check_text_inputs(self): """ Forzar autocontestado en opciones de entrada de texto con valor por defecto . . . """ - + grupos = self.box_encuesta.get_children() # grupos de preguntas - + for grupo in grupos: preguntas = grupo.box_preguntas.get_children() - + for pregunta in preguntas: widget_options = pregunta.widget_obtions - + if widget_options.nombre == "TextInput": widget_options.check_text_inputs() - + class My_FileChooser(gtk.FileChooserDialog): """ Selector de Archivos para poder cargar archivos desde cualquier dispositivo o directorio. """ - + __gsignals__ = { "load":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))} - + def __init__(self, parent_window = None, action_type = None, filter_type = None, title = None): - + gtk.FileChooserDialog.__init__(self, parent = parent_window, action = action_type, title = title) - + self.modify_bg(0, gdk.color_parse("#d8eeb1")) - + self.set_modal(True) self.set_size_request( 640, 480 ) self.set_select_multiple(False) self.set_current_folder_uri("file:///%s" % WORKPATH) - + if filter_type != None: filter = gtk.FileFilter() filter.set_name(filter_type) filter.add_mime_type(filter_type) self.add_filter(filter) - + hbox = gtk.HBox() - + texto = "" if action_type == gtk.FILE_CHOOSER_ACTION_OPEN: texto = "Abrir" - + elif action_type == gtk.FILE_CHOOSER_ACTION_SAVE: texto = "Guardar" - + abrir = gtk.Button(texto) salir = gtk.Button("Salir") - + hbox.pack_end(salir, False, False, 5) hbox.pack_end(abrir, False, False, 5) - + self.set_extra_widget(hbox) - + salir.connect("clicked", self.__salir) abrir.connect("clicked", self.__abrir) - + self.show_all() - + def __abrir(self, widget): - + self.emit("load", self.get_filename()) self.__salir(None) def __salir(self, widget): - + self.destroy() - + class Lista(gtk.TreeView): """ Lista Dinámica de encuestados para encuestas de tipo normal. """ - + __gsignals__ = { "new-selection":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, ))} - + def __init__(self, encuestados): - + encabezado = encuestados[0] encuestados = encuestados[1:] - + gtk.TreeView.__init__(self) - + self.set_property("rules-hint", True) self.set_headers_clickable(True) self.set_headers_visible(True) self.valor_select = None - + strings = [] - + for x in encabezado: strings.append(gobject.TYPE_STRING) - + self.modelo = gtk.ListStore(*strings) - + for item in encabezado: - + visible = False - + if item == "CI" or item == "NOMBRE" or item == "ID": visible = True - + self.append_column( self.__construir_columa( item, encabezado.index(item), visible)) - + self.treeselection = self.get_selection() - + self.treeselection.set_select_function( self.__selecciones, self.modelo) - + self.set_model(self.modelo) self.show_all() - + self.add_encuestados(encuestados) - + def __selecciones(self, path, model): """ Cuando se selecciona un item en la lista. """ - + iter = model.get_iter(path) - + encuestado = "" - + for index in range(0, len(self.get_columns())): encuestado += "%s " % model.get_value(iter, index) - + encuestado = encuestado.strip() - + if self.valor_select != encuestado: self.valor_select = encuestado self.emit("new-selection", self.valor_select) - + return True - + def __construir_columa(self, text, index, visible): - + render = gtk.CellRendererText() columna = gtk.TreeViewColumn(text, render, text=index) columna.set_sort_column_id(index) columna.set_property("visible", visible) columna.set_property("resizable", False) columna.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) - + return columna - + def add_encuestados(self, encuestados): """ Recibe lista de: encuestados y Comienza secuencia de agregado. """ - + gobject.idle_add(self.__run_add_encuestado, encuestados) - + def __run_add_encuestado(self, encuestados): """ Agrega los items a la lista, uno a uno, actualizando. """ - + if not encuestados: - - if not self.valor_select: - self.__seleccionar_primero() - + self.seleccionar_ultimo() return - + encuestado = encuestados[0] - + self.modelo.append( encuestado ) - + encuestados.remove(encuestado) - + gobject.idle_add(self.__run_add_encuestado, encuestados) def __seleccionar_primero(self, widget = None): - + """ + Selecciona el primer elemento en la lista. + """ + self.treeselection.select_path(0) - + def get_selected_item(self): """ Devuelve modelo de la lista e iter seleccionado. """ - + modelo, iter = self.treeselection.get_selected() - + return (modelo, iter) - + def get_num_columns(self): """ Devuelve la cantidad de columnas de la lista. """ - + return len(self.get_columns()) - + + def seleccionar_ultimo(self): + """ + Selecciona el último elemento en la lista. + """ + + model = self.get_model() + item = model.get_iter_first() + + iter = None + + while item: + iter = item + item = model.iter_next(item) + + if iter: + self.treeselection.select_iter(iter) + path = model.get_path(iter) + self.scroll_to_cell(path) + class Grupo(gtk.Frame): """ Frame para grupo de Preguntas de la encuesta. - + Un grupo es: "0": { "name": "group 0", "fields": { . . . => Preguntas} } """ - + __gsignals__ = { "new":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, @@ -720,50 +759,50 @@ class Grupo(gtk.Frame): gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT))} - + def __init__(self, indice_grupo, grupo): - + gtk.Frame.__init__(self) - + self.modify_bg(0, gdk.color_parse("#d8eeb1")) - + self.indice = indice_grupo # indice del grupo en la encuesta self.grupo = grupo.copy() # Diccionario del grupo en la encuesta - + self.set_label(self.grupo["name"]) - + self.box_preguntas = gtk.VBox() self.add(self.box_preguntas) - + preguntas = self.grupo["fields"] - + keys = preguntas.keys() keys.sort() - + for indice in keys: pregunta = Pregunta(indice, preguntas[indice]) self.box_preguntas.pack_start(pregunta, False, True, 3) pregunta.connect("new", self.__change) pregunta.connect("text_and_change", self.__emit_text_and_change) - + self.show_all() - + def __emit_text_and_change(self, pregunta, id_opcion, text, activan): """ Cuando el usuario ingresa algún valor en una entrada de texto, se manda guardar los datos y chequear las dependencias. """ - + self.emit("text_and_change", pregunta, id_opcion, text, activan) - + def __change(self, widget, activan): """ Cuando se contesta una pregunta, chequea las dependencias y se guardan los datos. """ - + self.emit("new", widget, activan) - + def update(self, dict): """ Cuando se selecciona un usuario que ha @@ -771,9 +810,9 @@ class Grupo(gtk.Frame): actualiza la interfaz gráfica de la misma con esos valores. """ - + for child in self.box_preguntas.get_children(): - + # Si se respondió esta pregunta if dict["fields"].get(child.indice, False): child.update(dict["fields"][child.indice]) @@ -781,9 +820,9 @@ class Grupo(gtk.Frame): class Pregunta(gtk.HBox): """ Box con Pregunta. - + Una pregunta es: - + { "0": { "widget_type": "RadioButton", @@ -796,72 +835,72 @@ class Pregunta(gtk.HBox): } } """ - + __gsignals__ = { "new":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,(gobject.TYPE_PYOBJECT,)), "text_and_change":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,(gobject.TYPE_STRING, gobject.TYPE_STRING,gobject.TYPE_PYOBJECT))} - + def __init__(self, indice_pregunta, pregunta): - + gtk.HBox.__init__(self) - + self.indice = indice_pregunta self.pregunta = pregunta.copy() - + self.widget_obtions = None widget = self.pregunta["widget_type"] - + if widget == "DropDownList": self.widget_obtions = Widget_DropDownList(self.pregunta["options"].copy()) self.widget_obtions.connect("new", self.__change) - + elif widget == "TextInput": self.widget_obtions = Widget_TextInput(self.pregunta["options"].copy()) self.widget_obtions.connect("text_and_change", self.__emit_text_and_change) - + elif widget == "MultipleCheckBox" or widget == "ImageCheckBox": self.widget_obtions = Widget_MultipleCheckBox(self.pregunta["options"].copy()) self.widget_obtions.connect("new", self.__change) - + elif widget == "RadioButton" or widget == "ImageRadioButton": self.widget_obtions = Widget_RadioButon(self.pregunta["options"].copy()) self.widget_obtions.connect("new", self.__change) - + else: print "Widget no Considerado", widget - + label = gtk.Label(self.pregunta["name"]) - + pangoFont = pango.FontDescription("10") - + label.modify_font(pangoFont) label.modify_fg(0, gdk.Color(0, 0, 65000)) - + self.pack_start(label, False, True, 5) self.pack_end(self.widget_obtions, True, True, 0) - + self.show_all() - + def __emit_text_and_change(self, widget, id_opcion, text, activan): """ Cuando el usuario ingresa algún valor en una entrada de texto, se manda guardar los datos y chequear las dependencias. """ - + self.emit("text_and_change", id_opcion, text, activan) - + def __change(self, widget, activan): """ Cuando se Contesta una pregunta, se chequean las dependencia y se guardan los datos. """ - + self.emit("new", activan) - + def update(self, dict): """ Cuando se selecciona un usuario que ha @@ -869,227 +908,226 @@ class Pregunta(gtk.HBox): actualiza la interfaz gráfica de la misma con esos valores. """ - + self.widget_obtions.update(dict) - + def reset(self): """ Devolver la pregunta a su estado original. - + Descontestar cualquier respuesta ingresada. """ - + self.widget_obtions.reset() - + class Widget_DropDownList(gtk.ComboBox): """ Contenedor de opciones para respuestas posibles en una pregunta. - + Opciones es: - + "options": { "00001": {"text": "opcion 1"}, "00002": {"text": "opcion 2"} } """ - + __gsignals__ = { "new":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))} - + def __init__(self, options): - + model = gtk.ListStore(gobject.TYPE_STRING) cell = gtk.CellRendererText() - + gtk.ComboBox.__init__(self, model) - + self.nombre = "DropDownList" - + self.pack_start(cell) self.add_attribute(cell, 'text', 0) self.set_model(model) - + self.options = options.copy() self.updating = False - + for key in self.options.keys(): self.append_text(self.options[key]["text"]) - + self.show_all() - + def get_active_options(self): """ Devuelve los indices de las opciones activas. """ - + activas = [] - + for key in self.options.keys(): if self.options[key]["text"] == self.get_active_text(): - + if not key in activas: activas.append(key) - + elif not self.options[key]["text"] == self.get_active_text(): - + if key in activas: activas.remove(key) - + return activas - + def do_changed(self): """ Cuando el usuario hace click sobre una opción, se checkean dependencias y se guardan los datos. """ - + if self.updating: return - + activan = [] - + for key in self.options.keys(): if self.options[key]["text"] == self.get_active_text(): - + if not key in activan: activan.append(key) - + elif not self.options[key]["text"] == self.get_active_text(): - + if key in activan: activan.remove(key) - + self.emit("new", activan) - + def update(self, dict): """ Cuando el usuario cambia de encuestado, actualiza sus respuestas en la pregunta. """ - + self.updating = True - + model = self.get_model() item = model.get_iter_first() - + count = 0 - + for default in dict.get("default", []): - + while item: if model.get_value(item, 0) == \ dict["options"][default]["text"]: - + self.set_active(count) self.updating = False return - + item = model.iter_next(item) count += 1 - + self.updating = False - + def reset(self): """ La pregunta vuelve a su estado original. """ - + self.get_model().clear() - + activan = [] - + for key in self.options.keys(): self.append_text(self.options[key]["text"]) self.show_all() ### Porque se debe avisar que esta pregunta se ha desactivado. self.emit("new", activan) - + class Widget_TextInput(gtk.Entry): """ Contenedor para entrada de texto para respuesta a una pregunta. - + Opciones es: - + "options":{ "00001":{"text": ""} } """ - + __gsignals__ = { "text_and_change":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT))} - + def __init__(self, options): - + gtk.Entry.__init__(self) - + self.nombre = "TextInput" - + self.options = options.copy() - + self.updating = False - + key = self.options.keys()[0] - + text = self.options[key].get("text", False) if text: self.set_text(text) - + self.show_all() - + def do_key_release_event(self, void): """ Cuando el usuario ingresa algún valor en la opción, se manda guardar los datos y chequear las dependencias. """ - + if self.updating: return - + activan = [] - + key = self.options.keys()[0] text = self.get_text() - + if text: activan.append(key) - + else: - #text = " " return self.reset() - + self.emit("text_and_change", key, text, activan) - + def get_active_options(self): """ Devuelve los indices de las opciones activas. """ - + activas = [] - + key = self.options.keys()[0] - + text = self.options[key].get("text", False) if text: activas.append(key) - + return activas - + def update(self, dict): """ Cuando el usuario cambia de encuestado, actualiza sus respuestas en la pregunta. """ - + self.updating = True - + key = self.options.keys()[0] - + if dict["options"][key].get("newtext", False): self.set_text(dict["options"][key]["newtext"]) - + else: text = self.options[key].get("text", "") self.set_text(text) - + self.updating = False def reset(self): @@ -1098,17 +1136,17 @@ class Widget_TextInput(gtk.Entry): Si esta opción tenían un valor por defecto, luego de ser reseteada, ese valor ya no se tomará en cuenta. """ - + key = self.options.keys()[0] - + text = " " self.set_text("") - + activan = [] - + ### Porque se debe avisar que esta pregunta se ha desactivado. self.emit("text_and_change", key, text, activan) - + def check_text_inputs(self): """ Cuando una opcion del tipo entrada de texto trae @@ -1117,313 +1155,313 @@ class Widget_TextInput(gtk.Entry): que de lo contrario, solo se guardará si el usuario contesta en forma explicita esta opción, modificando el valor por defecto. """ - + key = self.options.keys()[0] - + if not self.options[key].get("newtext", False) and self.options[key].get("text", False): - + activan = [] text = self.options[key]["text"] activan.append(key) - + self.emit("text_and_change", key, text, activan) - + class Widget_RadioButon(gtk.ButtonBox): """ Contenedor de opciones para respuestas posibles en una pregunta. - + Opciones es: - + "options": { "00001": {"text": "opcion 1"}, "00002": {"text": "opcion 2"} } """ - + __gsignals__ = { "new":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))} - + def __init__(self, options): - + gtk.ButtonBox.__init__(self) - + self.nombre = "RadioButton" - + # Grupo de radio buttons. Necesario para pregunta sin contestar. self.null_button = gtk.RadioButton() - + self.options = options.copy() self.updating = False - + grupo = None - + keys = self.options.keys() keys.sort() - + for key in keys: - + radio = MyRadioButton(key) - + text = self.options[key].get("text", "") imagen = self.options[key].get("img", "") - + if text: radio.set_label(text) - + if imagen: loader = gdk.PixbufLoader() image_string = base64.b64decode(imagen) loader.write(image_string) loader.close() - + pixbuf = loader.get_pixbuf().scale_simple( 80, 80, gdk.INTERP_BILINEAR) - + radio.set_image(gtk.image_new_from_pixbuf(pixbuf)) - + radio.set_group(self.null_button) - + self.pack_start(radio, False, False, 3) - + self.null_button.set_active(True) - + radio.connect("toggled", self.__change) - + self.show_all() - + def get_active_options(self): """ Devuelve los indices de las opciones activas. """ - + activas = [] - + options = self.get_children() - + for child in options: - + if child.get_active(): activas.append(child.indice) - + return activas - + def __change(self, widget): """ Cuando el usuario hace click sobre una opción, se checkean dependencias y se guardan los datos. """ - + if self.updating: return - + options = self.get_children() activan = [] - + for child in options: - + if child.get_active(): activan.append(child.indice) - + self.emit("new", activan) - + def update(self, dict): """ Cuando el usuario cambia de encuestado, actualiza sus respuestas en la pregunta. """ - + self.updating = True - + options = self.get_children() - + for child in options: if child.indice in dict.get("default", []): child.set_active(True) - + else: child.set_active(False) - + self.updating = False - + def reset(self): """ La pregunta vuelve a su estado original. """ - + options = self.get_children() - + activan = [] - + for child in options: child.set_active(False) - + self.null_button.set_active(True) - + ### Porque se debe avisar que esta pregunta se ha desactivado. self.emit("new", activan) - + class Widget_MultipleCheckBox(gtk.Table): """ Contenedor de opciones para respuestas posibles en una pregunta. - + Opciones es: - + "options": { "00001": {"text": "opcion 1"}, "00002": {"text": "opcion 2"} } """ - + __gsignals__ = { "new":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))} - + def __init__(self, options): - + self.nombre = "MultipleCheckBox" - + columns = 2 - + rows = int(len(options)/columns) - + while rows*columns < int(len(options)): rows += 1 - + gtk.Table.__init__( self, rows = rows, columns = columns, homogeneous = True) - + self.options = options.copy() self.updating = False - + keys = self.options.keys() keys.sort() - + col = 0 row = 0 - + for key in keys: - + check = MyCheckButton(key) - + text = self.options[key].get("text", "") imagen = self.options[key].get("img", "") - + if text: check.set_label(text) - + if imagen: loader = gdk.PixbufLoader() image_string = base64.b64decode(imagen) loader.write(image_string) loader.close() - + pixbuf = loader.get_pixbuf().scale_simple( 80, 80, gdk.INTERP_BILINEAR) - + check.set_image(gtk.image_new_from_pixbuf(pixbuf)) - + self.attach_defaults(check, col, col+1, row, row+1) - + col += 1 - + if col == columns: col = 0 row += 1 - + check.connect("toggled", self.__change) - + self.show_all() - + def get_active_options(self): """ Devuelve los indices de las opciones activas. """ - + activas = [] - + options = self.get_children() - + for child in options: - + if child.get_active(): activas.append(child.indice) - + return activas - + def __change(self, widget): """ Cuando el usuario hace click sobre una opción, se checkean dependencias y se guardan los datos. """ - + if self.updating: return - + options = self.get_children() - + activan = [] - + for child in options: - + if child.get_active(): activan.append(child.indice) - + self.emit("new", activan) - + def update(self, dict): """ Cuando el usuario cambia de encuestado, actualiza sus respuestas en la pregunta. """ - + self.updating = True - + options = self.get_children() - + for child in options: if child.indice in dict.get("default", []): child.set_active(True) - + else: child.set_active(False) - + self.updating = False - + def reset(self): """ La pregunta vuelve a su estado original. """ - + options = self.get_children() - + activan = [] - + for child in options: child.set_active(False) - + ### Porque se debe avisar que esta pregunta se ha desactivado. self.emit("new", activan) - + class MyCheckButton(gtk.CheckButton): - + def __init__(self, indice): - + gtk.CheckButton.__init__(self) - + self.indice = indice - + self.show_all() - + class MyRadioButton(gtk.RadioButton): - + def __init__(self, indice): - + gtk.RadioButton.__init__(self) - + self.indice = indice - + self.show_all() class My_Alert_Dialog(gtk.Dialog): @@ -1431,43 +1469,43 @@ class My_Alert_Dialog(gtk.Dialog): Dialogo que alerta al usuario sobre una acción que obliga a perder los datos. """ - + def __init__(self, parent_window = None, label = ""): - + gtk.Dialog.__init__( self, title = "ATENCION !", parent = parent_window, flags = gtk.DIALOG_MODAL, buttons = ("OK", gtk.RESPONSE_ACCEPT)) - + self.modify_bg(0, gdk.color_parse("#d8eeb1")) - + label = gtk.Label(label) label.show() - + self.set_border_width(10) - + self.vbox.pack_start(label, True, True, 0) class ToolbarEncuesta(gtk.Toolbar): - + __gsignals__ = { "accion":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))} - + def __init__(self): - + gtk.Toolbar.__init__(self) - + self.modify_bg(0, gdk.color_parse("#d8eeb1")) - + separador = gtk.SeparatorToolItem() separador.props.draw = False separador.set_size_request(0, -1) separador.set_expand(True) - + self.insert(separador, -1) - + item = gtk.ToolItem() item.set_expand(False) self.anterior = gtk.Button("Pag. Anterior") @@ -1476,7 +1514,7 @@ class ToolbarEncuesta(gtk.Toolbar): self.anterior.show() item.add(self.anterior) self.insert(item, -1) - + item = gtk.ToolItem() item.set_expand(False) self.siguiente = gtk.Button("Pag. Siguiente") @@ -1485,85 +1523,102 @@ class ToolbarEncuesta(gtk.Toolbar): self.siguiente.show() item.add(self.siguiente) self.insert(item, -1) - + self.show_all() - + def __button_clicked(self, widget): - + self.emit("accion", widget.get_label()) class InfoWidget(gtk.EventBox): """ Widget con información sobre encuesta en proceso. """ - + def __init__(self): - + gtk.EventBox.__init__(self) - + self.modify_bg(0, gdk.color_parse("#d8eeb1")) - + self.toolbar = gtk.Toolbar() - + self.info = {} - + self.poll_name = gtk.Label("Encuesta: ") self.pollster_username = gtk.Label("Encuestador: ") - + self.encuestado = gtk.Label("Encuestado: ") + self.poll_name.show() self.pollster_username.show() - + self.encuestado.show() + separador = gtk.SeparatorToolItem() separador.props.draw = False separador.set_size_request(5, -1) separador.set_expand(False) self.toolbar.insert(separador, -1) - + item = gtk.ToolItem() item.set_expand(False) item.add(self.poll_name) self.toolbar.insert(item, -1) - + separador = gtk.SeparatorToolItem() separador.props.draw = False separador.set_size_request(5, -1) separador.set_expand(False) self.toolbar.insert(separador, -1) - + item = gtk.ToolItem() item.set_expand(False) item.add(self.pollster_username) self.toolbar.insert(item, -1) - + + separador = gtk.SeparatorToolItem() + separador.props.draw = False + separador.set_size_request(5, -1) + separador.set_expand(False) + self.toolbar.insert(separador, -1) + + item = gtk.ToolItem() + item.set_expand(False) + item.add(self.encuestado) + self.toolbar.insert(item, -1) + separador = gtk.SeparatorToolItem() separador.props.draw = False separador.set_size_request(0, -1) separador.set_expand(True) self.toolbar.insert(separador, -1) - + self.add(self.toolbar) - + self.show_all() - + + def set_encuestado(self, encuestado): + + self.encuestado.set_text("Encuestado: %s" % encuestado) + def set_info(self, dict): """ Ejemplo: - + dict = { "poll_name": "Encuesta de Prueba", "poll_id": "111111111111111111111111", "pollster_id": "5163fe24421aa9263991b229", "pollster_username": "José Antonio Rodriguez"} """ - + for key in dict.keys(): self.info[key] = dict[key] - + self.poll_name.set_text("Encuesta: %s" % self.info["poll_name"]) self.pollster_username.set_text("Encuestador: %s" % self.info["pollster_username"]) def get_info(self): - + return self.info class GeneralWidget(gtk.VBox): @@ -1571,229 +1626,236 @@ class GeneralWidget(gtk.VBox): Lista Dinámica de encuestados, para encuestas de tipo general. """ - + __gsignals__ = { "new-selection":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "new_encuestado":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, ))} - + def __init__(self, encuestados): - + gtk.VBox.__init__(self) - + self.lista = None self.listas = {} - + encabezado = encuestados[0] encuestados = encuestados[1:] - + grupos = [] - + id_grado = encabezado.index("GRADO") id_grupo = encabezado.index("GRUPO") - + ### Obteniendo los grupos en la lista. for encuestado in encuestados: grado = encuestado[id_grado] grupo = encuestado[id_grupo] - + item = "%s %s" % (grado, grupo) - + if not item in grupos: grupos.append(item) self.listas[item] = [encabezado] - + self.listas[item].append(encuestado) - + combo = ComboGrupos() - + self.pack_start(combo, False, False, 0) - + for g in grupos: combo.append_text(g) - + self.scroll_list = gtk.ScrolledWindow() - + self.scroll_list.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) # self.scroll_list.add_with_viewport(self.lista) - + self.pack_start(self.scroll_list, True, True, 0) - + box = gtk.HBox() - - anterior = gtk.Button("Anterior") + + continuar = gtk.Button("Continuar") siguiente = gtk.Button("Siguiente") - - box.pack_start(anterior, True, True, 0) + + box.pack_start(continuar, True, True, 0) box.pack_start(siguiente, True, True, 0) - + self.pack_start(box, False, False, 0) - + self.show_all() - + combo.connect("new", self.__new_group) - + combo.select(grupos[0]) self.__new_group(None, grupos[0]) # Forzar nueva lista - - anterior.connect("clicked", self.__anterior) + + continuar.connect("clicked", self.__continuar) siguiente.connect("clicked", self.__siguiente) - - def __anterior(self, widget): - - modelo, iter = self.get_selected_item() - # FIXME: No existe iter_previous - ''' - if modelo.iter_previous(iter): - while gtk.events_pending(): - gtk.main_iteration() - - self.lista.treeselection.select_iter(modelo.iter_previous(iter))''' - + def __siguiente(self, widget): """ Obtiene el item seleccionado en la lista. Si hay más delante de éste, pasa al siguiente. De lo contrario crear uno nuevo y lo selecciona. """ - + + msg = "¿Esta seguro que desea terminar esta encuesta y seguir con una nueva?" + dialog = My_Alert_Dialog2( + parent_window = self.get_toplevel(), label = msg) + + response = dialog.run() + + if gtk.ResponseType(response) != gtk.RESPONSE_ACCEPT: + dialog.destroy() + return + + dialog.destroy() + modelo, iter = self.get_selected_item() - + if not modelo.iter_next(iter): item = [] - + for x in range(0, self.get_num_columns()): valor = modelo.get_value(iter, x) item.append(str(valor)) - + item[-1] = str(int(item[-1]) + 1) - + ### Agregar a la lista de este grupo columnas = self.lista.get_columns() - + for columna in columnas: cabecera = columna.get_title() - + if cabecera == "GRADO": id_grado = columnas.index(columna) - + if cabecera == "GRUPO": id_grupo = columnas.index(columna) - + grado = modelo.get_value(iter, id_grado) grupo = modelo.get_value(iter, id_grupo) - + valor = "%s %s" % (grado, grupo) self.listas[valor].append(item) ### Agregar a la lista de este grupo - + self.lista.add_encuestados([item]) - + self.emit("new_encuestado", item) - + while gtk.events_pending(): gtk.main_iteration() - + self.lista.treeselection.select_iter(modelo.iter_next(iter)) - + # FIXME: Ver si se puede insensibilizar la linea. # Probablemente no se pueda y haya que usar filtros. # modelo[iter] http://faq.pygtk.org/index.py?file=faq13.048.htp&req=show - + def __new_group(self, widget, valor): - + if self.lista: self.lista.destroy() - + self.lista = Lista(self.listas[valor]) self.lista.set_headers_clickable(False) - + self.lista.connect("new-selection", self.__new_selection) self.scroll_list.add_with_viewport(self.lista) - + self.scroll_list.set_size_request(200,-1) - + + def __continuar(self, widget): + + self.get_parent().get_parent().get_parent().hide() + def __new_selection(self, widget, encuestado): """ Cuando el usuario cambia de Encuestado. """ - + self.emit("new-selection", encuestado) - + + self.scroll_list.get_children()[0].hide() + def get_selected_item(self): """ Devuelve modelo de la lista e iter seleccionado. """ - + return self.lista.get_selected_item() - + def get_num_columns(self): """ Devuelve la cantidad de columnas de la lista. """ return self.lista.get_num_columns() - + class ComboGrupos(gtk.ComboBox): - + __gsignals__ = { "new":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))} - + def __init__(self): - + model = gtk.ListStore(gobject.TYPE_STRING) cell = gtk.CellRendererText() - + gtk.ComboBox.__init__(self, model) - + self.pack_start(cell) self.add_attribute(cell, 'text', 0) self.set_model(model) - + self.updating = False - + self.show_all() - + def select(self, valor): """ Setea el combo a un valor específico. """ - + self.updating = True - + model = self.get_model() item = model.get_iter_first() - + count = 0 - + while item: if model.get_value(item, 0) == str(valor): self.set_active(count) self.updating = False - + return - + item = model.iter_next(item) count += 1 - + self.updating = False - + def do_changed(self): """ Cuando el usuario hace click sobre una opción. """ - + if self.updating: return - + self.emit("new", self.get_active_text()) class Wizard(gtk.Dialog): - + def __init__(self, parent_window = None): - + gtk.Dialog.__init__( self, title = "Asistente", parent = parent_window, @@ -1801,27 +1863,27 @@ class Wizard(gtk.Dialog): buttons = ( "Proceder", gtk.RESPONSE_ACCEPT, "Cancelar", gtk.RESPONSE_CANCEL)) - + self.modify_bg(0, gdk.color_parse("#d8eeb1")) - + self.set_border_width(5) - + abrirencuesta = gtk.Button("Buscar . . .") abrirlista = gtk.Button("Buscar . . .") cargarencuesta = gtk.Button("Buscar . . .") - + abrirencuesta.connect("clicked", self.__abrir_encuesta) abrirlista.connect("clicked", self.__abrir_lista) cargarencuesta.connect("clicked", self.__cargar_encuesta) - + self.label_1 = gtk.Label("") self.label_2 = gtk.Label("") self.label_3 = gtk.Label("") - + frame0 = gtk.Frame() box0 = gtk.VBox() frame0.add(box0) - + frame = gtk.Frame() frame.set_label("Seleccionar Nueva Encuesta. (archivo *.json)") box = gtk.HBox() @@ -1829,9 +1891,9 @@ class Wizard(gtk.Dialog): box.pack_start(self.label_1, False, False, 0) frame.add(box) frame.show_all() - + box0.pack_start(frame, False, False, 10) - + frame = gtk.Frame() frame.set_label("Seleccionar Nueva Lista. (archivo *.csv)") box = gtk.HBox() @@ -1839,14 +1901,14 @@ class Wizard(gtk.Dialog): box.pack_start(self.label_2, False, False, 0) frame.add(box) frame.show_all() - + box0.pack_start(frame, False, False, 10) - + vbox_base = gtk.VBox() vbox_base.pack_start(frame0, False, False, 30) - + frame0.show_all() - + frame = gtk.Frame() frame.set_label("Seleccionar Encuesta Anterior. (archivo *.encuesta)") box = gtk.HBox() @@ -1854,90 +1916,145 @@ class Wizard(gtk.Dialog): box.pack_start(self.label_3, False, False, 0) frame.add(box) frame.show_all() - + vbox_base.pack_start(frame, False, False, 20) - + scroll = gtk.ScrolledWindow() - + scroll.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scroll.add_with_viewport(vbox_base) - + scroll.show_all() - + self.vbox.pack_start(scroll, True, True, 0) - + self.set_border_width(5) self.set_size_request(500, 300) - + def __abrir_encuesta(self, widget): """ Recuperar encuesta parcial o totalmente respondida. """ - + filechooser = My_FileChooser( parent_window = self, action_type = gtk.FILE_CHOOSER_ACTION_OPEN, filter_type = None, title = "Cargar Nueva Encuesta") - + filechooser.connect("load", self.__set_encuesta) - + def __abrir_lista(self, widget): """ Abrir lista a encuestar. """ - + filechooser = My_FileChooser( parent_window = self, action_type = gtk.FILE_CHOOSER_ACTION_OPEN, filter_type = "text/csv", title = "Cargar Lista a Encuestar") - + filechooser.connect("load", self.__set_encuestados) - + def __cargar_encuesta(self, widget): """ Abrir encuesta vacía. """ - + filechooser = My_FileChooser( parent_window = self, action_type = gtk.FILE_CHOOSER_ACTION_OPEN, #filter_type = "text/encuesta", title = "Recuperar Encuesta") - + filechooser.connect("load", self.__set_encuesta_respondida) - + def __set_encuesta(self, widget, archivo): """ Las encuestas respondidas son *.json o *.slv. """ - + extension = os.path.splitext(os.path.split(archivo)[1])[1] - + if "json" in extension or "slv" in extension: self.label_1.set_text(archivo) - + def __set_encuestados(self, widget, archivo): """ Las listas son *.csv. """ - + extension = os.path.splitext(os.path.split(archivo)[1])[1] - + if "csv" in extension: self.label_2.set_text(archivo) - + def __set_encuesta_respondida(self, widget, archivo): """ Las encuestas respondidas son *.encuesta. """ - + extension = os.path.splitext(os.path.split(archivo)[1])[1] - + if "encuesta" in extension: self.label_3.set_text(archivo) -
\ No newline at end of file + +class Password_Dialog(gtk.Dialog): + """ + Dialogo para introdicir password y acceder a + opciones de Encuestador. + """ + + def __init__(self, parent_window = None, title = "ATENCION !", label = ""): + + gtk.Dialog.__init__( + self, title = title, + parent = parent_window, + flags = gtk.DIALOG_MODAL, + buttons = ( + "Aceptar", gtk.RESPONSE_ACCEPT, + "Cancelar", gtk.RESPONSE_CANCEL) + ) + + label = gtk.Label(label) + label.show() + + self.entry = gtk.Entry() + self.entry.show() + + self.set_border_width(10) + + self.vbox.pack_start(label, True, True, 0) + self.vbox.pack_start(self.entry, True, True, 0) + + def get_password(self): + """ + Deveulve el password introducido. + """ + + return self.entry.get_text().strip() + +class My_Alert_Dialog2(gtk.Dialog): + + def __init__(self, parent_window = None, label = ""): + + gtk.Dialog.__init__( + self, title = "ATENCION !", + parent = parent_window, + flags = gtk.DIALOG_MODAL, + buttons = ( + "Aceptar", gtk.RESPONSE_ACCEPT, + "Cancelar", gtk.RESPONSE_CANCEL) + ) + + label = gtk.Label(label) + label.show() + + self.set_border_width(10) + + self.vbox.pack_start(label, True, True, 0) + diff --git a/CeibalEncuesta/gtk2/CeibalEncuesta/__init__.py b/CeibalEncuesta/gtk2/CeibalEncuesta/__init__.py index 93f5256..8b13789 100644 --- a/CeibalEncuesta/gtk2/CeibalEncuesta/__init__.py +++ b/CeibalEncuesta/gtk2/CeibalEncuesta/__init__.py @@ -1 +1 @@ -__init__.py
\ No newline at end of file + diff --git a/CeibalEncuesta/gtk3/CeibalEncuesta/CeibalEncuesta.py b/CeibalEncuesta/gtk3/CeibalEncuesta/CeibalEncuesta.py index 5d262e9..fe779b0 100755 --- a/CeibalEncuesta/gtk3/CeibalEncuesta/CeibalEncuesta.py +++ b/CeibalEncuesta/gtk3/CeibalEncuesta/CeibalEncuesta.py @@ -47,7 +47,7 @@ TEMPPATH = os.path.join(WORKPATH, "temp.encuesta") if not os.path.exists(WORKPATH): os.mkdir(WORKPATH) os.chmod(WORKPATH, 0755) - + archivo = open(TEMPPATH, "w") archivo.close() @@ -61,202 +61,202 @@ context.add_provider_for_screen( screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER) - + GObject.threads_init() Gdk.threads_init() class CeibalEncuesta(Gtk.Window): - + def __init__(self): - + Gtk.Window.__init__(self) - + self.set_title("Ceibal Encuesta") - + self.set_icon_from_file( os.path.join(PATH, "Iconos", "ceibal.png")) - + self.set_resizable(True) self.set_size_request(640, 480) self.set_border_width(5) - + self.set_position(Gtk.WindowPosition.CENTER) - + self.path = TEMPPATH - + self.out_dict = {} # keys = Encuestados, Values = Encuesta respondida - + box = Gtk.VBox() - + self.infowidget = InfoWidget() self.panel = Panel() - + # menuitems self.guardar = None self.exportar = None - + box.pack_start(self.__get_menu(), False, False, 5) box.pack_start(self.infowidget, False, False, 5) box.pack_start(self.panel, True, True, 0) - + self.add(box) - + self.show_all() self.realize() - + self.infowidget.hide() self.panel.hide() - + self.panel.connect("new", self.__change) self.panel.connect("text_and_change", self.__set_text_and_change) self.panel.connect("new-selection", self.__new_selection) - + self.connect("key-press-event", self.__key_press_event) self.connect("destroy", self.__salir) - + self.__init() - + self.fullscreen() - + def __init(self, widget = None): """ Abre encuesta y lista a través del asistente. """ - + reset = False - + dialog = Wizard(parent_window = self) - + response = dialog.run() - + if Gtk.ResponseType(response) == Gtk.ResponseType.CANCEL: pass - + else: encuesta_nueva = dialog.label_1.get_text() lista = dialog.label_2.get_text() encuesta_anterior = dialog.label_3.get_text() - + if encuesta_nueva and lista and not encuesta_anterior: self.__load_encuesta(None, encuesta_nueva) - + while Gtk.events_pending(): Gtk.main_iteration() - + self.__load_encuestados(None, lista) - + elif encuesta_anterior and not encuesta_nueva and not lista: self.__load_encuesta_respondida(None, encuesta_anterior) - + else: reset = True - + dialog.destroy() - + if reset: self.__init() - + def __key_press_event(self, widget, event): """ Eventos de Teclas. """ - + if self.panel.encuesta_tipo == "normal": return - + ### Cuando se presiona escape if event.keyval == 65307: from Widgets import Password_Dialog - + dialog = Password_Dialog( parent_window = self, title = "Administrar", label = "Password:") - + response = dialog.run() - + password = 0 - + if Gtk.ResponseType(response) == Gtk.ResponseType.ACCEPT: password = dialog.get_password() - + dialog.destroy() - - if password == "123456789": + + if password == "123": self.panel.show_lista() - + def do_draw(self, context): """ Pinta una imagen si no se ha cargado una lista a encuestar o una encuesta a aplicar. """ - + if self.panel.get_visible(): self.infowidget.show() return False - + from gi.repository import GdkPixbuf from gi.repository import Gdk - + import cairo - + archivo = os.path.join(PATH, "Iconos", "screen.svg") - + pixbuf = GdkPixbuf.Pixbuf.new_from_file(archivo) - + rect = self.get_allocation() x, y, w, h = (rect.x, rect.y, rect.width, rect.height) ww, hh = pixbuf.get_width(), pixbuf.get_height() - + scaledPixbuf = pixbuf.scale_simple( w, h, GdkPixbuf.InterpType.BILINEAR) - + surface = cairo.ImageSurface( cairo.FORMAT_ARGB32, scaledPixbuf.get_width(), scaledPixbuf.get_height()) - + tmpcontext = cairo.Context(surface) Gdk.cairo_set_source_pixbuf(tmpcontext, scaledPixbuf, 0, 0) tmpcontext.paint() context.set_source_surface(surface) context.paint() - + def __set_text_and_change(self, widget, encuestado, grupo, pregunta, dict_pregunta): """ Cuando se ingresa texto en una pregunta cuyo widgets es un Gtk.Entry, se almacenan los datos. """ - + indice_grupo = grupo.indice grupo_name = grupo.get_label() - + indice_pregunta = pregunta.indice - + user = "" for item in encuestado: user += " %s" % item - + encuestado = user.strip() # Entrada para encuestado if not encuestado in self.out_dict.keys(): self.out_dict[encuestado] = {} - + # Entrada para grupo if not self.out_dict[encuestado].get(indice_grupo, False): self.out_dict[encuestado][indice_grupo] = {} - + # Entrada para pregunta if not self.out_dict[encuestado][indice_grupo].get("fields", False): self.out_dict[encuestado][indice_grupo]["fields"] = {} - + self.out_dict[encuestado][indice_grupo]["name"] = grupo_name - + self.out_dict[encuestado][indice_grupo]["fields"][indice_pregunta] = dict_pregunta - + self.__save_json(path = self.path) - + def __change(self, widget, encuestado, indice_grupo, grupo_name, indice_pregunta, dict_pregunta): @@ -264,152 +264,152 @@ class CeibalEncuesta(Gtk.Window): Recibe los cambios en la encuesta y almacena los datos. """ - + user = "" for item in encuestado: user += " %s" % item - + encuestado = user.strip() - + # Entrada para encuestado if not encuestado in self.out_dict.keys(): self.out_dict[encuestado] = {} - + # Entrada para grupo if not self.out_dict[encuestado].get(indice_grupo, False): self.out_dict[encuestado][indice_grupo] = {} - + # Entrada para pregunta if not self.out_dict[encuestado][indice_grupo].get("fields", False): self.out_dict[encuestado][indice_grupo]["fields"] = {} - + self.out_dict[encuestado][indice_grupo]["name"] = grupo_name - + self.out_dict[encuestado][indice_grupo]["fields"][indice_pregunta] = dict_pregunta - + self.__save_json(path = self.path) - + def __new_selection(self, widget, encuestado): """ Cuando el usuario cambia de Encuestado. """ - + import json import codecs - + archivo = codecs.open(self.path, "r", "utf-8") enc = json.JSONDecoder("utf-8").decode(archivo.read()) - + self.out_dict = {} self.out_dict = enc["groups"] - + if self.out_dict.get(encuestado, False): self.panel.update(self.out_dict[encuestado]) - + else: self.out_dict[encuestado] = {} self.panel.update({}) - + self.infowidget.set_encuestado(encuestado) - + def __get_menu(self): """ Crea y devuelve el menú de la aplicación. """ - + menu_bar = Gtk.MenuBar() menu_bar.show() - + file_menu = Gtk.Menu() - + abrir = Gtk.MenuItem("Abrir Encuesta . . .") abrir.set_tooltip_text("Abrir una Encuesta.") file_menu.append(abrir) abrir.connect_object("activate", self.__init, "") - + self.guardar = Gtk.MenuItem("Guardar Encuesta . . .") self.exportar = Gtk.MenuItem("Exportar Encuesta . . .") salir = Gtk.MenuItem("Salir") - + self.guardar.set_tooltip_text( "Guardar la Encuesta Actual.") self.exportar.set_tooltip_text( "Exportar Encuesta a Formato csv") salir.set_tooltip_text( "Salir de la Aplicación.") - + file_menu.append(self.guardar) file_menu.append(self.exportar) file_menu.append(salir) - + self.guardar.connect_object("activate", self.__guardar_encuesta, "") self.exportar.connect_object("activate", self.__exportar_encuesta, "") salir.connect_object("activate", self.__salir, "") - + salir.show() - + file_item = Gtk.MenuItem("Archivo") file_item.show() file_item.set_submenu(file_menu) menu_bar.append(file_item) - + self.guardar.set_sensitive(False) self.exportar.set_sensitive(False) - + return menu_bar - + def __exportar_encuesta(self, widget = None, senial = None): """ Exporta los datos a un archivo con el formato necesario para ser enviado a web app. """ - + ### Asegurandose de que se haya guardado toda la información. self.__save_json() - + import json import codecs - + archivo = codecs.open(self.path, "r", "utf-8") enc = json.JSONDecoder("utf-8").decode(archivo.read()) - + ### Cabecera para lista de encuestados. cabecera = enc["encuestados"][0] - + polltype = "monitoreo" if "ID" in cabecera: polltype = "general" - + ### Encuestados. encuestados = enc["encuestados"][1:] - + ### Respuestas respuestas = enc["groups"] - + ### Formando salida para encuestados. polled_dict = {} - + for item in cabecera: polled_dict[item] = "" - + ### llenando la salida para este encuestado. result = {} contador = 0 - + for encuestado in encuestados: - + ### polled polled = polled_dict.copy() for item in encuestado: polled[cabecera[encuestado.index(item)]] = item - + ### answers user = "" for item in encuestado: user += " %s" % item - + encue = user.strip() - + answers = respuestas.get(encue, {}) for group_order, fields in answers.iteritems(): @@ -433,9 +433,9 @@ class CeibalEncuesta(Gtk.Window): del field_data[key_to_del] result[contador] = {"polled": polled, "answers": answers} - + contador += 1 - + ### Salida Final. out_dict = { "result": result, @@ -444,15 +444,15 @@ class CeibalEncuesta(Gtk.Window): "pollster_id": enc.get("pollster_id", ""), "pollster_username": enc.get("pollster_username", ""), "poll_type": polltype} - + import time - + poll_id = enc.get("poll_id", "") hash = int(time.time() * 1000) path = os.path.join(WORKPATH, "%s_%s.poll_result" % (poll_id, hash)) - + import simplejson - + archivo = open(path, "w") archivo.write( simplejson.dumps( @@ -463,224 +463,224 @@ class CeibalEncuesta(Gtk.Window): ) ) archivo.close() - + dialog = My_Alert_Dialog( parent_window = self, label = "Encuesta Exportada Correctamente.") - + response = dialog.run() - + dialog.destroy() - + def __guardar_encuesta(self, widget = None, senial = None): """ Abre Filechooser para guardar la encuesta respondida o parcialmente respondida. """ - + filechooser = My_FileChooser( parent_window = self, action_type = Gtk.FileChooserAction.SAVE, filter_type = "text/encuesta", title = "Guardar Encuesta") - + filechooser.connect("load", self.__save_encuesta) - + def __save_encuesta(self, widget, archivo): """ Guarda encuesta en formato json. """ - + name, ext = os.path.splitext(archivo) - + if ext: if ext != "encuesta": ext = ".encuesta" - + else: ext = ".encuesta" - + archivo = "%s%s" % (name, ext) - + self.__save_json(path = os.path.join(archivo)) - + def __load_encuesta_respondida(self, widget, archivo): """ Carga una encuesta parcial o totalmente respondida, desde un archivo json. """ - + if os.path.exists(TEMPPATH): os.remove(TEMPPATH) - + self.path = archivo - + extension = os.path.splitext(os.path.split(archivo)[1])[1] - + if "encuesta" in extension: import json import codecs - + archivo = codecs.open(archivo, "r", "utf-8") enc = json.JSONDecoder("utf-8").decode(archivo.read()) - + self.out_dict = enc["groups"] self.panel.load_encuesta(enc["encuesta"]) - + poll_name = enc["poll_name"] poll_id = enc["poll_id"] pollster_id = enc["pollster_id"] pollster_username = enc["pollster_username"] - + dict = { "poll_name": poll_name, "poll_id": poll_id, "pollster_id": pollster_id, "pollster_username": pollster_username} - + self.infowidget.set_info(dict) - + self.panel.load_encuestados(enc["encuestados"]) - + self.__check_sensitive() - + def __load_encuestados(self, widget, archivo): """ Recibe archivo csv con la lista a encuestar y la manda cargar en la aplicación. """ - + if os.path.exists(TEMPPATH): os.remove(TEMPPATH) - + self.path = TEMPPATH - + arch = open(self.path, "w") arch.close() - + self.out_dict = {} - + self.__save_json(path = self.path) - + encuestados = G.cargar_encuestados(os.path.join(archivo)) - + self.panel.load_encuestados(encuestados) - + self.__check_sensitive() - + def __load_encuesta(self, widget, archivo): """ Carga una encuesta almacenada en un archivo json o shelve. """ - + if os.path.exists(TEMPPATH): os.remove(TEMPPATH) - + self.path = TEMPPATH - + arch = open(self.path, "w") arch.close() - + # Mantiene la lista de encuestados cargada actualmente. encuestados = self.out_dict.keys() - + self.out_dict = {} - + for encuestado in encuestados: self.out_dict[encuestado] = {} - + encuesta = {} - + poll_name = "" poll_id = "" pollster_id = "" pollster_username = "" - + extension = os.path.splitext(os.path.split(archivo)[1])[1] - + if "json" in extension: import json import codecs - + archivo = codecs.open(archivo, "r", "utf-8") enc = json.JSONDecoder("utf-8").decode(archivo.read()) encuesta = enc["groups"] - + poll_name = enc["poll_name"] poll_id = enc["poll_id"] pollster_id = enc["pollster_id"] pollster_username = enc["pollster_username"] - + elif "slv" in extension: import shelve - + archivo = shelve.open(archivo) - + enc = archivo["groups"] - + poll_name = archivo["poll_name"] poll_id = archivo["poll_id"] pollster_id = archivo["pollster_id"] pollster_username = archivo["pollster_username"] - + for key in enc.keys(): encuesta[key] = enc[key] - + archivo.close() - + self.panel.load_encuesta(encuesta) - + dict = { "poll_name": poll_name, "poll_id": poll_id, "pollster_id": pollster_id, "pollster_username": pollster_username} - + self.infowidget.set_info(dict) - + while Gtk.events_pending(): Gtk.main_iteration() - + self.__save_json(path = self.path) - + self.__check_sensitive() - + def __check_sensitive(self): - + if self.panel.encuesta and self.panel.lista: self.guardar.set_sensitive(True) self.exportar.set_sensitive(True) - + else: self.guardar.set_sensitive(False) self.exportar.set_sensitive(False) - + def __save_json(self, path = TEMPPATH): """ Guarda encuesta en formato json. """ - + self.path = path - + encuestados = [] encuesta = {} poll_name = "" poll_id = "" pollster_id = "" pollster_username = "" - + if self.panel: if self.panel.encuestados: encuestados = self.panel.encuestados if self.panel.encuesta: encuesta = self.panel.encuesta - + if self.infowidget: dict = self.infowidget.get_info() pull_name = dict["poll_name"] poll_id = dict["poll_id"] pollster_id = dict["pollster_id"] pollster_username = dict["pollster_username"] - + salida = { "encuestados": encuestados, "groups": self.out_dict, @@ -689,22 +689,22 @@ class CeibalEncuesta(Gtk.Window): "poll_id": poll_id, "pollster_id": pollster_id, "pollster_username": pollster_username} - + import simplejson archivo = open(self.path, "w") archivo.write(simplejson.dumps(salida)) archivo.close() - + if os.path.exists(TEMPPATH): if TEMPPATH != path: os.remove(TEMPPATH) - + def __salir(self, widget = None, senial = None): - + sys.exit(0) - + if __name__ == "__main__": - + ceibalencuesta = CeibalEncuesta() Gtk.main() - + diff --git a/CeibalEncuesta/gtk3/CeibalEncuesta/Widgets.py b/CeibalEncuesta/gtk3/CeibalEncuesta/Widgets.py index 1eeab49..e1487b9 100755 --- a/CeibalEncuesta/gtk3/CeibalEncuesta/Widgets.py +++ b/CeibalEncuesta/gtk3/CeibalEncuesta/Widgets.py @@ -1708,10 +1708,11 @@ class GeneralWidget(Gtk.Box): Si hay más delante de éste, pasa al siguiente. De lo contrario crear uno nuevo y lo selecciona. """ - + + msg = "¿Esta seguro que desea terminar esta encuesta y seguir con una nueva?" dialog = My_Alert_Dialog2( - parent_window = self.get_toplevel(), label = "Texto") - + parent_window = self.get_toplevel(), label = msg) + response = dialog.run() if Gtk.ResponseType(response) != Gtk.ResponseType.ACCEPT: @@ -2038,4 +2039,4 @@ class My_Alert_Dialog2(Gtk.Dialog): self.set_border_width(10) self.vbox.pack_start(label, True, True, 0) -
\ No newline at end of file + |