#!/usr/bin/env python # -*- coding: utf-8 -*- # Widgets.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 gi from gi.repository import Gtk from gi.repository import GObject from gi.repository import GdkPixbuf def get_boton(stock, tooltip): """Devuelve un botón generico.""" boton = Gtk.ToolButton.new_from_stock(stock) boton.set_tooltip_text(tooltip) return boton def get_separador(draw = False, ancho = 0, expand = False): """Devuelve un separador generico.""" separador = Gtk.SeparatorToolItem() separador.props.draw = draw separador.set_size_request(ancho, -1) separador.set_expand(expand) return separador LICENCIAS = ['GPL2', 'GPL3', 'LGPL 2.1', 'LGPL 3', 'BSD', 'MIT X11'] class Menu(Gtk.MenuBar): """ Toolbar Principal. """ __gsignals__ = { 'accion': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,))} def __init__(self): Gtk.MenuBar.__init__(self) item_proyectos = Gtk.MenuItem('Proyectos') item_archivos = Gtk.MenuItem('Archivos') item_edicion = Gtk.MenuItem('Edición') item_ver = Gtk.MenuItem('Ver') item_codigo = Gtk.MenuItem('Código') item_ayuda = Gtk.MenuItem('Ayuda') menu_proyectos = Gtk.Menu() menu_archivos = Gtk.Menu() menu_edicion = Gtk.Menu() menu_ver = Gtk.Menu() menu_codigo = Gtk.Menu() menu_ayuda = Gtk.Menu() item_proyectos.set_submenu(menu_proyectos) item_archivos.set_submenu(menu_archivos) item_edicion.set_submenu(menu_edicion) item_ver.set_submenu(menu_ver) item_codigo.set_submenu(menu_codigo) item_ayuda.set_submenu(menu_ayuda) self.append(item_proyectos) self.append(item_archivos) self.append(item_edicion) self.append(item_ver) self.append(item_codigo) self.append(item_ayuda) # Items del Menú Proyectos item = Gtk.MenuItem('Nuevo') item.connect("activate", self.__emit_accion, "Nuevo proyecto") menu_proyectos.append(item) item = Gtk.MenuItem('Abrir') item.connect("activate", self.__emit_accion, "Abrir proyecto") menu_proyectos.append(item) item = Gtk.MenuItem('Editar') item.connect("activate", self.__emit_accion, "Editar proyecto") menu_proyectos.append(item) item = Gtk.MenuItem('Cerrar') item.connect("activate", self.__emit_accion, "Cerrar proyecto") menu_proyectos.append(item) item = Gtk.MenuItem('Guardar') item.connect("activate", self.__emit_accion, "Guardar proyecto") menu_proyectos.append(item) # Items del Menú Archivos item = Gtk.MenuItem('Nuevo') item.connect("activate", self.__emit_accion, "Nuevo") menu_archivos.append(item) item = Gtk.MenuItem('Abrir') item.connect("activate", self.__emit_accion, "Abrir") menu_archivos.append(item) item = Gtk.MenuItem('Cerrar') item.connect("activate", self.__emit_accion, "Cerrar") menu_archivos.append(item) item = Gtk.MenuItem('Guardar') item.connect("activate", self.__emit_accion, "Guardar") menu_archivos.append(item) item = Gtk.MenuItem('Guardar como...') item.connect("activate", self.__emit_accion, "Guardar como") menu_archivos.append(item) # Items del Menú Edición item = Gtk.MenuItem('Deshacer') item.connect("activate", self.__emit_accion, "Deshacer") menu_edicion.append(item) item = Gtk.MenuItem('Rehacer') item.connect("activate", self.__emit_accion, "Rehacer") menu_edicion.append(item) item = Gtk.MenuItem('Cortar') item.connect("activate", self.__emit_accion, "Cortar") menu_edicion.append(item) item = Gtk.MenuItem('Copiar') item.connect("activate", self.__emit_accion, "Copiar") menu_edicion.append(item) item = Gtk.MenuItem('Pegar') item.connect("activate", self.__emit_accion, "Pegar") menu_edicion.append(item) item = Gtk.MenuItem('Sangrar') item.connect("activate", self.__emit_accion, "Sangrar") menu_edicion.append(item) item = Gtk.MenuItem('Quitar Sangrado') item.connect("activate", self.__emit_accion, "Quitar Sangrado") menu_edicion.append(item) item = Gtk.MenuItem('Buscar') item.connect("activate", self.__emit_accion, "Buscar") menu_edicion.append(item) item = Gtk.MenuItem('Reemplazar') item.connect("activate", self.__emit_accion, "Reemplazar") menu_edicion.append(item) item = Gtk.MenuItem('Seleccionar Todo') item.connect("activate", self.__emit_accion, "Seleccionar Todo") menu_edicion.append(item) # Items del menú Ver item = Gtk.MenuItem('Aumentar') item.connect("activate", self.__emit_accion, "Aumentar") menu_ver.append(item) item = Gtk.MenuItem('Disminuir') item.connect("activate", self.__emit_accion, "Disminuir") menu_ver.append(item) # Items del Menú Código item = Gtk.MenuItem('Ejecutar archivo') item.connect("activate", self.__emit_accion, "Ejecutar archivo") menu_codigo.append(item) item = Gtk.MenuItem('Ejecutar proyecto') item.connect("activate", self.__emit_accion, "Ejecutar proyecto") menu_codigo.append(item) item = Gtk.MenuItem('Detener') item.connect("activate", self.__emit_accion, "Detener") menu_codigo.append(item) item = Gtk.MenuItem('Remover espacios en blanco') item.connect("activate", self.__emit_accion, "Remover espacios en blanco") menu_codigo.append(item) item = Gtk.MenuItem('Reemplazar Tabulaciones por Espacios') item.connect("activate", self.__emit_accion, "Reemplazar Tabulaciones por Espacios") menu_codigo.append(item) # Items del Menú Ayuda item = Gtk.MenuItem('Créditos') item.connect("activate", self.__emit_accion, "Créditos") menu_ayuda.append(item) self.show_all() def __emit_accion(self, widget, accion): self.emit('accion', accion) class MainToolbar(Gtk.Toolbar): """ Toolbar Principal. """ def __init__(self): Gtk.Toolbar.__init__(self) # Botones - Proyecto self.nuevo_proyecto = get_boton(Gtk.STOCK_NEW, "Nuevo proyecto") self.abrir_proyecto = get_boton(Gtk.STOCK_OPEN, "Abrir proyecto") self.cerrar_proyecto = get_boton(Gtk.STOCK_CLOSE, "Cerrar proyecto actual") # Botones - Archivos self.nuevo_archivo = get_boton(Gtk.STOCK_NEW, "Nuevo") self.abrir_archivo = get_boton(Gtk.STOCK_OPEN, "Abrir") self.cerrar_archivo = get_boton(Gtk.STOCK_CLOSE, "Cerrar") self.guardar_archivo = get_boton(Gtk.STOCK_SAVE, "Guardar") self.guardar_como = get_boton(Gtk.STOCK_SAVE_AS, "Guardar como") # Botones - Edicion self.deshacer = get_boton(Gtk.STOCK_UNDO, "Deshacer") self.rehacer = get_boton(Gtk.STOCK_REDO, "Rehacer") self.cortar = get_boton(Gtk.STOCK_CUT, "Cortar") self.copiar = get_boton(Gtk.STOCK_COPY, "Copiar") self.pegar = get_boton(Gtk.STOCK_PASTE, "Pegar") self.sangrar = get_boton(Gtk.STOCK_INDENT, "Sangrar") self.quitar_sangria = get_boton(Gtk.STOCK_UNINDENT, "Quitar Sangría") self.buscar = get_boton(Gtk.STOCK_FIND, "Buscar") self.seleccionar_todo = get_boton(Gtk.STOCK_SELECT_ALL, "Seleccionar todo") # Botones - Ver self.aumentar = get_boton(Gtk.STOCK_ZOOM_IN, "Aumentar") self.disminuir = get_boton(Gtk.STOCK_ZOOM_OUT, "Disminuir") # Botones - Código self.ejecutar = get_boton(Gtk.STOCK_MEDIA_PLAY, "Ejecutar Archivo") self.ejecutar_p = get_boton(Gtk.STOCK_MEDIA_PLAY, "Ejecutar Proyecto") self.detener = get_boton(Gtk.STOCK_MEDIA_STOP, "Detener") self.remover_blanco = get_boton(Gtk.STOCK_CLEAR, "Remover espacios en blanco") self.remplazar_tab_espacio = get_boton(Gtk.STOCK_CLEAR, "Reemplazar Tabulaciones por Espacios") # Botones - Ayuda self.creditos = get_boton(Gtk.STOCK_ABOUT, "Créditos") self.insert(self.nuevo_proyecto, -1) self.insert(self.abrir_proyecto, -1) self.insert(self.cerrar_proyecto, -1) self.insert(get_separador(draw = True, ancho = 0, expand = False), -1) self.insert(self.nuevo_archivo, -1) self.insert(self.abrir_archivo, -1) self.insert(self.cerrar_archivo, -1) self.insert(self.guardar_archivo, -1) self.insert(self.guardar_como, -1) self.insert(get_separador(draw = True, ancho = 0, expand = False), -1) self.insert(self.deshacer, -1) self.insert(self.rehacer, -1) self.insert(self.cortar, -1) self.insert(self.copiar, -1) self.insert(self.pegar, -1) self.insert(self.sangrar, -1) self.insert(self.quitar_sangria, -1) self.insert(self.buscar, -1) self.insert(self.seleccionar_todo, -1) self.insert(get_separador(draw = True, ancho = 0, expand = False), -1) self.insert(self.aumentar, -1) self.insert(self.disminuir, -1) self.insert(get_separador(draw = True, ancho = 0, expand = False), -1) self.insert(self.ejecutar, -1) self.insert(self.ejecutar_p, -1) self.insert(self.detener, -1) self.insert(self.remover_blanco, -1) self.insert(self.remplazar_tab_espacio, -1) self.insert(get_separador(draw = True, ancho = 0, expand = False), -1) self.insert(self.creditos, -1) self.show_all() class TryToolbar(Gtk.Toolbar): """ Toolbar para barra de estado. """ def __init__(self): Gtk.Toolbar.__init__(self) self.show_all() class DialogoProyecto(Gtk.Dialog): """ Diálogo para crear un nuevo proyecto. """ def __init__(self, parent_window = None, title = "Crear Proyecto Nuevo"): Gtk.Dialog.__init__(self, title = title, parent = parent_window, flags = Gtk.DialogFlags.MODAL, buttons = [ "Aceptar", Gtk.ResponseType.ACCEPT, "Cancelar", Gtk.ResponseType.CANCEL]) self.set_size_request(500, 300) self.set_border_width(15) ### Entradas de datos. self.nombre = Gtk.Entry() self.main = Gtk.ComboBoxText() self.path = Gtk.Label() self.version = Gtk.Entry() self.descripcion = Gtk.TextView() self.descripcion.set_editable(True) self.descripcion.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) scroll_descripcion = Gtk.ScrolledWindow() scroll_descripcion.set_policy( Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scroll_descripcion.add_with_viewport(self.descripcion) scroll_descripcion.set_size_request(200, 100) self.licencia = Gtk.ComboBoxText() self.url = Gtk.Entry() self.icon_path = Gtk.Label() ### Box para despues agregarlo a un scroll self.box = Gtk.Box(orientation = Gtk.Orientation.VERTICAL) ### Scroll scroll = Gtk.ScrolledWindow() scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scroll.add_with_viewport(self.box) self.vbox.pack_start(scroll, True, True, 0) ### Autores self.autores = WidgetAutores() ### Imagen para el preview del icono self._icono_preview = Gtk.Image() ### botones internos boton_buscar_icono = Gtk.Button(Gtk.STOCK_FIND) boton_buscar_icono.set_use_stock(True) boton_buscar_icono.connect("clicked", self.__buscar, "icono") internal_widgets = [ self.__get_pack_box( [self.__get_label('Nombre:'), self.nombre] ), self.__get_pack_box( [self.__get_label('Archivo Principal:'), self.main] ), self.__get_pack_box( [self.__get_label('Directorio del proyecto:'), self.path] ), self.__get_pack_box( [self.__get_label('Versión:'), self.version] ), self.__get_pack_box( [self.__get_label('Licencia:'), self.licencia] ), self.__get_pack_box( [self.__get_label('Web:'), self.url] ), self.__get_pack_box( [self.__get_label('Icono:'), self.icon_path, self._icono_preview, boton_buscar_icono] ), self.__get_pack_box( [self.__get_label("Autores:"), self.autores] ), self.__get_pack_box( [self.__get_label('Descripción:'), scroll_descripcion] )] for widget in internal_widgets: self.box.pack_start(widget, True, True, 3) for licencia in LICENCIAS: self.licencia.append_text(licencia) self.licencia.set_active(0) self.show_all() self.nombre.connect("key_release_event", self.__check_nombre) for button in self.get_action_area().get_children(): if self.get_response_for_widget(button) == Gtk.ResponseType.ACCEPT: button.set_sensitive(False) break def __check_nombre(self, widget, event): """ Activa y Desactiva el boton aceptar, según tenga nombre el proyecto o no. """ boton = None for button in self.get_action_area().get_children(): if self.get_response_for_widget(button) == Gtk.ResponseType.ACCEPT: boton = button break nombre = self.nombre.get_text() if nombre: nombre = nombre.strip() if nombre: boton.set_sensitive(True) else: boton.set_sensitive(False) def __get_label(self, text): """ Recibe un texto y devuelve un Gtk.Label con él. """ label = Gtk.Label(text) return label def __get_pack_box(self, widgets): """ Recibe una lista de Widgets y devuelve un box, con esos widgets empaquetados. """ box = Gtk.Box(orientation = Gtk.Orientation.HORIZONTAL) box.pack_start(widgets[0], False, False, 5) for widget in widgets[1:]: box.pack_start(widget, True, True, 5) return box def __buscar(self, widget, tipo): """ Abre Filechooser para guardar la encuesta respondida o parcialmente respondida. """ if tipo == "icono": filechooser = My_FileChooser( parent_window = self, action_type = Gtk.FileChooserAction.OPEN, filter_type = "image/*", title = "Buscar Icono") else: return filechooser.connect('load', self.__run_buscar, tipo) def __run_buscar(self, widget, archivo, tipo): """ Asigna el path del icono. """ if not archivo or not tipo: return if tipo == "icono": self.icon_path.set_text(archivo) self._icono_preview.set_from_pixbuf( GdkPixbuf.Pixbuf.new_from_file_at_size( archivo, 100, 100)) else: return def get_proyecto(self): """ Devuelve un diccionario con la definición del proyecto. """ buffer = self.descripcion.get_buffer() nombre = self.nombre.get_text() main = self.main.get_active_text() path = self.path.get_text() buffer = buffer.get_text( buffer.get_start_iter(), buffer.get_end_iter(), True) version = self.version.get_text() licencia = self.licencia.get_active_text() icon_path = self.icon_path.get_text() url = self.url.get_text() if nombre: nombre = nombre.strip() if main: main = main.strip() if path: path = path.strip() if buffer: buffer = buffer.strip() if version: version = version.strip() if licencia: licencia = licencia.strip() if icon_path: icon_path = icon_path.strip() if url: url = url.strip() dict = { "nombre": nombre, "main": main, "path": path, "descripcion": buffer, "version": version, "licencia": licencia, "icon_path": icon_path, "url": url, "autores": self.autores.get_autores() } return dict def set_proyecto(self, diccionario): """ Establece los datos del diccionario introducido """ self.nombre.set_text(diccionario["nombre"]) self.path.set_text(diccionario["path"]) self.version.set_text(diccionario["version"]) self.descripcion.get_buffer().set_text(diccionario["descripcion"]) self.licencia.set_active(LICENCIAS.index(diccionario["licencia"])) self.url.set_text(diccionario["url"]) self.autores.set_autores(diccionario["autores"]) ### Actualizar preview del icono. if os.path.exists(diccionario["icon_path"]): self.icon_path.set_text(diccionario["icon_path"]) self._icono_preview.set_from_pixbuf( GdkPixbuf.Pixbuf.new_from_file_at_size( diccionario["icon_path"], 100, 100)) ### Setear Combo para archivo Main. if diccionario.get("path", False): import glob arch = glob.glob("%s/*.py" % diccionario["path"]) self.main.remove_all() for archivo in arch: self.main.append_text(os.path.basename(archivo)) model = self.main.get_model() item = model.get_iter_first() count = 0 while item: if model.get_value(item, 0) == diccionario["main"]: self.main.set_active(count) break item = model.iter_next(item) count += 1 ### Setear sensibilidad en el boton aceptar. for button in self.get_action_area().get_children(): if self.get_response_for_widget(button) == Gtk.ResponseType.ACCEPT: nombre = self.nombre.get_text() if nombre: nombre.strip() if not nombre: button.set_sensitive(False) else: button.set_sensitive(True) break 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, path = None): Gtk.FileChooserDialog.__init__(self, parent = parent_window, action = action_type, flags = Gtk.DialogFlags.MODAL, title = title) self.set_default_size( 640, 480 ) self.set_select_multiple(False) self.set_current_folder_uri("file:///%s" % path) if filter_type != None: filter = Gtk.FileFilter() filter.set_name(filter_type) filter.add_mime_type(filter_type) self.add_filter(filter) hbox = Gtk.Box(orientation = Gtk.Orientation.HORIZONTAL) texto = "" if action_type == Gtk.FileChooserAction.OPEN or \ action_type == Gtk.FileChooserAction.SELECT_FOLDER: texto = "Abrir" elif action_type == Gtk.FileChooserAction.SAVE: texto = "Guardar" abrir = Gtk.Button(texto) salir = Gtk.Button("Salir") hbox.pack_end(salir, True, True, 5) hbox.pack_end(abrir, True, True, 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 WidgetAutores(Gtk.Box): """ Box para agregar datos de los Autores """ def __init__(self): Gtk.Box.__init__(self, orientation = Gtk.Orientation.VERTICAL) self.__agregar(None) self.show_all() def __agregar(self, widget): """ Función para agregar información de un autor. """ box = Gtk.Box(orientation = Gtk.Orientation.HORIZONTAL) entry1 = Gtk.Entry() entry2 = Gtk.Entry() remover = get_boton(Gtk.STOCK_REMOVE, "Eliminar") agregar = get_boton(Gtk.STOCK_ADD, "Agregar") box.pack_start(entry1, False, False, 5) box.pack_start(entry2, False, False, 0) box.pack_start(remover, False, False, 0) box.pack_end(agregar, False, False, 0) self.pack_start(box, False, False, 0) agregar.connect("clicked", self.__agregar) remover.connect("clicked", self.__quitar) self.show_all() def __quitar(self, widget): """ Función para eliminar informacion de un autor. """ if len(self.get_children()) == 1: widget.get_parent().get_children()[0].set_text("") widget.get_parent().get_children()[1].set_text("") else: widget.get_parent().destroy() def get_autores(self): """ Devuelve una lista de tuplas (nombre, mail), con todos los autores definidos. """ autores = [] for autor in self.get_children(): nombre = autor.get_children()[0] mail = autor.get_children()[1] nombre = nombre.get_text() nombre = nombre.strip() mail = mail.get_text() mail = mail.strip() if nombre and mail: autores.append( (nombre, mail) ) return autores def set_autores(self, autores): """ Setea los autores. """ for x in range(len(autores)-1): self.__agregar(None) for autor in autores: nombre, mail = autor linea = self.get_children()[autores.index(autor)] linea.get_children()[0].set_text(nombre) linea.get_children()[1].set_text(mail)