Monday, June 9, 2008

Апплет для Gnome на Python

Постановка задачи.

Как и многим другим разработчикам, мне приходится контролировать затраченное на работу время - для написания тайм-репортов и даже просто самоконтроля. Конечно, можно было бы использовать готовые приложения, например Gnome Time Tracker, но у всех подобных программ есть один существенный для меня недостаток - они требуют к себе слишком много внимания. К тому же, на моих предпочтениях сказывается и специфика работы - я работаю в офисе на постоянной основе, а отчеты составляю лишь к концу месяца, при этом особая детализация в этих отчетах не требуется - нужно лишь предоставить временные интервалы. Т.о., мне нужно небольшое приложение, при помощи которого я смог бы легко записывать время прихода и ухода. Задача действительно тривиальна, написание подобной утилитки под силу любому школьнику.
Однако, чтобы было интересней, я решил оформить решение в виде апплета для панели Gnome. Так приложение будет всегда на виду и легко доступно, а при желании я смогу и расширить его функциональность. Задача немного усложняется тем, что из тех мануалов о написании апплетов, что я нашел, все были устаревшими, так что многое пришлось подбирать методом проб и ошибок.
Но не будем слишком углубляться. Для начала, нам понадобится подобный .server файл, описывающий фабрику(TimeTrackApplet_Factory.server):
<oaf_info>
<oaf_server iid="OAFIID:TimeTrackApplet_Factory" type="exe"
location="/usr/lib/gnome-panel/timetrackapplet">

<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:Bonobo/GenericFactory:1.0"/>
<item value="IDL:Bonobo/Unknown:1.0"/>
</oaf_attribute>
<oaf_attribute name="name" type="string" value="Time Track Applet Factory"/>
<oaf_attribute name="description" type="string" value="Factory to create the time track applet"/>
</oaf_server>

<oaf_server iid="OAFIID:TimeTrackApplet" type="factory"
location="OAFIID:TimeTrackApplet_Factory">

<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>
<item value="IDL:Bonobo/Control:1.0"/>
<item value="IDL:Bonobo/Unknown:1.0"/>
</oaf_attribute>
<oaf_attribute name="name" type="string" value="Time Track Applet"/>
<oaf_attribute name="description" type="string" value="TimeTrack applet"/>
<oaf_attribute name="panel:category" type="string" value="Amusements"/>
<oaf_attribute name="panel:icon" type="string" value="myicon.png"/>
</oaf_server>
</oaf_info>
Содержимое файла говорит само за себя. Если кратко - здесь содержится описание нашего апплета и всего, что нужно для его запуска. Стоит отметить, что название фабрики - TimeTrackApplet_Factory должно совпадать с именем файла. Также стоит запомнить путь /usr/lib/gnome-panel/timetrackapplet - это место, где будет размещаться исполняемый файл апплета. Естественно, при желании можно менять любые описания, названия и иконки.
Обычно этот .server файл помещается в каталог /usr/lib/bonobo/servers/. После того, как мы создали и поместили этот файл в нужное место, перейдем к самому апплету. Ниже я приведу полный исходный код, благо он не очень велик:
#! /usr/bin/env python
# -*- coding: UTF-8 -*-

import pygtk
pygtk.require('2.0')
import gtk
import gobject
import gnome
import gnomeapplet

import logging
from datetime import datetime

logging.basicConfig(filename="path/to/applet.log") # я решил, что простого сохранения в лог мне хватит :)
log = logging.getLogger("TimeTrack")
log.setLevel(logging.INFO)

class TimeTrackApplet(gnomeapplet.Applet):# основной класс
def update_tooltip(self, text = None):
if text is None:
self.tooltip.set_tip(self.applet, self.tooltip_text)
else:
self.tooltip_text = text
self.update_tooltip()

def update_text(self,text=None):
if text is None:
self.temp.set_text(self.data)
else:
self.data = text
self.update_text()

def create_applet(self): # создание апплета, самая смыслонагруженная часть
app_window = self.applet
event_box = gtk.EventBox()
event_box.set_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.POINTER_MOTION_MASK |
gtk.gdk.POINTER_MOTION_HINT_MASK |
gtk.gdk.CONFIGURE )

self.temp = gtk.Label()
self.data = "TT" # я не стал искать иконку и ограничился надписью TT
self.update_text()

self.inside_applet = gtk.HBox()
self.inside_applet.pack_start(self.temp)

self.tooltip = gtk.Tooltips() # в качестве демонстрации, создадим также всплывающую подсказку
self.tooltip_text = "Middle click for tooltip update"
self.update_tooltip()

event_box.add(self.inside_applet)
app_window.add(event_box)
app_window.show_all()
return event_box

def button_pressed(self, widget, event, *args, **kwargs):
if event.button==2:# средняя кнопка мыши, обновить подсказку
self.update_tooltip(datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"))
elif event.button==1:# левая кнопка мыши, записать в лог
log.info("Button Pressed: %s",datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"))

def __init__(self,applet,iid):
self.__gobject_init__()
self.applet = applet

self.box = self.create_applet()
self.applet.connect("button-press-event",self.button_pressed) # добавляем обработчик события клика
log.info("Applet created succesfully")

gobject.type_register(TimeTrackApplet)

DEBUG = False

def timetrack_applet_factory(applet, iid): # Реализация фабрики
log.info("Creating the applet...")
TimeTrackApplet(applet, iid)
return True

log.info("Starting...")
gnomeapplet.bonobo_factory("OAFIID:TimeTrackApplet_Factory",
TimeTrackApplet.__gtype__,
"TimeTrack",
"0.1",
timetrack_applet_factory) # Запуск всего механизма
log.info("Stopping...")
Данный файл нужно скопировать на то место, которое указано в .server файле. Большая часть кода - gnome-specific, поэтому я постарался объяснить только самые общие моменты(экскурс в gnome+python не является моей целью сейчас) при помощи комментариев.
Итак, для тех, кто код прочитал( :) ), понятно, что по щелчку левой кнопкой мыши дата и время щелчка (в UTC) записываются в лог-файл. Для меня это удобно - в конце месяца я смогу восстановить по этому файлу временные интервалы, а если когда забуду щелкнуть, то вряд ли будет трудно разобраться в этом человеку(это объяснение тому, что я не добавил в утилиту возможность автоматического подсчета интервалов).
Надеюсь, этот простой пример поможет кому-нибудь в написании собственных апплетов. Удачи!

Ссылки по теме:

-http://www.gnome.org/projects/ORBit2/appletstutorial.html (примеры на С)
-http://www.pygtk.org/articles/applets_arturogf/ (устаревший пример на Python)
-http://computertemp.berlios.de/ (готовый апплет, наиболее полезным оказался)
-http://www.pygtk.org/docs/pygtk/ (reference для pygtk)

1 comment:

  1. Здравствуйте. Меня мучает вопрос, как запустить апплет из командной строки (терминала)?

    ReplyDelete