Ils seront nôtres.

written by nicoe, on Mar 16, 2011 7:26:00 AM.

On a fait notre choix :

/static/nicoe/pumpkin.jpg /static/nicoe/confluence.jpg

Plus qu'à choisir les couleurs maintenant.

Two small pygtk recipes : autohide and notebook window creation

written by nicoe, on Feb 11, 2011 2:23:00 PM.

Here are two small python + GTk recipes that might comes handy when people are searching for howtos about autohide and window creation from notebook drag and drop.

Auto-hiding part of a window with pygtk

First you create a gtk.Paned widget wich will hold the main screen and the widgets that will be hidden automatically. Then in the left part of pane window the trick is to use an EventBox around your VBox so that you can listen for the enter-notify-event and leave-notify-event signals.

import gtk

def toggle_max(widget, event):
    pane.set_position(65)

def toggle_min(widget, event):
    pane.set_position(15)

window = gtk.Window()
pane = gtk.HPaned()
eventbox = gtk.EventBox()
vbox = gtk.VBox()
eventbox.add(vbox)
entry1 = gtk.Entry()
vbox.pack_start(entry1)
entry2 = gtk.Entry()
pane.add1(eventbox)
pane.add2(entry2)

eventbox.connect('enter-notify-event', toggle_max)
eventbox.connect('leave-notify-event', toggle_min)

window.add(pane)
window.show_all()

gtk.main()

Notebook window creation

One very neat feature I discovered with chromium is the creation of another window once you drag and drop a tab in your root window. Since I am thinking about integrating this feature in the tryton client, I give it a shot in a very small script. The tricky part was debugging the create_window_from_tab function, kudos go to Juhaz from #pygtk who helped me with this.

import gtk

def check_pages(notebook, child, page_num):
    page_nbr = notebook.get_n_pages()
    if page_nbr == 0:
        parent_win = notebook.get_parent_window()
        parent_win.destroy()

def create_window_from_tab(notebook, page, drop_x, drop_y):
    window = gtk.Window()
    nb = gtk.Notebook()
    nb.set_group_id(42)
    nb.connect('create-window', create_window_from_tab)
    nb.connect('page-removed', check_pages)
    window.add(nb)
    window.show_all()
    window.maximize()
    return nb

dialog = gtk.Window()
image_tab1 = gtk.Image()
image_tab1.set_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION, gtk.ICON_SIZE_BUTTON)
label_tab1 = gtk.Label('Tab 1')
image_tab2 = gtk.Image()
image_tab2.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
label_tab2 = gtk.Label('Tab 2')
image_tab3 = gtk.Image()
image_tab3.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_BUTTON)
label_tab3 = gtk.Label('Tab 3')

notebook = gtk.Notebook()
notebook.set_group_id(42)
notebook.append_page(image_tab1, label_tab1)
notebook.set_tab_detachable(image_tab1, True)
notebook.append_page(image_tab2, label_tab2)
notebook.set_tab_detachable(image_tab2, True)
notebook.append_page(image_tab3, label_tab3)
notebook.set_tab_detachable(image_tab3, True)
notebook.connect('create-window', create_window_from_tab)
notebook.connect('page-removed', check_pages)

dialog.add(notebook)
dialog.show_all()

gtk.main()

One vim server per desktop

written by nicoe, on Jan 27, 2011 9:14:00 PM.

I usually organize my desktop 'semantically'. The first desktop is where I do my main development, the second one is where I test those developments, the third one is used for my tests in bpython or when I need to write some little examples. The last desktops is where I have my luakit windows and the next to last one is where I have my gajim, xchat and mutt windows. The five other desktops are usually empty but are there in case of need.

And here is what my typical desktop looks like:

/static/nicoe/thumb_desktop_20110127.png

One thing that annoy the hell out of me is the fact that I cannot open a specific file in my already running vim from one of the command line. So today, I finally stop complaining about that and I read about the remote option of vim.

So here is my script that will create a server per desktop and if a server is already running on this desktop than it will connect to it and open the file into it.

#!/bin/sh
if test -n "$DISPLAY"; then
    desktop="SERVER$(wmctrl -d | grep '\*' | cut -f 1 -d ' ')"
    vim --serverlist | grep $desktop
    if [ $? -eq 1 ]
    then
        urxvtcd +sb -geometry 80x57 -e vim --servername $desktop $* >> /dev/null &
    else
        vim --servername $desktop --remote $*
    fi
else
    vim $*
fi

The trickier part was finding the wmctrl tool which is a nice utility to interact through the command line with EWMH/NetWM compatible X Window managers (and thus with my the greatest WM of all time : openbox ;)).

How to make mutually beneficient unfriendly forks ?

written by nicoe, on Jan 18, 2011 5:53:00 PM.

Last week I learned about aeroolib a not so friendly fork of relatorio. It left me wondering about how to handle such a situation. Granted relatorio suffered from a lack of attention since I started to work for PCSol, but since I left, I intend to push for a greater integration of it into tryton.

I was disappointed because I never heard of this company using relatorio and all of a sudden they announce that they forked our project and added some nice features. The guy behind this company had posted 2 bugs (one of them after having talk with him in great length on IRC) and never posted any message on our mailing list. One thing amongst other that really got on my nerves was that the new project fixed a (so called) security breach, and they did not warn us about that issue ! And eventhough they did grant us the copyright on our work (they had too, that's why I choose the GPL when writing this piece of software after all) I felt that the collaboration should have been better.

But next time you intend to fork project do it right:

  • keep the development history (for such little projects using tailor is a piece of cake), it might prove usefull and you have the opportunity to clearly separate what are your developments and what were the original ones. For now all we have is a big fat commit and it has made our work of patching relatorio more difficult (on a side note : do not comment stuff in your repository, bazaar won't forget those lines you are deleting you know).
  • do not, I repeat, do not removed all the test cases : I bet that sooner or later you will have to write them again.
  • talk to the maintainers on the mailing list or on IRC about your issues. We now have to libraries, amongst many others, that do opendocument rendering based on genshi templates.

Those little advices will ease our work and yours. A fork, even an unfriendly one, might be mutually beneficient.

New year's changes

written by nicoe, on Dec 25, 2010 3:55:00 PM.

This first of January I will start working with Cédric Krier and Bertrand Chenal from b2ck. I will work with Cédric on a Tryton project in Holland. This project is really interesting and will bring a lot of improvements to the tryton client and server. I am really happy with this turn in my life since it will allow me to work on more interesting problems in a better and more thought-challenging environment.

The first development I am working on is a functionality that will propagate constraints from domain to the opened tabs in the tryton client. To make things clearer an example is probably necessary. With tryton (or openerp) you can set a constraint on fields or views by setting what is called a domain. So to ensure some business rules are enforced we sometimes need to inverse the domain so that people creating object won't be able to violate the rules we defined with the domain.

So what I needed was a module that could do this (taken from my tests):

>>> domain = ['OR', ('x', '=', 3), ('y', '>', 5), ('z', '=', 'abc')]
>>> inversion(domain, 'x')
[('x', '=', 3)]
>>> inversion(domain, 'x', {'y': 4})
[('x', '=', 3)]
>>> inversion(domain, 'x', {'y': 7})
True

The last result stating that there is no constraint on the x fields since the domain constraint is already met by the y value in the context.

Another focus point will be the creation of a connection manager inspired by the one used by gajim. This will prove a nice UI addition for less technical users.

Using distant OpenERP objects pythonically

written by nicoe, on May 19, 2010 10:03:00 PM.

At work we have a project to realize a pygtk POS interface for OpenERP. It is getting closer and closer everyday and after much hagglings to create the right UI, I had to connect it to the underlying server. Using the so called netrpc protocol out of the box is not really the most pythonic you can get.

So I came up with those classes that made me fells just like home when I needed to work with the OpenERP objects.

class MetaOEObject(type):

  def __init__(cls, name, bases, dict):
      super(MetaOEObject, cls).__init__(name, bases, dict)
      cls.proxy = Config.client.create_proxy(Config.database,
                                             dict['dotted_name'])
      cls.fields = cls.proxy.fields_get()
      OEObject.proxies[dict['dotted_name']] = cls


class OEObject(object):

  proxies = {}

  def __init__(self, id=None):
      self.id = id
      if id is not None:
          self.value = self.proxy.read(id)

  @classmethod
  def select(cls, condition):
      ids = cls.proxy.search(condition)
      return [cls(id) for id in ids]

  def __getattr__(self, name):
      if name not in self.fields:
          raise AttributeError
      elif self.fields[name]['type'] == 'many2one':
          oeobj = OEObject.proxies[self.fields[name]['relation']]
          if self.value[name]:
              return oeobj(self.value[name][0])
          else:
              return None
      elif self.fields[name]['type'] == 'one2many':
          oeobj = OEObject.proxies[self.fields[name]['relation']]
          return [oeobj(id) for ids in self.value[name]]
      elif self.fields[name]['type'] == 'binary':
          if not self.value[name]:
              return None
          filename = os.tempnam()
          fd = open(filename, 'w')
          fd.write(base64.b64decode(self.value[name]))
          fd.flush()
          return filename
      return self.value[name]

  def __str__(self):
      print self.dotted_name, self.id
      return '<%s (%d)>' % (self.dotted_name, self.id)


class Category(OEObject):
  __metaclass__ = MetaOEObject
  dotted_name = 'product.category'


class Product(OEObject):
  __metaclass__ = MetaOEObject
  dotted_name = 'product.product'

Those kind of classes makes use of metaclasses so that proxy and fields are class-attributes which seems nicer to me. It allows me write pieces of code like this

for category in Category.select([('parent_id', '=', None)]):
    page = self.create_category_page(category, notebook)
    for product in Product.select([('categ_id', '=', category.id)]):
        page.add_product(product)

Which populates a GtkIconView into a notebook used to display products sorted by categories.

Nokia 5800 et rhythmbox

written by nicoe, on May 19, 2010 8:57:00 AM.

J'ai enfin décidé d'utiliser les propriétés de lecteur MP3 de mon Nokia. Le déclic ce fut l'importation des 45 CDs achetés lors la (triste) liquidation de Caroline Musique. Il faut que je trouve du temps pour écouter tout ça ! Temps tout trouvé puisque je passe vingt cinq minutes dans le bus tous les matins.

libmtp est bien faite et détecte mon téléphone malheureusement soit elle, soit rhythmbox est incapable de transférer les fichiers musicaux correctement puisqu'ils ne respectent pas la hiérarchie Artiste/Album. Tant pis, je l'utilise alors en mass-storage et j'ajoute le fichier .is_audio_player suivant permettant à rhythmbox de correctement transcoder mes précieux flac en mp3 parfaitement compréhensibles par mon GSM.

audio_folders=Music/
folder_depth=2
output_formats=audio/mpeg

De retour

written by nicoe, on May 17, 2010 5:37:00 PM.

Après quelques mois de mort clinique, ce blog est reparti. Pour combien de temps, nous verrons.

epiphany utilise webkit

written by nicoe, on Sep 25, 2009 8:15:00 PM.

Avec la sortie de la nouvelle version du bureau GNOME arrive la fonctionnalité que j'attendais vraiment : le passage à WebKit d'epiphany.

WebKit c'est un moteur de rendu Web. WebKit c'est aussi un troll (mourrant) sur l'implication d'Apple dans le logiciel libre car ce moteur est basé sur KHTML et la collaboration entre l'équipe de KDE et celle de la Pomme n'a pas toujours été parfaite.

Mais WebKit c'est surtout une bibliothèque ultra-rapide, j'ai l'impression de revivre et que le net va 5× plus vite depuis que je l'utilise.

Tirage de la CL ...

written by nicoe, on Aug 28, 2009 9:12:00 PM.

Et le voila, cet hymne qu'on attendait depuis si longtemps. Il va retentir dans le stade à l'affiche de FIFA 2010. Le tirage avait lieu hier, et on est maintenant fixé sur les adversaires du Standard :

Toutes les équipes jouent en rouge et blanc, ce sera l'occasion de voir nos joueurs avec le maillot brun. C'est pas plus mal. Et l'un dans l'autre, le tirage est relativement abordable. Ça pourrait le faire.

Demain rendez-vous à Sclessin pour choper des places pour les trois matches.

EDIT: C'est fait j'ai mes places ! 20 minutes de file, seulement 5 personnes devant moi, le rêve du à une communication très approximative du Standard.