~adeodato/ code/ minirok/ csl2.blog/ entries/ 2008/ 03/ 29/ Una historia de grrr, ooh y... yay?

Una historia de grrr, ooh y... yay?

Bueno. Me siento como si hubieran pasado meses desde la última vez que escribí aquí. Supongo que cuando uno está trabajando y no hace más que encontrarse con muros, el tiempo pasa más despacio. Esta entrada también se podría haber titulado: De cómo reescribí la vista en árbol en una semana. Ah, y perdón por adelantado, que esto va a ser largo.

En una entrada anterior comenté cómo los problemas de rendimiento al hacer búsquedas en la vista en árbol eran debidos a la propia librería Qt, y cómo sus autores me habían recomendado que la migrara al paradigma modelo/vista de Qt4. El mismo que la lista de reproducción ya usa.

Parte 1: Grrr, y más grrr

Comencé intentando utilizar algo ya existente en las librerías de KDE, y KDirModel parecía muy prometedor. Le dediqué un rato, y en un par de horas, puede que algo menos, tuve algo funcionando. Sin embargo, pese a ser fácil de utilizar, tuve que abandonarlo: era demasiado inflexible a la hora de realizar un listado recursivo del sistema de ficheros — y, de todas maneras, al no tener control de las estructuras internas, hubiera sido algo más complejo realizar búsquedas en dicha jerarquía.

A continuación, pues, comencé a implementar mi propio modelo, intentando preservar lo máximo posible del código existente para leer los directorios. Decidí representar el árbol como una lista de arrays y un mapa de índices, y me estuve peleando sin conseguir que funcionara: no conseguía encontrar el error por ninguna parte. Así las cosas, decidí desechar este modelo, y escribir uno nuevo basándome al pie de la letra en un ejemplo de la documentación de Qt.

Una vez tuve el modelo basado en el ejemplo casi funcionando, lo comparé al mío original y descubrí el error: había estado heredando de QAbstractTableModel en lugar de QAbstractItemModel! De todas maneras, me gustó más esta segunda manera (con un verdadero árbol de ítems, en lugar de una lista de arrays), y me lo quedé. Pero, terminé de copiar el ejemplo y... bum!, crash al expandir los ítems. Tras otro buen rato de depuración, encontré el fallo: pequeño error de transcripción del ejemplo (C++) a mi código (Python). Y mientras tanto el tiempo iba pasando...

Ya que estaba restructurando la vista en árbol, me dije que sería una buena oportunidad para implementar al mismo tiempo la tarea 790: leer el contenido de los directorios en un hilo aparte, para no bloquear la interfaz, particularmente si el directorio está en un sistema de ficheros en red. Pero na-nay: se seguía bloqueando la interfaz, y casi que más. Entonces pensé: con KDirModel no se bloqueaba, voy a ver si puedo investigar cómo lo hace.

Parte 2: Ooh, un KListDir

KDirModel utiliza kioslaves para realizar la lectura de los directorios. La ventaja principal de los kioslaves es que son un proceso separado, por lo que la aplicación no se bloquea en absoluto. Win!

En particular, KDirModel utiliza un objeto de la clase KDirLister, que es como una capa de abstracción sobre los kioslave. Y es una pa-sa-da: no sólo proporciona a la aplicación con la lista de contenidos de un directorio (filtrando incluso por tipo MIME, lo que le viene de perlas a Minirok), sino que se queda observando los directorios abiertos y notifica a la aplicación si se crean, borran o renombran ficheros en ellos!

El funcionamiento es sencillo, mediante señales de Qt. La aplicación solicita al objeto la lectura de un directorio con openUrl(), y el objeto devolverá los contenidos del mismo en una o varias señales newItems(), más una señal completed() al finalizar.

Así, la parte principal del modelo la componen los slots conectados a esas señales. Y la tarea 790, hecha!

Parte 3: Yay?

Tras tener una primera version del modelo con KDirLister hace unos días, no sé por qué no terminaba de quedarme un buen sabor de boca del todo. Me parecía que KDirLister iba un poco más lento que mi código anterior, y que utiliza más memoria. Sin embargo, al ir pasando los días este sentimiento se ha ido disipando, afortunadamente.

Porque ventajas las hay, por un tubo. No sólo el hecho de refrescar en tiempo real es fantástico, sino que ahora Minirok puede leer cualquier directorio al que KDE pueda acceder, por ejempo unidades compartidas de Windows. (Lamentablemente aún no podría reproducir de ellas, ya que el motor de reproducción es todavía GStreamer. Phonon no tiene Python bindings aún.)

Así que, me digo, creo que ha sido un cambio para mejor. Por cierto, el diff (gigante) es éste, y el mensaje de la revisión (la 631), aquí.

Addendum

“¿Y de la búsqueda qué?” Que, claro, fue el motivo inicial para todo esto. Pues, funciona razonablemente bien, aunque no ha sido un camino de rosas tampoco. Lo explicaré con más detalles en una entrada dentro de unos días.

Para terminar, dos cosas más: