<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3306111055137036769</id><updated>2012-02-15T22:47:51.094-08:00</updated><category term='presentación'/><category term='conceptos'/><category term='diseño'/><category term='recursos'/><category term='prototipos'/><category term='programando'/><category term='&quot;sabias que...&quot;'/><title type='text'>Twin Panel</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>MagMax</name><uri>http://www.blogger.com/profile/08268918285138584096</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-airFMWXsH8U/TyD3DHp5N9I/AAAAAAAAAE0/JrVWqKYSZSI/s220/magmaxpark.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-1348041136638720801</id><published>2010-01-12T02:01:00.000-08:00</published><updated>2010-01-13T01:39:50.540-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='prototipos'/><title type='text'>Primer prototipo TP 2.0</title><content type='html'>¡Hola!&lt;br /&gt;&lt;br /&gt;Según avanzamos en el diseño de la nueva versión de TwinPanel, se hace necesario "prototipar" determinadas cosas. De este modo, podemos capturar requisitos no visibles a primera vista, y comprobar en cierto modo la viabilidad de algunas propuestas.&lt;br /&gt;&lt;br /&gt;Por eso, presentamos el primer prototipo escrito teniendo en cuenta parte del nuevo diseño. Básicamente está formado por dos partes: el entorno de objetos distribuidos y los clientes (aunque, en este caso, sólo hay uno ;) )&lt;br /&gt;&lt;br /&gt;Aunque el prototipo es funcional, no está escrito a fuego, por lo que es posible que cambien muchas cosas. Aún así, vamos a desgranarlo un poco, para entenderlo bien.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Distributed Component Platform&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;El nombre todavía no es definitivo, pero de alguna forma hay que llamarlo. DCP es el conjunto de objetos (plugins, factorías, etc.) que dan servicio a los clientes. De el forman parte los sirvientes que presentan un modelo de datos o de acceso para determinado recurso, así como las factorías utilizadas para la gestión de estos componentes.&lt;br /&gt;&lt;br /&gt;En el prototipo hay dos factorías. La primera gestiona los plugins que proveen modelos de acceso a determinado recurso. Tiene un método, &lt;i&gt;getThingFromURI&lt;/i&gt;, que analiza una URI, y crea un sirviente para dar acceso a esa URI. El objeto que se retorna puede tener diferentes interfaces, dependiendo de los plugins que soporte. En el prototipo, sólo hay uno registrado, que presenta una interfaz de tipo FILE, y que soporta el esquema HTTP.&lt;br /&gt;&lt;br /&gt;La segunda factoría, gestiona modelos de datos. Aunque la interfaz tiene varios métodos, el más interesante es &lt;i&gt;simpleCreateDataModel&lt;/i&gt;, que crea un sirviente para un modelo de acceso determinado. Los plugins de esta factoría son capaces de "entender" y manipular el recurso, presentando una interfaz para manipularlo. El único plugin registrado en el prototipo es &lt;i&gt;HTMLDir&lt;/i&gt;, que reconoce el formato HTML, lo "parsea" y genera una estructura de directorios con el contenido servido.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Cliente&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;La otra parte del prototipo es el cliente. Su cometido es sencillo: obtiene los proxies a las factorías antes mencionadas, y crea los sirvientes adecuados para explorar una URI de tipo HTTP (como "http://www.google.es"). Crea una interfaz gráfica muy sencilla (a modo de Skin) con un IconView para mostrar el modelo generado a partir del HTML.&lt;br /&gt;&lt;br /&gt;He de remarcar que es un prototipo, por lo que no está depurado, no es tolerante a fallos y puede comportarse de forma indefinida, aunque por lo general, hará lo que le dices :) El código fuente está disponible para todo el que lo quiera probar. Depende de python-zeroc-ice y de &lt;a href="http://www.zeroc.com/forums/projects/4666-icebox-python.html"&gt;pyicebox&lt;/a&gt;. Para probarlo, es necesario lanzar por un lado el DCP, usando:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ ./launchFactories.sh&lt;/pre&gt;&lt;br /&gt;y por otro, el cliente, de una forma parecida a:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ ./Client.py --Ice.Config=client.cfg http://www.google.es&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Conclusiones&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Todavía quedan muchas cosas por pulir:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Es necesario definir un mecanismo para registrar los plugins en las factorías correspondientes. En caso de que sea la factoría quien los cargue, es necesario establecer una interfaz para los plugins (interfaz que se implementará en el módulo).&lt;/li&gt;&lt;li&gt;Definir el mecanismo de interacción entre plugins, es decir, es necesario especificar aquellas interfaces que cierto plugin es capaz de manipular.&lt;/li&gt;&lt;li&gt;Se han de especificar las relaciones entre componentes activos, inactivos y no instanciados, así como los protocolos de reutilización, compartición y limpieza de recursos.&lt;/li&gt;&lt;li&gt;Es preciso determinar si es escalable o no, y la forma de hacerlo escalable. Por ejemplo, en un recurso con múltiples ficheros ¿se debería crear un sirviente por cada nodo? ¿Se podría utilizar un default servant?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Algo que he visto bastante acertado es la separación entre la "plataforma de componentes" y los clientes. Esto nos permite mucha flexibilidad a la hora de diseñar diferentes interfaces de usuario, o de hacer pruebas a la plataforma. También hace más sencillo entender todo como conjunto (divide y vencerás), y escribir sus partes, siempre que estas sean lo más ortogonales posible.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Descargas&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://arco.esi.uclm.es/svn/public/prj/twinpanel/proto1.tgz"&gt;Prototipo 1&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://arco.esi.uclm.es/svn/public/prj/pyicebox/"&gt;PyIceBox&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-1348041136638720801?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/1348041136638720801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=1348041136638720801' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/1348041136638720801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/1348041136638720801'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2010/01/primer-prototipo-tp-20.html' title='Primer prototipo TP 2.0'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-3599215668930693805</id><published>2009-12-21T02:52:00.000-08:00</published><updated>2009-12-21T02:53:04.811-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><category scheme='http://www.blogger.com/atom/ns#' term='conceptos'/><title type='text'>Organización de ideas</title><content type='html'>El pasado viernes estuvimos discutiendo algunos aspectos interesantes de TwinPanel. De ahí, obtuvimos varias ideas clave y otros puntos un poco difusos (al menos, para mi).&lt;br /&gt;&lt;br /&gt;Partimos de la idea de Recurso, que fué una de las más controvertidas ;). Un Recurso no deja de ser un modelo (de acceso, si se quiere aclarar), al igual que los otros modelos que ya teníamos (los modelos de datos). La distinción que queríamos hacer principalmente se mantiene (la que diferencia entre el mecanismo de acceso a los datos, y la manipulación de estos), pero no se añade (a primera vista) una capa más (aunque esto es discutible :P)&lt;br /&gt;&lt;br /&gt;Queremos respetar el MVC a toda costa, algo que me parece muy bunea idea, dada la pluralidad de interfaces de usuario que vamos a tener. &lt;br /&gt;&lt;br /&gt;También quedó claro que la arquitectura para todo esto nos la provee perfectamente Ice, más concretamente IceBox + Slice. Usaremos el evictor de IceBox para gestionar dinámicamente los plugins instanciados (una pena que PyIceBox no tenga evictor, así que o lo implementamos o usamos otros lenguajes...). Por tanto, algo en lo que tenemos que trabajar primero es en la factoría de plugins. &lt;br /&gt;&lt;br /&gt;Si, por ejemplo, queremos inspeccionar una URI dada, como "http://www.google.es", tendríamos primero que comprobar si denota un proxy válido (pues cualquier cosa que se desee explorar, deberá primero tener forma de proxy). Si no lo es, habrá un componente que se encargue de convertir esa URI. Ese componente, que posiblemente esté asociado a la factoría, deberá buscar un plugin capaz de manipular ese recurso, en este caso, un plugin para HTTP. Se creará (o se retornará) una instancia que manipule nuestra URI y ya tendremos el proxy que buscábamos (al modelo de acceso). Ahora, necesitaremos otro plugin para manipular el contenido del recurso, que se creará de forma análoga. Por último, una tercera entidad deberá representar de forma visual el contenido de los datos, aunque esta parte no es imprescindible, pues este modelo puede ser fuente para otro modelo, que a su vez... Sí, los modelos son 'stackables' :)&lt;br /&gt;&lt;br /&gt;Como vemos, otra labor vital que resolverá parte de los problemas actuales de TP, será definir las interfaces para todos los tipos de modelos necesarios.&lt;br /&gt;&lt;br /&gt;Un problema que tendremos que resolver será el mecanismo para decidir que modelo escoger. Por ejemplo, el de HTTP puede ofrecer una interfaz de tipo FILE, la más común. Pero también se puede diseñar un interfaz de tipo HTTP, que implemente los verbos correspondientes: get, post, etc. En el siguiente nivel (modelo de datos), ocurre exáctamente lo mismo, y también en la capa de presentación.&lt;br /&gt;&lt;br /&gt;Por otra parte, en lo que se refiere a la factoría, también se han oido ideas curiosas que hay que resolver, como el hecho de que sea distribuida (y por tanto, sea necesario un mecanismo de descubrimiento de "factorías", o búsqueda, con algo como ASD.Search). &lt;br /&gt;&lt;br /&gt;El caso es que esto está tomando un cáriz interesante :D Ahora te toca a ti, busca los siete gazapos :P&lt;br /&gt;&lt;br /&gt;再见!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-3599215668930693805?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/3599215668930693805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=3599215668930693805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/3599215668930693805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/3599215668930693805'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/12/organizacion-de-ideas.html' title='Organización de ideas'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-7109624133531807105</id><published>2009-12-08T13:08:00.000-08:00</published><updated>2009-12-08T13:35:10.443-08:00</updated><title type='text'>Un par de sugerencias</title><content type='html'>Buenas llevo tiempo detrás de escribir un par de sugerencias, hasta ahora sólo he estado leyendo los post y comentarios, y hoy me he decidido a hacerlo. Tened en cuenta que aunque he estado mirando algo de código estoy muy muy verde, gracias por vuestra comprensión y espero que os sirvan de algo.&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;1)    	Desacoplar Twin Panel - GTK&lt;/span&gt;&lt;/span&gt;&lt;meta equiv="CONTENT-TYPE" content="text/html; charset=utf-8"&gt; &lt;title&gt;&lt;/title&gt; 	&lt;meta name="GENERATOR" content="OpenOffice.org 3.0  (Linux)"&gt; 	&lt;style type="text/css"&gt; 	&lt;!-- 		@page { margin: 2cm } 		P { margin-bottom: 0.21cm } 	--&gt; 	&lt;/style&gt;  &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;p style="margin-bottom: 0cm; text-align: justify;"&gt;Hasta ahora por temas de rendimiento Twin Panel utiliza TreeViewPanel de GTK como representación interna, pero para permitir el desacople con GTK o con cualquier otra tecnología se puede recurrir al patrón Factoría, de forma que según el tipo de interfaz requerida (puede seleccionarse a través de un fichero de configuración o un parámetro en el arranque), genere una instancia especifica que es utilizada a través de una interfaz genérica. Vamos con un ejemplo:  &lt;span style="font-style: italic;"&gt;Si a la factoría se le pide una instancia de la aplicación para escritorio, esta construirá un TreeViewPanel de GTK, como hasta ahora; si en lugar de esto se le llama solicitándole la aplicación para consola, devolverá una instancia con otra representación interna; pero ambas tienen la misma interfaz.&lt;/span&gt;&lt;/p&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;p style="margin-bottom: 0cm; text-align: justify;"&gt;Es decir, sería necesario especificar una interfaz con los métodos necesarios para trabajar con los modelos de representación interna, de forma que se permita desacoplar la tecnología, y permitir además la implementación multiplataforma pero sin perder la eficiencia que proporciona el trabajar con un modelo interno específico.&lt;/p&gt;&lt;p style="margin-bottom: 0cm; text-align: justify;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm; text-align: justify; font-weight: bold;"&gt;&lt;span style="font-size:130%;"&gt;2) Sobre la inspeción de recursos.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm; text-align: justify;"&gt;   	&lt;meta equiv="CONTENT-TYPE" content="text/html; charset=utf-8"&gt; 	&lt;title&gt;&lt;/title&gt; 	&lt;meta name="GENERATOR" content="OpenOffice.org 3.0  (Linux)"&gt; 	&lt;style type="text/css"&gt; 	&lt;!-- 		@page { margin: 2cm } 		P { margin-bottom: 0.21cm } 	--&gt; 	&lt;/style&gt;  &lt;/p&gt;&lt;p style="margin-bottom: 0cm; text-decoration: none;"&gt;Como bien han comentado David y Oscar en anteriores posts, uno de los problemas de TP es que mezcla la forma de acceder a un recurso con la forma de analizar o usar dicho recurso.  &lt;/p&gt; &lt;p style="margin-bottom: 0cm; text-decoration: none;"&gt;Por lo tanto debe de haber un analizador de URIs que por un lado, sepa qué usar para acceder a ese recurso (según el método o protocolo que se haya especificado) y por otro lado decidir el inspector a usar.  &lt;/p&gt;  &lt;p style="margin-bottom: 0cm; text-decoration: none;"&gt;Por ejemplo tenemos &lt;span style="font-style: italic;"&gt;http://example.org/video.avi&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;ftp://example.org/video.avi&lt;/span&gt; para ese recurso una vez se accede a él a través de un protocolo, se pueden realizar diferentes acciones, como abrir el navegador web, abrir un dialogo para almacenar el fichero, mostrar un resumen de la información del vídeo, traer el vídeo, lanzar un reproductor, etc. Todas estas acciones pueden ser realizadas con el recurso definido por esa URI, por tanto, puede que según el tipo de protocolo y de fichero, y los inspectores que se tengan instalados, puede haber un despachador que tenga una serie de reglas definidas, de forma que pueda o bien ejecutar la regla seleccionada (o la establecida por defecto) o solicitar la elección de una acción (preguntar por la regla a ejecutar y permitiendo a su vez que sea guardada como regla por defecto). Este comportamiento es el similar al que tienen los sistemas operativos con respecto a un fichero, donde según su extensión pueden tener definido quién es el programa encargado en atender ese fichero, o pueden ofrecer una lista de candidatos y elegir quién lo va a atender.  &lt;/p&gt; &lt;p style="margin-bottom: 0cm; text-decoration: none;"&gt;De la misma forma, al instalar un plugin este registra una serie de tipos de recursos que puede atender. Y así el despachador puede saber mirando la reglas que tenga, si debe utilizar un inspector u otro, o debe ofrecer los posibles candidatos para atender ese recurso.&lt;/p&gt;  &lt;p style="margin-bottom: 0cm; text-decoration: none;"&gt;Y enlazando con el post anterior si se indica en la ruta al recurso el modo o forma de acceder se usará el indicado, si no se usará el marcado por defecto para este tipo de recurso o si no se preguntará al usuario.&lt;/p&gt; &lt;p&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm; text-align: justify;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm; text-align: justify;"&gt;&lt;br /&gt;&lt;/p&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-7109624133531807105?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/7109624133531807105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=7109624133531807105' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7109624133531807105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7109624133531807105'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/12/un-par-de-sugerencias.html' title='Un par de sugerencias'/><author><name>Carlos Ruiz</name><uri>http://www.blogger.com/profile/05027584621463278821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-1779747454069692277</id><published>2009-12-03T08:11:00.000-08:00</published><updated>2009-12-03T08:11:16.362-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><category scheme='http://www.blogger.com/atom/ns#' term='conceptos'/><title type='text'>URI, URL, URN y otras hierbas</title><content type='html'>Todo Resource debe ser identificado de alguna forma. A ser posible, que sea 'human readable' (como el XML :P). Esto no es nada nuevo, pero sería interesante comentar las opciones que tenemos, sean o no estándar, y que se adapten a nuestras necesidades. Sobre todo, sería muy interesante poder coger cualquier 'identificador' estándar y poder explorarlo.&lt;br /&gt;&lt;br /&gt;En la primera versión de TwinPanel, usábamos algo llamado 'URI', pero que no se adecuaba a ningún estándar. Por ejemplo, para explorar un objeto Ice, usábamos algo como "ice://objeto -t:tcp -h host -p 1234". En los objetos complejos, que tienen jerarquía, separábamos el objeto de la "ruta" hacia el nodo, por ejemplo "ice://[objeto -t:tcp -h host -p 1234]/cameras/garage/". Si además es necesario añadir autenticación, entonces se puede añadir antes del recurso, por ejemplo "ftp://user:passwd@hostname/path/to/file".&lt;br /&gt;&lt;br /&gt;La primera parte de estas URIs (lo que hay antes del '://') especificaba el tipo de acceso al recurso (ice://, http://, etc.). Ahora bien, nos surge la necesidad de especificar el acceso al recurso, pero también el tipo del recurso. Por ejemplo, subversion utiliza uris de la forma 'svn+ssh://box/path'. El recurso es un repositorio subversion, y la forma de acceder a el es por medio de ssh. A nosotros nos pasa algo parecido. Por ejemplo, tenemos un fichero zip, accesible por medio de http. En este caso, se podría omitir el modelo y dejar que algún mecanismo de introspección detectara que es. Esto es muchas veces caro, y alguna inviable. Por eso, surge la necesidad de ampliar nuestro esquema de nombrado de recursos.&lt;br /&gt;&lt;br /&gt;Un ejemplo algo más claro: una imagen SVG modelada como un byteseq de Ice. Si no se especifica de algún modo el contenido de ese byteseq, se puede interpretar de muchas formas. Se podría detectar, analizando el byteseq, pero para eso, habría que obtenerlo primero (además, no siempre es posible detectar así el modelo). También se podría especificar como una propiedad, pero entonces se complica si queremos modelarlo como otra cosa (por ejemplo, como texto plano). Si esta información la añadimos al identificador del recurso, es inmediata la elección del modelo, y nos permite cambiar fácilmente entre distintos modelos. &lt;br /&gt;&lt;br /&gt;Ahora, sería interesante elegir un esquema de direccionamiento. Uno de ellos podría ser &lt;a href="http://en.wikipedia.org/wiki/Uniform_Resource_Name"&gt;URN&lt;/a&gt;, un identificador independiente de la localización, que es un tipo de URI. Básicamente, este esquema se compone de un identificador del dominio, mas un identificador dependiente del dominio. Algo así como 'urn:ice:object@adapter'. Esto sería perfecto si no fuera por la cantidad de restricciones que tenemos para componer el identificador dependiente del dominio. Cosas vitales como '/' o '[]' no son admitidas. Sí lo son en formato hexadecimal, lo cual es una carga a la hora de trabajar manualmente con ellas. Una posible solución pasaría por permitir al usuario entrar URN 'prohibidas' y convertirlas inmediatamente para manipularlas internamente. Así, se adaptaría al estándar a la vez que serían manejables. En esos casos, obviamente, prescindiríamos del prefijo 'urn:', con lo que tendríamos cosas como 'http:svg:server/path/file.svg', que sería traducida internamente a 'urn:http:svg:server%40path%40file.svg', o algo parecido.&lt;br /&gt;&lt;br /&gt;¿Qué opinais?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-1779747454069692277?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/1779747454069692277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=1779747454069692277' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/1779747454069692277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/1779747454069692277'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/12/uri-url-urn-y-otras-hierbas.html' title='URI, URL, URN y otras hierbas'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-762765008695333185</id><published>2009-11-27T02:32:00.000-08:00</published><updated>2009-11-27T03:52:28.209-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursos'/><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Interfaces: Resource</title><content type='html'>¡Hola!&lt;br /&gt;&lt;br /&gt;Creo que es hora de ir pensando en cosas más profundas. Por ejemplo, en definir las interfaces que hemos visto hasta ahora. Por estos lares ando con un poco de miedo, pues la causa del "fracaso" del anterior diseño fue esto mismo: un mal diseño. Meter la pata a estas alturas nos va a costar mucho posteriormente.&lt;br /&gt;&lt;br /&gt;De todos modos, por algún sitio hay que empezar. Y supongo que con la experiencia anterior, podremos ahorrarnos algunos errores. ¿Y qué tal si empezamos por los Recursos? Ok.&lt;br /&gt;&lt;br /&gt;Ya hemos definido lo que es un recurso. También se comentó lo interesante que sería que todos los recursos compartiesen una misma interfaz. Así, todos los tipos de Modelo que pueda haber son accesibles usando cualquier mecanismo de acceso. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Un inciso:&lt;/b&gt; propongo cambiar la nomenclatura: recurso por acceso, pues me parece más próximo a la realidad. En este post, usaré Access como el mecanismo de acceso al recurso (por ejemplo, HTTP, FTP, File, etc).&lt;br /&gt;&lt;br /&gt;Por ejemplo, si tenemos un AccessHttp, y añadimos un Modelo nuevo, con sus correspondientes inspectores, no es necesario hacer nada especial para que este modelo use el AccessHttp. Esto es una ventaja considerable, pero para ello, tenemos que ver si sería posible acceder a todos los recursos existentes usando una misma interfaz.&lt;br /&gt;&lt;br /&gt;Podemos intentar ver si TODOS los casos son factibles. O mejor, encontrar uno que no encaje. Veamos, el mecanismo de acceso que se utiliza más comunmente es el consabido par &lt;i&gt;get/set&lt;/i&gt;. Supongamos que dotamos al acceso de esta interfaz:&lt;br /&gt;&lt;pre class="python" name="code"&gt;class Recurso:&lt;br /&gt;    def get(): pass&lt;br /&gt;    def set(blob): pass&lt;br /&gt;&lt;/pre&gt;Para HTTP, FTP, File... es válida. Son accesos que te proporcionan el recurso entero. Si las condiciones te lo permiten, es viable. Veamos un caso más complejo: Ice/CORBA/etc. Aquí, dependemos del tipo del recurso. Si es un entero o un byteseq, se puede seguir usando. Pero, ¿y si el "objeto" tiene una interfaz más compleja, por ejemplo AVStreams? Tendríamos un problema. Claramente no nos sirve, porque a lo que estamos accediendo no es a un recurso que se pueda tratar como un fichero o una imagen. &lt;br /&gt;&lt;br /&gt;Vemos que una úinca interfaz, aunque interesante, no es posible. Tendríamos que crear una para cada &lt;i&gt;tipo&lt;/i&gt; de recurso. Ya no es dependiente del mecanismo de acceso, porque es posible acceder a una fichero zip usando Ice, o a un objeto Bool usando File. Tendríamos un Access para recursos de tipo, llamemosle Data, que cubre un amplio espectro de uso. Pero también habría un Access para otros tipos de recursos (hay que pensar cuales).&lt;br /&gt;&lt;br /&gt;Esto complica la estructura. Ya no solo clasificamos los Access por el mecanismo de acceso (FTP, etc.), sino también por el tipo de recurso al que se accede (un "Data", etc.). Quizá no sea esto lo que queremos. &lt;br /&gt;&lt;br /&gt;¿Qué pensáis? Necesito ideas...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[Edición]&lt;/b&gt; Se me ocurre que en el caso de objetos Ice con interfaces complejas, podríamos considerar que la interfaz es parte intrínseca del Objeto, y que es el inspector quien sabe como usarla. Así, tendríamos un Access que provee la capacidad de "llamar" a métodos Ice (ya sea usando Ice, HTTP o File), sin conocer la interfaz real (es decir, un Access con dynamic Ice). Delegamos en el inspector el tratamiento del recurso. Esto se parece a lo que teníamos, pero con la salvedad de que ahora el acceso al recurso es transparente para el inspector (el inspector pide los ice_ids del objeto, y si el AccessX los obtiene de una base de datos, eso no importa). Y lo que es más, el inspector no tiene porqué conocer siquiera si el objeto está implementado en Ice o en CORBA. Eso es tarea del Access.&lt;br /&gt;&lt;br /&gt;Quizá este tratamiento se pueda generalizar. Así tendríamos sólo tres o cuatro tipos de Access.&lt;br /&gt;La siguiente figura es un ejemplo de cómo lo veo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_VBuzYhvtQwo/Sw-8k0fM_UI/AAAAAAAAAKM/KhL7lxDiALs/s1600/d2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VBuzYhvtQwo/Sw-8k0fM_UI/AAAAAAAAAKM/KhL7lxDiALs/s400/d2.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Un Model concreto podría dar soporte a una interfaz Access, por ejemplo, a DataAccess, siendo independiente del Access real que se use (DAFile, DAIce, etc.).&lt;br /&gt;&lt;br /&gt;¿Como lo véis? ¡¡Feedback!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-762765008695333185?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/762765008695333185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=762765008695333185' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/762765008695333185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/762765008695333185'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/11/interfaces.html' title='Interfaces: Resource'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_VBuzYhvtQwo/Sw-8k0fM_UI/AAAAAAAAAKM/KhL7lxDiALs/s72-c/d2.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-7485198411448759239</id><published>2009-11-25T05:18:00.000-08:00</published><updated>2009-11-27T01:27:21.288-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><category scheme='http://www.blogger.com/atom/ns#' term='conceptos'/><title type='text'>Cuestión de conceptos</title><content type='html'>Bueno, dado el anterior post de David, ahora tengo claros algunos conceptos más. Pero, para mi sigue siendo un montón de ideas en el aire, con relaciones parciales entre ellas. Necesito ponerlas en algún sitio, establecer esas relaciones y verlo todo como un conjunto conexo. Por eso, me gustaría empezar a distinguir y definir conceptos. Por supuesto, las cosas que falten, ya sabéis... comentarios.&lt;br /&gt;&lt;br /&gt;A primera vista, los conceptos son: Recurso, Modelo, URI, Factoría, Inspector, Skin... TwinPanel :P De momento, un conjunto de nombres. Pongámosle caras.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Recurso&lt;/b&gt;: es el "qué". Aquello que se quiere utilizar, es la entidad a la que se desea acceder (no se me ocurren palabras más genéricas que realmente digan algo).&amp;nbsp; Por ejemplo, un fichero zip en un directorio ftp de cierta máquina de nuestra red (como URL, sería "ftp://abox/ftp/afile.zip"). A nivel de TP, el recurso se puede considerar como un "proxy", un representante de lo que se quiere utilizar, y que sabe como acceder a él. El recurso (para TP) encapsula el mecanismo de acceso a esa entidad.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Modelo&lt;/b&gt;: especifica cómo se debe manipular el recurso. En el ejemplo anterior, tendríamos un fichero comprimido. El "modelo" es quien sabe lo que se puede hacer con ese fichero comprimido: leer su contenido, descomprimirlo, añadir otros ficheros, etc. El modelo es una entidad abstracta, que será instanciada por los Inspectores.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;URI&lt;/b&gt;: es un identificador del recurso. Bien puede decir qué es (&lt;a href="http://en.wikipedia.org/wiki/Uniform_Resource_Name"&gt;URN&lt;/a&gt;), o bien dónde está (&lt;a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator"&gt;URL&lt;/a&gt;). Este concepto es el más claro, aunque su estructura no la tenga tan clara... :D&lt;/li&gt;&lt;li&gt;&lt;b&gt;Factoría&lt;/b&gt;: es la entidad encargada de proveer los componentes necesarios para inspeccionar determinado recurso. Antes, era un componente bien conocido, pero puede que cambie un poco su "personalidad".&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt; Inspector&lt;/b&gt;: es el encargado de tratar con el contenido del recurso. Es la instanciación de un modelo. Para cada modelo puede haber varios inspectores, dependiendo de factores como la tecnología usada para tratar el recurso. Así, para el zip, tendríamos un inspector que usase "zip", y podríamos tener otro que se sirviera de un mecanismo online para ver el fichero, por ejemplo.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt; Skin&lt;/b&gt;: es la representación del recurso de cara al usuario: la vista del mismo. Este concepto tampoco ha variado mucho desde sus inicios, aunque sí la tecnología subyacente (¡ahora puede estar distribuido!). Utiliza un inspector para acceder al recurso.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Voy a intentar desempolvar los conceptos de UML para dibujar un ejemplo de clases.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_VBuzYhvtQwo/Sw6T3Hjh-RI/AAAAAAAAAKE/nBw3MwEIHf4/s1600/d1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_VBuzYhvtQwo/Sw6T3Hjh-RI/AAAAAAAAAKE/nBw3MwEIHf4/s400/d1.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Aquí se representan sólo las relaciones entre recursos, modelos e inspectores, y con ejemplos para verlo un poco más claro.&lt;br /&gt;&lt;br /&gt;Ahora, podemos discutir cosas. Por ejemplo, la interfaz que debe conocer un modelo de cierto recurso. Si es diferente para cada recurso, un modelo dado debe ser consciente de los recursos para los que está disponible, algo que no es desable. Entonces, debe ser la misma para todos los recursos. Habría que ver si es posible una interfaz que sea práctica para todos los casos posibles.&lt;br /&gt;&lt;br /&gt;De todos modos, ¿qué pensáis?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-7485198411448759239?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/7485198411448759239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=7485198411448759239' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7485198411448759239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7485198411448759239'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/11/cuestion-de-conceptos.html' title='Cuestión de conceptos'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_VBuzYhvtQwo/Sw6T3Hjh-RI/AAAAAAAAAKE/nBw3MwEIHf4/s72-c/d1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-2935683744026367668</id><published>2009-11-05T03:24:00.000-08:00</published><updated>2009-11-05T06:28:50.851-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Recursos y Modelos</title><content type='html'>Uno de los problemas de diseño que tiene el TP actual es que no separamos claramente dos cosas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El acceso al recurso&lt;/li&gt;&lt;li&gt;La forma de interpretar ese recurso&lt;/li&gt;&lt;/ul&gt;Eso nos llevó a varias soluciones basadas en métodos, dominios, inspectores y otras abstracciones que nunca acabaron de cuajar.&lt;br /&gt;&lt;br /&gt;Pongo un ejemplo para que se vea claro. Imagina que tienes un fichero "trabajo.zip" en el directorio "cosas" en tú máquina y que estás sirviendo a la vez ese mismo directorio con un servidor web y uno ftp. Eso te da dos URI's posibles para acceder al fichero.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;http://example.org/cosas/trabajo.zip&lt;/li&gt;&lt;li&gt;ftp://example.org/cosas/trabajo.zip&lt;/li&gt;&lt;/ul&gt;Para conseguir el fichero (el "recurso" en un sentido más general) puedes utilizar dos &lt;span style="font-weight: bold;"&gt;métodos &lt;/span&gt;distintos, pero no estás asumiendo aún nada sobre el contenido o estructura del fichero. Para eso necesitas un modelo (por medio de un inspector).&lt;br /&gt;&lt;br /&gt;Ahora imagina que tienes un inspector capaz de visualizar un fichero .zip como si fuera un directorio, pudiendo ver el nombre de los ficheros y sus atributos. Esto no es nada nuevo, gvfs + file-roller hacen eso mismo hoy día en GNOME (o lo intentan).&lt;br /&gt;&lt;br /&gt;La conclusión es que el mecanismo de acceso al recurso y la forma de entender el recurso DEBEN ser cosas diferentes y desacopladas. Eso no lo logramos en la versión actual de TP y es fuente de muchos problemas.&lt;br /&gt;&lt;br /&gt;Así que yo distinguiría entre Recursos e Inspectores, de modo que los inspectores necesitan una referencia a un recurso y nunca acceden "físicamente" a ningún fichero ni dispositivo. Esto encaja perfectamente con el modelo de tres capas en el que el Recurso estaría en la capa de persistencia/acceso y el Inspector en la capa de modelo.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ejemplos de Recursos: ftp, http, bluettooth, ssh, ice, etc.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Ejemplos de inspectores: zip, camera, json, media, hg, etc.&lt;/li&gt;&lt;/ul&gt;Desde el punto de vista de la plataforma eso es todo. Se asume que "alguien" crea un Recurso a partir de una URI y después le pasa la referencia a un Inspector. Algo como:&lt;br /&gt;&lt;br /&gt;zip = InspectorZip(ResourceHTTP("http://example.org/cosas/trabajo.zip"))&lt;br /&gt;&lt;br /&gt;Pero desde el punto de vista de TP debe haber una forma automágica de crear Recursos a partir de URI, algo que es en principio muy sencillo, basta mirar lo que hay antes del ://.&lt;br /&gt;&lt;br /&gt;Pero además debe haber una forma de elegir el Inspector más adecuado y también tener la posibilidad de cambiarlo si el usuario quiere. Un .tgz se puede ver con un inspector de "gzip" pero también con uno de "unp".&lt;br /&gt;&lt;br /&gt;En muchos casos eso se puede hacer mirando la extensión del fichero pero en otros no es tan fácil. Por ejemplo, un directorio que contiene un repo subversion... ¿cómo se sabe que lo es? "ssh://example.org/repos/mi_proyecto". Lo que hace subversion concretamente es crear una URI del tipo "svn+ssh://example.org/repos/mi_proyecto". Bueno, es una opción, pero estaría bien algo un poco más inteligente si es posible.&lt;br /&gt;&lt;br /&gt;Otro caso es un objeto tipo "ice://objeto1 @ adaptador". Aquí el Recurso es Icd pero ¿qué Inspector usas? La forma de determinarlo es invocar el método ice_ids() del objeto y buscar inspectores que lo puedan manejar. Algo que es MUY distinto a mirar la extensión o el prefijo de la URI porque implica USAR el recurso.&lt;br /&gt;&lt;br /&gt;Obviamente puede haber Inspectores que solo tengan sentido con un Recurso concreto pero eso no significa que deban estar acoplados, precisamente porque puede haber muchos Inspectores que pueden usar un mismo tipo de Recurso y algunos de ellos pueden no tener esa limitación.&lt;br /&gt;&lt;br /&gt;Y para terminar, imagina que el zip del que hablaba antes contuviera a su vez un .tgz o una base de datos sqlite... También queremos verla...&lt;br /&gt;&lt;br /&gt;Bueno, cómo véis, más problemas que soluciones... pero bueno, estamos capturando requisitos.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-2935683744026367668?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/2935683744026367668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=2935683744026367668' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2935683744026367668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2935683744026367668'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/11/recursos-y-modelos.html' title='Recursos y Modelos'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-2574766017073090412</id><published>2009-11-05T02:04:00.000-08:00</published><updated>2009-11-05T04:20:43.549-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Recapitulemos</title><content type='html'>Creo que podemos hacer un breve resumen de las cosas que tenemos hasta ahora. Por ejemplo, seguiremos pensando en usar patrones, pues eso nunca fué mala idea. Así pues, el &lt;a href="http://es.wikipedia.org/wiki/Modelo_Vista_Controlador"&gt;MVC&lt;/a&gt; se seguirá respetando. Con lo que las entidades "inspector" y "skin" (por lo menos, lo que representan) seguirán estando presentes.&lt;br /&gt;&lt;br /&gt;Twin Panel seguirá siendo un sistema &lt;i&gt;plugable&lt;/i&gt;, por lo que no podemos dejar de usar una factoría, aunque su estructura cambie bastante.&lt;br /&gt;&lt;br /&gt;Otra cuestión interesante que discutir, y que siempre ha sido bastante difusa, es la relación entre los métodos de acceso (los antes llamados "methods"), y los dominios; conceptos que siempre han dado que hablar.&lt;br /&gt;&lt;br /&gt;Creo que una muy buena manera de ver los componentes y sus relaciones es utilizando un &lt;a href="http://diagrama%20de%20secuencia/"&gt;diagrama de secuencia&lt;/a&gt;. Voy a intentar esbozar uno, y con la ayuda de todos, lo vamos mejorando, ¿vale? :p Intentaré ser lo más genérico posible, puesto que todavía no hay nada determinado. &lt;br /&gt;&lt;ol&gt;&lt;li&gt;Un usuario desea explorar su carpeta personal. Para ello, lanzaría TP de una forma parecida a esta:&amp;nbsp; &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$ tp file:///home/&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;user&lt;/span&gt;&lt;/b&gt; .&amp;nbsp;&lt;/li&gt;&lt;li&gt;tp (el binario/script que se ejecute) deberá analizar la URL, convertirla a la estructura que sea necesario, y pedir a "alguien" que se encargue de instanciar/despertar/... los componentes que entrarán en juego para la tarea. Lo podemos llamar "factoría", con comillas, pues puede que me cuele.&amp;nbsp;&lt;/li&gt;&lt;li&gt;La "factoría" determina los componentes a usar, siempre que no se hayan especificado antes (como opciones de configuración, u otra cosa). Esta se encargará de que esos componentes estén accesibles, bien instanciándolos, bien despertándolos, etc.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Alguien deberá encargarse de configurar estos componentes. Por ejemplo, al "inspector" deberá decirsele la URL que está inspeccionando, o al skin dónde debe pintar.&lt;/li&gt;&lt;/ol&gt;Mmm, creo que faltan muchas cosas intermedias, pero seguramente que en estas cuatro básicas, ya he metido la pata... &lt;br /&gt;&lt;br /&gt;Bueno, empieza la audiencia :D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-2574766017073090412?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/2574766017073090412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=2574766017073090412' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2574766017073090412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2574766017073090412'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/11/recapitulemos.html' title='Recapitulemos'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-1316149750962795254</id><published>2009-11-04T04:45:00.000-08:00</published><updated>2009-11-05T03:20:49.230-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Casos de uso</title><content type='html'>En vista de los cambios que pronto afrontaremos, debemos tener siempre presente aquello para lo que, en principio, queremos usar Twin Panel. Este post intentará recoger los casos de uso, para así capturar requisitos y poder emprender el diseño.&lt;br /&gt;&lt;br /&gt;Twin Panel debe ser una herramienta que permita explorar conjuntos de objetos. Casi cualquier cosa puede ser tratada como un objeto, desde un fichero hasta una máquina, o un mensaje. Dada esta pluralidad, es muy difícil concretar todos los casos de uso. Si encuentras alguno que falta, puedes comentarlo y se tendrá en cuenta.&lt;br /&gt;&lt;br /&gt;Consideramos "contenedor" al elemento del sistema que posee al resto de elementos, siendo posible que estos, a su vez, sean "contenedores". Para evitar duplicar el texto, definimos los grupos de acciones permitidas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;Acciones Mínimas&lt;/i&gt;: listar elementos del "contenedor".&lt;/li&gt;&lt;li&gt;&lt;i&gt;Acciones Básicas&lt;/i&gt;: las acciones mínimas, más: copiar, cortar, pegar, crear y eliminar elementos, entre nodos del mismo "contenedor".&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;Acciones Ampliadas&lt;/i&gt;: acciones básicas entre nodos de "contenedores" diferentes (compatibles). &lt;/li&gt;&lt;/ul&gt;La lista de casos de uso es la siguiente:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Exploración local de ficheros. Es el caso más obvio. Deber permitir explorar cualquier sistema de ficheros local (obviamente, que esté soportado por el kernel). Debe soportar las &lt;i&gt;Acciones Ampliadas&lt;/i&gt;. El mecanismo de acceso podría ser &lt;b&gt;GVFS&lt;/b&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Exploración remota de ficheros. La extensión al caso anterior. Los mecanismos de acceso pueden ser variados: &lt;b&gt;SSH, FTP, Ice&lt;/b&gt;... Debe soportar las &lt;i&gt;Acciones Ampliadas&lt;/i&gt;.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Explorar el conjunto de máquinas de una red. Deberían poderse listar tanto las máquinas (con sus nombres, IP's u otros identificadores), como los servicios que proveen. El conjunto de acciones permitido serían las &lt;i&gt;Acciones Mínimas&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Visualizar los elementos que componen un documento web. Dependiendo del método de acceso, debería soportarse el conjunto de &lt;i&gt;Acciones Básicas&lt;/i&gt; o &lt;i&gt;Acciones Ampliadas.&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;Podríamos tener descripciones similares para los siguientes casos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Objetos Ice&lt;/li&gt;&lt;li&gt;Elementos de UPnP&lt;/li&gt;&lt;li&gt;Servidor POP3&lt;/li&gt;&lt;li&gt;Dispositivos Bluetooth&lt;/li&gt;&lt;li&gt;Nodos ZigBee&lt;/li&gt;&lt;li&gt;Redes y AP's WiFi&lt;/li&gt;&lt;li&gt;Procesos del sistema&lt;/li&gt;&lt;li&gt;Puertos abiertos con sus servicios asociados&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Bibliotecas multimedia (picassa, flickr, youtube...)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Entornos sensibles a localización (GIS)&lt;/li&gt;&lt;li&gt;Dispositivos X10 de un entorno &lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;Examinando estos casos, surgen algunas cuestiones que tratar:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Debemos definir un mecanismo preciso para la interacción entre diferentes mecanismos de acceso a estos "contenedores" (por ejemplo, para copiar un fichero desde un SF remoto a uno local, usando SSH), algo que todavía no se había abordado.&lt;/li&gt;&lt;li&gt;Debemos ser muy estrictos con las interfaces que cada "plugin" debe cumplir. Uno de los problemas que presenta la versión actual es que no hay un conjunto bien definido de interfaces, lo que permite registrar plugins incompletos que desestabilizan el sistema.&lt;/li&gt;&lt;li&gt;Es necesario disponer de una buena documentación desde el principio. Si un desarrollador hace un plugin, pero no dispone de toda la documentación necesaria, perderá mucho tiempo, hará cosas duplicadas, y posiblemente causará otros problemas al resto del sistema.&lt;/li&gt;&lt;li&gt;Pruebas. He aprendido (por fin :D) que es un aspecto clave a la hora de desarrollar software. Como dice incansablemente David: "&lt;span style="font-size: small;"&gt;&lt;span style="color: black;"&gt;las pruebas merecen la pena", y yo añado "&lt;/span&gt;&lt;/span&gt;sin pruebas, se pierde tiempo y es muy difícil abordar problemas complejos (sin causar otros)".&lt;/li&gt;&lt;/ol&gt;Con el nuevo diseño que se está planteando, algunas de estas cosas se resuelven. Por ejemplo, el uso de interfaces; utilizando Zeroc-Ice, se fuerza la utilización de interfaces.&lt;br /&gt;&lt;br /&gt;Sigamos discutiendo aspectos del diseño.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-1316149750962795254?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/1316149750962795254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=1316149750962795254' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/1316149750962795254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/1316149750962795254'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/11/casos-de-uso.html' title='Casos de uso'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-8341976562106319789</id><published>2009-11-04T03:07:00.000-08:00</published><updated>2009-11-04T04:38:44.021-08:00</updated><title type='text'>Requisitos nuevos flamantes</title><content type='html'>Con vistas en el nuevo TP estamos acordando algunos requisitos bastante llamativos en relación a la implementación actual. A saber:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El núcleo de la aplicación van a ser los inspectores y los skins. La interfaz principal como tal va a perder algo de protagonismo. De hecho, la idea es poder manipular skins e inspectores como componentes de modo que pueda haber otras formas de cargarlos, incluso como programas individuales.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Queremos evitar la dependencia de GTK. Vamos a usar GTK como interfaz pero queremos poder usar otras cosas. Es decir, queremos poder hacer skins web o de consola, por ejemplo. También queremos que un cambio en GTK no sea demasiado traumático ni afecte a la implementación de los inspectores, solo a los skins. Esto tiene fuertes y traumáticas implicaciones:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;No podremos usar los stores de GTK como almacén para los modelos de los inspectores. Tendremos que definir una interfaz para acceder a los datos del modelo. Esto supondrá varias repercusiones en el rendimiento porque implica copiar (o indireccionar) el contenedor de datos del modelo a la vista.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;No podemos usar el UIManager para gestionar las "Actions" que pueden ofrecer los inspectores. Sin embargo, este sistema es muy flexible y quizá habría que copiarlo. De hecho ya lo copiamos en su momento sin saberlo.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Y agarraos los machos! Queremos que esos "componentes" sean distribuidos. Es decir, algo como lo que GNOME intentó con BONOBO, pero nosotros lo vamos a hacer bien :-S Y claro, para eso vamos a usar Ice. Cada skin e inspector posible ES un servicio. Y nuestra amada/odiada factoría es substituida (en parte) por IceBox. Él va a instanciar y eliminar skins y inspectores.&lt;/li&gt;&lt;/ul&gt;Lo más llamativo puede ser lo de usar Ice, aunque no es tan sorprendente. Paco lo dijo desde el principio de los tiempos, a magmax también le convencía y a mi me llamaba la idea sobre todo por el tema de imponer interfaces férreas gracias al slice, aunque siempre me ha preocupado la penalización que van a tener las invocaciones remotas (aunque sean locales) dado que es «otra capa de mierda» y me temo que se hará cierta esa frase que dice&lt;br /&gt;&lt;br /&gt;«Cualquier problema en ciencias de la computación puede ser solucionado con otra capa de indirección… pero usualmente creará otro problema» ― David Wheeler&lt;br /&gt;&lt;br /&gt;Pero ciertamente tiene muchas ventajas que espero que podamos explotar:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Hacer componentes en muchos y variados lenguajes. En particular esto nos permite prototipar en Python (aprovechando el código actual) y después las partes que sean estables, probadas y que sean críticas en cuanto a rendimiento se pueden pasar a C++.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Manipular inspectores remotos o locales de forma transparente, de modo que se puedan  interponer «inspectores-caché» o hacer aplicaciones GUI puras para dispositivos móviles.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;El modelo de datos puede estar perfectamente establecido por medio de un pequeño conjunto de interfaces, que como veremos se parece mucho a DUO, pues sigue el mismo principio: son interfaces de acceso puro a los datos, la semántica de los mismos la pone el que los interpreta.&lt;/li&gt;&lt;li&gt;Es posible utilizar inspectores ya creados por el sistema u otro usuario.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Hay muchas otras cosas que se pueden delegar a Ice:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Persistencia de la configuración&lt;/li&gt;&lt;li&gt;Gestión de la instanciación/liberación de los componentes&lt;/li&gt;&lt;li&gt;Instalación/actualización de componentes. El sistema de plugins ahora es IceBox.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;Pero usar Ice también plantea muchos problemas que tendremos que ir viendo y que trataremos en siguientes posts. Este es más que nada para que lo vayáis digiriendo. ;-)&lt;br /&gt;&lt;br /&gt;La primera conclusión es que ahora queremos dos cosas: Un programa para interacción entre colecciones de objetos cualesquiera (TP) y una plataforma de componentes (que no tiene nombre aún).&lt;br /&gt;&lt;br /&gt;Saludos&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-8341976562106319789?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/8341976562106319789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=8341976562106319789' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/8341976562106319789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/8341976562106319789'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/11/requisitos-nuevos-flamantes.html' title='Requisitos nuevos flamantes'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-5903525385178561112</id><published>2009-10-28T11:35:00.000-07:00</published><updated>2009-10-28T11:48:31.865-07:00</updated><title type='text'>Widgets personalizados en la barra de tareas</title><content type='html'>Como ya sabéis (o deberíais) Twinpanel usa una encapsulación del ActionGroup de GTK (menu.ActionManager) dónde se pueden añadir de forma muy parecida a cómo se hace en GTK acciones que se mostrarán, dependiendo de la "location" especificada, en la barra de menú o en la de herramientas.&lt;br /&gt;&lt;br /&gt;El problema de esto es que GTK solo proporciona algunos tipos de acciones (gtk.Action y algunos más) que generan elementos en el menú de herramientas, lo que hace imposible en principio añadir un widget genérico en dicha barra.&lt;br /&gt;&lt;br /&gt;Para poder hacer esto se debe crear una especialización de gtk.Action (de forma que el ActionGroup de GTK pueda aceptarlo como acción), registrarlo en la factoría de tipos de GObject y, tras ello, decirle que tipo de widget debe representar. El widget a su vez debe ser una especialización de gtk.ToolItem.&lt;br /&gt;&lt;br /&gt;¿Lioso? Bueno, no tanto. Como nosotros queremos añadir un widget personalizado tan solo deberíamos crear una especialización del gtk.ToolItem y, al ser estos también especialización de gtk.Container, añadir nuestro widget en ellos (y, por supuesto, no os olvidéis de hacer el "show" de nuestro widget).&lt;br /&gt;&lt;br /&gt;Con esto he creado un pequeño ejemplo que se puede ver en el fichero widget.py de la distribución "stable"de Twinpanel.&lt;br /&gt;&lt;br /&gt;Tenemos una clase "SpinAction", que hereda de gtk.Action y está registrada en la factoría de Gobject. La especialización de ToolItem en este caso es "SpinToolButton", que en su constructor crea un SpinButton y se lo añade y muestra. Además tiene una serie de métodos, propios de SpinButton, que nos permite acceder y modificar su valor, además de los callbacks que se conectan con los de SpinButton para emitir nuestras propias señales (que por supuesto están registradas en gobject unas líneas más abajo).&lt;br /&gt;&lt;br /&gt;Con esto simplemente tendremos que crear una instancia de SpinAction y añadirla a nuestro ActionManager con "add_real_action" (TODO: debe cambiarse dicho nombre para que sea "add_action", y cambiar el actual "add_action" a algo más apropiado).&lt;br /&gt;&lt;br /&gt;Lo mismo que con el ejemplo que acabo de explicar estoy intentando hacer con el MenuToolButton, para que podamos añadir una acción que defina un botón con menú asociado (al estilo de los que vemos todos los días en el navegador en los botones "Atrás" y "Adelante").  Lo malo de este tipo es que tiene un menú asociado, y añadirlo en tiempo de "diseño" de la interfaz parece que va a requerir algunos cambios en Twinpanel...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-5903525385178561112?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/5903525385178561112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=5903525385178561112' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/5903525385178561112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/5903525385178561112'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/10/widgets-personalizados-en-la-barra-de.html' title='Widgets personalizados en la barra de tareas'/><author><name>José-Luis Segura</name><uri>http://www.blogger.com/profile/01330405590078064402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_8jfDVrjBFek/SedfHPv37sI/AAAAAAAAAAU/5Fnvw3Md0-Q/S220/kUrh6B0kNPXfpimqsDdd.0.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-7150805651232586185</id><published>2009-09-17T02:16:00.000-07:00</published><updated>2009-09-17T02:24:03.308-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Rediseño del TwinPanel</title><content type='html'>Pues parece que vamos a hacer cierto rediseño del núcleo de TP dado que hay algunos problemas importantes que debemos resolver. Estos son algunos&amp;nbsp; de los más urgentes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No hay ninguna forma mínimamente cómoda de hacer baterías de pruebas.&amp;nbsp; Hay que pensar una forma lo menos invasiva posible de poder comprobar entradas y salidas. Yo estoy trabajando en un proyecto para hacer pruebas automáticas de GUIs, pero sería bueno poder probar el modelo sin GUI, o con una capa de presentación alternativa basada en linea de comandos o algún medio de comunicación programático. &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;li&gt;Los «stores» (ListStore y TreeStore) provocan mucha contención y no están convenientemente probados. Probablemente son la causa más importante de los cuelgues actuales de TP debido a la tácita enemistad entre GTK y los hilos.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;li&gt;El diseño basado en método y dominio no escala. Quedan muchos casos que ese modelo no cubre y complica el uso de la factoría. Necesitamos una forma de abstraer el acceso (http, ftp, ice, etc) del modelo (multimedia, repositorio, sensor, etc).&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;li&gt;Muchas de las interacciones entre plugins y core no están definidas por interfaces. Necesitamos documentar e imponer interfaces concretas de modo que TP se niegue a cargar plugins que no cumplan la interfaz. zope-interface parece una buena solución pero la hemos aplicado a muy pocas interfaces hasta el momento. &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;li&gt;Necesitamos un sistema de instalación y activación/desactivación de plugins, de modo que los que den problemas se "desactiven" automáticamente evitando la ristra de errores que aparecen al arrancar la aplicación.&lt;/li&gt;&lt;/ul&gt;Lo bueno es que todos estos cambios afectan (o deberían afectar) muy poco a los plugins que es dónde está la mayor parte del trabajo hecho hasta la fecha.&lt;br /&gt;&lt;br /&gt;David me dijo que Carlos está trabajando ya en algunos de estos problemas, principalmente en cuestiones de captura de requisitos y diseño pero no he sabido nada más. Empieza a ser urgente ponernos con esto porque la bola de nieve sigue creciendo y empieza a ser preocupante. Personalmente ha llegado un punto en el que me da miedo añadir o modificar nada en TP porque es imposible saber las consecuencias que tiene en el resto de la aplicación.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-7150805651232586185?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/7150805651232586185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=7150805651232586185' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7150805651232586185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7150805651232586185'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/09/rediseno-del-twinpanel.html' title='Rediseño del TwinPanel'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-425695987113643730</id><published>2009-04-09T09:55:00.001-07:00</published><updated>2009-04-09T10:02:39.937-07:00</updated><title type='text'>Galería de imágenes</title><content type='html'>He decidido añadir algunas imágenes de cómo se va viendo la aplicación.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dagph9ttikQ/Sd4oyFKzWtI/AAAAAAAAAAM/7gJkm9lOZcs/s1600-h/2panels.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 208px;" src="http://4.bp.blogspot.com/_dagph9ttikQ/Sd4oyFKzWtI/AAAAAAAAAAM/7gJkm9lOZcs/s320/2panels.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5322736650444561106" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Aquí podemos observar los paneles gemelos. A la izquierda está la lista de plugins (que es jerarquizable y, por tanto, se puede navegar) y a la derecha la lista de directorios. Se pueden ver también los tabs de distintas rutas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dagph9ttikQ/Sd4paySzIzI/AAAAAAAAAAU/P4B4ZOlDh28/s1600-h/netstat.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 310px; height: 400px;" src="http://3.bp.blogspot.com/_dagph9ttikQ/Sd4paySzIzI/AAAAAAAAAAU/P4B4ZOlDh28/s400/netstat.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5322737349752464178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;En esta otra imagen está un netstat tal cual se ve :-D&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dagph9ttikQ/Sd4poKpYWwI/AAAAAAAAAAc/UFcFRfWqhkY/s1600-h/ping.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 310px; height: 400px;" src="http://1.bp.blogspot.com/_dagph9ttikQ/Sd4poKpYWwI/AAAAAAAAAAc/UFcFRfWqhkY/s400/ping.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5322737579627928322" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Y aquí está la vista del ping.&lt;br /&gt;&lt;br /&gt;Pensaba poner también la lista de créditos, pero como sólo se iba a ver a uno de los creadores, creo que iba a ser algo muy feo y no la he añadido :-D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-425695987113643730?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/425695987113643730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=425695987113643730' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/425695987113643730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/425695987113643730'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2009/04/galeria-de-imagenes.html' title='Galería de imágenes'/><author><name>MagMax</name><uri>http://www.blogger.com/profile/08268918285138584096</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-airFMWXsH8U/TyD3DHp5N9I/AAAAAAAAAE0/JrVWqKYSZSI/s220/magmaxpark.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_dagph9ttikQ/Sd4oyFKzWtI/AAAAAAAAAAM/7gJkm9lOZcs/s72-c/2panels.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-2002434700024789102</id><published>2008-10-04T07:53:00.000-07:00</published><updated>2008-10-04T09:05:11.300-07:00</updated><title type='text'>MItem</title><content type='html'>Bueno, pues después de oir las duras críticas de Óscar, Magmax y las mías propias le he hecho algunos cambios al ModelCol. No supone un cambio muy importante, de hecho internamente no hay ningún cambio, solo en el API.&lt;br /&gt;&lt;br /&gt;Lo primero es que ha cambiado de nombre, ahora se llama MItem, que viene a ser algo así como "elemento del modelo". Si el modelo es una tabla, el MItem puede describir una columna, que es el caso habitual, pero también se podría ver como una fila si se requiere.&lt;br /&gt;&lt;br /&gt;No está ligado a TreeModel o TreeView, ni siquiera a GTK. A pesar de ello, lo voy a describir como el modelo de ListStore para que la explicación no quede tan abstracta. El MItem tiene los siguientes campos (todos opcionales):&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;title&lt;/span&gt; (str): Es el título de la cabecera de la columna.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;render&lt;/span&gt; (str): Identifica al encargado de representar el dato en ese columna (en el caso de TreeView, será un CellRenderer). Si no se indica, el render por defecto es "text". El significado real del render depende del encargado de representar el modelo, por ejemplo, el skin_list.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;id&lt;/span&gt; (int). Es una prioridad para esa columna. Lo usamos para crear los índices de ordenación. El "id" más alto es la columna de ordenación por defecto. Si una columna no tiene "id", no se puede ordenar por ella.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;var&lt;/span&gt; (bool). Indica (si es True) que para una misma fila, los valores de esa columna pueden cambiar con el tiempo. Por ejemplo, en un inspector que muestra la lista de unidades de disco, la columna de "espacio libre" sería "var". Si no se indica, es "False" por defecto.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Los parámetros de MItem se indican como un diccionarios (kargs que se dice en Python). A parte de los anteriores, se pueden indicar como clave cualquier palabra que pueda ser utilizada para identificar una propiedad de la columna que describe, en nuestro caso, hasta ahora solo los hemos utilizado para indicar propiedades de los CellRendereres de los TreeViewColumn.&lt;br /&gt;&lt;br /&gt;El valor de esas propiedades se puede indicar de dos modos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Por instancia (o fila). En este caso, el identificador va precedido de un guión bajo (_nombre) y el valor es el nombre de un atributo de un objeto del modelo. Cada fila tiene un valor propio para esa propiedad. Suena complicado, pero en los ejemplos vais a ver que es muy sencillo.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Fijo (por columna). En este caso, el identificador debe ir precedido de un doble guión bajo (__nombre). El valor indicado se interpreta como un literal y se aplica a toda la columna.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Limitaciones&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Los nombres de las propiedades no pueden empezar por guión bajo.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Los nombres de las propiedades tienen que ser identificadores Python válidos. En el caso de propiedades gobject, como "stock-id" el consumidor del metamodelo deberá hacer las transformaciones oportunas.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Ejemplos:&lt;br /&gt;&lt;/h2&gt;Voy a poner la versión MItem de los mismos ejemplo que para ModelCol. Si los comparáis veréis que el interfaz es más genérico y para el mismo caso es más corto casi siempre.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;MItem(title='Name')&lt;br /&gt;- Etiqueta de la columna: 'Name'&lt;br /&gt;- Renderer: 'text'&lt;br /&gt;- Asignar a la propiedad 'text' del renderer, el valor del atributo 'Name'&lt;br /&gt;&lt;br /&gt;MItem(title='Name', _text='filename')&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'filename'&lt;br /&gt;&lt;br /&gt;MItem(title='Name', id=10)&lt;br /&gt;- Ordenar por esta columna, prioridad: 10&lt;br /&gt;&lt;br /&gt;MItem(title='Value', _text='val', __xalign=1)&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'val'&lt;br /&gt;- Justificar el texto de esta columna a la derecha&lt;br /&gt;&lt;br /&gt;MItem(title="Level", _markup="level", id=10)&lt;br /&gt;- Asignar a la propiedad 'markup' el valor del atributo 'level'&lt;br /&gt;- Ordenar por esta columna, prioridad: 10&lt;br /&gt;&lt;br /&gt;MItem(title='Variable', _text='key',&lt;br /&gt; __background='gray', __background-set=True)&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'key'&lt;br /&gt;- Fijar color de fondo de esta columna a 'gray'&lt;br /&gt;&lt;br /&gt;MItem(render='pixbuf', __stock-id='gtk-file')&lt;br /&gt;- Columna sin título&lt;br /&gt;- Renderer: 'pixbuf'&lt;br /&gt;- Fijar la propiedad 'stock-id' a 'gtk-file' para cualquier fila&lt;br /&gt;&lt;br /&gt;MItem(title='Identity', _text='key', _markup='format')&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'key'&lt;br /&gt;- Asignar a la propiedad 'markup' el valor del atributo 'format'&lt;br /&gt;&lt;br /&gt;MItem(render='pixbuf', _stock-id='icon')&lt;br /&gt;- Columna sin título&lt;br /&gt;- Renderer: 'pixbuf'&lt;br /&gt;- Asignar a la propiedad 'stock-id' el valor del atributo 'icon'&lt;br /&gt;&lt;br /&gt;MItem(title="Installed", render="toggle", _active='installed',&lt;br /&gt; __activatable=True)&lt;br /&gt;- Renderer: 'toggle'&lt;br /&gt;- Asignar a la propiedad 'active' el valor del atributo 'installed'&lt;br /&gt;- Fijar la propiedad 'activatable' a True para todas las filas&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-2002434700024789102?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/2002434700024789102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=2002434700024789102' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2002434700024789102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2002434700024789102'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2008/10/mitem.html' title='MItem'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-3532576366112050407</id><published>2008-09-18T00:49:00.000-07:00</published><updated>2008-09-18T01:16:18.212-07:00</updated><title type='text'>Chrome tabs?</title><content type='html'>En los primeros prototipos de twinpanel, teníamos la "barra de direcciones" dentro de la página del notebook pero la barra de herramientas fuera. Pensamos que por "usabilidad" era mejor dejar las dos cosas fuera del notebook como hacen (hacían) todos los navegadores. &lt;br /&gt;&lt;br /&gt;El problema es que eso complica un poco la construcción del interfaz, porque al cambiar de solapa hay que configurar tanto la uri como la barra de botones de acuerdo al panel activo. Luego salió Google Chrome con su diseño "innovador" y me lo estoy volviendo a plantear: solapas arriba o solapas abajo? Tened en cuenta que de hacer el cambio, TwinPanel tendría una barra de herramientas y otra de URI en cada "side", lo que obviamente nos hace desperdiciar algo de espacio en la interfaz (no mucho).&lt;br /&gt;&lt;br /&gt;&lt;div style="display:block; margin:0px auto 10px; text-align:center;"&gt;&lt;img " src="http://www.hachemuda.com/wp-content/uploads/2008/09/google_chrome4.png" border="0" width="320px" alt="" /&gt;&lt;br&gt;by Google Chrome&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-3532576366112050407?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/3532576366112050407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=3532576366112050407' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/3532576366112050407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/3532576366112050407'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2008/09/chrome-tabs.html' title='Chrome tabs?'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-4193770041494683964</id><published>2008-09-01T16:53:00.000-07:00</published><updated>2008-09-01T17:16:25.114-07:00</updated><title type='text'>ModelCol</title><content type='html'>Como ya explicaba &lt;a href="http://twinpanel.blogspot.com/2007/09/probando-probando.html"&gt;hace tiempo&lt;/a&gt; disponemos de un sistema muy versátil y sencillo para construir TreeView, gracias a los skin_list y skin_treeview y una especificación desacoplada del modelo (un metamodelo). Hasta ahora hemos podido implementar cualquier listado utilizando unicamente estos dos skins independientemente del número de columnas o su tipo. Un metamodelo está formado por una lista (vector de Python) de instancias de la clase ModelCol. Nombre muy largo por cierto, seguramente lo renombraré a MCol o algo más corto.&lt;br /&gt;&lt;br /&gt;Lo siguiente es una lista de ejemplos de uso de ModelCol comentados. Quede aquí para futuras referencias. Este mismo listado lo meto en el fichero HowTo.ModelCol que está(rá) en el repo, y que iré ampliando.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ModelCol(title='Name')&lt;br /&gt;- Etiqueta de la columna: 'Name'&lt;br /&gt;- Renderer: Text&lt;br /&gt;- Asignar a la propiedad 'text' del renderer, el valor del atributo 'Name'&lt;br /&gt;&lt;br /&gt;ModelCol(title='Name', attr='filename')&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'filename'&lt;br /&gt;&lt;br /&gt;ModelCol(title='Name', id=10)&lt;br /&gt;- Ordenar por esta columna, prioridad: 10&lt;br /&gt;&lt;br /&gt;ModelCol(title='Value', attr='val', static={'xalign':1})&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'val'&lt;br /&gt;- Justificar el texto de esta columna a la derecha&lt;br /&gt;&lt;br /&gt;ModelCol(title="Level", attr="level", id=10, prop='markup')&lt;br /&gt;- Asignar a la propiedad 'markup' el valor del atributo 'level'&lt;br /&gt;- Ordenar por esta columna, prioridad: 10&lt;br /&gt;&lt;br /&gt;ModelCol(title='Variable', attr='key', static={'background':'gray',&lt;br /&gt;                                       'background-set':True})&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'key'&lt;br /&gt;- Fijar color de fondo de esta columna a 'gray'&lt;br /&gt;&lt;br /&gt;ModelCol(render='pixbuf', static={'stock-id':'gtk-file'})&lt;br /&gt;- Columna sin título&lt;br /&gt;- Renderer: pixbuf&lt;br /&gt;- Fijar la propiedad 'stock-id' a 'gtk-file' para todas las filas&lt;br /&gt;&lt;br /&gt;ModelCol(title='Identity', attr='key', props={'markup':'format'})&lt;br /&gt;- Asignar a la propiedad 'text' el valor del atributo 'key'&lt;br /&gt;- Asignar a la propiedad 'markup' el valor del atributo 'format'&lt;br /&gt;&lt;br /&gt;ModelCol(attr='icon', render='pixbuf', prop='stock-id')&lt;br /&gt;- Columna sin título&lt;br /&gt;- Renderer: Pixbuf&lt;br /&gt;- Asignar a la propiedad 'stock-id' el valor del atributo 'icon'&lt;br /&gt;&lt;br /&gt;ModelCol(title="Installed", render="toggle", prop="active", attr="installed",&lt;br /&gt;      static={'activatable': True})&lt;br /&gt;- Renderer: Toggle&lt;br /&gt;- Asignar a la propiedad 'active' el valor del atributo 'installed'&lt;br /&gt;- Fijar la propiedad 'activatable' a True&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Aunque tiene muchas posibilidades, no es la panacea. Le faltan algunas cosas, pero creo que se podrá hacer sin demasiado problema. En especial:&lt;br /&gt;&lt;br /&gt;- Soporte para desactivación/ocultación de columnas del modelo, a elección del usuario. Esto requiere un gestor de configuración que es en si mismo todo un reto (hablaremos de esto otro día)&lt;br /&gt;- Soporte para formato de las columnas. Los datos se almacenan en crudo en el modelo. Por ejemplo, las fechas se almacenan en tiempo UNIX. Es el usuario el que elige el formato en el que desea que se representen (año-mes-día, mes-año, con hora, GMT, etc). De nuevo esto tiene mucho que ver con el gestor de configuración.&lt;br /&gt;&lt;br /&gt;Después de lo cual concluyo que el soporte de ModelCol y de los skins es casi lo de menos. Necesitamos un gestor de configuración, que por la pinta va a ser casi tan complejo como el propio TwinPanel... mañana hablamos del tema...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PD: Una de las limitaciones que comentaba en el post de "probando, probando" está solventada como veis en los ejemplos. Me refiero a la que decía:&lt;br /&gt;&lt;blockquote&gt;Cada elemento del metamodelo sólo puede afectar a un atributo de la columna correspondiente. Esta puede que sea una limitación inadmisible, habrá que discutirlo. Puede que en este caso esté justificado enriquecer el metamodelo para hacerlo posible.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;PD: No dejéis esa cantidad abrumadora de comentarios que se me van a quitar las ganas de seguir escribiendo ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-4193770041494683964?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/4193770041494683964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=4193770041494683964' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/4193770041494683964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/4193770041494683964'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2008/09/modelcol.html' title='ModelCol'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-9219936727538019091</id><published>2008-08-31T15:24:00.000-07:00</published><updated>2008-09-01T02:50:25.937-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Seguimos vivos</title><content type='html'>A pesar de que el blog ha estado completamente parado durante prácticamente un año, el desarrollo de TwinPanel ha avanzado muchísimo. Aunque ha habido altibajos, el desarrollo no ha estado completamente parado en ningún momento. Gran parte de la culpa de la "desconexión" con el blog se debió al cambio de gnome-vfs a GIO por parte de GNOME.&lt;br /&gt;&lt;br /&gt;Como ya comenté, decidimos utilizar gnome-vfs como backend para todos los inspectores relacionados con el sistema de ficheros, sftp, ftp, samba y demás. Al producirse el cambio a GIO, decidimos dejar en suspenso el desarrollo de esos inspectores hasta que estuvieran disponibles los &lt;a href="http://blogs.gnome.org/johan/2008/07/15/gio-python-bindings/"&gt;bindings de Python para GIO&lt;/a&gt;, que por fin ha llegado. No pensé que tardaran tanto...&lt;br /&gt;&lt;br /&gt;Aunque hay disponibles algunos inspectores funcionales, tengo claro que son demasiado específicos como para que TP pueda llamar la atención de potenciales usuarios beta-testers. Sin duda, disponer de los inspectores básicos de manejo de ficheros (gracias a GIO) permitirá dar un uso cotidiano a TP y podremos plantearnos en breve lanzar una primera release funcional que pueda descargarse, instalar y usar cualquiera que tenga interés en ello.&lt;br /&gt;&lt;br /&gt;En breve escribiré un post hablando del diseño de TP, que en esencia ha seguido las directrices iniciales. También está en la recamara otro post sobre el sistema de instlación de plugins y su interacción con el sistema de gestión de paquetes de la distro. Óscar está escribiendo un tutorial para desarrollar un inspector desde cero. Espero que sea la primera piedra del futuro "Manual de TwinPanel para Desarrolladores". Y no menos importante, en los próximos días subiremos al repo de GNA! la primera versión funcional del core de TwinPanel y algunos inspectores y skins(las antiguas "vistas") para ir abriendo boca.&lt;br /&gt;&lt;br /&gt;Hasta pronto.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-9219936727538019091?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/9219936727538019091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=9219936727538019091' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/9219936727538019091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/9219936727538019091'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2008/08/seguimos-vivos.html' title='Seguimos vivos'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-3849611306045866014</id><published>2008-08-18T08:13:00.001-07:00</published><updated>2008-08-19T00:04:32.220-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='&quot;sabias que...&quot;'/><title type='text'>¿Sabias que... usamos python-sexy?</title><content type='html'>Si instalas el paquete &lt;a href="http://packages.debian.org/sid/python/python-sexy"&gt;python-sexy&lt;/a&gt;, ciertos widgets tendrán una apariencia y herramientas diferentes. Por ejemplo, es común que el 'GtkEntry' que aparece en los mensajes de error ahora tenga un icono para copiar la URI malformada y pegarla donde desees.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_VBuzYhvtQwo/SKpwS4-XrkI/AAAAAAAAAHs/aVmavOTiFoA/s1600-h/TP-libsexy.jpg"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_VBuzYhvtQwo/SKpwS4-XrkI/AAAAAAAAAHs/aVmavOTiFoA/s320/TP-libsexy.jpg" alt="" id="BLOGGER_PHOTO_ID_5236120986605563458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-3849611306045866014?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/3849611306045866014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=3849611306045866014' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/3849611306045866014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/3849611306045866014'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2008/08/sabias-que-usamos-python-sexy.html' title='¿Sabias que... usamos python-sexy?'/><author><name>Oscar Aceña</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_VBuzYhvtQwo/SKpwS4-XrkI/AAAAAAAAAHs/aVmavOTiFoA/s72-c/TP-libsexy.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-4560146554818028392</id><published>2007-09-16T12:27:00.001-07:00</published><updated>2008-09-01T02:51:39.556-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><category scheme='http://www.blogger.com/atom/ns#' term='programando'/><title type='text'>Probando, probando</title><content type='html'>Pues como íbamos diciendo en posts anteriores, ya es hora de ir escribiendo algo de código. He puesto en el &lt;a href="http://svn.gna.org/svn/twinpanel/trunk/"&gt;repo de twinpanel&lt;/a&gt; un ejemplo mínimo de inspector/vista/controlador llamado &lt;a href="http://svn.gna.org/svn/twinpanel/trunk/prototipos/mvc.py"&gt;mvc.py&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tal como hablábamos Oscar y yo, no es posible desacoplar totalmente vista y modelo cuando se usa "gtk.TreeView", ya que obliga a que el formato del modelo (colores y demás atributos) también esté en el modelo. A pesar de que rompe la idea de MVC, parece conveniente apostar por TreeView porque nos da gran parte del trabajo ya hecho.&lt;br /&gt;&lt;br /&gt;Otro problema de TreeView es que, al menos en el uso habitual, la configuración de las columnas "visibles" (TreeViewColumn, TVC) se realiza en base al modelo (store) disponible, con lo cual hay mucho acoplamiento entre ambos. Y esto va totalmente en contra de nuestra idea de hacer vistas "plugables" que puedan utilizarse con muchos inspectores diferentes.&lt;br /&gt;&lt;br /&gt;Afortunadamente, TreeView dispone de un mecanismo que permite rellenar las columnas utilizando un callback en lugar de indicar una columna de un store: set_cell_data_func(). Utilizando esta alternativa y definiendo un &lt;span style="font-weight: bold;"&gt;metamodelo&lt;/span&gt; (que describe el modelo) es posible hacer vistas totalmente genéricas, que se autoconfiguran en base a la información facilitada por cada inspector concreto.&lt;br /&gt;&lt;br /&gt;En cualquier caso, TreeView sigue necesitando un store. Hemos optado por hacerlo lo más simple posible: un array de objetos. La clase de esos objetos la define cada inspector, y su metamodelo indica cómo obtener los datos a partir de los objetos contenidos en el store. De modo que es muy flexible y con el acoplamiento más pequeño posible (de los que se nos han ocurrido).&lt;br /&gt;&lt;br /&gt;Tal cómo está implementado en el programa que refería, este sistema tiene algunas limitaciones:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Cada elemento del metamodelo corresponde a una columna de la vista. Por cada TVC, se crea un único 'cellrenderer' (indicado en el metamodelo). Se podría enriquecer el metamodelo para soportar varios cellrenders pero personalmente aquí aplicaría KISS.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Cada elemento del metamodelo sólo puede afectar a un atributo de la columna correspondiente. Esta puede que sea una limitación inadmisible, habrá que discutirlo. Puede que en este caso esté justificado enriquecer el metamodelo para hacerlo posible.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;El store es una lista (ListStore) lo que implica que, en principio, no sería posible hacer vistas arbóreas. Yo creo que esto no es una limitación perjudicial en lo referente al store.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Raramente será admisible cargar toda una jerarquía en el modelo. Yo creo que sería más adecuada una solución similar a la de nautilus: sólo se cargan los hijos cuando se expande el árbol. Para lograr eso podríamos crear un nuevo inspector para ese directorio y combinar los nuevos objetos en el store existente. Aquí hay varias alternativas de implementación que habría que probar.&lt;/li&gt;&lt;li&gt;Al ser el store un array de objetos, las modificaciones en esos objetos no actualizan la vista. Esto sólo pasa con cambios asíncronos, por ejemplo, si cambia la fecha de un fichero cuando ya ha sido representado en la vista, ese cambio no se muestra. Se puede solucionar de una forma sencilla aunque no sé si muy elegante, forzando una modificación del store cuando sea necesaria. A la vez también es una ventaja, puesto que podemos modificar el modelo real sin que eso implique necesariamente que la vista deba recargarse.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Secuencia de operaciones:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Lo que voy a describir a continuación es un posible método para instanciación de inspectores y vistas. Una parte de esto es lo que pretende ser el ejemplo mvc.py.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Al arrancar TP se registran en una 'factoría abstracta' todos los inspectors y vistas disponibles.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;El 'manager' recibe una petición para gestionar un uri.&lt;/li&gt;&lt;li&gt;El 'manager' pide a la factoría un inspector que pueda manejar esa uri (puede haber varios). Se instancia el inspector pasándole una referencia al manager.&lt;/li&gt;&lt;li&gt;El inspector crea un modelo básico, No hace falta calcular todos los datos hasta que sean necesarios (los pida la vista). Es decir, puede ser un modelo creado bajo demanda.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;El 'manager' pide a la factoría una vista que pueda representar ese inspector (puede haber varios). Se instancia la vista pasándole una referencia al inspector.&lt;/li&gt;&lt;li&gt;La 'vista' se configura utilizando el metamodelo del inspector que se le pasa.&lt;/li&gt;&lt;li&gt;El 'manager' pide a la vista el 'gui' y lo incrusta en la UI dónde corresponda.&lt;/li&gt;&lt;/ol&gt;Como ya he dicho, el ejemplo del repo no tiene factoría ni manager (aún) pero creo que sirve para hacerse una idea.&lt;br /&gt;&lt;br /&gt;Saludos, y espero comentarios.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-4560146554818028392?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/4560146554818028392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=4560146554818028392' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/4560146554818028392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/4560146554818028392'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2007/09/probando-probando.html' title='Probando, probando'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-6129339513298840493</id><published>2007-09-15T11:23:00.000-07:00</published><updated>2008-09-01T02:51:54.120-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Vistas e inspectores</title><content type='html'>Después de discutirlo, hemos decidido que lo que antes llamábamos "frontends" pasarán a llamarse "vistas" (lo siento Oscar) y los "backends" pasarán a llamarse "inspectores", dado que los nombres anteriores eran demasiado genéricos.&lt;br /&gt;&lt;br /&gt;Aparte de este pequeño apunte sobre nomenclatura, hay una cuestión que debemos decidir lo antes posible porque puede afectar mucho a la estructura, funcionalidad e interfaces de TP. Probablemente vamos a tener dos tipos de inspectores:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Los que manipulan un modelo compuesto, es decir, manejan una lista. Esto incluye los que pueden representar un tgz como la lista de ficheros que contiene, y similares.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Los que manipulan un objeto concreto (una hoja), es decir, un inspector que puede manipular una imagen, una película, etc. Normalmente TP utilizará aplicaciones externas para manejar hojas, pero es muy posible que se nos presente la necesidad de desarrollar algunas que no existen, dado el ámbito en el que pretendemos movernos con TP.&lt;/li&gt;&lt;/ul&gt;En el caso de los inspectores de archivos ('archives', o sea tar, zip, etc)  parece claro que al explorarlos se crea un inspector cuya vista substituye a la actual (como hace Total Commander), pero, en el caso de los "inspectores de objetos discretos", ¿qué hacemos?&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Sustituyen en el panel a la vista que los lanzó.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Crean una nueva solapa&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Aparecen en una ventana diferente.&lt;/li&gt;&lt;/ol&gt;Me podéis decir que esto es simplemente una cuestión de configuración como hace firefox, pero en el caso de TP, esta decisión tiene implicaciones que no hay en firefox. Dado que TP asume que "el panel activo es el origen  y &lt;span style="font-style: italic;"&gt;el otro&lt;/span&gt; es el destino", elegir la opción 3 invalidaría ese principio. De modo que estaríamos dejando en la configuración algo que afecta mucho a las posibilidades de uso del inspector. Por otra parte, tenerlo como solapa (substituya o no a la que lo lanza) supone un problema de ortogonalidad puesto que rara vez tendrán sentido operaciones "inspector de discreto" &lt;-&gt; "inspector de compuesto", o sí?&lt;br /&gt;&lt;br /&gt;No lo sé, ¿qué pensáis? ¿qué casos se os ocurren? Espero comentarios&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-6129339513298840493?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/6129339513298840493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=6129339513298840493' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/6129339513298840493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/6129339513298840493'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2007/09/vistas-e-inspectores.html' title='Vistas e inspectores'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-8560048389185151649</id><published>2007-09-15T10:57:00.001-07:00</published><updated>2008-09-01T02:52:42.315-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Interfaces</title><content type='html'>Mmmm, esto va despacito, pero al menos parece que no se nos va de la cabeza, y eso es señal de que queremos que tire para adelante.&lt;br /&gt;&lt;br /&gt;Lo cierto es que la idea tras TP da para mucho, casi cada día se me ocurren posibles funcionalidades que TP podría tener con relativamente poco esfuerzo (y no soy el único). Visto con cierta perspectiva, TP va camino de convertirse en el programa con más features de la historia de la informática, de llegar a hacerse, claro. Un buen slogan para el proyecto sería: "The most featured thing manager in the world" :-)&lt;br /&gt;&lt;br /&gt;Ahora en serio, las conclusiones de nuestras primeras reuniones deberían dar lugar a un documento de diseño importante: el diagrama de clases, como forma de concretar esas decisiones. También deberíamos escribir (aquí mismo) una Especificación de Requisitos del Sistema. Aquí el problema básico es que los requisitos de usuario son prácticamente imposibles de fijar. Dado que la potencia de TP está en su flexibilidad, cada restricción le resta interés.&lt;br /&gt;&lt;br /&gt;Las "interfaces" (en el más amplio sentido de la palabra) van a determinar cuan flexible podrá ser TP, pero está claro que las necesitamos. Elegir mal las interfaces, hará que la complejidad sea pronto inmanejable. Resumiendo, dudo que seamos capaces de definir unas interfaces perfectas a la primera (ni a la segunda). Por eso, creo que lo mejor es pensar que estamos desarrollando un prototipo evolutivo/desechable que nos permitirá probar nuestras ideas y a su vez capturar nuevos requisitos. Pero tenemos que tener claro desde el principio que habrá que tirarlo casi todo a la basura unas cuantas veces antes de llegar a un compromiso entre flexibilidad y complejidad. A partir de ese momento, nos podremos poner a programar plugins como locos, pero no antes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-8560048389185151649?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/8560048389185151649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=8560048389185151649' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/8560048389185151649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/8560048389185151649'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2007/09/interfaces.html' title='Interfaces'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-6666977177877786711</id><published>2007-08-30T01:30:00.000-07:00</published><updated>2008-09-01T02:52:34.652-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentación'/><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>Conclusiones (2007-08-28)</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Motivación&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; El día 2007-08-28 celebramos una reunión David, Óscar y yo Miguel Ángel, con el objetivo de definir con mayor precisión el ámbito de la aplicación. Así mismo se pretendía comenzar la construcción de la aplicación.&lt;br /&gt;&lt;br /&gt; Este texto recoge la mayor parte de las conclusiones de dicha reunión.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ámbito&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;  &lt;li&gt;¿Hasta qué punto es bueno casarse con GTK? ¿Existirá la posibilidad de utilizar otra librería gráfica en el futuro (QT, ncurses, ...), de manera que reutilice la mayor parte de la aplicación? Si dependemos de GTK, la aplicación será más rápida, pero si no lo hacemos, será más dinámica.&lt;br /&gt;       La conclusión final es que no nos importa demasiado depender de GTK, ya que, al fin y al cabo, realmente no vamos a implementar ninguna otra interfaz.&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt;Se utilizará un patrón modelo-vista-controlador. Las vistas serán componentes GTK que pueden cambiarse (árbol, lista, iconos, ...).&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt; Por definición, la aplicación contendrá en todo momento dos paneles. Cada panel, un notebook y una línea que indique la URI actual, que sea editable y permita también el cambio de URI. Un cambio de URI puede provocar la destrucción del backend asociado a la página del notebook para cargar otro (ejemplo: estábamos en "/home" y pasamos a "smb://192.0.0.1"). Además, contendrá un log ocultable (que será un objeto que admite escribir partes de un texto - bien un treestore, bien un textarea - con formato).&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt;Existirá una línea de órdenes global a ambos paneles, aunque siempre actuará sobre el panel activo.&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt;Siempre existirá un panel activo y uno no activo. Sin embargo, esto no se puede tratar mediante el foco, ya que es probable que el foco pertenezca a la línea de órdenes anteriormente citada.&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt;Un plugin puede contener una vista, un backend o bien una vista y un backend.&lt;br /&gt;   &lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Operaciones del backends&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;   En principio, se pueden dividir las operaciones realizables por el usuario en tres tipos:&lt;br /&gt; &lt;ul&gt;&lt;li&gt;&lt;b&gt;Unarias&lt;/b&gt;: Siempre tendrán como origen y destino un único panel. &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Binarias&lt;/b&gt;: Se requiere un panel de origen y uno de destino.  &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Externas&lt;/b&gt;: Requieren de un elemento externo a TwinPanel.  &lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Operaciones unarias&lt;/span&gt;&lt;br /&gt;   &lt;ul&gt;&lt;li&gt;Obtener lista de elementos que se pueden crear para un vector de URI determinadas. Si se solicita sin URI, se devolverá una lista de todos los objetos que el backend es capaz de crear. Si se proporciona más de una URI, el resultado serán los objetos creables en todos ellos.&lt;br /&gt;     El resultado se ofrecerá de la forma: id, cadena (nombre a mostrar), tipo (indefinido, folder, leaf), id del icono.&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt;Obtener lista de elementos para una URI.&lt;/li&gt;    &lt;li&gt;Obtener identificación y versión del backend.&lt;/li&gt;    &lt;li&gt;Eliminar lista de URIs.&lt;/li&gt;    &lt;li&gt;Mover lista de tupla de URIs.&lt;/li&gt;    &lt;li&gt;Obtener lista de acciones soportadas para una lista de URIs. Si no se proporciona la lista, se devolverán todas las acciones soportadas por cualquier elemento del backend.&lt;br /&gt;       Existirán dos métodos: uno para las acciones más comunes (Abrir, borrar, copiar, pegar, ...) y otro para las propias del backend. La existencia de estos dos métodos queda justificada, ya que las acciones comunes serán una Hash, mientras que las acciones propias se devolverán en forma de lista. &lt;/li&gt;    &lt;li&gt; Obtener un descriptor de fichero. Éste puede ser de lectura o de escritura. &lt;/li&gt;   &lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Operaciones binarias&lt;/span&gt;&lt;br /&gt;  &lt;ul&gt;&lt;li&gt;Copy. Se descompone en leer origen, escribir destino. Los permisos dependen de estas operaciones unarias.&lt;/li&gt;    &lt;li&gt;Move. Se descompone en leer origen y borrar origen, escribir destino. Los permisos dependen de estas operaciones unarias.&lt;br /&gt;   &lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;li&gt;Se obtiene el descriptor de fichero de origen de solo lectura.&lt;/li&gt;    &lt;li&gt;Se obtiene el descriptor de fichero de destino de solo escritura.&lt;/li&gt;    &lt;li&gt;Se van copiando los datos del origen al destino.&lt;br /&gt; &lt;/li&gt;&lt;/ol&gt;   Esta opción siempre estará disponible para todos los backends.&lt;br /&gt;&lt;p&gt;&lt;/p&gt;Como bien me recuerda Oscar, existe la posibilidad de que un backend sea capaz de crear otro y cargarlo internamente para realizar distintas opciones (como las arriba citadas del archivo zip).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Operaciones externas&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En principio no nos interesan. Se trabajará con el clipboard.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;   Glosario&lt;/span&gt;&lt;br /&gt;   &lt;ul&gt;&lt;li&gt;Panel: Cada uno de los lados de nuestra aplicación.&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt;URI: Cadena de texto que permite volver a generar un acceso a un punto&lt;br /&gt;     determinado de una estructura jerárquica de forma unívoca.&lt;br /&gt;   &lt;/li&gt;    &lt;li&gt;Backend: Objeto que permite tratar en última instancia un contenedor de&lt;br /&gt;     la estructura jerárquica.&lt;br /&gt;   &lt;/li&gt;&lt;br /&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-6666977177877786711?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/6666977177877786711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=6666977177877786711' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/6666977177877786711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/6666977177877786711'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2007/08/conclusiones-2007-08-28.html' title='Conclusiones (2007-08-28)'/><author><name>MagMax</name><uri>http://www.blogger.com/profile/08268918285138584096</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-airFMWXsH8U/TyD3DHp5N9I/AAAAAAAAAE0/JrVWqKYSZSI/s220/magmaxpark.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-2097750561155568352</id><published>2007-08-11T11:10:00.000-07:00</published><updated>2008-09-01T02:52:19.485-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentación'/><category scheme='http://www.blogger.com/atom/ns#' term='diseño'/><title type='text'>What is Twin Panel?</title><content type='html'>Usually navigators like MS IExplorer, Nautilus or Konqueror have not all the capabilities we want. And they have only one panel to operate.&lt;br /&gt;&lt;br /&gt;There are a lot of programs with two panels: FreeCommander, TotalCommander, ... But all of them have any problem: or they are very limited, or they are non-free.&lt;br /&gt;&lt;br /&gt;Now we want to forget everything we have found in these navigators, and we want to wonder "what in the hell I really need". We want to use it as a Computer Engineering practice, by using so many patterns as possible in design.&lt;br /&gt;&lt;br /&gt;The result... Well. It must be the very best of the navigators, the last project in the bin or something in the middle. We will see it in the future.&lt;br /&gt;&lt;br /&gt;How can you help us? Easy:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;By using the betas and reporting the bugs.&lt;/li&gt;&lt;li&gt;By speaking about it to your friends.&lt;/li&gt;&lt;li&gt;By adding any plugin.&lt;/li&gt;&lt;/ol&gt;And that's all. Here you will find our Twin Panel, free like "freedom", and not like "free beer".&lt;br /&gt;&lt;br /&gt;Thank you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-2097750561155568352?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/2097750561155568352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=2097750561155568352' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2097750561155568352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/2097750561155568352'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2007/08/what-is-twin-panel.html' title='What is Twin Panel?'/><author><name>MagMax</name><uri>http://www.blogger.com/profile/08268918285138584096</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-airFMWXsH8U/TyD3DHp5N9I/AAAAAAAAAE0/JrVWqKYSZSI/s220/magmaxpark.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306111055137036769.post-7473187771217836522</id><published>2007-08-11T10:35:00.000-07:00</published><updated>2007-08-12T03:17:29.388-07:00</updated><title type='text'>Obviedades</title><content type='html'>Pues como dice el título, este post va sobre asunciones de perogrullo, o no tanto... El objetivo es que todos tengamos claros cuales son los elementos y objetivo básico de Twin Panel (TP). Aprovecho también para definir un poco de nomenclatura para que podamos discutir detalles sin volvernos locos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Paneles&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El panel es el componente esencial de TP. En principio la aplicación está pensada para facilitar las clásicas operaciones con ficheros que involucran un origen y un destino, idea más que explotada en aplicaciones como Midnight Commander, Total commander y otros tantos. Por esa razón, TP presentará por defecto 2 paneles (de ahí su nombre)  aunque nuestra idea es que sea lo suficientemente flexible para soportar 2 bloques de n paneles cada uno.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Arquitectura&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;TP consta de tres elementos principales, que encajan perfectamente en el clásico modelo de tres capas.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Backends (persistencia). Son clases especializadas en filesystems, entendiendo filesystem de una manera un tanto peculiar como se verá después. TP sólo incluirá de serie un backend para gestión de ficheros y directorios. Los demás se distribuirán como plugins.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Frontends (presentación). Son clases especializadas en representación. Cada panel está ocupado por únicamente por un frontend. El frontend básico es una lista con columnas. Aunque están desacoplados, lo habitual será que los plugins traigan frontends específicos; por ejemplo una vista de mapa para ver la topología de una red ofrecida por el backend correspondiente. A parte de los frontends que representan listas de elementos, también existen otros que representan preferencias y opciones de usuario, como por ejemplo los datos de conexión de un FTP.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Core (modelo). El core de la aplicación es el encargado de cargar frontends y backends y asegurar la consistencia. Por ejemplo puede cargar un frontend "lista" y otro "árbol" para &lt;span style="font-style: italic;"&gt;renderizar&lt;/span&gt; el contenido de un mismo backend "ftp". El core también se encarga de realizar operaciones sobre los backends y entre ellos. Por ejemplo, copia de ficheros desde un backend "samba" a uno "ftp". También provee los mecanismos para determinar qué operaciones tienen sentido sobre cada backend.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ámbito&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;O sea, ¿qué cosas se van a poder navegar con TP? En general cualquier cosa que esté estructurada como un árbol (un grafo es un árbol con "enlaces").&lt;br /&gt;&lt;br /&gt;Siendo más específicos podemos distinguir dos tipos de elementos "listables":&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Hojas: elementos terminales no manejables con TP a menos que exista un backend para ellos, por ejemplo un fichero .zip. Cuando un backend cargue un elemento "hoja" usando un backend ha de abrirse un nuevo panel. Es decir, no se pueden mezclar en el mismo panel elementos gestionados por diferentes backends.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Compuestos: son elementos que pueden contener elementos hoja y también elementos compuestos. El ejemplo evidente es un directorio.&lt;/li&gt;&lt;/ul&gt;Tanto las "hojas" como los "compuestos" pueden contener cualquier número de propiedades, pero, para un mismo backend, todos los elementos deben tener las mismas propiedades, aunque para algunos de ellos estén vacías (como una tabla en un base de datos). Cada propiedad tiene un nombre (de tipo cadena) y un valor que ha de ser un escalar (cadena, entero, flotante, fecha, permisos)&lt;br /&gt;&lt;br /&gt;Y esto es todo por ahora. ¿comentarios?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306111055137036769-7473187771217836522?l=twinpanel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://twinpanel.blogspot.com/feeds/7473187771217836522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306111055137036769&amp;postID=7473187771217836522' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7473187771217836522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306111055137036769/posts/default/7473187771217836522'/><link rel='alternate' type='text/html' href='http://twinpanel.blogspot.com/2007/08/obviedades.html' title='Obviedades'/><author><name>David</name><uri>http://www.blogger.com/profile/05787054800388890711</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_QpSJMlJK64A/S98xPomVgsI/AAAAAAAAACk/Sjw0eGpBpg4/S220/picture-3.png'/></author><thr:total>0</thr:total></entry></feed>
