diff options
Diffstat (limited to 'CeibalEncuesta/CeibalEncuesta.py')
-rw-r--r-- | CeibalEncuesta/CeibalEncuesta.py | 479 |
1 files changed, 419 insertions, 60 deletions
diff --git a/CeibalEncuesta/CeibalEncuesta.py b/CeibalEncuesta/CeibalEncuesta.py index 1e637a4..8d0e856 100644 --- a/CeibalEncuesta/CeibalEncuesta.py +++ b/CeibalEncuesta/CeibalEncuesta.py @@ -18,18 +18,50 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# Notas: +# Las listas de Encuestados se abren desde un archivo csv. +# Las encuestas sin Responder se abren desde un archivo slv (shelve) o json. +# Las Encuestas respondidas o parcialmente respondidas se guardan en archivos .encuesta (json) + import os import sys import gi from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GObject from Widgets import Panel from Widgets import My_FileChooser +from Widgets import My_Alert_Dialog import Globales as G PATH = os.path.dirname(__file__) +HOME = os.environ["HOME"] +WORKPATH = os.path.join(HOME, "CeibalEncuesta") +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() + +screen = Gdk.Screen.get_default() +css_provider = Gtk.CssProvider() +style_path = os.path.join(PATH, "CssStyle.css") +css_provider.load_from_path(style_path) +context = Gtk.StyleContext() + +context.add_provider_for_screen( + screen, + css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_USER) + +GObject.threads_init() +Gdk.threads_init() class CeibalEncuesta(Gtk.Window): @@ -45,69 +77,179 @@ class CeibalEncuesta(Gtk.Window): self.set_resizable(True) self.set_size_request(640, 480) - self.set_border_width(2) + 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.panel = Panel() - box.pack_start(self.get_menu(), False, False, 0) + # menuitems + self.guardar = None + self.exportar = None + + box.pack_start(self.__get_menu(), False, False, 0) box.pack_start(self.panel, True, True, 0) self.add(box) self.show_all() + self.panel.hide() + self.panel.connect("new", self.__change) + self.panel.connect("text", self.__set_text) self.panel.connect("new-selection", self.__new_selection) + self.connect("destroy", self.__salir) - self.out_dict = None + 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(): return False + + from gi.repository import GdkPixbuf + from gi.repository import Gdk + + import cairo + + archivo = os.path.join(PATH, + "Iconos", "screen.svg") - def __change(self, widget, new_dict): - """Recibe los cambios en la encuesta.""" + pixbuf = GdkPixbuf.Pixbuf.new_from_file(archivo) - if self.out_dict == None: - self.out_dict = {} + 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(self, widget, + encuestado, id_grupo, id_pregunta, id_opcion, text): + """ + Cuando se ingresa texto en una opción + del tipo Entry. (caso particular). + """ + + user = '' + for item in encuestado: + user += ' %s' % item + + encuestado = user.strip() + + if text: + self.out_dict[encuestado][id_grupo]['fields'][id_pregunta]['options'][id_opcion]['newtext'] = text + + else: + del self.out_dict[encuestado][id_grupo]['fields'][id_pregunta]['options'][id_opcion]['newtext'] + + self.__save_json(path = self.path) + + def __change(self, widget, encuestado, + indice_grupo, grupo_name, + indice_pregunta, dict_pregunta): + """ + 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] = {} - self.out_dict[new_dict.keys()[0]] = new_dict[new_dict.keys()[0]] + # Entrada para grupo + if not indice_grupo in self.out_dict[encuestado].keys(): + self.out_dict[encuestado][indice_grupo] = {} + + # Entrada para pregunta + if not 'fields' in self.out_dict[encuestado][indice_grupo].keys(): + 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 - #print self.out_dict + self.__save_json(path = self.path) def __new_selection(self, widget, data): - """Cuando el usuario cambia de Encuestado.""" + """ + Cuando el usuario cambia de Encuestado. + """ - if self.out_dict != None: - if data in self.out_dict.keys(): - self.panel.update(self.out_dict[data]) + if data in self.out_dict.keys(): + self.panel.update(self.out_dict[data]) - def get_menu(self): - """Crea y devuelve el menú de la aplicación.""" + def __get_menu(self): + """ + Crea y devuelve el menú de la aplicación. + """ menu_bar = Gtk.MenuBar() menu_bar.show() file_menu = Gtk.Menu() - alumnos = Gtk.MenuItem("Cargar Encuestados") - encuesta = Gtk.MenuItem("Cargar Encuesta") - #guardar = Gtk.MenuItem("Guardar") + encuestados = Gtk.MenuItem("Nueva Lista . . .") + encuesta = Gtk.MenuItem("Nueva Encuesta . . .") + recuperar = Gtk.MenuItem("Abrir Encuesta . . .") + self.guardar = Gtk.MenuItem("Guardar Encuesta . . .") + self.exportar = Gtk.MenuItem("Exportar Encuesta . . .") salir = Gtk.MenuItem("Salir") - file_menu.append(alumnos) + encuestados.set_tooltip_text( + "Cargar una Nueva Lista a Encuestar.") + encuesta.set_tooltip_text( + "Cargar una Nueva Encuesta para ser Aplicada a la Lista.") + recuperar.set_tooltip_text( + "Abrir una Encuesta Total o Parcialmente Respondida.") + 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(encuestados) file_menu.append(encuesta) - #file_menu.append(guardar) + file_menu.append(recuperar) + file_menu.append(self.guardar) + #file_menu.append(self.exportar) file_menu.append(salir) - alumnos.connect_object ("activate", self.__cargar_alumnos, '') - encuesta.connect_object ("activate", self.__cargar_encuesta, '') - #guardar.connect_object ("activate", self.__guardar, '') - salir.connect_object ("activate", self.__salir, '') + encuestados.connect_object("activate", self.__cargar_encuestados, '') + encuesta.connect_object("activate", self.__cargar_encuesta, '') + recuperar.connect_object("activate", self.__recuperar_encuesta, '') + self.guardar.connect_object("activate", self.__guardar_encuesta, '') + self.exportar.connect_object("activate", self.__exportar_encuesta, '') + salir.connect_object("activate", self.__salir, '') - alumnos.show() - #guardar.show() + encuestados.show() salir.show() file_item = Gtk.MenuItem("Archivo") @@ -116,44 +258,233 @@ class CeibalEncuesta(Gtk.Window): 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 __cargar_alumnos(self, widget = None, senial = None): - """Abre Filechooser para cargar el archivo con la - lista de alumnos a encuestar.""" + def __exportar_encuesta(self, widget = None, senial = None): + """ + Abre Filechooser para Exportar la encuesta a un + archivo csv. + """ + + filechooser = My_FileChooser( + parent_window = self, + action_type = Gtk.FileChooserAction.SAVE, + filter_type = 'text/csv', + title = "Exportar Encuesta") + + filechooser.connect('load', self.__export_encuesta) + + def __export_encuesta(self, widget, archivo): + """ + Exporta la encuesta a un archivo csv. + """ + + name, ext = os.path.splitext(archivo) + + if ext: + if ext != "csv": + ext = ".csv" + + else: + ext = ".csv" + + archivo = "%s%s" % (name, ext) + + print "Exportar:", archivo + + 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)) + + # FIXME: A partir de este momento, la encuesta se + # guardará automáticamente en este archivo, analizar + # mejor si esto debe hacerse así o solo debe guardarse + # acá cuando el usuario lo decide. + + def __recuperar_encuesta(self, widget = None, senial = None): + """ + Abre Filechooser para cargar el archivo con la + encuesta respondida o parcialmente respondida. + """ + + if self.panel.lista and self.panel.encuesta: + dialog = My_Alert_Dialog(parent_window = self, + label = "¿ Proceder sin Guardar ?") + + response = dialog.run() + + dialog.destroy() + + if Gtk.ResponseType(response) == Gtk.ResponseType.CANCEL: + return + + filechooser = My_FileChooser( + parent_window = self, + action_type = Gtk.FileChooserAction.OPEN, + #filter_type = 'text/encuesta', + title = "Recuperar Encuesta") + + filechooser.connect('load', self.__load_encuesta_respondida) + + 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']) + self.panel.load_encuestados(enc['encuestados']) + + def __cargar_encuestados(self, widget = None, senial = None): + """ + Abre Filechooser para cargar el archivo con la + lista a encuestar. + """ + + if self.panel.lista and self.panel.encuesta: + dialog = My_Alert_Dialog(parent_window = self, + label = "¿ Proceder sin Guardar ?") + + response = dialog.run() + + dialog.destroy() + + if Gtk.ResponseType(response) == Gtk.ResponseType.CANCEL: + return + filechooser = My_FileChooser( parent_window = self, action_type = Gtk.FileChooserAction.OPEN, - filter_type = 'text/csv') + filter_type = 'text/csv', + title = "Cargar Lista a Encuestar") - filechooser.connect('load', self.__load_alumnos) - - def __load_alumnos(self, widget, archivo): - """Recibe archivo csv con la lista de alumnos a encuestar y - la manda cargar en la aplicación.""" + filechooser.connect('load', self.__load_encuestados) + + def __load_encuestados(self, widget, archivo): + """ + Recibe archivo csv con la lista a encuestar + y la manda cargar en la aplicación. + """ - self.out_dict = None + if os.path.exists(TEMPPATH): + os.remove(TEMPPATH) - alumnos = G.cargar_alumnos(os.path.join(archivo)) - self.panel.load_alumnos(alumnos) + self.path = TEMPPATH + + arch = open(self.path, 'w') + arch.close() + + self.out_dict = {} + encuestados = G.cargar_encuestados(os.path.join(archivo)) + + for encue in encuestados[1:]: + user = '' + + for item in encue: + user += ' %s' % item + + encuestado = user.strip() + + if not encuestado in self.out_dict.keys(): + self.out_dict[encuestado] = {} + + self.panel.load_encuestados(encuestados) + + GObject.idle_add(self.__save_json, self.path) + + self.__check_sensitive() def __cargar_encuesta(self, widget = None, senial = None): - """Abre Filechooser para cargar el - archivo con la encuesta.""" + """ + Abre Filechooser para cargar el + archivo con la encuesta. + """ + + if self.panel.lista and self.panel.encuesta: + dialog = My_Alert_Dialog(parent_window = self, + label = "¿ Proceder sin Guardar ?") + + response = dialog.run() + + dialog.destroy() + + if Gtk.ResponseType(response) == Gtk.ResponseType.CANCEL: + return filechooser = My_FileChooser( parent_window = self, action_type = Gtk.FileChooserAction.OPEN, - filter_type = None) + filter_type = None, + title = "Cargar Nueva Encuesta") filechooser.connect('load', self.__load_encuesta) - + def __load_encuesta(self, widget, archivo): - """Carga una encuesta almacenada en - un archivo json o en un archivo shelve.""" + """ + Carga una encuesta almacenada en + un archivo json o shelve. + """ - self.out_dict = None + 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() + + for encuestado in encuestados: + self.out_dict[encuestado] = {} + encuesta = {} extension = os.path.splitext(os.path.split(archivo)[1])[1] @@ -163,35 +494,63 @@ class CeibalEncuesta(Gtk.Window): import codecs archivo = codecs.open(archivo, "r", "utf-8") - encuesta = json.JSONDecoder("utf-8").decode(archivo.read()) + enc = json.JSONDecoder("utf-8").decode(archivo.read()) + encuesta = enc['groups'] elif 'slv' in extension: - import shelve archivo = shelve.open(archivo) - for key in archivo.keys(): - encuesta[key] = archivo[key] + enc = archivo['groups'] + + for key in enc.keys(): + encuesta[key] = enc[key] archivo.close() - + self.panel.load_encuesta(encuesta) - def __guardar(self, widget = None, senial = None): - """Abre Filechooser para guardar la encuesta.""" + GObject.idle_add(self.__save_json, self.path) - filechooser = My_FileChooser( - parent_window = self, - action_type = Gtk.FileChooserAction.OPEN, - filter_type = 'text/csv') - - #filechooser.connect('load', self.__load_alumnos) - + self.__check_sensitive() + + self.panel.update({}) + + 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 + + salida = { + 'encuestados': self.panel.encuestados, + 'groups': self.out_dict, + 'encuesta': self.panel.encuesta} + + 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__": |