#!/usr/bin/env python # -*- coding: utf-8 -*- # InfoNotebook.py por: # Cristian García # Ignacio Rodriguez # Flavio Danesse # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os import re import gi from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GObject from Widgets import get_boton class InfoNotebook(Gtk.Notebook): """ Notebook Izquierdo, para introspección y Estructura de proyecto. """ __gsignals__ = { 'new_select': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))} def __init__(self): Gtk.Notebook.__init__(self) self.estructura_proyecto = Estructura_Proyecto() self.introspeccion = Introspeccion() scroll = Gtk.ScrolledWindow() scroll.set_policy( Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scroll.add_with_viewport(self.introspeccion) self.append_page(scroll, Gtk.Label("Introspección")) scroll = Gtk.ScrolledWindow() scroll.set_policy( Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scroll.add_with_viewport(self.estructura_proyecto) self.append_page(scroll, Gtk.Label("Proyecto")) self.show_all() self.introspeccion.connect("new_select", self.__re_emit_new_select) def __re_emit_new_select(self, widget, texto): """ Emite la señal new_select cuando se hace doble click sobre una fila en la instrospeccion. """ self.emit('new_select', texto) def set_path_estructura(self, path): """ Setea estructura de directorios y archivos del proyecto según path. """ self.estructura_proyecto.set_path_estructura(path) def set_introspeccion(self, nombre, texto): """ Recibe nombre y contenido de archivo para realizar introspeccion sobre él. """ if nombre == "False": nombre = "Introspección" self.set_tab_label_text(self.get_nth_page(0), nombre) self.introspeccion.set_introspeccion(nombre, texto) class Introspeccion(Gtk.TreeView): """ TreeView para la Introspección """ __gsignals__ = { 'new_select': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))} def __init__(self): Gtk.TreeView.__init__(self, Gtk.TreeStore(GObject.TYPE_STRING, Gdk.Color)) self.__set_columnas() self.set_headers_visible(False) self.show_all() def do_row_activated(self, path, column): """ Emite la señal new_select cuando se hace doble click sobre una fila """ iter = self.get_model().get_iter(path) texto = self.get_model().get_value(iter, 0) self.emit('new_select', texto) def set_introspeccion(self, nombre, texto): """ Recibe nombre y contenido de archivo para realizar introspeccion sobre él. """ self.get_model().clear() if not texto: return analisis = re.compile(r'(^[ \t]*?class\s.*[(:])|(^[ \t]*?def\s.*[(:])|(^[\t]*?import\s.*$)|(^[ \t]*?from\s.*$)|(^\s*#---.+)', re.MULTILINE) datos, posiciones = self.__get_datos_introspeccion(texto, analisis) actual = 0 self.iteractual = None modelo = self.get_model() for dato in datos: if dato.startswith("import ") or dato.startswith("from ") or dato.startswith("def "): if dato.startswith("import ") or dato.startswith("from "): color = Gdk.color_parse("dark green") else: color = Gdk.color_parse("#FF0D00") modelo.append( None, [dato, color]) if dato.startswith("class "): self.iteractual = modelo.append( None, [dato, Gdk.color_parse("purple")]) if dato[0:13] == "-Tabulacion- " and dato[14] != "T": nuevodato = dato.replace("-Tabulacion- ", "") self.ultimodef = modelo.append( self.iteractual, [nuevodato, Gdk.color_parse("#FF0D00")]) if dato[0:26] == "-Tabulacion- -Tabulacion- ": nuevodato = dato.replace("-Tabulacion- ", "") self.ultimodef = modelo.append( self.ultimodef, [nuevodato, Gdk.color_parse("#FF0D00")]) actual += 1 def __get_datos_introspeccion(self, texto, objetos): """ Devuelve dos listas, una con los datos y otra con las posiciones """ datos = [] posiciones = [] objetos = objetos.finditer(texto) try: resultado = objetos.next() except: resultado = None while resultado is not None: dato_nuevo = resultado.group().replace(" ", "-Tabulacion- ") datos.append(dato_nuevo) posiciones.append(resultado.start()) try: resultado = objetos.next() except: resultado = None return datos, posiciones def __set_columnas(self): """ Crea y agrega las columnas. """ render = Gtk.CellRendererText() columna1 = Gtk.TreeViewColumn('Datos', render , text=0) columna1.add_attribute(render, 'foreground-gdk', 1) self.append_column(columna1) def do_key_press_event(self, event): """ Funciones adicionales para moverse en el TreeView """ tecla = event.keyval model, iter = self.get_selection().get_selected() if iter is None: return path = self.get_model().get_path(iter) if tecla == 65293: if self.row_expanded(path): self.collapse_row(path) else: self.expand_to_path(path) elif tecla == 65361: if self.row_expanded(path): self.collapse_row(path) elif tecla == 65363: if not self.row_expanded(path): self.expand_to_path(path) elif tecla == 65364: siguiente = self.get_model().iter_next(iter) if siguiente: self.get_selection().select_iter(siguiente) elif tecla == 65362: anterior = self.get_model().iter_previous(iter) if anterior: self.get_selection().select_iter(anterior) else: pass return False class Estructura_Proyecto(Gtk.TreeView): """ TreeView para la estructura del proyecto. """ __gsignals__ = { 'open': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))} def __init__(self): Gtk.TreeView.__init__(self, Gtk.TreeStore( GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING)) self.set_property("enable-grid-lines", True) self.set_property("rules-hint", True) self.set_property("enable-tree-lines", True) self.add_events( Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.TOUCH_MASK) self.__set_columnas() self.set_headers_visible(False) self.show_all() def set_path_estructura(self, path): """ Carga la estructura de directorios y archivos del proyecto. """ self.get_model().clear() if not path: return iter = self.get_model().get_iter_first() self.get_model().append( iter, [Gtk.STOCK_DIRECTORY, os.path.basename(path), path]) estructura = [] estructura.append((path, None)) GObject.idle_add(self.__load_estructura, estructura) def __set_columnas(self): """ Crea y agrega las columnas al TreeView. """ render = Gtk.CellRendererPixbuf() columna = Gtk.TreeViewColumn('pixbuf', render, stock_id=0) columna.set_property('resizable', False) columna.set_property('visible', True) columna.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.append_column(columna) render = Gtk.CellRendererText() columna = Gtk.TreeViewColumn('text', render, text=1) columna.set_property('resizable', False) columna.set_property('visible', True) columna.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.append_column(columna) render = Gtk.CellRendererText() columna = Gtk.TreeViewColumn('text', render, text=2) columna.set_property('resizable', False) columna.set_property('visible', False) columna.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.append_column(columna) def __load_estructura(self, estructura): """ Función Recursiva que agrega directorios y archivos al modelo, según "estructura". estructura es: una lista de tuplas que contienen: (directorio, path en el modelo donde debe agregarse). """ if not estructura: self.expand_all() return item = estructura[0] directorio, path = item estructura.remove(item) ### Establecer el iter donde debe agregarse el item if path: iter = self.get_model().get_iter(path) else: iter = self.get_model().get_iter_first() ### Leer archivos y directorios en este nivel archivos = [] for archivo in os.listdir(os.path.join(directorio)): if "proyecto.json" in archivo: continue direccion = os.path.join(directorio, archivo) ### Si es un directorio, se agrega y se guarda ### en una lista para hacer recurrencia sobre esta función. if os.path.isdir(direccion): iteractual = self.get_model().append( iter, [Gtk.STOCK_DIRECTORY, archivo, direccion]) ### Para Recursividad. estructura.append( (direccion, self.get_model().get_path(iteractual)) ) ### Si es un archivo. elif os.path.isfile(direccion): archivos.append(direccion) ### Agregar todos los archivos en este nivel. for x in archivos: archivo = os.path.basename(x) self.get_model().append( iter,[Gtk.STOCK_FILE, archivo, x]) ### Recursividad en la función. self.__load_estructura(estructura) def do_row_activated(self, path, column): """ Cuando se hace doble click sobre una fila """ iter = self.get_model().get_iter(path) direccion = self.get_model().get_value(iter, 2) if os.path.isdir(direccion): if self.row_expanded(path): self.collapse_row(path) else: self.expand_to_path(path) elif os.path.isfile(os.path.join(direccion)): self.emit('open', direccion) def do_key_press_event(self, event): """ Funciones adicionales para moverse en el TreeView """ tecla = event.keyval model, iter = self.get_selection().get_selected() if iter is None: return path = self.get_model().get_path(iter) if tecla == 65293: if self.row_expanded(path): self.collapse_row(path) else: self.expand_to_path(path) elif tecla == 65361: if self.row_expanded(path): self.collapse_row(path) elif tecla == 65363: if not self.row_expanded(path): self.expand_to_path(path) elif tecla == 65364: siguiente = self.get_model().iter_next(iter) if siguiente: self.get_selection().select_iter(siguiente) elif tecla == 65362: anterior = self.get_model().iter_previous(iter) if anterior: self.get_selection().select_iter(anterior) else: pass return False