Merge lp:~sncf-pde/specto/pattern_search into lp:specto

Proposed by kouao aaron
Status: Needs review
Proposed branch: lp:~sncf-pde/specto/pattern_search
Merge into: lp:specto
Diff against target: 29980 lines (+29110/-39) (has conflicts)
95 files modified
build/lib.linux-i686-2.6/spectlib/about.py (+88/-0)
build/lib.linux-i686-2.6/spectlib/add_watch.py (+278/-0)
build/lib.linux-i686-2.6/spectlib/balloons.py (+102/-0)
build/lib.linux-i686-2.6/spectlib/bdd.py (+317/-0)
build/lib.linux-i686-2.6/spectlib/config.py (+104/-0)
build/lib.linux-i686-2.6/spectlib/console.py (+54/-0)
build/lib.linux-i686-2.6/spectlib/constants.py (+7/-0)
build/lib.linux-i686-2.6/spectlib/contact.py (+330/-0)
build/lib.linux-i686-2.6/spectlib/crawl.py (+149/-0)
build/lib.linux-i686-2.6/spectlib/edit_watch.py (+316/-0)
build/lib.linux-i686-2.6/spectlib/export_watch.py (+231/-0)
build/lib.linux-i686-2.6/spectlib/gtkconfig.py (+588/-0)
build/lib.linux-i686-2.6/spectlib/i18n.py (+50/-0)
build/lib.linux-i686-2.6/spectlib/i18n_safedict.py (+70/-0)
build/lib.linux-i686-2.6/spectlib/imail.py (+294/-0)
build/lib.linux-i686-2.6/spectlib/import_watch.py (+281/-0)
build/lib.linux-i686-2.6/spectlib/logger.py (+344/-0)
build/lib.linux-i686-2.6/spectlib/main.py (+417/-0)
build/lib.linux-i686-2.6/spectlib/notifier.py (+1080/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_im_pidgin.py (+188/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_mail_evolution.py (+70/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_mail_gmail.py (+380/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_mail_gwave.py (+271/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_mail_imap.py (+272/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_mail_pop3.py (+287/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_music_amarok.py (+74/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_music_banshee.py (+88/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_music_lastfm.py (+160/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_music_rhythmbox.py (+89/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_sn_facebook.py (+355/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_sn_twitter.py (+1699/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_system_file.py (+168/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_system_folder.py (+222/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_system_mumbles.py (+110/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_system_pdf_file.py (+289/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_system_port.py (+115/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_system_process.py (+193/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_vc_bazaar.py (+168/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_vc_subversion.py (+145/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_web_greader.py (+312/-0)
build/lib.linux-i686-2.6/spectlib/plugins/watch_web_static.py (+643/-0)
build/lib.linux-i686-2.6/spectlib/preferences.py (+405/-0)
build/lib.linux-i686-2.6/spectlib/tools/indicator.py (+184/-0)
build/lib.linux-i686-2.6/spectlib/tools/iniparser.py (+783/-0)
build/lib.linux-i686-2.6/spectlib/tools/keyringmanager.py (+67/-0)
build/lib.linux-i686-2.6/spectlib/tools/networkmanager.py (+140/-0)
build/lib.linux-i686-2.6/spectlib/tools/sound.py (+50/-0)
build/lib.linux-i686-2.6/spectlib/tools/specto_gconf.py (+107/-0)
build/lib.linux-i686-2.6/spectlib/tools/web_proxy.py (+41/-0)
build/lib.linux-i686-2.6/spectlib/trayicon.py (+209/-0)
build/lib.linux-i686-2.6/spectlib/util.py (+117/-0)
build/lib.linux-i686-2.6/spectlib/watch.py (+720/-0)
build/scripts-2.6/specto (+30/-0)
data/uis/contact.ui (+131/-0)
data/uis/contact_dialog.ui (+176/-0)
data/uis/group_contact_dialog.ui (+119/-0)
data/uis/notifier.ui (+16/-2)
data/uis/preferences.ui (+831/-2)
doc/Manual.rst (+1/-1)
installed_files (+148/-0)
spectlib/add_watch.py (+14/-0)
spectlib/bdd.py (+317/-0)
spectlib/contact.py (+330/-0)
spectlib/crawl.py (+152/-0)
spectlib/gtkconfig.py (+42/-0)
spectlib/imail.py (+295/-0)
spectlib/main.py (+31/-0)
spectlib/notifier.py (+26/-0)
spectlib/plugins/pdfminer/Makefile (+9/-0)
spectlib/plugins/pdfminer/__init__.py (+4/-0)
spectlib/plugins/pdfminer/arcfour.py (+49/-0)
spectlib/plugins/pdfminer/ascii85.py (+81/-0)
spectlib/plugins/pdfminer/cmap/Makefile (+9/-0)
spectlib/plugins/pdfminer/cmapdb.py (+421/-0)
spectlib/plugins/pdfminer/converter.py (+497/-0)
spectlib/plugins/pdfminer/encodingdb.py (+58/-0)
spectlib/plugins/pdfminer/fontmetrics.py (+46/-0)
spectlib/plugins/pdfminer/glyphlist.py (+4339/-0)
spectlib/plugins/pdfminer/latin_enc.py (+241/-0)
spectlib/plugins/pdfminer/layout.py (+675/-0)
spectlib/plugins/pdfminer/lzw.py (+101/-0)
spectlib/plugins/pdfminer/pdfcolor.py (+33/-0)
spectlib/plugins/pdfminer/pdfdevice.py (+174/-0)
spectlib/plugins/pdfminer/pdffont.py (+702/-0)
spectlib/plugins/pdfminer/pdfinterp.py (+834/-0)
spectlib/plugins/pdfminer/pdfparser.py (+791/-0)
spectlib/plugins/pdfminer/pdftypes.py (+260/-0)
spectlib/plugins/pdfminer/psparser.py (+686/-0)
spectlib/plugins/pdfminer/rijndael.py (+1078/-0)
spectlib/plugins/pdfminer/runlength.py (+50/-0)
spectlib/plugins/pdfminer/utils.py (+276/-0)
spectlib/plugins/watch_system_pdf_file.py (+289/-0)
spectlib/plugins/watch_web_static.py (+329/-30)
spectlib/preferences.py (+198/-3)
spectlib/watch.py (+0/-1)
Text conflict in data/uis/preferences.ui
To merge this branch: bzr merge lp:~sncf-pde/specto/pattern_search
Reviewer Review Type Date Requested Status
Jeff Fortin Tam Needs Fixing
Review via email: mp+97351@code.launchpad.net
To post a comment you must log in.
lp:~sncf-pde/specto/pattern_search updated
169. By Aaron KOUAO <email address hidden>

add possibility to choose whether to send email to inform

Revision history for this message
Jeff Fortin Tam (kiddo) wrote :

Bonjour,
I couldn't run the code yet, it adds a bunch of dependencies, some of which [like "MySQLdb"] are not available in linux distributions and I'm not sure what to expect from such a huge merge.

However, from a look at the surface of things, there are various problems that I've detected. Just run a directory comparison with meld (http://meld.sf.net) between your branch and the "main" branch and it should become quite apparent.
- You committed a bunch of unrelated files from a build/ directory.
- The merge is unclean (there are merge conflicts). If possible, rebase your branch onto the latest code (maybe you could use for this if you're used to it).
- You added code that is commented out, and print statements. Please do not add unused code.
- You added a huge amount of "public domain" code as a pdfminer directory. Instead, you should depend on a pdfminer library being packaged by Linux distributions, not copy-paste/statically link all that code into specto (which I can't afford to maintain anyway)...

In short, the code needs fixing, various things shouldn't be part of the commits at all (like the build stuff or the pdfminer library) and you should ideally rebase everything onto the latest lp:specto to make the merge easier.

Thanks in advance!

review: Needs Fixing

Unmerged revisions

169. By Aaron KOUAO <email address hidden>

add possibility to choose whether to send email to inform

168. By Aaron KOUAO <email address hidden>

Add the possibility to crawl pdf page

167. By Fabien_SNCF-PDE

- Add a window to set database settings and check them in preferences (default set to sqlite). database in bdd.py and sqlalchemy. Don't finished actually, still work with files
- Add a class to crawl webpage "crawl.py" manually. actually just crawl, don't check pattern and no difference between rss and html page
- Add a window to manage contact and mail address in group (work with database)
- Add possibility to check multiple pattern and exception

166. By Fabien_SNCF-PDE

- Fix a little bug in the previous version
- Add a window to set settings for send mails and check them in preferences
- Add a little window to alert if settings are not set when adding a watch (if you give mail adress to the watch without set smtp server the watch will ignore it)
- Add mail settings to gconf and use keyring for password

165. By Fabien_SNCF-PDE

Add class to send email when a pattern is found in rss page and a best work for detecting new pattern

164. By Fabien_SNCF-PDE

First very simple version

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'build'
2=== added directory 'build/lib.linux-i686-2.6'
3=== added directory 'build/lib.linux-i686-2.6/spectlib'
4=== added file 'build/lib.linux-i686-2.6/spectlib/__init__.py'
5=== added file 'build/lib.linux-i686-2.6/spectlib/about.py'
6--- build/lib.linux-i686-2.6/spectlib/about.py 1970-01-01 00:00:00 +0000
7+++ build/lib.linux-i686-2.6/spectlib/about.py 2012-03-14 09:03:18 +0000
8@@ -0,0 +1,88 @@
9+# -*- coding: utf-8 -*-
10+
11+# Specto , Unobtrusive event notifier
12+#
13+# about.py
14+#
15+# See the AUTHORS file for copyright ownership information
16+
17+# This program is free software; you can redistribute it and/or
18+# modify it under the terms of the GNU General Public
19+# License as published by the Free Software Foundation; either
20+# version 2 of the License, or (at your option) any later version.
21+#
22+# This program is distributed in the hope that it will be useful,
23+# but WITHOUT ANY WARRANTY; without even the implied warranty of
24+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25+# General Public License for more details.
26+#
27+# You should have received a copy of the GNU General Public
28+# License along with this program; if not, write to the
29+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
30+# Boston, MA 02111-1307, USA.
31+
32+import os
33+import pygtk
34+pygtk.require("2.0")
35+import gtk
36+
37+from spectlib.util import show_webpage, get_path
38+
39+
40+class About:
41+ """
42+ Class to create a window with the credits
43+ and licensing information about Specto.
44+ """
45+
46+ def __init__(self, specto):
47+ self.specto = specto
48+
49+ license_file_path = (os.path.join(get_path(category="doc"), "COPYING"))
50+ with open(license_file_path, "r") as license_file:
51+ license = license_file.read()
52+
53+ authors_file_path = (os.path.join(get_path(category="doc"), "AUTHORS"))
54+ with open(authors_file_path, "r") as authors_file:
55+ # this is a hack, because gtk.AboutDialog expects a list, not a file
56+ authors = authors_file.readlines()
57+
58+ logo = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_about.png"))
59+
60+ # gtk.AboutDialog will detect if "translator-credits" is untranslated,
61+ # and hide the tab.
62+ translator_credits = _("translator-credits")
63+
64+ #create tree
65+ self.about = gtk.AboutDialog()
66+
67+ self.about.set_name("Specto")
68+ self.about.set_version(self.specto.VERSION)
69+ self.about.set_copyright("Copyright © Jean-François Fortin Tam & Wout Clymans")
70+ self.about.set_comments(_("Be notified of everything"))
71+ self.about.set_license(license)
72+ #self.wTree.set_wrap_license(license)
73+ gtk.about_dialog_set_url_hook(lambda about, url: show_webpage(url))
74+ self.about.set_website("http://specto.sourceforge.net")
75+ self.about.set_website_label(_("Specto's Website"))
76+ self.about.set_authors(authors)
77+ #self.about.set_documenters(documenters)
78+ #self.about.set_artists(artists)
79+ self.about.set_translator_credits(translator_credits)
80+ self.about.set_logo(logo)
81+
82+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
83+ self.about.set_icon(icon)
84+
85+ self.about.connect("response", lambda d, r: self.close())
86+
87+ self.about.show_all()
88+
89+ def close(self):
90+ self.about.destroy()
91+
92+
93+if __name__ == "__main__":
94+ #run the gui
95+ app = About()
96+ gtk.main()
97
98=== added file 'build/lib.linux-i686-2.6/spectlib/add_watch.py'
99--- build/lib.linux-i686-2.6/spectlib/add_watch.py 1970-01-01 00:00:00 +0000
100+++ build/lib.linux-i686-2.6/spectlib/add_watch.py 2012-03-14 09:03:18 +0000
101@@ -0,0 +1,278 @@
102+# -*- coding: utf-8 -*-
103+
104+# Specto , Unobtrusive event notifier
105+#
106+# add_watch.py
107+#
108+# See the AUTHORS file for copyright ownership information
109+
110+# This program is free software; you can redistribute it and/or
111+# modify it under the terms of the GNU General Public
112+# License as published by the Free Software Foundation; either
113+# version 2 of the License, or (at your option) any later version.
114+#
115+# This program is distributed in the hope that it will be useful,
116+# but WITHOUT ANY WARRANTY; without even the implied warranty of
117+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
118+# General Public License for more details.
119+#
120+# You should have received a copy of the GNU General Public
121+# License along with this program; if not, write to the
122+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
123+# Boston, MA 02111-1307, USA.
124+
125+import os
126+try:
127+ import pygtk
128+ pygtk.require("2.0")
129+except:
130+ pass
131+
132+try:
133+ import gtk
134+ import spectlib.gtkutil
135+except:
136+ pass
137+
138+
139+class Add_watch:
140+ """Class to create the add watch dialog."""
141+ # Please do not use confusing widget names such as 'lbl' and 'tbl',
142+ # Use full names like 'label' and 'table'.
143+ def __init__(self, specto, notifier, watch_type):
144+ self.specto = specto
145+ self.notifier = notifier
146+ #create tree
147+ uifile = os.path.join(self.specto.PATH, "uis/add_watch.ui")
148+ windowname = "add_watch"
149+ self.builder = gtk.Builder()
150+ self.builder.set_translation_domain("specto")
151+ self.builder.add_from_file(uifile)
152+
153+ self.watch_type = watch_type
154+ #save the option for hiding the table
155+ self.option_visible = -1
156+
157+ #catch some events
158+ dic = {"on_button_cancel_clicked": self.cancel_clicked,
159+ "on_button_add_clicked": self.add_clicked,
160+ "on_button_help_clicked": self.help_clicked,
161+ "on_add_watch_delete_event": self.delete_event,
162+ "check_command_toggled": self.command_toggled,
163+ "check_open_toggled": self.open_toggled,
164+ "on_refresh_unit_changed": self.set_refresh_values}
165+
166+ #attach the events
167+ self.builder.connect_signals(dic)
168+
169+ self.add_watch = self.builder.get_object("add_watch")
170+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
171+ self.add_watch.set_icon(icon)
172+ self.add_watch.set_resizable(False)
173+
174+ self.name = self.builder.get_object("name")
175+ self.refresh = self.builder.get_object("refresh")
176+ self.refresh_unit = self.builder.get_object("refresh_unit")
177+
178+ #create the gui
179+ self.plugins_ = {}
180+ self.watch_options = {}
181+
182+ self.set_options(watch_type)
183+
184+ #set the default values
185+ self.refresh_unit.set_active(2)
186+ self.refresh.set_value(1.0)
187+
188+ self.name.grab_focus()
189+
190+ def set_options(self, watch_type):
191+ """ Show the table with the right watch options. """
192+ self.watch_options[watch_type] = []
193+ if hasattr(self.specto.watch_db.plugin_dict[watch_type], 'get_add_gui_info'):
194+ values = self.specto.watch_db.plugin_dict[watch_type].get_add_gui_info()
195+ else:
196+ values = []
197+
198+ try:
199+ if self.specto.watch_db.plugin_dict[watch_type].dbus_watch == True:
200+ self.refresh.hide()
201+ self.refresh_unit.hide()
202+ self.builder.get_object("label_refresh1").hide()
203+ except:
204+ pass
205+
206+ #create the options gui
207+ if len(values) > 0:
208+ self.table = gtk.Table(rows=len(values), columns=1, homogeneous=False)
209+ self.table.set_row_spacings(6)
210+ self.table.set_col_spacings(6)
211+ self.watch_options[watch_type] = {}
212+
213+ i = 0
214+ for value, widget in values:
215+ table, _widget = widget.get_object()
216+ self.table.attach(table, 0, 1, i, i + 1)
217+ self.watch_options[watch_type].update({value: widget})
218+ i += 1
219+
220+ self.table.show()
221+ vbox = self.builder.get_object("vbox_watch_options")
222+ vbox.pack_start(self.table, False, False, 0)
223+
224+ def set_refresh_values(self, widget):
225+ """ Set the max and min values for the refresh unit. """
226+ digits = 0
227+ climb_rate = 1.0
228+ refresh_unit = self.refresh_unit.get_active()
229+ self.old_refresh_value = self.refresh.get_value_as_int() # Grab the current value for reuse after the scale changes
230+
231+ # Set the new ranges for the refresh value spinbutton
232+ if refresh_unit == 0 or refresh_unit == 1:
233+ adjustment = gtk.Adjustment(value=1, lower=1, upper=60, step_incr=1, page_incr=10, page_size=0)
234+ if refresh_unit == 2:
235+ adjustment = gtk.Adjustment(value=1, lower=1, upper=24, step_incr=1, page_incr=10, page_size=0)
236+ if refresh_unit == 3:
237+ adjustment = gtk.Adjustment(value=1, lower=1, upper=365, step_incr=1, page_incr=30, page_size=0)
238+
239+ self.refresh.configure(adjustment, climb_rate, digits)
240+ self.refresh.set_value(self.old_refresh_value) # Reuse the previous value, otherwise setting the new scales will reset it to 1
241+
242+ def add_clicked(self, widget):
243+ """
244+ Add the watch to the watches repository.
245+ """
246+ values = {}
247+ #get the standard options from a watch
248+ values['name'] = self.name.get_text()
249+
250+ #check if the watch is unique
251+ if self.specto.watch_io.is_unique_watch(values['name']):
252+ unique_dialog = Unique_Dialog(self.specto)
253+ result = unique_dialog.run()
254+
255+ if result ==1:
256+ self.name.grab_focus()
257+ else: #edit the existing watch
258+ self.add_watch.hide_all()
259+ name = values['name']
260+ self.notifier.show_edit_watch(-1, name)
261+
262+ else:
263+ values['refresh'] = self.specto.watch_db.set_interval(self.refresh.get_value_as_int(), self.refresh_unit.get_active())
264+ values['type'] = self.watch_type
265+ values['active'] = True
266+ values['last_changed'] = ""
267+ values['changed'] = False
268+ if self.builder.get_object("check_command").get_active() == True:
269+ values['command'] = self.builder.get_object("entry_changed_command").get_text()
270+
271+ if self.builder.get_object("check_open").get_active() == True:
272+ values['open_command'] = self.builder.get_object("entry_open_command").get_text()
273+ use_standard_command = False
274+ else:
275+ values['open_command'] = ""
276+ use_standard_command = True
277+
278+ if hasattr(self.specto.watch_db.plugin_dict[values['type']], 'get_add_gui_info'):
279+ gui_values = self.specto.watch_db.plugin_dict[values['type']].get_add_gui_info()
280+ window_options = self.watch_options[values['type']]
281+
282+ for key in window_options:
283+ values[key] = window_options[key].get_value()
284+ window_options[key].set_color(0xFFFF, 0xFFFF, 0xFFFF)
285+
286+ self.builder.get_object("name").modify_base(gtk.STATE_NORMAL, gtk.gdk.Color(0xFFFF, 0xFFFF, 0xFFFF))
287+
288+ try:
289+ id = self.specto.watch_db.create({0: values})[0] #write the options in the configuration file
290+ except AttributeError, error_fields:
291+ fields = str(error_fields).split(",")
292+ i = 1
293+ for field in fields:
294+ if field == " name":
295+ self.builder.get_object("name").modify_base(gtk.STATE_NORMAL, gtk.gdk.Color(65535, 0, 0))
296+ self.builder.get_object("name").grab_focus()
297+ else:
298+ field = window_options[field.strip()]
299+ if i == 1:
300+ field.grab_focus()
301+ i = 0
302+ field.set_color(65535, 0, 0)
303+ else:
304+ self.add_watch.destroy()
305+ if use_standard_command:
306+ try:
307+ self.specto.watch_db[id].open_command = self.specto.watch_db[id].standard_open_command
308+ except:
309+ self.specto.watch_db[id].open_command = ""
310+ #very simple dialog to display, there is no smtp server in the gconf and block any try to send mail
311+ if (self.specto.specto_gconf.get_entry("smtp_entry") == "") and ( values['mail'] != ""):
312+ boite = gtk.Dialog("Attention !", self.add_watch,
313+ gtk.DIALOG_MODAL,
314+ (gtk.STOCK_OK, gtk.RESPONSE_OK))
315+
316+ label2 = gtk.Label()
317+ label2.set_text("Veuillez renseigner les paramètres d'envoi d'email dans préférences \n L'envoi de mail n'est pas possible pour l'instant, les autres fonctionnalités fonctionnent normalement")
318+ boite.vbox.pack_start(label2, True, False, 0)
319+ boite.vbox.show_all()
320+ boite.run()
321+ boite.destroy()
322+
323+
324+ self.specto.watch_io.write_watch(values)
325+ self.notifier.add_notifier_entry(id)
326+ self.specto.watch_db[id].start()
327+
328+ def help_clicked(self, widget):
329+ """ Call the show help function. """
330+ self.specto.util.show_webpage("http://code.google.com/p/specto/wiki/AddingWatches")
331+
332+ def cancel_clicked(self, widget):
333+ """ Destroy the add watch window. """
334+ self.add_watch.destroy()
335+
336+ def delete_event(self, widget, event, data=None):
337+ """ Destroy the window. """
338+ self.add_watch.destroy()
339+ return True
340+
341+ def command_toggled(self, widget):
342+ sensitive = self.builder.get_object("check_command").get_active()
343+ self.builder.get_object("entry_changed_command").set_sensitive(sensitive)
344+
345+ def open_toggled(self, widget):
346+ sensitive = self.builder.get_object("check_open").get_active()
347+ self.builder.get_object("entry_open_command").set_sensitive(sensitive)
348+
349+
350+class Unique_Dialog:
351+ """
352+ Class to create a message when you add a watch with an existing name.
353+ """
354+
355+ def __init__(self, specto):
356+ self.specto = specto
357+ self.uifile = os.path.join(self.specto.PATH, "uis/dialog_add_watch.ui")
358+ self.dialogname = "dialog"
359+ self.builder = gtk.Builder()
360+ self.builder.set_translation_domain("specto")
361+ self.builder.add_from_file(self.uifile)
362+ self.unique_dialog = self.builder.get_object("dialog")
363+
364+ def run(self):
365+ """ Show the unique dialog. """
366+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
367+ self.unique_dialog.set_icon(icon)
368+ self.unique_dialog.set_resizable(False)
369+ result = self.unique_dialog.run()
370+
371+ self.unique_dialog.destroy()
372+
373+ return result
374+
375+
376+if __name__ == "__main__":
377+ #run the gui
378+ app = Add_watch()
379+ gtk.main()
380
381=== added file 'build/lib.linux-i686-2.6/spectlib/balloons.py'
382--- build/lib.linux-i686-2.6/spectlib/balloons.py 1970-01-01 00:00:00 +0000
383+++ build/lib.linux-i686-2.6/spectlib/balloons.py 2012-03-14 09:03:18 +0000
384@@ -0,0 +1,102 @@
385+# -*- coding: utf-8 -*-
386+
387+# Specto , Unobtrusive event notifier
388+#
389+# balloons.py
390+#
391+# See the AUTHORS file for copyright ownership information
392+
393+# This program is free software; you can redistribute it and/or
394+# modify it under the terms of the GNU General Public
395+# License as published by the Free Software Foundation; either
396+# version 2 of the License, or (at your option) any later version.
397+#
398+# This program is distributed in the hope that it will be useful,
399+# but WITHOUT ANY WARRANTY; without even the implied warranty of
400+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
401+# General Public License for more details.
402+#
403+# You should have received a copy of the GNU General Public
404+# License along with this program; if not, write to the
405+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
406+# Boston, MA 02111-1307, USA.
407+
408+import pygtk
409+pygtk.require('2.0')
410+import pynotify
411+import sys
412+import gtk
413+import spectlib.util
414+from time import sleep
415+
416+notifyInitialized = False
417+
418+
419+class NotificationToast:
420+ _notifyRealm = 'Specto'
421+ _Urgencies = {'low': pynotify.URGENCY_LOW,
422+ 'critical': pynotify.URGENCY_CRITICAL,
423+ 'normal': pynotify.URGENCY_NORMAL}
424+
425+ def __open_watch(self, n, action, id):
426+ if self.specto.notifier.open_watch(id):
427+ self.specto.notifier.mark_watch_as_read('', id)
428+
429+ def __init__(self, specto, notifier):
430+ global notifyInitialized
431+ self.specto = specto
432+ self.notifier = notifier
433+
434+ if not notifyInitialized:
435+ pynotify.init(self._notifyRealm)
436+ notifyInitialized = True
437+
438+ # Check the features available from the notification daemon
439+ self.capabilities = {'actions': False,
440+ 'body': False,
441+ 'body-hyperlinks': False,
442+ 'body-images': False,
443+ 'body-markup': False,
444+ 'icon-multi': False,
445+ 'icon-static': False,
446+ 'sound': False,
447+ 'image/svg+xml': False,
448+ 'append': False}
449+ caps = pynotify.get_server_caps()
450+ if caps is None:
451+ print "Failed to receive server caps."
452+ sys.exit(1)
453+ for cap in caps:
454+ self.capabilities[cap] = True
455+
456+ def show_toast(self, body, icon=None, urgency="low", summary=_notifyRealm, name=None):
457+ tray_x = 0
458+ tray_y = 0
459+
460+ if notifyInitialized:
461+ sleep(0.5) # FIXME: issue #43, associate the balloon with the notification icon properly. Currently, this is a hack to leave time for the tray icon to appear before getting its coordinates
462+ if self.notifier.tray:
463+ tray_x = self.notifier.tray.get_x()
464+ tray_y = self.notifier.tray.get_y()
465+ else:
466+ tray_x = 0
467+ tray_y = 0
468+ self.toast = pynotify.Notification(summary, body)
469+ if name:
470+ # If name is not None and exists in specto.watch_db, a button is added to the notification
471+ w = self.specto.watch_db.find_watch(name)
472+ if w != -1 and self.capabilities["actions"]: # Don't request action buttons if the notification daemon (ex: notify-osd) rejects them
473+ self.toast.add_action("clicked", gtk.stock_lookup(gtk.STOCK_JUMP_TO)[1].replace('_', ''), self.__open_watch, w)
474+ self.toast.set_urgency(self._Urgencies[urgency])
475+ if icon:
476+ #self.toast.set_property('icon-name', icon) # We now use a pixbuf in the line below to allow themable icons
477+ self.toast.set_icon_from_pixbuf(icon)
478+
479+ if tray_x != 0 and tray_y != 0: # grab the x and y position of the tray icon and make the balloon emerge from it
480+ self.toast.set_hint("x", tray_x)
481+ self.toast.set_hint("y", tray_y)
482+
483+ try:
484+ self.toast.show()
485+ except:
486+ self.specto.logger.log(_("Cannot display notification message. Make sure that libnotify and D-Bus are available on your system."), "error", self.specto)
487
488=== added file 'build/lib.linux-i686-2.6/spectlib/bdd.py'
489--- build/lib.linux-i686-2.6/spectlib/bdd.py 1970-01-01 00:00:00 +0000
490+++ build/lib.linux-i686-2.6/spectlib/bdd.py 2012-03-14 09:03:18 +0000
491@@ -0,0 +1,317 @@
492+# -*- coding: utf-8 -*-
493+
494+# Specto , Unobtrusive event notifier
495+#
496+# bdd.py
497+#
498+# See the AUTHORS file for copyright ownership information
499+
500+# This program is free software; you can redistribute it and/or
501+# modify it under the terms of the GNU General Public
502+# License as published by the Free Software Foundation; either
503+# version 2 of the License, or (at your option) any later version.
504+#
505+# This program is distributed in the hope that it will be useful,
506+# but WITHOUT ANY WARRANTY; without even the implied warranty of
507+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
508+# General Public License for more details.
509+#
510+# You should have received a copy of the GNU General Public
511+# License along with this program; if not, write to the
512+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
513+# Boston, MA 02111-1307, USA.
514+
515+from sqlalchemy import MetaData, create_engine, Column, Integer, String, Text, Boolean, Float, DateTime
516+from sqlalchemy.orm import scoped_session, sessionmaker, mapper, column_property
517+from sqlalchemy.schema import Table
518+import datetime
519+
520+class Group(object):
521+ """ This class represents the group information """
522+ def __init__(self, name="", description=""):
523+ self.name = name
524+ self.description = description
525+ self.listmail = []
526+
527+ def adduser(self, mail):
528+ self.listmail.append(mail)
529+
530+ def deluser(self, mail):
531+ pass
532+
533+ def getinfo(self):
534+ return [self.name, self.description]
535+
536+ def getmail(self):
537+ return self.listmail
538+
539+class Mail(object):
540+ """This class represents all the mail information"""
541+
542+ def __init__(self, name="", firstname="", mail="", group=""):
543+
544+ self.name = name
545+ self.firstname = firstname
546+ self.mail = mail
547+ self.group = group
548+
549+ def getinfo(self):
550+ return [self.name, self.firstname, self.mail, self.group]
551+
552+ def setinfo(self, name, firstname, mail, group):
553+ self.name = name
554+ self.firstname = firstname
555+ self.mail = mail
556+ self.group = group
557+
558+class List_rss(object):
559+ """ class to save alert in rss page """
560+ def __init__(self,title,link,description,page,pattern,mail,observateur):
561+ self.title = title
562+ self.link = link
563+ self.description = description
564+ self.page = page.decode('utf-8')
565+ self.pattern = pattern
566+ self.mail = mail
567+ self.obs = observateur
568+
569+
570+class List_html(object):
571+ """ class to save alert in html page """
572+ def __init__(self,txt,link,page,pattern,mail,observateur):
573+ self.txt = txt
574+ self.link = link
575+ self.page = page
576+ self.pattern = pattern
577+ self.mail = mail
578+ self.obs = observateur
579+
580+class Crawl(object):
581+ """ class to save already crawled webpage """
582+ def __init__(self,pid, curl, title):
583+ self.parentid = pid
584+ self.url = curl
585+ self.title = title
586+
587+#class Save_watch(object):
588+# pass
589+
590+class Cache(object):
591+ """ class to save capture of page """
592+ def __init__(self, name, page, size):
593+ self.name = name
594+ self.page = page
595+ self.size = size
596+
597+class Queue(object):
598+ """ class to get a queue to crawl """
599+ def __init__(self,parent,depth,url):
600+ self.parent = parent
601+ self.depth = depth
602+ self.url = url
603+
604+class Bdd( object ):
605+ """this is an sql handler"""
606+ def __init__(self,**datas):
607+ url = self.url(**datas)
608+ self.metadata = MetaData(url)
609+ self.table_contact = Table('contact', self.metadata,
610+ Column('id', Integer, primary_key=True),
611+ Column('name', String(40)),
612+ Column('firstname', String(40)),
613+ Column('mail', String(40)),
614+ Column('group', String(40)),
615+ )
616+ self.table_group = Table('groupe', self.metadata,
617+ Column('id_g', Integer, primary_key=True),
618+ Column('name', String(40)),
619+ Column('description', String(40)),
620+ )
621+ self.table_list_rss = Table('list_rss', self.metadata,
622+ Column('id', Integer, primary_key=True),
623+ Column('title', String(1000)),
624+ Column('link', Text),
625+ Column('description', Text),
626+ Column('page', Text),
627+ Column('pattern', Text),
628+ Column('mail', String(60)),
629+ Column('watch', String(40)),
630+ Column('date', DateTime(timezone=True), default=datetime.datetime.now())
631+ )
632+ self.table_list_html = Table('list_html', self.metadata,
633+ Column('id', Integer, primary_key=True),
634+ Column('txt', String(1000)),
635+ Column('link', Text),
636+ Column('page', Text),
637+ Column('pattern', Text),
638+ Column('mail', String(60)),
639+ Column('watch', String(40)),
640+ Column('date', DateTime(timezone=True), default=datetime.datetime.now())
641+ )
642+ """self.table_watch = Table('watch', self.metadata,
643+ Column('id', Integer, primary_key=True),
644+ Column('name', String(60)),
645+ Column('username', String(60)),
646+ Column('redirect', Boolean),
647+ Column('error_margin', Float),
648+ Column('pattern', Text),
649+ Column('open_command', Text),
650+ Column('changed', Boolean),
651+ Column('last_changed', Text),
652+ Column('refresh', Integer),
653+ Column('uri', Text),
654+ Column('command', Text),
655+ Column('mail', String(60)),
656+ Column('active', Boolean),
657+ Column('password', String(60)),
658+ Column('type', String(60)),
659+ Column('crawl', Boolean),
660+ Column('deep', Integer),
661+ )don't work"""
662+ """self.table_crawl = Table('crawl', self.metadata,
663+ Column('id', Integer, primary_key=True),
664+ Column('parent_id', Integer),
665+ Column('depth', Integer),
666+ Column('url', String(60)),
667+ Column('title', Text),
668+ Column('date', DateTime),
669+ Column('id_watch', Integer),
670+ Column('name_watch', String(60)),
671+ Column('page', Text),
672+ Column('size', Integer),
673+ ) for now don't work with this table but more intersting for future"""
674+ self.table_cache = Table('cache', self.metadata,
675+ Column('id', Integer, primary_key=True),
676+ Column('name', String(60)),
677+ Column('page', Text),
678+ Column('size', Integer),
679+ )
680+ self.table_crawl = Table('crawl', self.metadata,
681+ Column('id',Integer,primary_key=True),
682+ Column('parentid',Integer),
683+ Column('url',Text),
684+ Column('title',Text),
685+ Column('date', DateTime(timezone=True), default=datetime.datetime.now()),
686+ )
687+ self.table_queue = Table('queue', self.metadata,
688+ Column('id',Integer,primary_key=True),
689+ Column('parent',Integer),
690+ Column('depth',Integer),
691+ Column('url',Text),
692+ )
693+
694+ engine = create_engine(url)
695+ self.Session = scoped_session(sessionmaker(bind=engine,autoflush=True,autocommit=True))
696+ self.session = self.Session()
697+ #if table don't exist we create them
698+ try:
699+ if not engine.engine.has_table('contact'):
700+ engine.create(self.table_contact)
701+ if not engine.engine.has_table('groupe'):
702+ engine.create(self.table_group)
703+ if not engine.engine.has_table('list_rss'):
704+ engine.create(self.table_list_rss)
705+ if not engine.engine.has_table('list_html'):
706+ engine.create(self.table_list_html)
707+ if not engine.engine.has_table('watch'):
708+ engine.create(self.table_watch)
709+ if not engine.engine.has_table('cache'):
710+ engine.create(self.table_cache)
711+ if not engine.engine.has_table('crawl'):
712+ engine.create(self.table_crawl)
713+ if not engine.engine.has_table('queue'):
714+ engine.create(self.table_queue)
715+ except Exception, err:
716+ print err
717+ #Map class with table
718+ contact_mapper = mapper(Mail,self.table_contact)
719+ group_mapper = mapper(Group,self.table_group)
720+ list_rss_mapper = mapper(List_rss,self.table_list_rss)
721+ list_html_mapper = mapper(List_html,self.table_list_html)
722+ #list_watch_mapper = mapper(Save_watch,self.table_watch)
723+ cache_mapper = mapper(Cache,self.table_cache)
724+ crawl_mapper = mapper(Crawl,self.table_crawl)
725+ queue_mapper = mapper(Queue,self.table_queue)
726+
727+ def url( self, **datas):
728+ if datas["type"]=="sqlite":
729+ return "%(type)s:///%(directory)s"%datas
730+ else:
731+ return "%(type)s://%(user)s:%(pass)s@%(host)s:%(port)s/%(name)s"%datas
732+
733+ def getAll(self,obj):
734+ return self.session.query(obj).all()
735+
736+ def get(self, obj, name):
737+ try:
738+ return self.session.query(obj).filter(getattr(Cache,"name") == "%s"%name).one()
739+ except Exception, err:
740+ print err
741+ return 'True'
742+
743+ def getlink(self, obj, name):
744+ try:
745+ return self.session.query(obj).filter(getattr(Queue,"url") == "%s"%name).one()
746+ except:
747+ return 'True'
748+
749+ def getqueue(self, obj):
750+ try:
751+ return self.session.query(obj).first()
752+ except Exception, err:
753+ print err
754+ return 'False'
755+
756+ def add(self, obj):
757+ """ Add a row in the table matching with object type """
758+ try:
759+ self.session.begin(subtransactions=True)
760+ self.session.add(obj)
761+ self.session.flush()
762+ self.session.commit()
763+ except Exception,err:
764+ self.session.rollback()
765+ print err
766+ finally:
767+ try:
768+ pass
769+ #self.session.close()
770+ except:
771+ pass
772+
773+ def delete(self,obj):
774+ """ delete the row in table matching with object """
775+ try:
776+ self.session.begin(subtransactions=True)
777+ self.session.delete(obj)
778+ self.session.flush()
779+ self.session.commit()
780+ #self.session.close()
781+ except Exception, err:
782+ #print "probleme suppression"
783+ print err
784+
785+ def updatecontact(self,obj,newname):
786+ self.session.begin(subtransactions=True)
787+ for c in self.session.query(type(obj)):
788+ if c.group == obj.group:
789+ c.group = newname
790+ self.session.flush()
791+ self.session.commit()
792+
793+ def updatepage(self, obj, new):
794+ self.session.begin(subtransactions=True)
795+ for c in self.session.query(type(obj)):
796+ if c.page == obj.page:
797+ c.page = new
798+ self.session.flush()
799+ self.session.commit()
800+
801+ def update(self,obj,column,new):
802+ self.session.begin(subtransactions=True)
803+ for c in self.session.query(type(obj)):
804+ if c.column == obj.column:
805+ c.column = new
806+ self.session.flush()
807+ self.session.commit()
808+#can be in the same method but i didn't find the correct syntax
809
810=== added file 'build/lib.linux-i686-2.6/spectlib/config.py'
811--- build/lib.linux-i686-2.6/spectlib/config.py 1970-01-01 00:00:00 +0000
812+++ build/lib.linux-i686-2.6/spectlib/config.py 2012-03-14 09:03:18 +0000
813@@ -0,0 +1,104 @@
814+# -*- coding: utf-8 -*-
815+
816+# Specto , Unobtrusive event notifier
817+#
818+# config.py
819+#
820+# See the AUTHORS file for copyright ownership information
821+
822+# This program is free software; you can redistribute it and/or
823+# modify it under the terms of the GNU General Public
824+# License as published by the Free Software Foundation; either
825+# version 2 of the License, or (at your option) any later version.
826+#
827+# This program is distributed in the hope that it will be useful,
828+# but WITHOUT ANY WARRANTY; without even the implied warranty of
829+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
830+# General Public License for more details.
831+#
832+# You should have received a copy of the GNU General Public
833+# License along with this program; if not, write to the
834+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
835+# Boston, MA 02111-1307, USA.
836+
837+class Integer():
838+ """A config node containing a integer value.
839+ Supports restricting the valid values to a range.
840+ """
841+
842+ def __init__(self, mandatory, low=None, high=None):
843+ self.mandatory = mandatory
844+ self.low = low
845+ self.high = high
846+
847+ def checkRestrictions(self, value):
848+ try:
849+ val = int(value)
850+ except ValueError:
851+ return False, -1
852+ return True, val
853+
854+ def getStandardValue(self):
855+ return -1
856+
857+
858+class String():
859+ """A config node containing a string value."""
860+
861+ def __init__(self, mandatory):
862+ self.mandatory = mandatory
863+
864+ def checkRestrictions(self, value):
865+ try:
866+ val = str(value)
867+ except ValueError:
868+ return False
869+ return True, val
870+
871+ def getStandardValue(self):
872+ return ""
873+
874+
875+class Dec():
876+ """
877+ A config node containing a decimal value.
878+ """
879+
880+ def __init__(self, mandatory):
881+ self.mandatory = mandatory
882+
883+ def checkRestrictions(self, value):
884+ try:
885+ val = float(value)
886+ except ValueError:
887+ return False
888+ return True, val
889+
890+ def getStandardValue(self):
891+ return -1
892+
893+
894+class Boolean():
895+ """
896+ A config node containing a boolean value.
897+ """
898+
899+ def __init__(self, mandatory):
900+ self.mandatory = mandatory
901+
902+ def checkRestrictions(self, value):
903+ valid = False
904+ if value == "True" or value == 1 or value == True:
905+ val = True
906+ valid = True
907+ if value == "False" or value == 0 or value == False:
908+ val = False
909+ valid = True
910+
911+ if valid == False:
912+ return False, ""
913+ else:
914+ return True, val
915+
916+ def getStandardValue(self):
917+ return False
918
919=== added file 'build/lib.linux-i686-2.6/spectlib/console.py'
920--- build/lib.linux-i686-2.6/spectlib/console.py 1970-01-01 00:00:00 +0000
921+++ build/lib.linux-i686-2.6/spectlib/console.py 2012-03-14 09:03:18 +0000
922@@ -0,0 +1,54 @@
923+# -*- coding: utf-8 -*-
924+
925+# Specto , Unobtrusive event notifier
926+#
927+# notifier.py
928+#
929+# See the AUTHORS file for copyright ownership information
930+
931+# This program is free software; you can redistribute it and/or
932+# modify it under the terms of the GNU General Public
933+# License as published by the Free Software Foundation; either
934+# version 2 of the License, or (at your option) any later version.
935+#
936+# This program is distributed in the hope that it will be useful,
937+# but WITHOUT ANY WARRANTY; without even the implied warranty of
938+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
939+# General Public License for more details.
940+#
941+# You should have received a copy of the GNU General Public
942+# License along with this program; if not, write to the
943+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
944+# Boston, MA 02111-1307, USA.
945+
946+
947+class Console:
948+
949+ def __init__(self, specto, args):
950+ self.specto = specto
951+ self.only_changed = False
952+
953+ if args:
954+ if args == "--only-changed":
955+ self.only_changed = True
956+
957+ def start_watches(self):
958+ self.specto.watch_db.restart_all_watches()
959+
960+ def mark_watch_status(self, status, id):
961+ """ show the right icon for the status from the watch. """
962+ watch = self.specto.watch_db[id]
963+
964+ if status == "changed":
965+ print watch.name, "-", _("Watch has changed.")
966+ print watch.get_extra_information()
967+ elif self.only_changed:
968+ return
969+ elif status == "checking":
970+ print watch.name, "-", _("Watch started checking.")
971+ elif status == "idle":
972+ print watch.name, "-", _("Watch is idle.")
973+ elif status == "no-network":
974+ print _("No network connection detected")
975+ elif status == "error":
976+ print watch.name, "-", _("There was an error checking the watch")
977
978=== added file 'build/lib.linux-i686-2.6/spectlib/constants.py'
979--- build/lib.linux-i686-2.6/spectlib/constants.py 1970-01-01 00:00:00 +0000
980+++ build/lib.linux-i686-2.6/spectlib/constants.py 2012-03-14 09:03:18 +0000
981@@ -0,0 +1,7 @@
982+# -*- coding: utf-8 -*-
983+
984+# The Specto version
985+VERSION = "0.3.1"
986+
987+# The prefix were Specto is installed to.
988+PREFIX = "/usr/local"
989
990=== added file 'build/lib.linux-i686-2.6/spectlib/contact.py'
991--- build/lib.linux-i686-2.6/spectlib/contact.py 1970-01-01 00:00:00 +0000
992+++ build/lib.linux-i686-2.6/spectlib/contact.py 2012-03-14 09:03:18 +0000
993@@ -0,0 +1,330 @@
994+# -*- coding: utf-8 -*-
995+
996+# Specto , Unobtrusive event notifier
997+#
998+# contact.py
999+#
1000+# See the AUTHORS file for copyright ownership information
1001+
1002+# This program is free software; you can redistribute it and/or
1003+# modify it under the terms of the GNU General Public
1004+# License as published by the Free Software Foundation; either
1005+# version 2 of the License, or (at your option) any later version.
1006+#
1007+# This program is distributed in the hope that it will be useful,
1008+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1009+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1010+# General Public License for more details.
1011+#
1012+# You should have received a copy of the GNU General Public
1013+# License along with this program; if not, write to the
1014+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1015+# Boston, MA 02111-1307, USA.
1016+
1017+import os
1018+import gobject
1019+from spectlib.bdd import Group, Mail
1020+try:
1021+ import pygtk
1022+ pygtk.require("2.0")
1023+except:
1024+ pass
1025+
1026+try:
1027+ import gtk
1028+except:
1029+ pass
1030+
1031+
1032+class Contact:
1033+ """ Display the contact window. """
1034+ def __init__(self, specto, notifier):
1035+
1036+ self.specto = specto
1037+ self.notifier = notifier
1038+ self.base = self.specto.base
1039+
1040+ uifile = os.path.join(self.specto.PATH, "uis/contact.ui")
1041+ windowname = "contact"
1042+ self.builder = gtk.Builder()
1043+ self.builder.set_translation_domain("specto")
1044+ self.builder.add_from_file(uifile)
1045+
1046+ #catch some events
1047+ dic = {"on_add_contact_clicked": self.add_contact_clicked,
1048+ "on_add_group_clicked": self.add_group_clicked,
1049+ "on_modify_button_clicked": self.modify_button_clicked,
1050+ "on_delete_button_clicked": self.delete_button_clicked,
1051+ "on_contact_view_button_press_event": self.contact_view_button_press_event}
1052+
1053+ #attach the events
1054+ self.builder.connect_signals(dic)
1055+ self.contact = self.builder.get_object("contact")
1056+ self.contact.set_size_request(500,300)
1057+
1058+ self.groupes = gtk.TreeViewColumn()
1059+ self.groupes.set_title("Groups")
1060+
1061+ self.cell = gtk.CellRendererText()
1062+ self.groupes.pack_start(self.cell, True)
1063+ self.groupes.add_attribute(self.cell, "text", 0)
1064+ #Get the treeView from the widget Tree
1065+ self.contactview = self.builder.get_object("contact_view")
1066+ self.contactview.props.has_tooltip = True
1067+ self.contactview.connect("query-tooltip", self.query_tooltip_tree_view_cb)
1068+ self.contactview.get_selection().connect("changed",
1069+ self.selection_changed_cb, self.contactview)
1070+
1071+ self.liststore1 = gtk.TreeStore(str, gobject.TYPE_PYOBJECT)
1072+ self.contactview.append_column(self.groupes)
1073+ self.contactview.set_model(self.liststore1)
1074+ self.gettree()
1075+
1076+ def add_group_clicked(self, widget):
1077+ """Called when the use wants to add a group"""
1078+ #Create the dialog, show it, and store the results
1079+ groupDlg = Group_Dialog(self.specto)
1080+ result,newgroup = groupDlg.run()
1081+ self.already_exist = 0
1082+ if (result == gtk.RESPONSE_OK):
1083+ it = self.liststore1.append(None, [newgroup.name, newgroup])
1084+ self.base.add(newgroup)
1085+
1086+ def add_contact_clicked(self, widget):
1087+ """ Open contact dialog """
1088+ #Create the dialog, show it, and store the results
1089+ contactDlg = Contact_Dialog(self.specto, self.liststore1)
1090+ result,self.newuser = contactDlg.run()
1091+ if (result == gtk.RESPONSE_OK):
1092+ self.liststore1.foreach(self.add, self.newuser)
1093+ self.base.add(self.newuser)
1094+
1095+ def add(self, model, path, iter, user):
1096+ """ add a user """
1097+ value = model.get(iter, 1)
1098+ if value[0].name == user.group:#FIXME specto got trouble when a group got same name with a mail
1099+ model.append(iter, [(user.name+" "+user.firstname), user])
1100+
1101+ def modify_button_clicked(self, widget):
1102+ """ Open contact dialog for modify"""
1103+ #récupère les valeurs de l'élement selectionné
1104+ try:
1105+ model, iter = self.contactview.get_selection().get_selected()
1106+ value = model.get(iter, 1)
1107+ except:
1108+ quit
1109+
1110+ if isinstance(value[0], Group):
1111+ groupDlg = Group_Dialog(self.specto)
1112+ groupDlg.setvalue(value[0].name, value[0].description)
1113+ result,self.newgroup = groupDlg.run()
1114+ if (result == gtk.RESPONSE_OK):
1115+ dest = model.append(None,[self.newgroup.name, self.newgroup])
1116+ if value[0].name != self.newgroup.name:
1117+ nb = model.iter_n_children(iter)
1118+ n = 0
1119+ while n < nb:
1120+ it = model.iter_children(iter)
1121+ valeurs1 = model.get(it, 1)[0]
1122+ valeurs0 = model.get(it, 0)[0]
1123+ model.remove(it)
1124+ #self.base.delete(valeurs1)
1125+ model.append(dest, [valeurs0, valeurs1])
1126+ #self.base.add(Mail(valeurs1.name, valeurs1.firstname, valeurs1.mail, self.newgroup.name))
1127+ #self.base.update(valeurs1,"contact",self.newgroup.name)
1128+ self.base.updatecontact(valeurs1,self.newgroup.name)
1129+ n = n + 1
1130+ model.remove(iter)
1131+ self.base.delete(value[0])
1132+ self.base.add(self.newgroup)
1133+ else:
1134+ nb = model.iter_n_children(iter)
1135+ n = 0
1136+ while n < nb:
1137+ it = model.iter_children(iter)
1138+ valeurs1 = model.get(it, 1)[0]
1139+ valeurs0 = model.get(it, 0)[0]
1140+ model.remove(it)
1141+ model.append(dest, [valeurs0, valeurs1])
1142+ n = n + 1
1143+ model.remove(iter)
1144+ self.base.delete(value[0])
1145+ self.base.add(self.newgroup)
1146+ #model.set_value(iter, 0, [self.newgroup.name, self.newgroup][0])
1147+
1148+ if isinstance(value[0], Mail):
1149+ contactDlg = Contact_Dialog(self.specto, self.liststore1)
1150+ contactDlg.setvalue(value[0].name, value[0].firstname, value[0].mail)
1151+ result,self.newuser = contactDlg.run()
1152+ if (result == gtk.RESPONSE_OK):
1153+ model.remove(iter)
1154+ self.base.delete(value[0])
1155+ self.base.add(self.newuser)
1156+ self.liststore1.foreach(self.add, self.newuser)
1157+
1158+ def delete_button_clicked(self, widget):
1159+ """ delete item selected """
1160+ try:
1161+ model, iter = self.contactview.get_selection().get_selected()
1162+ value = model.get(iter, 1)
1163+ if isinstance(value[0], Group):
1164+ nb = model.iter_n_children(iter)
1165+ n = 0
1166+ while n < nb:
1167+ it = model.iter_children(iter)
1168+ valeurs1 = model.get(it, 1)[0]
1169+ valeurs0 = model.get(it, 0)[0]
1170+ model.remove(it)
1171+ self.base.delete(valeurs1)
1172+ n = n + 1
1173+ model.remove(iter)
1174+ self.base.delete(value[0])
1175+ else:
1176+ self.base.delete(value[0])
1177+ model.remove(iter)
1178+ except:
1179+ pass
1180+
1181+ def query_tooltip_tree_view_cb(self, widget, x, y, keyboard_tip, tooltip):
1182+ """ show tooltip """
1183+ if not widget.get_tooltip_context(x, y, keyboard_tip):
1184+ return False
1185+ else:
1186+ model, path, iter = widget.get_tooltip_context(x, y, keyboard_tip)
1187+ value = model.get(iter, 1)
1188+ if isinstance(value[0], Group):
1189+ tooltip.set_markup("%s" %(value[0].description))
1190+ else:
1191+ tooltip.set_markup("%s" %(value[0].mail))
1192+ widget.set_tooltip_row(tooltip, path)
1193+ return True
1194+
1195+ def selection_changed_cb(self, selection, tree_view):
1196+ tree_view.trigger_tooltip_query()
1197+
1198+ def contact_view_button_press_event(self, treeview, event):
1199+ """clic sur un element"""
1200+ if event.button == 3:
1201+ x = int(event.x)
1202+ y = int(event.y)
1203+ pthinfo = treeview.get_path_at_pos(x, y)
1204+ if pthinfo != None:
1205+ path, col, cellx, celly = pthinfo
1206+ treeview.grab_focus()
1207+ treeview.set_cursor( path, col, 0)
1208+ model = treeview.get_model()
1209+ iter = model.get_iter(path)
1210+ #Je récupère la troisième valeur
1211+ content = model[iter][0]
1212+
1213+ def gettree(self):
1214+ listg = self.base.getAll(Group)
1215+ listm = self.base.getAll(Mail)
1216+ for group in listg:
1217+ it = self.liststore1.append(None, [group.name, group])
1218+
1219+ for mail in listm:
1220+ self.liststore1.foreach(self.add, mail)
1221+
1222+class Group_Dialog:
1223+ """ This class is used to show Group dialog """
1224+
1225+ def __init__(self, specto):
1226+
1227+ self.specto = specto
1228+ uifile = os.path.join(self.specto.PATH, "uis/group_contact_dialog.ui")
1229+ windowname = "group_dialog"
1230+ self.builder = gtk.Builder()
1231+ self.builder.set_translation_domain("specto")
1232+ self.builder.add_from_file(uifile)
1233+
1234+ def run(self):
1235+ self.group_dlg = self.builder.get_object("group_dialog")
1236+ self.result = self.group_dlg.run()
1237+ self.getparam()
1238+ self.group_dlg.destroy()
1239+ return self.result,self.group
1240+
1241+ def getparam(self):
1242+ self.name = self.builder.get_object("groupname_entry")
1243+ self.n = self.name.get_text()
1244+ self.description = self.builder.get_object("description_entry")
1245+ self.d = self.description.get_text()
1246+ self.group = Group(self.n,self.d)
1247+
1248+ def setvalue(self, name, description):
1249+ self.name = self.builder.get_object("groupname_entry")
1250+ self.name.set_text(name)
1251+ self.description = self.builder.get_object("description_entry")
1252+ self.description.set_text(description)
1253+
1254+class Contact_Dialog:
1255+ """ This class is used to show Contact dialog """
1256+
1257+ def __init__(self, specto, model):
1258+
1259+ self.specto = specto
1260+ self.model = model
1261+ uifile = os.path.join(self.specto.PATH, "uis/contact_dialog.ui")
1262+ windowname = "contact_dialog"
1263+ self.builder = gtk.Builder()
1264+ self.builder.set_translation_domain("specto")
1265+ self.builder.add_from_file(uifile)
1266+ #catch some events
1267+ dic = {"on_combo_changed": self.combo_changed}
1268+ #attach the events
1269+ self.builder.connect_signals(dic)
1270+
1271+ def run(self):
1272+ self.setparam()
1273+ self.contact_dlg = self.builder.get_object("contact_dialog")
1274+ self.result = self.contact_dlg.run()
1275+ self.getparam()
1276+ self.contact_dlg.destroy()
1277+ return self.result,self.email
1278+
1279+ def combo_changed(self, widget):
1280+ model = self.group.get_model()
1281+ index = self.group.get_active()
1282+ if index:
1283+ self.groupname = model[index][0]
1284+ else:
1285+ self.groupname = "pas recu"
1286+
1287+ def getparam(self):
1288+ self.name = self.builder.get_object("name_entry")
1289+ self.n = self.name.get_text()
1290+ self.firstname = self.builder.get_object("firstname_entry")
1291+ self.f = self.firstname.get_text()
1292+ self.mail = self.builder.get_object("mail_entry")
1293+ self.m = self.mail.get_text()
1294+ self.email = Mail(self.n,self.f,self.m,self.groupname)
1295+
1296+ def setparam(self):
1297+ self.group = self.builder.get_object("combo")
1298+ self.liststore1 = gtk.ListStore(str)
1299+ self.case = gtk.CellRendererText()
1300+ self.group.pack_start(self.case, True)
1301+ self.group.add_attribute(self.case, 'text', 0)
1302+ self.liststore1.append(['Vous pouvez choisir un groupe:'])
1303+ self.model.foreach(self.addcombo)
1304+ self.group.set_model(self.liststore1)
1305+ self.group.set_active(0)
1306+
1307+ def setvalue(self, name, firstname, mail):
1308+ self.name = self.builder.get_object("name_entry")
1309+ self.name.set_text(name)
1310+ self.firstname = self.builder.get_object("firstname_entry")
1311+ self.firstname.set_text(firstname)
1312+ self.mail = self.builder.get_object("mail_entry")
1313+ self.mail.set_text(mail)
1314+
1315+ def addcombo(self, model, path, iter):
1316+ value = model.get(iter, 1)
1317+ if isinstance(value[0], Group):
1318+ self.liststore1.append([value[0].name])
1319+
1320+if __name__ == "__main__":
1321+ #run the gui
1322+ app = Contact()
1323+ gtk.main()
1324
1325=== added file 'build/lib.linux-i686-2.6/spectlib/crawl.py'
1326--- build/lib.linux-i686-2.6/spectlib/crawl.py 1970-01-01 00:00:00 +0000
1327+++ build/lib.linux-i686-2.6/spectlib/crawl.py 2012-03-14 09:03:18 +0000
1328@@ -0,0 +1,149 @@
1329+# -*- coding: utf-8 -*-
1330+
1331+# Specto , Unobtrusive event notifier
1332+#
1333+# crawl.py
1334+#
1335+# See the AUTHORS file for copyright ownership information
1336+
1337+# This program is free software; you can redistribute it and/or
1338+# modify it under the terms of the GNU General Public
1339+# License as published by the Free Software Foundation; either
1340+# version 2 of the License, or (at your option) any later version.
1341+#
1342+# This program is distributed in the hope that it will be useful,
1343+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1344+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1345+# General Public License for more details.
1346+#
1347+# You should have received a copy of the GNU General Public
1348+# License along with this program; if not, write to the
1349+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1350+# Boston, MA 02111-1307, USA.
1351+
1352+import urllib2
1353+##import lxml.html
1354+from spectlib.bdd import Bdd, Crawl, Queue
1355+import robotparser
1356+import threading
1357+import urlparse
1358+import sys, re
1359+import time
1360+
1361+class Crawler(threading.Thread):
1362+ """ class to crawl webpage """
1363+ def __init__(self, depth, domain, base, starturl):
1364+ threading.Thread.__init__(self)
1365+ self.rp = robotparser.RobotFileParser()
1366+ self.crawled = []
1367+ self.base = base
1368+ #add url to the queue
1369+ try:
1370+ self.base.add(Queue(0, 0, starturl))
1371+ except Exception,err:
1372+ print err
1373+ self.crawldepth = depth
1374+ self.domain = domain
1375+ def run(self):
1376+ while 1:
1377+ try:
1378+ # Get the first item from the queue
1379+ crawling = self.base.getqueue(Queue)
1380+
1381+ # if theres nothing in the que, then set the status to done and exit
1382+ # Remove the item from the queue
1383+ if crawling:
1384+ try:
1385+ self.base.delete(crawling)
1386+ except Exception,err:
1387+ print err
1388+ else:
1389+ return
1390+ except Exception, err:
1391+ print err
1392+
1393+ # Crawl the link
1394+ self.crawl(crawling)
1395+
1396+ def crawl(self, obj):
1397+ print "Crawling.........."
1398+ cid = obj.id
1399+ # parent id. 0 if start url
1400+ pid = obj.parent
1401+ # current depth
1402+ curdepth = obj.depth
1403+ # crawling url
1404+ curl = obj.url
1405+ # Split the link into its sections
1406+ url = urlparse.urlparse(curl)
1407+
1408+ try:
1409+ # Have our robot parser grab the robots.txt file and read it
1410+ self.rp.set_url('http://' + url[1] + '/robots.txt')
1411+ self.rp.read()
1412+
1413+ # If we're not allowed to open a url, return the function to skip it
1414+ if not self.rp.can_fetch('specto', curl):
1415+ print curl + " not allowed by robots.txt"
1416+ return
1417+ except:
1418+ pass
1419+
1420+ try:
1421+ # Add the link to the already crawled list
1422+ self.crawled.append(curl)
1423+ except MemoryError:
1424+ # If the crawled array is too big, deleted it and start over
1425+ del self.crawled[:]
1426+ try:
1427+ request = urllib2.Request(curl)
1428+ request.add_header("User-Agent", "specto")
1429+ opener = urllib2.build_opener()
1430+ msg = opener.open(request).read()
1431+ except:
1432+ return
1433+
1434+ # Find what's between the title tags
1435+ title = ""
1436+ startPos = msg.find('<title>')
1437+ if startPos != -1:
1438+ endPos = msg.find('</title>', startPos+7)
1439+ if endPos != -1:
1440+ title = msg[startPos+7:endPos]
1441+
1442+ #with lxml library, find all link in a page
1443+ if curdepth < self.crawldepth:
1444+ html = urllib2.urlopen(curl).read()
1445+ etree = lxml.html.fromstring(html)
1446+ for href in etree.xpath("//a/@href"):
1447+ row = self.base.getlink(Queue, href) #check if link don't exist already
1448+ if row != 'True':
1449+ continue
1450+ if not href.startswith("http://"):
1451+ if href.startswith('/'):
1452+ href = 'http://' + url[1] + href #complete the url
1453+ elif href.startswith('#'):
1454+ continue
1455+ elif not href.startswith('http'):
1456+ href = urlparse.urljoin(url.geturl(),href)
1457+ print href #to debug
1458+ if href not in self.crawled: #.decode('utf-8')
1459+ if self.domain == True and re.search("http://"+url[1],href):#check if url is in domain
1460+ try:
1461+ self.base.add(Queue(pid, curdepth+1, href))
1462+ except Exception, err:
1463+ print err
1464+ continue
1465+ else:
1466+ try:
1467+ self.base.add(Queue(pid, curdepth+1, href))
1468+ except Exception, err:
1469+ print err
1470+ continue
1471+ try:
1472+ # Put now crawled link into the db
1473+ self.base.add(Crawl(pid, curl, title))
1474+ except Exception, err:
1475+ print err
1476+ else:
1477+ pass
1478
1479=== added file 'build/lib.linux-i686-2.6/spectlib/edit_watch.py'
1480--- build/lib.linux-i686-2.6/spectlib/edit_watch.py 1970-01-01 00:00:00 +0000
1481+++ build/lib.linux-i686-2.6/spectlib/edit_watch.py 2012-03-14 09:03:18 +0000
1482@@ -0,0 +1,316 @@
1483+# -*- coding: utf-8 -*-
1484+
1485+# Specto , Unobtrusive event notifier
1486+#
1487+# add_watch.py
1488+#
1489+# See the AUTHORS file for copyright ownership information
1490+
1491+# This program is free software; you can redistribute it and/or
1492+# modify it under the terms of the GNU General Public
1493+# License as published by the Free Software Foundation; either
1494+# version 2 of the License, or (at your option) any later version.
1495+#
1496+# This program is distributed in the hope that it will be useful,
1497+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1498+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1499+# General Public License for more details.
1500+#
1501+# You should have received a copy of the GNU General Public
1502+# License along with this program; if not, write to the
1503+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1504+# Boston, MA 02111-1307, USA.
1505+
1506+import os
1507+try:
1508+ import pygtk
1509+ pygtk.require("2.0")
1510+except:
1511+ pass
1512+
1513+try:
1514+ import gtk
1515+ import spectlib.gtkconfig
1516+except:
1517+ pass
1518+
1519+
1520+class Edit_watch:
1521+ """Class to create the edit watch dialog."""
1522+ # Please do not use confusing widget names such as 'lbl' and 'tbl',
1523+ # use full names like 'label' and 'table'.
1524+ def __init__(self, specto, notifier, id):
1525+ self.specto = specto
1526+ self.notifier = notifier
1527+ self.watch = self.specto.watch_db[id]
1528+ # Create the tree
1529+ uifile = os.path.join(self.specto.PATH, "uis/edit_watch.ui")
1530+ windowname = "edit_watch"
1531+ self.builder = gtk.Builder()
1532+ self.builder.set_translation_domain("specto")
1533+ self.builder.add_from_file(uifile)
1534+
1535+ # Catch some events
1536+ dic = {"on_button_cancel_clicked": self.cancel_clicked,
1537+ "on_button_save_clicked": self.save_clicked,
1538+ "on_button_remove_clicked": self.remove_clicked,
1539+ #"on_button_clear_clicked": self.clear_clicked, # clear error_log textfield
1540+ "on_button_save_as_clicked": self.save_as_clicked, # save error_log text
1541+ "on_edit_watch_delete_event": self.delete_event,
1542+ "check_command_toggled": self.command_toggled,
1543+ "check_open_toggled": self.open_toggled,
1544+ "on_refresh_unit_changed": self.set_refresh_values}
1545+
1546+ # Attach the events
1547+ self.builder.connect_signals(dic)
1548+
1549+ # Set the info from the watch
1550+ self.edit_watch = self.builder.get_object("edit_watch")
1551+ self.edit_watch.set_title(_("Edit watch: ") + self.watch.name)
1552+ self.builder.get_object("name").set_text(self.watch.name)
1553+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
1554+ self.edit_watch.set_icon(icon)
1555+ self.edit_watch.set_resizable(False)
1556+
1557+ refresh, refresh_unit = self.specto.watch_db.get_interval(self.watch.refresh)
1558+ self.builder.get_object("refresh_unit").set_active(refresh_unit)
1559+ self.builder.get_object("refresh").set_value(refresh)
1560+
1561+ # Create the gui
1562+ self.watch_options = {}
1563+ self.create_edit_gui()
1564+
1565+ if not self.specto.DEBUG:
1566+ self.builder.get_object("notebook1").remove_page(2)
1567+ else:
1568+ if self.builder.get_object("notebook1").get_n_pages() == 3:
1569+ # Put the logfile in the textview
1570+ log_text = self.specto.logger.watch_log(self.watch.name)
1571+ self.log_buffer = self.builder.get_object("error_log").get_buffer()
1572+ self.log_buffer.create_tag("ERROR", foreground="#a40000")
1573+ self.log_buffer.create_tag("INFO", foreground="#4e9a06")
1574+ self.log_buffer.create_tag("WARNING", foreground="#c4a000")
1575+ iter = self.log_buffer.get_iter_at_offset(0)
1576+ for line in log_text:
1577+ self.log_buffer.insert_with_tags_by_name(iter, line[1], line[0])
1578+
1579+ def cancel_clicked(self, widget):
1580+ """ Destroy the edit watch dialog. """
1581+ self.edit_watch.destroy()
1582+
1583+ def set_refresh_values(self, widget):
1584+ """ Set the max and min values for the refresh unit. """
1585+ digits = 0
1586+ climb_rate = 1.0
1587+ refresh_unit = self.builder.get_object("refresh_unit").get_active()
1588+
1589+ if refresh_unit == 0 or refresh_unit == 1:
1590+ adjustment = gtk.Adjustment(value=1, lower=1, upper=60, step_incr=1, page_incr=10, page_size=0)
1591+ if refresh_unit == 2:
1592+ adjustment = gtk.Adjustment(value=1, lower=1, upper=24, step_incr=1, page_incr=10, page_size=0)
1593+ if refresh_unit == 3:
1594+ adjustment = gtk.Adjustment(value=1, lower=1, upper=365, step_incr=1, page_incr=30, page_size=0)
1595+
1596+ self.builder.get_object("refresh").configure(adjustment, climb_rate, digits)
1597+
1598+ def save_clicked(self, widget):
1599+ """ Save the new options from the edited watch. """
1600+ values = {}
1601+ #get the standard options from a watch
1602+ values['name'] = self.builder.get_object("name").get_text()#FIXME: cfgparse cannot have single quotes (') it seems. We must watch out for the watch name or arguments not to have them.
1603+
1604+ values['type'] = self.watch.type
1605+ refresh_value = self.builder.get_object("refresh").get_value_as_int()
1606+ refresh_unit = self.builder.get_object("refresh_unit").get_active()
1607+ values['refresh'] = self.specto.watch_db.set_interval(refresh_value, refresh_unit)
1608+ values['active'] = self.watch.active
1609+ values['last_changed'] = self.watch.last_changed
1610+
1611+ if self.builder.get_object("check_command").get_active() == True:
1612+ values['command'] = self.builder.get_object("entry_changed_command").get_text()
1613+
1614+ if self.builder.get_object("check_open").get_active() == True:
1615+ values['open_command'] = self.builder.get_object("entry_open_command").get_text()
1616+ else:
1617+ values['open_command'] = ""
1618+
1619+ if hasattr(self.specto.watch_db.plugin_dict[values['type']], 'get_add_gui_info'):
1620+ gui_values = self.specto.watch_db.plugin_dict[values['type']].get_add_gui_info()
1621+ window_options = self.watch_options[values['type']]
1622+
1623+ for key in window_options:
1624+ values[key] = window_options[key].get_value()
1625+ window_options[key].set_color(0xFFFF, 0xFFFF, 0xFFFF)
1626+
1627+ self.builder.get_object("name").modify_base(gtk.STATE_NORMAL, gtk.gdk.Color(0xFFFF, 0xFFFF, 0xFFFF))
1628+
1629+ try:
1630+ self.specto.watch_db[self.watch.id].set_values(values, True)
1631+ except AttributeError, error_fields:
1632+ fields = str(error_fields).split(",")
1633+ i = 1
1634+ for field in fields:
1635+ if field == " name":
1636+ self.builder.get_object("name").modify_base(gtk.STATE_NORMAL, gtk.gdk.Color(65535, 0, 0))
1637+ self.builder.get_object("name").grab_focus()
1638+ else:
1639+ field = window_options[field.strip()]
1640+ if i == 1:
1641+ field.grab_focus()
1642+ i = 0
1643+ field.set_color(65535, 0, 0)
1644+ else:
1645+ if not self.specto.watch_io.is_unique_watch(values['name']):
1646+ self.specto.watch_io.replace_name(self.watch.name, values['name'])
1647+ # Change the name in the notifier window
1648+ self.specto.notifier.change_name(values['name'], self.watch.id)
1649+
1650+ self.specto.watch_db[self.watch.id].set_values(values)
1651+
1652+ self.specto.watch_io.write_watch(values)
1653+ self.specto.notifier.show_watch_info()
1654+ self.edit_watch.destroy()
1655+
1656+ if self.watch.active == True:
1657+ self.specto.watch_db[self.watch.id].restart()
1658+
1659+ def remove_clicked(self, widget):
1660+ """ Remove the watch. """
1661+ dialog = spectlib.gtkconfig.RemoveDialog(_("Remove a watch"),
1662+ (_('<big>Remove the watch "%s"?</big>\nThis operation cannot be undone.') % self.watch.name))
1663+ answer = dialog.show()
1664+ if answer == True:
1665+ self.edit_watch.destroy()
1666+ self.notifier.remove_notifier_entry(self.watch.id)
1667+ self.specto.watch_db.remove(self.watch.id) #remove the watch
1668+ self.specto.watch_io.remove_watch(self.watch.name)
1669+ if self.notifier.tray:
1670+ self.notifier.tray.show_tooltip()
1671+
1672+ def clear_clicked(self, widget):
1673+ """ Clear the log window. """
1674+ self.specto.logger.remove_watch_log(self.watch.name)
1675+ self.log = self.specto.logger.watch_log(self.watch.name)
1676+ self.logwindow.set_text(self.log)
1677+
1678+ def save_as_clicked(self, widget):
1679+ """ Open the Save as dialog window. """
1680+ Save_dialog(self, self.log)
1681+
1682+ def delete_event(self, widget, event, data=None):
1683+ """ Destroy the window. """
1684+ self.edit_watch.destroy()
1685+ return True
1686+
1687+ def create_edit_gui(self):
1688+ """ Create the gui for the different kinds of watches. """
1689+ vbox_options = self.builder.get_object("vbox_watch_options")
1690+ watch_type = self.watch.type
1691+ self.watch_options[watch_type] = []
1692+ try:
1693+ self.table.destroy()
1694+ except:
1695+ pass
1696+
1697+ try:
1698+ if self.specto.watch_db.plugin_dict[watch_type].dbus_watch == True:
1699+ self.builder.get_object("refresh").hide()
1700+ self.builder.get_object("refresh_unit").hide()
1701+ self.builder.get_object("label_refresh1").hide()
1702+ except:
1703+ pass
1704+
1705+ if hasattr(self.specto.watch_db.plugin_dict[watch_type], 'get_add_gui_info'):
1706+ values = self.specto.watch_db.plugin_dict[watch_type].get_add_gui_info()
1707+ else:
1708+ values = []
1709+
1710+ watch_values = self.watch.get_values()
1711+
1712+ if watch_values['command'] != "":
1713+ self.builder.get_object("entry_changed_command").set_text(watch_values['command'])
1714+ self.builder.get_object("check_command").set_active(True)
1715+ else:
1716+ self.builder.get_object("entry_changed_command").set_text("")
1717+ self.builder.get_object("check_command").set_active(False)
1718+
1719+ if watch_values['open_command'] != "":
1720+ self.builder.get_object("entry_open_command").set_text(watch_values['open_command'])
1721+ self.builder.get_object("check_open").set_active(True)
1722+ else:
1723+ self.builder.get_object("entry_open_command").set_text("")
1724+ self.builder.get_object("check_open").set_active(False)
1725+
1726+
1727+ # Create the options gui
1728+ if len(values) > 0:
1729+ self.table = gtk.Table(rows=len(values), columns=2, homogeneous=False)
1730+ self.table.set_row_spacings(6)
1731+ self.table.set_col_spacings(6)
1732+ self.watch_options[watch_type] = {}
1733+
1734+ i = 0
1735+ for value, widget in values:
1736+ table, _widget = widget.get_object()
1737+ widget.set_value(watch_values[value])
1738+ self.table.attach(table, 0, 1, i, i + 1)
1739+ self.watch_options[watch_type].update({value: widget})
1740+ i += 1
1741+
1742+ self.table.show()
1743+ vbox_options.pack_start(self.table, False, False, 0)
1744+
1745+ def command_toggled(self, widget):
1746+ sensitive = self.builder.get_object("check_command").get_active()
1747+ self.builder.get_object("entry_changed_command").set_sensitive(sensitive)
1748+
1749+ def open_toggled(self, widget):
1750+ sensitive = self.builder.get_object("check_open").get_active()
1751+ self.builder.get_object("entry_open_command").set_sensitive(sensitive)
1752+
1753+
1754+class Save_dialog:
1755+ """
1756+ Class to create the save dialog.
1757+ """
1758+
1759+ def __init__(self, specto, *args):
1760+ """ Display the save as dialog. """
1761+ self.specto = specto
1762+ self.text = args[0]
1763+ # Create the tree
1764+ uifile = os.path.join(self.specto.PATH, "uis/edit_watch.ui")
1765+ windowname = "file_chooser"
1766+ self.builder = gtk.Builder()
1767+ self.builder.set_translation_domain("specto")
1768+ self.builder.add_from_file(uifile)
1769+ self.save_dialog = self.builder.get_object("file_chooser")
1770+
1771+ dic = {"on_button_cancel_clicked": self.cancel,
1772+ "on_button_save_clicked": self.save}
1773+ # Attach the events
1774+ self.builder.connect_signals(dic)
1775+
1776+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
1777+ self.save_dialog.set_icon(icon)
1778+ self.save_dialog.set_filename(os.environ['HOME'] + "/ ")
1779+
1780+ def cancel(self, *args):
1781+ """ Destroy the window. """
1782+ self.save_dialog.destroy()
1783+
1784+ def save(self, *args):
1785+ """ Save the file. """
1786+ file_name = self.save_dialog.get_filename()
1787+
1788+ f = open(file_name, "w")
1789+ f.write(self.text)
1790+ f.close()
1791+
1792+ self.save_dialog.destroy()
1793+
1794+
1795+if __name__ == "__main__":
1796+ # Run the gui
1797+ app = Edit_watch()
1798+ gtk.main()
1799
1800=== added file 'build/lib.linux-i686-2.6/spectlib/export_watch.py'
1801--- build/lib.linux-i686-2.6/spectlib/export_watch.py 1970-01-01 00:00:00 +0000
1802+++ build/lib.linux-i686-2.6/spectlib/export_watch.py 2012-03-14 09:03:18 +0000
1803@@ -0,0 +1,231 @@
1804+# -*- coding: utf-8 -*-
1805+
1806+# Specto , Unobtrusive event notifier
1807+#
1808+# import_export.py
1809+#
1810+# See the AUTHORS file for copyright ownership information
1811+
1812+# This program is free software; you can redistribute it and/or
1813+# modify it under the terms of the GNU General Public
1814+# License as published by the Free Software Foundation; either
1815+# version 2 of the License, or (at your option) any later version.
1816+#
1817+# This program is distributed in the hope that it will be useful,
1818+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1819+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1820+# General Public License for more details.
1821+#
1822+# You should have received a copy of the GNU General Public
1823+# License along with this program; if not, write to the
1824+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1825+# Boston, MA 02111-1307, USA.
1826+
1827+import os
1828+from spectlib.watch import Watch_io
1829+from spectlib.gtkconfig import SaveDialog
1830+
1831+try:
1832+ import pygtk
1833+ pygtk.require("2.0")
1834+except:
1835+ pass
1836+
1837+try:
1838+ import gtk
1839+ import gobject
1840+except:
1841+ pass
1842+
1843+
1844+class Export_watch:
1845+ """
1846+ Class to create the import/export watch dialog.
1847+ """
1848+
1849+ def __init__(self, specto, notifier):
1850+ self.specto = specto
1851+ self.notifier = notifier
1852+
1853+ #create tree
1854+ uifile = os.path.join(self.specto.PATH, "uis/import_export.ui")
1855+ windowname = "import_export"
1856+ self.builder = gtk.Builder()
1857+ self.builder.set_translation_domain("specto")
1858+ self.builder.add_from_file(uifile)
1859+ self.export_watch = self.builder.get_object("import_export")
1860+ self.export_watch.set_title(_("Export watches"))
1861+ self.builder.get_object("button_action").set_label(_("Export watches"))
1862+
1863+ self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gtk.gdk.Pixbuf, \
1864+ gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)
1865+ self.new_watch_db = {}
1866+
1867+ #catch some events
1868+ dic = {"on_button_select_all_clicked": self.select_all,
1869+ "on_button_deselect_all_clicked": self.deselect_all,
1870+ "on_button_action_clicked": self.do_action,
1871+ "on_button_close_clicked": self.delete_event}
1872+
1873+ #attach the events
1874+ self.builder.connect_signals(dic)
1875+
1876+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
1877+ self.export_watch.set_icon(icon)
1878+
1879+ self.treeview = self.builder.get_object("treeview")
1880+ self.treeview.set_model(self.model)
1881+ self.treeview.set_flags(gtk.TREE_MODEL_ITERS_PERSIST)
1882+ self.iter = {}
1883+
1884+ ### Checkbox
1885+ self.renderer = gtk.CellRendererToggle()
1886+ self.renderer.set_property("activatable", True)
1887+ self.renderer.connect("toggled", self.check_clicked, self.model)
1888+ self.columnCheck = gtk.TreeViewColumn(_("Select"), \
1889+ self.renderer, active=0)
1890+ self.treeview.append_column(self.columnCheck)
1891+
1892+ ### Icon
1893+ self.renderer = gtk.CellRendererPixbuf()
1894+ self.columnIcon = gtk.TreeViewColumn(_("Type"), \
1895+ self.renderer, pixbuf=1)
1896+ self.treeview.append_column(self.columnIcon)
1897+
1898+ ### Titre
1899+ self.renderer = gtk.CellRendererText()
1900+ self.columnTitel = gtk.TreeViewColumn(_("Name"), \
1901+ self.renderer, markup=2)
1902+ self.columnTitel.set_expand(True)
1903+ self.columnTitel.set_resizable(True)
1904+ self.treeview.append_column(self.columnTitel)
1905+
1906+ ### ID
1907+ self.renderer = gtk.CellRendererText()
1908+ self.column = gtk.TreeViewColumn(_("ID"), self.renderer, markup=3)
1909+ self.column.set_visible(False)
1910+ #self.column.set_sort_column_id(3)
1911+ self.treeview.append_column(self.column)
1912+
1913+ ### type
1914+ self.renderer = gtk.CellRendererText()
1915+ self.columnType = gtk.TreeViewColumn(_("TYPE"), \
1916+ self.renderer, markup=4)
1917+ self.columnType.set_visible(False)
1918+ #self.columnType.set_sort_column_id(4)
1919+ self.treeview.append_column(self.columnType)
1920+
1921+ for watch in self.specto.watch_db:
1922+ if watch.deleted == False:
1923+ self.add_watch_entry(watch.id)
1924+
1925+ def select_all(self, widget):
1926+ db = self.specto.watch_db
1927+
1928+ for watch in db:
1929+ if watch.deleted == False:
1930+ self.model.set_value(self.iter[watch.id], 0, 1)
1931+
1932+ def deselect_all(self, widget):
1933+ db = self.specto.watch_db
1934+
1935+ for watch in db:
1936+ if watch.deleted == False:
1937+ self.model.set_value(self.iter[watch.id], 0, 0)
1938+
1939+ def do_action(self, widget):
1940+ self.export_watch.hide_all()
1941+ export_save_dialog = ExportSaveDialog(self.specto, None, False, \
1942+ self.get_selected_watches())
1943+ response = export_save_dialog.run()
1944+ if response == gtk.RESPONSE_OK:
1945+ export_save_dialog.save()
1946+ else:
1947+ export_save_dialog.cancel()
1948+
1949+ def delete_event(self, widget, *args):
1950+ """ Destroy the window. """
1951+ self.export_watch.destroy()
1952+ return True
1953+
1954+ def get_selected_watches(self):
1955+ selected_watches_db = {}
1956+ i = 0
1957+ watch_db = self.specto.watch_db
1958+
1959+ for watch in watch_db:
1960+ if watch.deleted == False:
1961+ if self.model.get_value(self.iter[watch.id], 0) == True:
1962+ selected_watches_db[i] = watch
1963+ i += 1
1964+ return selected_watches_db
1965+
1966+ def add_watch_entry(self, id):
1967+ """ Add an entry to the notifier list. """
1968+ watch = self.specto.watch_db[id]
1969+ entry_name = watch.name.replace("&", "&amp;")
1970+ icon = self.notifier.get_icon(watch.icon, 50, False)
1971+ self.iter[id] = self.model.insert_before(None, None)
1972+ self.model.set_value(self.iter[id], 0, 0)
1973+ self.model.set_value(self.iter[id], 1, icon)
1974+ self.model.set_value(self.iter[id], 2, entry_name)
1975+ self.model.set_value(self.iter[id], 3, watch.id)
1976+ self.model.set_value(self.iter[id], 4, watch.type)
1977+
1978+ def set_new_watch_db(self, watch_db):
1979+ self.new_watch_db = watch_db
1980+
1981+ def check_clicked(self, object, path, model):
1982+ """ Call the main function to start/stop the selected watch. """
1983+ sel = self.treeview.get_selection()
1984+ sel.select_path(path)
1985+ model, iter = self.treeview.get_selection().get_selected()
1986+
1987+ if model.get_value(iter, 0):
1988+ model.set_value(iter, 0, 0)
1989+ else:
1990+ model.set_value(iter, 0, 1)
1991+
1992+
1993+class ExportSaveDialog(SaveDialog):
1994+ """
1995+ Class for displaying the save as dialog.
1996+ """
1997+
1998+ def __init__(self, specto, _import, action_type, watches_db):
1999+ SaveDialog.__init__(self, specto)
2000+ self.specto = specto
2001+ self._export = _import
2002+ windowname = "export_file_chooser"
2003+ self.action_type = action_type
2004+ self.watches_db = watches_db
2005+
2006+ def save(self, *args):
2007+ """ Save the file. """
2008+ file_name = self.get_filename()
2009+
2010+ for i in self.watches_db.keys():
2011+ values = {}
2012+ values['name'] = self.watches_db[i].name
2013+ values['type'] = self.watches_db[i].type
2014+ values['refresh'] = self.watches_db[i].refresh
2015+ values.update(self.watches_db[i].get_values())
2016+ self.write_options(file_name, values)
2017+
2018+ self.destroy()
2019+
2020+ def write_options(self, file_name, values):
2021+ """
2022+ Write or change the watch options in a configuration file.
2023+ Values has to be a dictionary with the name from the options
2024+ and the value. example: { 'name':'value', 'name':'value' }
2025+ If the name is not found, a new watch will be added,
2026+ else the excisting watch will be changed.
2027+ """
2028+ watch_io = Watch_io(self.specto, file_name)
2029+ watch_io.write_watch(values)
2030+
2031+if __name__ == "__main__":
2032+ #run the gui
2033+ app = Export_watch()
2034+ gtk.main()
2035
2036=== added file 'build/lib.linux-i686-2.6/spectlib/gtkconfig.py'
2037--- build/lib.linux-i686-2.6/spectlib/gtkconfig.py 1970-01-01 00:00:00 +0000
2038+++ build/lib.linux-i686-2.6/spectlib/gtkconfig.py 2012-03-14 09:03:18 +0000
2039@@ -0,0 +1,588 @@
2040+# -*- coding: utf-8 -*-
2041+
2042+# Specto , Unobtrusive event notifier
2043+#
2044+# gtkutil.py
2045+#
2046+# See the AUTHORS file for copyright ownership information
2047+
2048+# This program is free software; you can redistribute it and/or
2049+# modify it under the terms of the GNU General Public
2050+# License as published by the Free Software Foundation; either
2051+# version 2 of the License, or (at your option) any later version.
2052+#
2053+# This program is distributed in the hope that it will be useful,
2054+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2055+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2056+# General Public License for more details.
2057+#
2058+# You should have received a copy of the GNU General Public
2059+# License along with this program; if not, write to the
2060+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2061+# Boston, MA 02111-1307, USA.
2062+
2063+import gtk
2064+import os
2065+
2066+import spectlib.util
2067+
2068+
2069+class Entry():
2070+
2071+ def __init__(self, label, text=None):
2072+ self.table = gtk.Table(rows=1, columns=2)
2073+ self.gtkLabel = gtk.Label((label + ":"))
2074+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2075+ self.gtkLabel.show()
2076+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2077+
2078+ self.entry = gtk.Entry()
2079+ if text != None:
2080+ self.entry.set_text(text)
2081+ self.entry.show()
2082+ self.table.attach(self.entry, 1, 2, 0, 1, xoptions=gtk.FILL)
2083+ self.table.show()
2084+
2085+ def set_value(self, value):
2086+ self.entry.set_text(value)
2087+
2088+ def get_value(self):
2089+ return self.entry.get_text()
2090+
2091+ def get_object(self):
2092+ return self.table, self.entry
2093+
2094+ def set_color(self, red, blue, green):
2095+ self.entry.modify_base(gtk.STATE_NORMAL, \
2096+ gtk.gdk.Color(red, blue, green))
2097+
2098+ def grab_focus(self):
2099+ self.entry.grab_focus()
2100+
2101+
2102+class PasswordEntry():
2103+
2104+ def __init__(self, label, text=None):
2105+ self.table = gtk.Table(rows=1, columns=2)
2106+ self.gtkLabel = gtk.Label((label + ":"))
2107+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2108+ self.gtkLabel.show()
2109+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2110+
2111+ self.entry = gtk.Entry()
2112+ self.entry.set_visibility(False)
2113+ if text != None:
2114+ self.entry.set_text(text)
2115+ self.entry.show()
2116+ self.table.attach(self.entry, 1, 2, 0, 1, xoptions=gtk.FILL)
2117+ self.table.show()
2118+
2119+ def set_value(self, value):
2120+ self.entry.set_text(value)
2121+
2122+ def get_value(self):
2123+ return self.entry.get_text()
2124+
2125+ def get_object(self):
2126+ return self.table, self.entry
2127+
2128+ def set_color(self, red, blue, green):
2129+ self.entry.modify_base(gtk.STATE_NORMAL, \
2130+ gtk.gdk.Color(red, blue, green))
2131+
2132+ def grab_focus(self):
2133+ self.entry.grab_focus()
2134+
2135+
2136+class Spinbutton():
2137+
2138+ def __init__(self, label, value=1, lower=1, upper=100, \
2139+ step_incr=1, page_incr=10, page_size=0):
2140+ self.table = gtk.Table(rows=1, columns=2)
2141+ self.gtkLabel = gtk.Label((label + ":"))
2142+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2143+ self.gtkLabel.show()
2144+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2145+
2146+ adjustment = gtk.Adjustment(value, lower, upper, \
2147+ step_incr, page_incr, page_size)
2148+ self.spinbutton = gtk.SpinButton(adjustment)
2149+ self.spinbutton.show()
2150+ self.table.attach(self.spinbutton, 1, 2, 0, 1, xoptions=gtk.FILL)
2151+ self.table.show()
2152+
2153+ def set_value(self, value):
2154+ self.spinbutton.set_value(value)
2155+
2156+ def get_value(self):
2157+ return self.spinbutton.get_value()
2158+
2159+ def get_object(self):
2160+ return self.table, self.spinbutton
2161+
2162+ def set_color(self, red, blue, green):
2163+ self.spinbutton.modify_base(gtk.STATE_NORMAL, \
2164+ gtk.gdk.Color(red, blue, green))
2165+
2166+ def grab_focus(self):
2167+ self.spinbutton.grab_focus()
2168+
2169+
2170+class CheckButton():
2171+
2172+ def __init__(self, label, value=False):
2173+ self.table = gtk.Table(rows=1, columns=2)
2174+ self.gtkLabel = gtk.Label((label + ":"))
2175+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2176+ self.gtkLabel.show()
2177+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2178+
2179+ self.checkbutton = gtk.CheckButton()
2180+ self.checkbutton.set_active(value)
2181+ self.checkbutton.set_alignment(xalign=1.0, yalign=0.0)
2182+ self.checkbutton.show()
2183+ self.table.attach(self.checkbutton, 1, 2, 0, 1, xoptions=gtk.FILL)
2184+ self.table.show()
2185+
2186+ def set_value(self, value):
2187+ self.checkbutton.set_active(value)
2188+
2189+ def get_value(self):
2190+ return self.checkbutton.get_active()
2191+
2192+ def get_object(self):
2193+ return self.table, self.checkbutton
2194+
2195+ def set_color(self, red, blue, green):
2196+ self.checkbutton.modify_base(gtk.STATE_NORMAL, \
2197+ gtk.gdk.Color(red, blue, green))
2198+
2199+ def grab_focus(self):
2200+ self.checkbutton.grab_focus()
2201+
2202+
2203+class FileChooser():
2204+
2205+ def __init__(self, label, value=False):
2206+ self.table = gtk.Table(rows=2, columns=1)
2207+ self.gtkLabel = gtk.Label((label + ":"))
2208+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2209+ self.gtkLabel.show()
2210+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2211+
2212+ self.filechooser = gtk.FileChooserButton(_("Choose a file"))
2213+## filter = gtk.FileFilter()
2214+## filter.set_name("PDF files")
2215+## filter.add_pattern("*.pdf")
2216+## self.filechooser.add_filter(filter)
2217+
2218+ self.filechooser.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
2219+ self.filechooser.set_filename(os.environ['HOME'])
2220+ self.filechooser.show()
2221+ self.table.attach(self.filechooser, 0, 1, 1, 2, xoptions=gtk.FILL)
2222+ self.table.show()
2223+
2224+ def set_value(self, value):
2225+ self.filechooser.set_filename(value)
2226+
2227+ def get_value(self):
2228+ return self.filechooser.get_filename()
2229+
2230+ def get_object(self):
2231+ return self.table, self.filechooser
2232+
2233+ def set_color(self, red, blue, green):
2234+ self.filechooser.modify_base(gtk.STATE_NORMAL, \
2235+ gtk.gdk.Color(red, blue, green))
2236+
2237+ def grab_focus(self):
2238+ self.filechooser.grab_focus()
2239+
2240+class FileChooserpdf():
2241+
2242+ def __init__(self, label, value=False):
2243+ self.table = gtk.Table(rows=2, columns=1)
2244+ self.gtkLabel = gtk.Label((label + ":"))
2245+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2246+ self.gtkLabel.show()
2247+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2248+
2249+ self.filechooser = gtk.FileChooserButton(_("Choose a file"))
2250+ filter = gtk.FileFilter()
2251+ filter.set_name("PDF files")
2252+ filter.add_pattern("*.pdf")
2253+ self.filechooser.add_filter(filter)
2254+
2255+ self.filechooser.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
2256+ self.filechooser.set_filename(os.environ['HOME'])
2257+ self.filechooser.show()
2258+ self.table.attach(self.filechooser, 0, 1, 1, 2, xoptions=gtk.FILL)
2259+ self.table.show()
2260+
2261+ def set_value(self, value):
2262+ self.filechooser.set_filename(value)
2263+
2264+ def get_value(self):
2265+ return self.filechooser.get_filename()
2266+
2267+ def get_object(self):
2268+ return self.table, self.filechooser
2269+
2270+ def set_color(self, red, blue, green):
2271+ self.filechooser.modify_base(gtk.STATE_NORMAL, \
2272+ gtk.gdk.Color(red, blue, green))
2273+
2274+ def grab_focus(self):
2275+ self.filechooser.grab_focus()
2276+
2277+
2278+class FolderChooser():
2279+
2280+ def __init__(self, label, value=False):
2281+ self.table = gtk.Table(rows=2, columns=1)
2282+ self.gtkLabel = gtk.Label((label + ":"))
2283+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2284+ self.gtkLabel.show()
2285+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2286+
2287+ self.dirchooser = gtk.FileChooserButton(_("Choose a directory"))
2288+ self.dirchooser.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
2289+ self.dirchooser.set_filename(os.environ['HOME'])
2290+ self.dirchooser.show()
2291+ self.table.attach(self.dirchooser, 0, 1, 1, 2, xoptions=gtk.FILL)
2292+ self.table.show()
2293+
2294+ def set_value(self, value):
2295+ self.dirchooser.set_filename(value)
2296+
2297+ def get_value(self):
2298+ return self.dirchooser.get_filename()
2299+
2300+ def get_object(self):
2301+ return self.table, self.dirchooser
2302+
2303+ def set_color(self, red, blue, green):
2304+ self.dirchooser.modify_base(gtk.STATE_NORMAL, \
2305+ gtk.gdk.Color(red, blue, green))
2306+
2307+ def grab_focus(self):
2308+ self.dirchooser.grab_focus()
2309+
2310+
2311+class Scale():
2312+
2313+ def __init__(self, label, value=0, lower=0, upper=100, \
2314+ step_incr=1.0, page_incr=1.0, page_size=10):
2315+ self.table = gtk.Table(rows=2, columns=1)
2316+
2317+ self.gtkLabel = gtk.Label((label + ":"))
2318+ self.gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2319+ self.gtkLabel.show()
2320+ self.table.attach(self.gtkLabel, 0, 1, 0, 1)
2321+
2322+ self.value = value
2323+ self.lower = lower
2324+ self.upper = upper
2325+ self.step_incr = step_incr
2326+ self.page_incr = page_incr
2327+ self.page_size = page_size
2328+
2329+ _adjustment = gtk.Adjustment(value, lower, upper, \
2330+ step_incr, page_incr, page_size)
2331+ self.scale = gtk.HScale(adjustment=_adjustment)
2332+ self.scale.set_digits(1)
2333+ self.scale.set_value_pos(gtk.POS_RIGHT)
2334+ self.scale.show()
2335+ self.table.attach(self.scale, 0, 1, 1, 2, xoptions=gtk.FILL)
2336+ self.table.show()
2337+
2338+ def set_value(self, value):
2339+ _adjustment = gtk.Adjustment(value, self.lower, self.upper, \
2340+ self.step_incr, self.page_incr, self.page_size)
2341+ self.scale.set_adjustment(_adjustment)
2342+
2343+ def get_value(self):
2344+ return self.scale.get_value()
2345+
2346+ def get_object(self):
2347+ return self.table, self.scale
2348+
2349+ def set_color(self, red, blue, green):
2350+ self.scale.modify_base(gtk.STATE_NORMAL, \
2351+ gtk.gdk.Color(red, blue, green))
2352+
2353+ def grab_focus(self):
2354+ self.scale.grab_focus()
2355+
2356+
2357+class RemoveDialog():
2358+
2359+ def __init__(self, title, text):
2360+ dialog = gtk.Dialog(title, None, gtk.DIALOG_MODAL | \
2361+ gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None)
2362+ #HIG tricks
2363+ dialog.set_has_separator(False)
2364+
2365+ dialog.add_button(gtk.STOCK_CANCEL, -1)
2366+ dialog.add_button(gtk.STOCK_REMOVE, 3)
2367+
2368+ dialog.label_hbox = gtk.HBox(spacing=6)
2369+
2370+ icon = gtk.Image()
2371+ icon.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
2372+ dialog.label_hbox.pack_start(icon, True, True, 6)
2373+ icon.show()
2374+
2375+ text = text.replace("&", "&amp;")
2376+ label = gtk.Label(text)
2377+ label.set_use_markup(True)
2378+ dialog.label_hbox.pack_start(label, True, True, 6)
2379+ label.show()
2380+
2381+ dialog.vbox.pack_start(dialog.label_hbox, True, True, 12)
2382+ dialog.label_hbox.show()
2383+
2384+ icon = gtk.gdk.pixbuf_new_from_file(spectlib.util.get_path() \
2385+ + 'icons/specto_window_icon.svg')
2386+ dialog.set_icon(icon)
2387+ self.dialog = dialog
2388+
2389+ def show(self):
2390+ answer = self.dialog.run()
2391+ if answer == 3:
2392+ self.dialog.destroy()
2393+ return True
2394+ else:
2395+ self.dialog.destroy()
2396+ return False
2397+
2398+
2399+class ErrorDialog():
2400+
2401+ def __init__(self, specto, error_message):
2402+ self.specto = specto
2403+ uifile = os.path.join(self.specto.PATH, "uis/notifier.ui")
2404+ windowname = "error_dialog"
2405+ self.builder = gtk.Builder()
2406+ self.builder.set_translation_domain("specto")
2407+ self.builder.add_from_file(uifile)
2408+
2409+ self.builder.get_object("ok").connect("clicked", self.delete_event)
2410+ self.builder.get_object("send").connect("clicked", self.send)
2411+
2412+ self.error_dialog = self.builder.get_object("error_dialog")
2413+ self.error_dialog.show()
2414+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
2415+ self.error_dialog.set_icon(icon)
2416+
2417+ self.errorwindow = gtk.TextBuffer(None)
2418+ self.builder.get_object("error_message").set_buffer(self.errorwindow)
2419+ self.errorwindow.set_text(error_message)
2420+
2421+ self.builder.get_object("image").set_from_stock(gtk.STOCK_DIALOG_ERROR, \
2422+ gtk.ICON_SIZE_DIALOG)
2423+
2424+ self.builder.get_object("label4").set_use_markup(True)
2425+ self.builder.get_object("label4").set_label(_("<b>Specto encountered an error</b>\nPlease verify if this bug has been entered in our issue tracker, and if not, file a bug report so we can fix it."))
2426+
2427+ def send(self, *args):
2428+ url = "http://code.google.com/p/specto/issues/list"
2429+ os.system(spectlib.util.return_webpage(url) + " &")
2430+
2431+ def delete_event(self, widget, *args):
2432+ """ Destroy the window. """
2433+ self.error_dialog.destroy()
2434+ return True
2435+
2436+
2437+class SaveDialog(gtk.FileChooserDialog):
2438+ """
2439+ Class for displaying a generic save dialog for Specto.
2440+ """
2441+
2442+ def __init__(self, specto):
2443+ gtk.FileChooserDialog.__init__(self, _("Save file as"), None,
2444+ gtk.FILE_CHOOSER_ACTION_SAVE,
2445+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
2446+ gtk.STOCK_SAVE, gtk.RESPONSE_OK))
2447+ self.specto = specto
2448+ windowname = "filechooser"
2449+
2450+ self.set_icon(gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png")))
2451+ self.set_filename(os.environ['HOME'] + "/ ")
2452+
2453+ def cancel(self, *args):
2454+ """ Close the dialog. """
2455+ self.destroy()
2456+
2457+ def save(self, *args):
2458+ raise NotImplementedError
2459+
2460+class OpenDialog(gtk.FileChooserDialog):
2461+ """
2462+ Class for displaying a generic open dialog for Specto.
2463+ """
2464+
2465+ def __init__(self, specto):
2466+ gtk.FileChooserDialog.__init__(self, _("Open file"), None,
2467+ gtk.FILE_CHOOSER_ACTION_OPEN,
2468+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
2469+ gtk.STOCK_OPEN, gtk.RESPONSE_OK))
2470+ self.specto = specto
2471+ windowname = "open_file_chooser"
2472+
2473+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
2474+ self.set_icon(icon)
2475+ self.set_filename(os.environ['HOME'] + "/ ")
2476+
2477+ def cancel(self, *args):
2478+ """ Close the save as dialog. """
2479+ self.destroy()
2480+
2481+ def open(self, *args):
2482+ raise NotImplementedError
2483+
2484+
2485+def create_widget(table, widget_type, value, label, position):
2486+ i = position
2487+ watch_options = {}
2488+
2489+ if not widget_type == "scale":
2490+ gtkLabel = gtk.Label((label + ":"))
2491+ gtkLabel.set_alignment(xalign=0.0, yalign=0.5)
2492+ gtkLabel.show()
2493+ table.attach(gtkLabel, 0, 1, i, i + 1)
2494+
2495+ if widget_type == "entry":
2496+ entry = gtk.Entry()
2497+ entry.show()
2498+ watch_options.update({value: entry})
2499+ table.attach(entry, 1, 2, i, i + 1)
2500+ elif widget_type == "password":
2501+ entry = gtk.Entry()
2502+ entry.set_visibility(False)
2503+ entry.show()
2504+ watch_options.update({value: entry})
2505+ table.attach(entry, 1, 2, i, i + 1)
2506+ elif widget_type == "scale":
2507+ scale_table = gtk.Table(rows=2, columns=1, homogeneous=False)
2508+
2509+ adjustment_label = gtk.Label((label + ":"))
2510+ adjustment_label.set_alignment(xalign=0.0, yalign=0.5)
2511+ adjustment_label.show()
2512+ scale_table.attach(adjustment_label, 0, 1, 0, 1)
2513+
2514+ _adjustment = gtk.Adjustment(value=2.0, lower=0, upper=50, \
2515+ step_incr=0.1, page_incr=1.0, page_size=10)
2516+ scale = gtk.HScale(adjustment=_adjustment)
2517+ scale.set_digits(1)
2518+ scale.set_value_pos(gtk.POS_RIGHT)
2519+ scale.show()
2520+ scale_table.attach(scale, 0, 1, 1, 2)
2521+
2522+ watch_options.update({value: scale})
2523+ scale_table.show()
2524+ table.attach(scale_table, 0, 2, i, i + 1)
2525+ elif widget_type == "checkbox":
2526+ checkbox = gtk.CheckButton()
2527+ checkbox.show()
2528+ watch_options.update({value: checkbox})
2529+ table.attach(checkbox, 1, 2, i, i + 1)
2530+ elif widget_type == "filechooser":
2531+ filechooser = gtk.FileChooserButton(_("Choose a file"))
2532+ filechooser.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
2533+ filechooser.show()
2534+ watch_options.update({value: filechooser})
2535+ table.attach(filechooser, 1, 2, i, i + 1)
2536+ elif widget_type == "dirchooser":
2537+ dirchooser = gtk.FileChooserButton(_("Choose a directory"))
2538+ dirchooser.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
2539+ dirchooser.show()
2540+ watch_options.update({value: dirchooser})
2541+ table.attach(dirchooser, 1, 2, i, i + 1)
2542+ elif widget_type == "calendar":
2543+ calendar = gtk.Calendar()
2544+ #calendar.show()
2545+ watch_options.update({value: calendar})
2546+ table.attach(calendar, 1, 2, i, i + 1)
2547+ elif widget_type == "time":
2548+ time_table = gtk.Table(rows=1, columns=2, homogeneous=False)
2549+ minutes_adjustment = gtk.Adjustment(value=1, lower=1, upper=60, \
2550+ step_incr=1, page_incr=10, page_size=0)
2551+ hours_adjustment = gtk.Adjustment(value=1, lower=1, upper=24, \
2552+ step_incr=1, page_incr=10, page_size=0)
2553+ hours = gtk.SpinButton(hours_adjustment)
2554+ hours.show()
2555+ minutes = gtk.SpinButton(minutes_adjustment)
2556+ minutes.show()
2557+ time_table.attach(hours, 1, 2, 1, 2)
2558+ time_table.attach(minutes, 2, 3, 1, 2)
2559+ #time_table.show()
2560+ watch_options.update({value: (hours, minutes)})
2561+ table.attach(time_table, 1, 2, i, i + 1)
2562+
2563+ return watch_options, table
2564+
2565+
2566+def set_widget_value(widget_type, widget, value):
2567+ if widget_type == "entry" or widget_type == "password":
2568+ widget.set_text(value)
2569+ elif widget_type == "scale":
2570+ _adjustment = gtk.Adjustment(value=value * 100, lower=0, \
2571+ upper=50, step_incr=0.1, page_incr=1.0, page_size=10)
2572+ widget.set_adjustment(_adjustment)
2573+ elif widget_type == "checkbox":
2574+ if value == "True" or value == True:
2575+ widget.set_active(1)
2576+ else:
2577+ widget.set_active(0)
2578+ elif widget_type == "filechooser" or widget_type == "dirchooser":
2579+ widget.set_filename(value)
2580+ elif widget_type == "calendar":
2581+ try: #if value = string
2582+ value = value.replace("(", "")
2583+ value = value.replace(")", "")
2584+ value = value.split(",")
2585+ except: # value = tuple
2586+ pass
2587+ widget.select_month(int(value[1]), int(value[0]))
2588+ widget.select_day(int(value[2]))
2589+ elif widget_type == "time":
2590+ widget[0].set_value(int(value[0]))
2591+ widget[1].set_value(int(value[1]))
2592+
2593+
2594+def get_object_value(widget_type, value):
2595+ result = ""
2596+ if widget_type == "entry" or widget_type == "password":
2597+ result = value.values()[0].get_text()
2598+ elif widget_type == "scale":
2599+ result = value.values()[0].get_value()
2600+ elif widget_type == "checkbox":
2601+ result = value.values()[0].get_active()
2602+ elif widget_type == "filechooser" or widget_type == "dirchooser":
2603+ result = value.values()[0].get_filename()
2604+ elif widget_type == "calendar":
2605+ result = value.values()[0].get_date()
2606+ elif widget_type == "time":
2607+ result = (value.values()[0][0].get_value(), \
2608+ value.values()[0][1].get_value())
2609+
2610+ return result
2611+
2612+def create_menu_item(label, callback=None, icon=None):
2613+ menuItem = gtk.MenuItem(label, True)
2614+ if icon:
2615+ menuItem = gtk.ImageMenuItem(label)
2616+ image = gtk.Image()
2617+ # handle the icon as a stock icon.
2618+ try:
2619+ image.set_from_stock(icon, gtk.ICON_SIZE_MENU)
2620+ except TypeError:
2621+ # err, icon is a string, do nothing.
2622+ image = icon
2623+ menuItem.set_image(image)
2624+ image.show()
2625+ if callback:
2626+ menuItem.connect('activate', callback)
2627+ return menuItem
2628
2629=== added file 'build/lib.linux-i686-2.6/spectlib/i18n.py'
2630--- build/lib.linux-i686-2.6/spectlib/i18n.py 1970-01-01 00:00:00 +0000
2631+++ build/lib.linux-i686-2.6/spectlib/i18n.py 2012-03-14 09:03:18 +0000
2632@@ -0,0 +1,50 @@
2633+# -*- coding: utf-8 -*-
2634+
2635+# Specto , Unobtrusive event notifier
2636+#
2637+# il8n.py
2638+#
2639+# See the AUTHORS file for copyright ownership information
2640+
2641+# This program is free software; you can redistribute it and/or
2642+# modify it under the terms of the GNU General Public
2643+# License as published by the Free Software Foundation; either
2644+# version 2 of the License, or (at your option) any later version.
2645+#
2646+# This program is distributed in the hope that it will be useful,
2647+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2648+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2649+# General Public License for more details.
2650+#
2651+# You should have received a copy of the GNU General Public
2652+# License along with this program; if not, write to the
2653+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2654+# Boston, MA 02111-1307, USA.
2655+
2656+import os
2657+import gettext
2658+import locale
2659+
2660+# If Specto is installed read prefix from constants module
2661+MESSAGES_DIR = ''
2662+try:
2663+ from spectlib.constants import PREFIX
2664+ MESSAGES_DIR = "%s/share/locale" % PREFIX
2665+except ImportError:
2666+ pass
2667+
2668+def setup_locale_and_gettext():
2669+ package_name = 'specto'
2670+ # Install _() builtin for gettext; always returning unicode objects
2671+ # also install ngettext()
2672+ gettext.install(package_name, localedir=MESSAGES_DIR, unicode=True,
2673+ names=("ngettext",))
2674+ locale.bindtextdomain(package_name, MESSAGES_DIR)
2675+ locale.bind_textdomain_codeset(package_name, "UTF-8")
2676+
2677+ try:
2678+ locale.setlocale(locale.LC_ALL, "")
2679+ except locale.Error, e:
2680+ pass
2681+
2682+setup_locale_and_gettext()
2683
2684=== added file 'build/lib.linux-i686-2.6/spectlib/i18n_safedict.py'
2685--- build/lib.linux-i686-2.6/spectlib/i18n_safedict.py 1970-01-01 00:00:00 +0000
2686+++ build/lib.linux-i686-2.6/spectlib/i18n_safedict.py 2012-03-14 09:03:18 +0000
2687@@ -0,0 +1,70 @@
2688+# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
2689+#
2690+# This program is free software; you can redistribute it and/or
2691+# modify it under the terms of the GNU General Public License
2692+# as published by the Free Software Foundation; either version 2
2693+# of the License, or (at your option) any later version.
2694+#
2695+# This program is distributed in the hope that it will be useful,
2696+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2697+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2698+# GNU General Public License for more details.
2699+#
2700+# You should have received a copy of the GNU General Public License
2701+# along with this program; if not, write to the Free Software
2702+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2703+
2704+"""A `safe' dictionary for string interpolation."""
2705+
2706+from types import StringType
2707+from UserDict import UserDict
2708+
2709+COMMASPACE = ', '
2710+
2711+
2712+class SafeDict(UserDict):
2713+ """Dictionary which returns a default value for unknown keys.
2714+
2715+ This is used in maketext so that editing templates is a bit more robust.
2716+ """
2717+
2718+ def __getitem__(self, key):
2719+ try:
2720+ return self.data[key]
2721+ except KeyError:
2722+ if isinstance(key, StringType):
2723+ return '%('+key+')s'
2724+ else:
2725+ return '<Missing key: %s>' % `key`
2726+
2727+ def interpolate(self, template):
2728+ return template % self
2729+
2730+
2731+class MsgSafeDict(SafeDict):
2732+
2733+ def __init__(self, msg, dict=None):
2734+ self.__msg = msg
2735+ SafeDict.__init__(self, dict)
2736+
2737+ def __getitem__(self, key):
2738+ if key.startswith('msg_'):
2739+ return self.__msg.get(key[4:], 'n/a')
2740+ elif key.startswith('allmsg_'):
2741+ missing = []
2742+ all = self.__msg.get_all(key[7:], missing)
2743+ if all is missing:
2744+ return 'n/a'
2745+ return COMMASPACE.join(all)
2746+ else:
2747+ return SafeDict.__getitem__(self, key)
2748+
2749+ def copy(self):
2750+ d = self.data.copy()
2751+ for k in self.__msg.keys():
2752+ vals = self.__msg.get_all(k)
2753+ if len(vals) == 1:
2754+ d['msg_'+k.lower()] = vals[0]
2755+ else:
2756+ d['allmsg_'+k.lower()] = COMMASPACE.join(vals)
2757+ return d
2758
2759=== added file 'build/lib.linux-i686-2.6/spectlib/imail.py'
2760--- build/lib.linux-i686-2.6/spectlib/imail.py 1970-01-01 00:00:00 +0000
2761+++ build/lib.linux-i686-2.6/spectlib/imail.py 2012-03-14 09:03:18 +0000
2762@@ -0,0 +1,294 @@
2763+# -*- coding: utf-8 -*-
2764+
2765+# Specto , Unobtrusive event notifier
2766+#
2767+# imail.py
2768+#
2769+# See the AUTHORS file for copyright ownership information
2770+
2771+# This program is free software; you can redistribute it and/or
2772+# modify it under the terms of the GNU General Public
2773+# License as published by the Free Software Foundation; either
2774+# version 2 of the License, or (at your option) any later version.
2775+#
2776+# This program is distributed in the hope that it will be useful,
2777+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2778+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2779+# General Public License for more details.
2780+#
2781+# You should have received a copy of the GNU General Public
2782+# License along with this program; if not, write to the
2783+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2784+# Boston, MA 02111-1307, USA.
2785+
2786+import smtplib
2787+import sys
2788+
2789+keyring = True
2790+try:
2791+ from spectlib.tools.keyringmanager import Keyring
2792+except:
2793+ keyring = False
2794+
2795+from email.mime.multipart import MIMEMultipart
2796+from email.mime.text import MIMEText
2797+from spectlib.bdd import Group, Mail
2798+
2799+class Imail():
2800+ """Class who send email alert """
2801+ def __init__(self,adresse,specto,name,values,item):
2802+ self.specto_adr = "specto@mail.com"
2803+ self.adr = adresse
2804+## print values
2805+ # Create message container - the correct MIME type is multipart/alternative.
2806+ self.msg = MIMEMultipart('alternative')
2807+ self.msg['Subject'] = "Alerte specto"
2808+ self.msg['From'] = self.specto_adr
2809+ self.msg['To'] = self.adr
2810+ self.specto = specto
2811+ self.name = name
2812+ #get settings
2813+ self.smtp = self.specto.specto_gconf.get_entry("smtp_entry")
2814+## print self.smtp
2815+ self.User = self.specto.specto_gconf.get_entry("login_entry")
2816+ if self.specto.use_keyring == True and keyring == True:
2817+ try:
2818+ k = Keyring("password_entry", "Specto " + "password_entry", "network")
2819+ self.Password = k.get_credentials()[1]
2820+ except:
2821+ self.Password = self.specto.specto_gconf.get_entry("password_entry")
2822+ self.tls = self.specto.specto_gconf.get_entry("button_tls")
2823+
2824+ listgroup = self.specto.base.getAll(Group)
2825+ listmail = self.specto.base.getAll(Mail)
2826+ self.list = self.get_mail_tosend(listmail,listgroup)
2827+## self.alert_html(name,values['pattern'],item,values['uri'])
2828+
2829+ def alert_rss(self,name,pattern,title,link,description):
2830+ """ Send Email for rss alert"""
2831+ description = '"'+description+'"'
2832+ # Create the body of the message (a plain-text and an HTML version).
2833+ text = "Bonjour,\nUne alerte a été générée par l'observateur "+name+" suite à l'apparition du motif "+pattern+"\n"+title+"\n"+link+"\n"+description+""
2834+ html = """\
2835+ <html>
2836+ <head></head>
2837+ <body>
2838+ <p>Bonjour,<br><br>
2839+ Une alerte a été générée par l'observateur <u>"""+name+"""</u> suite à l'apparition du motif <i>"""+pattern+"""</i><br><br>
2840+ <a href="""+link+""">"""+title+"""</a><br>
2841+ """+description+"""
2842+ </p>
2843+ </body>
2844+ </html>
2845+ """
2846+
2847+ # Record the MIME types of both parts - text/plain and text/html.
2848+ part1 = MIMEText(text, 'plain')
2849+ part2 = MIMEText(html, 'html')
2850+
2851+ # Attach parts into message container.
2852+ # According to RFC 2046, the last part of a multipart message, in this case
2853+ # the HTML message, is best and preferred.
2854+ self.msg.attach(part1)
2855+ self.msg.attach(part2)
2856+
2857+ try:
2858+ if (self.smtp != ""):
2859+ for m in self.list:
2860+ self.s = smtplib.SMTP(self.smtp)
2861+ if self.tls == True:
2862+ self.s.ehlo()
2863+ self.s.starttls()
2864+ self.s.ehlo()
2865+ if (self.User != "") and (self.Password != ""):
2866+ self.s.login(self.User, self.Password)
2867+ self.s.sendmail(self.specto_adr, m, self.msg.as_string())
2868+ self.s.quit()
2869+ except:
2870+ self.set_error()
2871+
2872+ def alert_html(self,name,pattern,item,link):
2873+## print "bonjour alerte html dans imail"
2874+## print name,pattern,item,link
2875+ """ Send Email for html alert """
2876+ # Create the body of the message (a plain-text and an HTML version).
2877+ text = "Bonjour,\nUne alerte a ete generee par l'observateur "+name+" suite a l'apparition du motif "+pattern+"\n Lien vers la page : "+link+"\n"+item+"\n"
2878+ html = """\
2879+ <html>
2880+ <head></head>
2881+ <body>
2882+ <p>Bonjour,<br><br>
2883+ Une alerte a été générée par l'observateur <u>"""+name+"""</u> suite à l'apparition du motif <i>"""+pattern+"""</i><br><br>
2884+ <a href="""+link+""">Lien vers la page</a><br>
2885+ """+item+"""
2886+ </p>
2887+ </body>
2888+ </html>
2889+ """
2890+ # Record the MIME types of both parts - text/plain and text/html.
2891+ part1 = MIMEText(text, 'plain')
2892+ #part2 = MIMEText(html, 'html')
2893+
2894+ # Attach parts into message container.
2895+ # According to RFC 2046, the last part of a multipart message, in this case
2896+ # the HTML message, is best and preferred.
2897+ self.msg.attach(part1)
2898+ #self.msg.attach(part2)
2899+
2900+ try:
2901+ if (self.smtp != ""):
2902+ for m in self.list:
2903+ self.s = smtplib.SMTP(self.smtp)
2904+ if self.tls == True:
2905+ self.s.ehlo()
2906+ self.s.starttls()
2907+ self.s.ehlo()
2908+ if (self.User != "") and (self.Password != ""):
2909+ self.s.login(self.User, self.Password)
2910+## print "before"
2911+ self.s.sendmail(self.specto_adr, m, self.msg.as_string())
2912+## print "Message send"
2913+ self.s.quit()
2914+ except:
2915+ self.set_error()
2916+
2917+ def alert_pdfhtml(self,name,pattern,item,link):
2918+## print "bonjour alerte pdfhtml dans imail"
2919+## print name,pattern,item,link
2920+ """ Send Email for html alert """
2921+ # Create the body of the message (a plain-text and an HTML version).
2922+ text = "Bonjour,\nUne alerte a ete generee par l'observateur "+name+" suite a l'apparition du motif "+pattern+"\n dans le document PDF : "+link+"\n"+item+"\n"
2923+ html = """\
2924+ <html>
2925+ <head></head>
2926+ <body>
2927+ <p>Bonjour,<br><br>
2928+ Une alerte a été générée par l'observateur <u>"""+name+"""</u> suite à l'apparition du motif <i>"""+pattern+"""</i><br><br>
2929+ <a href="""+link+""">Document PDF</a><br>
2930+ """+item+"""
2931+ </p>
2932+ </body>
2933+ </html>
2934+ """
2935+ # Record the MIME types of both parts - text/plain and text/html.
2936+ part1 = MIMEText(text, 'plain')
2937+ #part2 = MIMEText(html, 'html')
2938+
2939+ # Attach parts into message container.
2940+ # According to RFC 2046, the last part of a multipart message, in this case
2941+ # the HTML message, is best and preferred.
2942+ self.msg.attach(part1)
2943+ #self.msg.attach(part2)
2944+## print html
2945+ try:
2946+ if (self.smtp != ""):
2947+ for m in self.list:
2948+ self.s = smtplib.SMTP(self.smtp)
2949+ if self.tls == True:
2950+ self.s.ehlo()
2951+ self.s.starttls()
2952+ self.s.ehlo()
2953+ if (self.User != "") and (self.Password != ""):
2954+ self.s.login(self.User, self.Password)
2955+## print "before"
2956+ self.s.sendmail(self.specto_adr, m, self.msg.as_string())
2957+## print "Message send"
2958+ self.s.quit()
2959+ except:
2960+ self.set_error()
2961+
2962+ def get_adr(self):
2963+ """ return adress """
2964+ return self.adr
2965+
2966+ def set_error(self, message=""):
2967+ self.error = True
2968+ if message != "":
2969+ self.error_message = str(message).replace('\n',' ')
2970+ self.specto.logger.log(('%s') % self.error_message, "error", self.name)
2971+ else:
2972+ self.error_message = _("Unexpected error:") + " " + str(sys.exc_info()[1])
2973+ self.specto.logger.log(self.error_message, "error", self.name)
2974+
2975+ def check_mail_conf(self):
2976+ """ check if something change in mail settings """
2977+ if (self.specto.specto_gconf.get_entry("smtp_entry") != self.smtp):
2978+ self.smtp = self.specto.specto_gconf.get_entry("smtp_entry")
2979+ self.User = self.specto.specto_gconf.get_entry("login_entry")
2980+
2981+ if self.specto.use_keyring == True and keyring == True:
2982+ try:
2983+ k = Keyring("password_entry", "Specto " + "password_entry", "network")
2984+ self.Password = k.get_credentials()[1]
2985+ except:
2986+ self.Password = self.specto.specto_gconf.get_entry("password_entry")
2987+
2988+ def get_mail_tosend(self,listmail,listgroup):
2989+ tosend = []
2990+ for g in listgroup:
2991+ if g.name == self.adr:
2992+ for m in listmail:
2993+ if m.group == self.adr:
2994+ tosend.append(m.mail)
2995+ if len(tosend) == 0:
2996+ tosend.append(self.adr)
2997+ return tosend
2998+
2999+class Mail_test():
3000+ """ class to test mail settings"""
3001+ def __init__(self,specto,tmp_smtp,tmp_log,tmp_pass,tmp_mail,tmp_tls):
3002+ self.specto_adr = "specto@mail.com"
3003+ self.adr = tmp_mail
3004+
3005+ self.msg = MIMEMultipart('alternative')
3006+ self.msg['Subject'] = "Message de test"
3007+ self.msg['From'] = self.specto_adr
3008+ self.msg['To'] = self.adr
3009+ self.specto = specto
3010+ self.error_message = "Un message de test a été envoyé sur votre adresse"
3011+
3012+ self.smtp = tmp_smtp
3013+ self.User = tmp_log
3014+ self.Password = tmp_pass
3015+ self.tls = tmp_tls
3016+
3017+ def test_settings(self):
3018+ """ method to test mail settings """
3019+ text = "Bonjour,\nSi vous voyez ce message c'est que vos paramètres sont bien configurés\n Enjoy!"
3020+ html = """\
3021+ <html>
3022+ <head></head>
3023+ <body>
3024+ <p>Bonjour,<br><br>
3025+ Si vous voyez ce message c'est que vos paramètres sont bien configurés\n<br><br>
3026+ Enjoy !
3027+ </p>
3028+ </body>
3029+ </html>
3030+ """
3031+
3032+ part1 = MIMEText(text, 'plain')
3033+ part2 = MIMEText(html, 'html')
3034+
3035+ self.msg.attach(part1)
3036+ self.msg.attach(part2)
3037+
3038+ if (self.smtp != ""):
3039+ try:
3040+ self.s = smtplib.SMTP(self.smtp)
3041+ if self.tls == True:
3042+ self.s.ehlo()
3043+ self.s.starttls()
3044+ self.s.ehlo()
3045+ if (self.User != "") and (self.Password != ""):
3046+ self.s.login(self.User, self.Password)
3047+ self.s.sendmail(self.specto_adr, self.adr, self.msg.as_string())
3048+ self.s.quit()
3049+ except:
3050+ self.set_error()
3051+
3052+ def set_error(self, message=""):
3053+ self.error_message = _("Unexpected error:")+ str(sys.exc_info()[1])
3054+
3055+ def get_error(self):
3056+ return self.error_message
3057
3058=== added file 'build/lib.linux-i686-2.6/spectlib/import_watch.py'
3059--- build/lib.linux-i686-2.6/spectlib/import_watch.py 1970-01-01 00:00:00 +0000
3060+++ build/lib.linux-i686-2.6/spectlib/import_watch.py 2012-03-14 09:03:18 +0000
3061@@ -0,0 +1,281 @@
3062+# -*- coding: utf-8 -*-
3063+
3064+# Specto , Unobtrusive event notifier
3065+#
3066+# import_export.py
3067+#
3068+# See the AUTHORS file for copyright ownership information
3069+
3070+# This program is free software; you can redistribute it and/or
3071+# modify it under the terms of the GNU General Public
3072+# License as published by the Free Software Foundation; either
3073+# version 2 of the License, or (at your option) any later version.
3074+#
3075+# This program is distributed in the hope that it will be useful,
3076+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3077+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3078+# General Public License for more details.
3079+#
3080+# You should have received a copy of the GNU General Public
3081+# License along with this program; if not, write to the
3082+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
3083+# Boston, MA 02111-1307, USA.
3084+
3085+import os
3086+from spectlib.watch import Watch_io
3087+from spectlib.watch import Watch_collection
3088+from spectlib.gtkconfig import OpenDialog
3089+
3090+try:
3091+ import pygtk
3092+ pygtk.require("2.0")
3093+except:
3094+ pass
3095+
3096+try:
3097+ import gtk
3098+ import gobject
3099+except:
3100+ pass
3101+
3102+
3103+class Import_watch:
3104+ """
3105+ Class to create the import/export watch dialog.
3106+ """
3107+
3108+ def __init__(self, specto, notifier):
3109+ self.specto = specto
3110+ self.notifier = notifier
3111+
3112+ self.import_open_dialog = ImportOpenDialog(self.specto, self, None)
3113+ response = self.import_open_dialog.run()
3114+ if response == gtk.RESPONSE_OK:
3115+ self.import_open_dialog.open()
3116+ else:
3117+ self.import_open_dialog.cancel()
3118+
3119+ def create_import_window(self):
3120+ #create tree
3121+ uifile = os.path.join(self.specto.PATH, "uis/import_export.ui")
3122+ windowname = "import_export"
3123+ self.builder = gtk.Builder()
3124+ self.builder.set_translation_domain("specto")
3125+ self.builder.add_from_file(uifile)
3126+ self.import_watch = self.builder.get_object("import_export")
3127+
3128+ self.import_watch.set_title(_("Import watches"))
3129+ self.builder.get_object("button_action").set_label(_("Import watches"))
3130+
3131+ self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)
3132+ self.new_watch_db = {}
3133+
3134+ #catch some events
3135+ dic = {"on_button_select_all_clicked": self.select_all,
3136+ "on_button_deselect_all_clicked": self.deselect_all,
3137+ "on_button_action_clicked": self.import_watches,
3138+ "on_button_close_clicked": self.delete_event}
3139+
3140+ #attach the events
3141+ self.builder.connect_signals(dic)
3142+
3143+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
3144+ self.import_watch.set_icon(icon)
3145+
3146+ self.treeview = self.builder.get_object("treeview")
3147+ self.treeview.set_model(self.model)
3148+ self.treeview.set_flags(gtk.TREE_MODEL_ITERS_PERSIST)
3149+ self.iter = {}
3150+
3151+ ### Checkbox
3152+ self.renderer = gtk.CellRendererToggle()
3153+ self.renderer.set_property("activatable", True)
3154+ self.renderer.connect("toggled", self.check_clicked, self.model)
3155+ self.columnCheck = gtk.TreeViewColumn(_("Select"), self.renderer, active=0)
3156+ self.treeview.append_column(self.columnCheck)
3157+
3158+ ### Icon
3159+ self.renderer = gtk.CellRendererPixbuf()
3160+ self.columnIcon = gtk.TreeViewColumn(_("Type"), self.renderer, pixbuf=1)
3161+ self.treeview.append_column(self.columnIcon)
3162+
3163+ ### Titre
3164+ self.renderer = gtk.CellRendererText()
3165+ self.columnTitel = gtk.TreeViewColumn(_("Name"), self.renderer, markup=2)
3166+ self.columnTitel.set_expand(True)
3167+ self.columnTitel.set_resizable(True)
3168+ self.treeview.append_column(self.columnTitel)
3169+
3170+ ### ID
3171+ self.renderer = gtk.CellRendererText()
3172+ self.column = gtk.TreeViewColumn(_("ID"), self.renderer, markup=3)
3173+ self.column.set_visible(False)
3174+ #self.column.set_sort_column_id(3)
3175+ self.treeview.append_column(self.column)
3176+
3177+ ### type
3178+ self.renderer = gtk.CellRendererText()
3179+ self.columnType = gtk.TreeViewColumn(_("TYPE"), self.renderer, markup=4)
3180+ self.columnType.set_visible(False)
3181+ #self.columnType.set_sort_column_id(4)
3182+ self.treeview.append_column(self.columnType)
3183+
3184+ def select_all(self, widget):
3185+ db = self.new_watch_db
3186+ for watch in db:
3187+ if watch.deleted == False:
3188+ self.model.set_value(self.iter[watch.id], 0, 1)
3189+
3190+ def deselect_all(self, widget):
3191+ db = self.new_watch_db
3192+ for watch in db:
3193+ if watch.deleted == False:
3194+ self.model.set_value(self.iter[watch.id], 0, 0)
3195+
3196+ def import_watches(self, widget):
3197+ self.import_watch.hide_all()
3198+
3199+ watches = self.get_selected_watches()
3200+ all_values = {}
3201+ for i in watches:
3202+ values = {}
3203+ watch = self.new_watch_db[watches[i].id]
3204+ values.update(self.new_watch_db[watches[i].id].get_values())
3205+
3206+ values['name'] = watch.name
3207+ if self.specto.watch_io.is_unique_watch(values['name']):
3208+ y = 1
3209+ while self.specto.watch_io.is_unique_watch(values['name'] + str(y)):
3210+ y += 1
3211+ values['name'] = values['name'] + str(y)
3212+
3213+ values['type'] = watch.type
3214+ values['refresh'] = watch.refresh
3215+ values['active'] = True
3216+ values['last_changed'] = watch.last_changed
3217+ values['changed'] = False
3218+ all_values[i] = values
3219+ _id = self.specto.watch_db.create(all_values)
3220+
3221+ for values in all_values.values():
3222+ self.specto.watch_io.write_watch(values)
3223+
3224+ for id in _id: # Create notifier entries
3225+ self.specto.notifier.add_notifier_entry(id)
3226+
3227+ for id in _id: # Start the new watches
3228+ self.specto.watch_db[id].start()
3229+
3230+ def delete_event(self, widget, *args):
3231+ """ Destroy the window. """
3232+ self.import_watch.destroy()
3233+ return True
3234+
3235+ def get_selected_watches(self):
3236+ selected_watches_db = {}
3237+ i = 0
3238+ watch_db = self.new_watch_db
3239+ for watch in watch_db:
3240+ if watch.deleted == False:
3241+ if self.model.get_value(self.iter[watch.id], 0) == True:
3242+ selected_watches_db[i] = watch
3243+ i += 1
3244+ return selected_watches_db
3245+
3246+ def add_watch_entry(self, id):
3247+ """ Add an entry to the notifier list. """
3248+ watch = self.new_watch_db[id]
3249+ entry_name = watch.name.replace("&", "&amp;")
3250+ icon = self.notifier.get_icon(watch.icon, 50, False)
3251+ self.iter[id] = self.model.insert_before(None, None)
3252+ self.model.set_value(self.iter[id], 0, 0)
3253+ self.model.set_value(self.iter[id], 1, icon)#self.specto.notifier.make_transparent(icon, 50))#does not need transparency here
3254+ self.model.set_value(self.iter[id], 2, entry_name)
3255+ self.model.set_value(self.iter[id], 3, watch.id)
3256+ self.model.set_value(self.iter[id], 4, watch.type)
3257+
3258+ def set_new_watch_db(self, watch_db):
3259+ self.new_watch_db = watch_db
3260+
3261+ def check_clicked(self, object, path, model):
3262+ """ Call the main function to start/stop the selected watch. """
3263+ sel = self.treeview.get_selection()
3264+ sel.select_path(path)
3265+ model, iter = self.treeview.get_selection().get_selected()
3266+
3267+ if model.get_value(iter, 0):
3268+ model.set_value(iter, 0, 0)
3269+ else:
3270+ model.set_value(iter, 0, 1)
3271+
3272+
3273+class ImportOpenDialog(OpenDialog):
3274+ """
3275+ Class for displaying the open dialog.
3276+ """
3277+
3278+ def __init__(self, specto, _import, watches_db):
3279+ OpenDialog.__init__(self, specto)
3280+ self.specto = specto
3281+ self._import = _import
3282+ windowname = "import_file_chooser"
3283+
3284+ def open(self, *args):
3285+ """ Save the file. """
3286+ self.hide_all()
3287+ self._import.create_import_window()
3288+ file_name = self.get_filename()
3289+ self.read_options(file_name)
3290+ self._import.import_watch.show()
3291+ self.destroy()
3292+
3293+ def read_options(self, file_name):
3294+ watch_io = Watch_io(self.specto, file_name)
3295+ if watch_io.valid == False:
3296+ return False
3297+
3298+ values = watch_io.read_all_watches()
3299+ for i in values:
3300+ try:
3301+ int(values[i]['type'])
3302+ except:
3303+ pass
3304+ else:
3305+ values[i]['open_command'] = ""
3306+ values[i]['last_changed'] = ""
3307+
3308+ # Import from Specto 0.2
3309+ # FIXME: wouldn't this code be more efficient with a case/switch?
3310+ if values[i]['type'] == "0":
3311+ values[i]['type'] = "Watch_web_static"
3312+ elif values[i]['type'] == "1":
3313+ if values[i]['prot'] == "0":
3314+ values[i]['type'] = "Watch_mail_pop3"
3315+ if values[i]['prot'] == "1":
3316+ values[i]['type'] = "Watch_mail_imap"
3317+ if values[i]['prot'] == "2":
3318+ values[i]['type'] = "Watch_mail_gmail"
3319+ del values[i]['prot']
3320+ elif values[i]['type'] == "2":
3321+ if values[i]['mode'] == "file":
3322+ values[i]['type'] = "Watch_system_file"
3323+ else:
3324+ values[i]['type'] = "Watch_system_folder"
3325+ del values[i]['mode']
3326+ elif values[i]['type'] == "3":
3327+ values[i]['type'] = "Watch_system_process"
3328+ elif values[i]['type'] == "4":
3329+ values[i]['type'] = "Watch_system_port"
3330+ elif values[i]['type'] == "5":
3331+ values[i]['type'] = "Watch_web_greader"
3332+ watch_collection = Watch_collection(self.specto)
3333+ watch_collection.create(values)
3334+ self._import.set_new_watch_db(watch_collection)
3335+ for watch in watch_collection:
3336+ self._import.add_watch_entry(watch.id)
3337+
3338+
3339+if __name__ == "__main__":
3340+ # Run the gui
3341+ app = Import_watch()
3342+ gtk.main()
3343
3344=== added file 'build/lib.linux-i686-2.6/spectlib/logger.py'
3345--- build/lib.linux-i686-2.6/spectlib/logger.py 1970-01-01 00:00:00 +0000
3346+++ build/lib.linux-i686-2.6/spectlib/logger.py 2012-03-14 09:03:18 +0000
3347@@ -0,0 +1,344 @@
3348+# -*- coding: utf-8 -*-
3349+
3350+# Specto , Unobtrusive event notifier
3351+#
3352+# logger.py
3353+#
3354+# See the AUTHORS file for copyright ownership information
3355+
3356+# This program is free software; you can redistribute it and/or
3357+# modify it under the terms of the GNU General Public
3358+# License as published by the Free Software Foundation; either
3359+# version 2 of the License, or (at your option) any later version.
3360+#
3361+# This program is distributed in the hope that it will be useful,
3362+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3363+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3364+# General Public License for more details.
3365+#
3366+# You should have received a copy of the GNU General Public
3367+# License along with this program; if not, write to the
3368+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
3369+# Boston, MA 02111-1307, USA.
3370+import logging
3371+import sys
3372+import os
3373+import re
3374+from datetime import datetime
3375+import traceback
3376+import shutil
3377+
3378+try:
3379+ import pygtk
3380+ pygtk.require("2.0")
3381+except:
3382+ pass
3383+
3384+try:
3385+ import gtk
3386+except:
3387+ pass
3388+
3389+from spectlib.gtkconfig import SaveDialog
3390+
3391+
3392+class Log_dialog:
3393+ """
3394+ Class to create the log dialog window.
3395+ """
3396+
3397+ def __init__(self, specto, notifier):
3398+ self.specto = specto
3399+ self.notifier = notifier
3400+ #create tree
3401+ uifile = os.path.join(self.specto.PATH, "uis/log_dialog.ui")
3402+ windowname = "log_dialog"
3403+ self.builder = gtk.Builder()
3404+ self.builder.set_translation_domain("specto")
3405+ self.builder.add_from_file(uifile)
3406+
3407+ dic = {"on_button_help_clicked": self.show_help,
3408+ "on_button_save_clicked": self.save,
3409+ "on_button_clear_clicked": self.clear,
3410+ "on_button_close_clicked": self.delete_event,
3411+ "on_button_find_clicked": self.find}
3412+
3413+ #attach the events
3414+ self.builder.connect_signals(dic)
3415+
3416+ self.log_dialog = self.builder.get_object("log_dialog")
3417+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.png"))
3418+ self.log_dialog.set_icon(icon)
3419+
3420+ self.builder.get_object("combo_level").set_active(0)
3421+
3422+ #read the log file
3423+ self.read_log()
3424+
3425+ self.logwindow = gtk.TextBuffer(None)
3426+ self.log_buffer = self.builder.get_object("log_field").get_buffer()
3427+ self.log_buffer.create_tag("ERROR", foreground="#a40000")
3428+ self.log_buffer.create_tag("INFO", foreground="#4e9a06")
3429+ self.log_buffer.create_tag("WARNING", foreground="#c4a000")
3430+ self.log_buffer.create_tag("DEBUG", foreground="#815902")
3431+ self.log_buffer.create_tag("CRITICAL", foreground="#2e3436")
3432+
3433+ start = self.log_buffer.get_start_iter()
3434+ end = self.log_buffer.get_end_iter()
3435+ self.log_buffer.delete(start, end)
3436+
3437+ iter = self.log_buffer.get_iter_at_offset(0)
3438+ self.log = self.log.split("\n")
3439+ for line in self.log:
3440+ if line != "":
3441+ tag = line.split(" - ")[1].strip()
3442+ self.log_buffer.insert_with_tags_by_name(iter, \
3443+ line + "\n", tag)
3444+
3445+ def save(self, widget):
3446+ """ Save the text in the logwindow. """
3447+ text = self.log_buffer.get_text(self.log_buffer.get_start_iter(), \
3448+ self.log_buffer.get_end_iter())
3449+ logger_save_dialog = LoggerSaveDialog(self.specto, text)
3450+ response = logger_save_dialog.run()
3451+ if response == gtk.RESPONSE_OK:
3452+ logger_save_dialog.save()
3453+ else:
3454+ logger_save_dialog.cancel()
3455+
3456+
3457+ def clear(self, widget):
3458+ """ Clear the text in the log window and from the log file. """
3459+ start = self.log_buffer.get_start_iter()
3460+ end = self.log_buffer.get_end_iter()
3461+ self.log_buffer.delete(start, end)
3462+ f = open(self.file_name, "w")
3463+ f.write("")
3464+ f.close()
3465+ os.chmod(self.file_name, 0600)
3466+
3467+ def find(self, widget):
3468+ """ Find the lines in the log file that contain the filter word. """
3469+ self.read_log()
3470+ level = self.builder.get_object("combo_level").get_active()
3471+ buffer_log = self.log.split("\n")
3472+ filtered_log = ""
3473+
3474+ if level == 1:
3475+ pattern = ("DEBUG")
3476+ elif level == 2:
3477+ pattern = ("INFO")
3478+ elif level == 3:
3479+ pattern = ("WARNING")
3480+ elif level == 4:
3481+ pattern = ("ERROR")
3482+ elif level == 5:
3483+ pattern = ("CRITICAL")
3484+ elif level == -1:
3485+ pattern = self.builder.get_object("combo_level").child.get_text()
3486+
3487+ start = self.log_buffer.get_start_iter()
3488+ end = self.log_buffer.get_end_iter()
3489+ self.log_buffer.delete(start, end)
3490+ iter = self.log_buffer.get_iter_at_offset(0)
3491+
3492+ if level == 0: # Show everything
3493+ for line in buffer_log:
3494+ if line: # If the line is not empty
3495+ tag = line.split(" - ")[1].strip()
3496+ self.log_buffer.insert_with_tags_by_name(iter, \
3497+ line + "\n", tag)
3498+ else: # Show the filtered log
3499+ # Do the filtering
3500+ for i in buffer_log:
3501+ if re.search(pattern, i, re.IGNORECASE):
3502+ filtered_log += i + "\n"
3503+ filtered_log = filtered_log.split("\n")
3504+ for line in filtered_log:
3505+ if line: # If the line is not empty
3506+ tag = line.split(" - ")[1].strip()
3507+ self.log_buffer.insert_with_tags_by_name(iter, \
3508+ line + "\n", tag)
3509+
3510+ def read_log(self):
3511+ """ Read the log file. """
3512+ self.file_name = self.specto.SPECTO_DIR + "/specto.log"
3513+ if not os.path.exists(self.file_name):
3514+ f = open(self.file_name, "w")
3515+ f.close()
3516+ os.chmod(self.file_name, 0600)
3517+
3518+ log_file = open(self.file_name, "r")
3519+ self.log = log_file.read().replace("&Separator;", " - ")
3520+ log_file.close()
3521+
3522+ def show_help(self, widget):
3523+ """ Show the help webpage. """
3524+ self.specto.util.show_webpage(\
3525+ "http://code.google.com/p/specto/wiki/Troubleshooting")
3526+
3527+ def delete_event(self, widget, *args):
3528+ """ Close the window. """
3529+ self.log_dialog.destroy()
3530+ return True
3531+
3532+
3533+class LoggerSaveDialog(SaveDialog):
3534+ """
3535+ Class for displaying the save as dialog.
3536+ """
3537+
3538+ def __init__(self, specto, *args):
3539+ SaveDialog.__init__(self, specto)
3540+ windowname = "logger_file_chooser"
3541+
3542+ self.text = args[0]
3543+
3544+ def save(self, *args):
3545+ """ Save the file. """
3546+ file_name = self.get_filename()
3547+
3548+ if not os.path.exists(file_name):
3549+ f = open(file_name, "w")
3550+ f.close()
3551+ os.chmod(file_name, 0600)
3552+
3553+ f = open(file_name, "w")
3554+ f.write(self.text)
3555+ f.close()
3556+
3557+ self.destroy()
3558+
3559+
3560+class Logger:
3561+ """
3562+ Class for logging in Specto.
3563+ """
3564+
3565+ def __init__(self, specto):
3566+ self.specto = specto
3567+ self.file_name = self.specto.SPECTO_DIR + "/specto.log"
3568+
3569+ if not os.path.exists(self.file_name):
3570+ f = open(self.file_name, "a")
3571+ f.close()
3572+ os.chmod(self.file_name, 0600)
3573+
3574+ self.error_file = self.specto.SPECTO_DIR + "/error.log"
3575+ if not os.path.exists(self.error_file):
3576+ f = open(self.error_file, "a")
3577+ f.close()
3578+ os.chmod(self.error_file, 0600)
3579+
3580+ self.log_rotation()
3581+
3582+ #write to log file
3583+ #TODO:XXX: Do we need to gettextize it? Maybe just the date.
3584+ logging.basicConfig(level=logging.INFO,
3585+ format='%(asctime)s &Separator; %(levelname)s &Separator;' \
3586+ + ' %(name)s &Separator; %(message)s',
3587+ datefmt='%Y-%m-%d %H:%M:%S',
3588+ filename=self.file_name,
3589+ filemode='a')
3590+
3591+ #write to console
3592+ console = logging.StreamHandler()
3593+ console.setLevel(logging.DEBUG)
3594+
3595+ formatter = logging.Formatter('%(levelname)s - %(name)s - %(message)s')
3596+ #formatter = logging.Formatter('%(levelname)s - %(message)s')
3597+ console.setFormatter(formatter)
3598+ logging.getLogger('').addHandler(console)
3599+
3600+ def log(self, message, level, logger):
3601+ """ Log a message. """
3602+ log = logging.getLogger(str(logger))
3603+
3604+ if self.specto.DEBUG == True:
3605+ if level == "debug":
3606+ log.debug(message)
3607+ elif level == "info":
3608+ log.info(message)
3609+ elif level == "warning":
3610+ log.warn(message)
3611+ elif level == "error":
3612+ log.error(message)
3613+ self.log_error()
3614+ else:
3615+ log.critical(message)
3616+ self.log_error()
3617+
3618+ def read_log(self):
3619+ """ Read the log file. """
3620+ #get the info from the log file
3621+ log_file = open(self.file_name, "r")
3622+ self.logfile = log_file.read()
3623+ self.logfile.replace("&Separator;", " - ")
3624+ log_file.close()
3625+
3626+ def watch_log(self, watch_name):
3627+ """ Filter the log for a watch name. """
3628+ self.read_log()
3629+ buffer_log = self.logfile.split("\n")
3630+ filtered_log = []
3631+
3632+ for line in buffer_log:
3633+ if line != "" and line.split("&Separator;")[2].strip() == \
3634+ watch_name:
3635+ info = line.split("&Separator;")
3636+ filtered_log.append([info[1].strip(), info[0] + " - " \
3637+ + info[3] + "\n"])
3638+ return filtered_log
3639+
3640+ def remove_watch_log(self, watch_name):
3641+ """ Remove a watch from the log file. """
3642+ self.read_log()
3643+ buffer_log = self.logfile.split("\n")
3644+ filtered_log = ""
3645+
3646+ for i in buffer_log:
3647+ if not re.search(watch_name, i) and i != "":
3648+ filtered_log += i + "\n"
3649+
3650+ f = open(self.file_name, "w")
3651+ f.write(filtered_log)
3652+ f.close()
3653+
3654+ def clear_log(self, *args):
3655+ """ Clear the log file. """
3656+ f = open(self.file_name, "w")
3657+ f.write("")
3658+ f.close()
3659+ os.chmod(self.file_name, 0600)
3660+
3661+ def log_error(self):
3662+ error_message = "Error on: " + \
3663+ datetime.today().strftime("%A %d %b %Y %H:%M") + "\n"
3664+
3665+ et, ev, tb = sys.exc_info()
3666+ while tb:
3667+ co = tb.tb_frame.f_code
3668+ error_message += "Filename: " + str(co.co_filename) + "\n"
3669+ error_message += "Error Line # : " \
3670+ + str(traceback.tb_lineno(tb)) + "\n"
3671+ tb = tb.tb_next
3672+
3673+ error_message += "Type: " + str(et) + "\n" + "Error: " + \
3674+ str(ev) + "\n\n"
3675+
3676+ f = open(self.error_file, "a")
3677+ f.write(error_message)
3678+ f.close()
3679+
3680+ def log_rotation(self):
3681+ if os.path.getsize(self.file_name) > 150000:
3682+ shutil.move(self.file_name, self.file_name + ".1")
3683+ f = open(self.file_name, "a")
3684+ f.close()
3685+ os.chmod(self.file_name, 0600)
3686+
3687+ if os.path.getsize(self.error_file) > 150000:
3688+ shutil.move(self.error_file, self.error_file + ".1")
3689+ f = open(self.error_file, "a")
3690+ f.close()
3691+ os.chmod(self.error_file, 0600)
3692
3693=== added file 'build/lib.linux-i686-2.6/spectlib/main.py'
3694--- build/lib.linux-i686-2.6/spectlib/main.py 1970-01-01 00:00:00 +0000
3695+++ build/lib.linux-i686-2.6/spectlib/main.py 2012-03-14 09:03:18 +0000
3696@@ -0,0 +1,417 @@
3697+# -*- coding: utf-8 -*-
3698+
3699+# Specto , Unobtrusive event notifier
3700+#
3701+# main.py
3702+#
3703+# See the AUTHORS file for copyright ownership information
3704+
3705+# This program is free software; you can redistribute it and/or
3706+# modify it under the terms of the GNU General Public
3707+# License as published by the Free Software Foundation; either
3708+# version 2 of the License, or (at your option) any later version.
3709+#
3710+# This program is distributed in the hope that it will be useful,
3711+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3712+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3713+# General Public License for more details.
3714+#
3715+# You should have received a copy of the GNU General Public
3716+# License along with this program; if not, write to the
3717+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
3718+# Boston, MA 02111-1307, USA.
3719+
3720+# Definition of the watch_db
3721+# watch_db[0] = instance of the first watch
3722+
3723+global GTK
3724+global DEBUG #the DEBUG constant which controls how much info is output
3725+
3726+# Setup locale and gettext
3727+import spectlib.i18n
3728+
3729+import os
3730+import sys
3731+import signal
3732+import gobject
3733+import gettext
3734+
3735+import spectlib.util as util
3736+from spectlib.watch import Watch_collection
3737+from spectlib.watch import Watch_io
3738+from spectlib.console import Console
3739+from spectlib.logger import Logger
3740+from spectlib.tools.specto_gconf import Specto_gconf
3741+from spectlib.tools import networkmanager as conmgr
3742+from spectlib.bdd import Bdd
3743+
3744+
3745+VERSION = "undefined"
3746+try:
3747+ from spectlib.constants import VERSION
3748+except ImportError:
3749+ with open("VERSION", 'r') as version_file:
3750+ VERSION = version_file.read().strip()
3751+
3752+#create a gconf object
3753+specto_gconf = Specto_gconf("/apps/specto")
3754+
3755+DEBUG = specto_gconf.get_entry("debug_mode")
3756+
3757+try:
3758+ import pygtk
3759+ pygtk.require("2.0")
3760+ import gtk
3761+except:
3762+ print _("no GTK, activating console mode")
3763+ GTK = False
3764+else:
3765+ GTK = True
3766+ from spectlib.notifier import Notifier, INDICATOR
3767+
3768+keyring = True
3769+try:
3770+ from spectlib.tools.keyringmanager import Keyring
3771+except:
3772+ keyring = False
3773+
3774+
3775+class Specto:
3776+ """ The main Specto class. """
3777+
3778+ def __init__(self):
3779+ self.DEBUG = DEBUG
3780+ self.util = util
3781+
3782+ self.PATH = self.util.get_path()
3783+ self.SRC_PATH = self.util.get_path("src")
3784+ self.SPECTO_DIR = self.util.get_path("specto")
3785+ self.CACHE_DIR = self.util.get_path("tmp")
3786+ self.FILE = self.util.get_file()
3787+
3788+ self.logger = Logger(self)
3789+
3790+ self.VERSION = VERSION # The Specto version number
3791+
3792+ self.GTK = GTK
3793+
3794+ if not self.check_instance(): #see if specto is already running
3795+ self.specto_gconf = specto_gconf
3796+ self.check_default_settings()
3797+
3798+ self.connection_manager = conmgr.get_net_listener()
3799+ self.use_keyring = self.specto_gconf.get_entry("use_keyring")
3800+
3801+ if self.specto_gconf.get_entry("button_mysql"):
3802+ print "Mysql"
3803+ if self.use_keyring == True and keyring == True:
3804+ try:
3805+ k = Keyring("entry_passwd", "Specto " + "entry_passwd", "network")
3806+ password = k.get_credentials()[1]
3807+ except:
3808+ password = specto_gconf.get_entry("entry_passwd")
3809+
3810+ datas = {"type":"mysql",
3811+ "user":self.specto_gconf.get_entry("entry_username"),
3812+ "pass":password,
3813+ "host":self.specto_gconf.get_entry("entry_server"),
3814+ "port":self.specto_gconf.get_entry("entry_port"),
3815+ "name":self.specto_gconf.get_entry("entry_database")}
3816+ else:
3817+ print "sql lite"
3818+ datas = {"type":"sqlite",
3819+ "directory":"ici.db"}
3820+ self.base = Bdd(**datas)
3821+
3822+ #create the watch collection and add the watches
3823+ self.watch_db = Watch_collection(self)
3824+ self.watch_io = Watch_io(self, self.FILE)
3825+
3826+ if (sys.argv[1:] and "--console" in sys.argv[1:][0]) or not self.GTK:
3827+ self.logger.log(_("Console mode enabled."), "debug", "specto")
3828+ self.GTK = False
3829+ self.CONSOLE = True
3830+ try:
3831+ args = sys.argv[1:][1]
3832+ except:
3833+ args = ""
3834+ self.console = Console(self, args)
3835+
3836+ elif self.GTK:
3837+ self.GTK = True
3838+ self.CONSOLE = False
3839+ self.icon_theme = gtk.icon_theme_get_default()
3840+
3841+ #allow users to hide the window on startup
3842+ if sys.argv[1:] and "--no-window" in sys.argv[1:][0]:
3843+ self.notifier_hide = True
3844+ #always show if there's no icon and no indicator support
3845+ elif self.specto_gconf.get_entry("always_show_icon") == False and not INDICATOR:
3846+ self.notifier_hide = False
3847+ elif self.specto_gconf.get_entry("show_notifier")==True:
3848+ self.notifier_hide = False
3849+ elif self.specto_gconf.get_entry("show_notifier")==False:
3850+ self.notifier_hide = True
3851+ else:#just in case the entry was never created in gconf
3852+ self.notifier_keep_hidden = False
3853+
3854+ self.notifier = Notifier(self)
3855+ else:
3856+ sys.exit(0)
3857+
3858+ #listen for gconf keys
3859+ self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug")
3860+
3861+ values = self.watch_io.read_all_watches(True)
3862+ try:
3863+ self.watch_db.create(values)
3864+ except AttributeError, error_fields:
3865+ self.logger.log(_("Could not create a watch, because it is corrupt."), \
3866+ "critical", "specto")
3867+
3868+
3869+ if self.GTK:
3870+ for watch in self.watch_db:
3871+ self.notifier.add_notifier_entry(watch.id)
3872+
3873+ # Listen for USR1. If received, answer and show the window
3874+ def listen_for_USR1(signum, frame):
3875+ f = open(self.SPECTO_DIR + "/" + "specto.pid.boot")
3876+ pid = int(f.readline())
3877+ f.close()
3878+ os.kill(pid, signal.SIGUSR1)
3879+ # If window was not shown, make it appear
3880+ if not self.notifier.get_state():
3881+ self.logger.log("Showing window, the user ran another instance of specto", "debug", "specto")
3882+ self.toggle_notifier()
3883+ else:
3884+ # Based on http://www.pygtk.org/docs/pygtk/class-gtkwindow.html#method-gtkwindow--present
3885+ self.logger.log("Window is already visible! Raising it to the front.", "debug", "specto")
3886+ self.notifier.notifier.present()
3887+
3888+ signal.signal(signal.SIGUSR1, listen_for_USR1)
3889+
3890+ self.notifier.refresh_all_watches()
3891+ else:
3892+ self.console.start_watches()
3893+
3894+ if self.GTK:
3895+ gtk.main()
3896+ else:
3897+ try:
3898+ self.go = gobject.MainLoop()
3899+ self.go.run()
3900+ except (KeyboardInterrupt, SystemExit):
3901+ sys.exit(0)
3902+
3903+ def key_changed(self, *args):
3904+ """ Listen for gconf keys. """
3905+ label = args[3]
3906+
3907+ if label == "debug":
3908+ self.DEBUG = self.specto_gconf.get_entry("debug_mode")
3909+
3910+ def check_default_settings(self):
3911+ """ This is used to set the default settings
3912+ properly the first time Specto is run,
3913+ without using gconf schemas """
3914+ #check if the ekiga sounds exists
3915+ if os.path.exists("/usr/share/sounds/ekiga/voicemail.wav"):
3916+ changed_sound = "/usr/share/sounds/ekiga/voicemail.wav"
3917+ else:
3918+ changed_sound = ""
3919+
3920+ self.default_settings = (
3921+ ["always_show_icon", False], #True would be against the HIG!
3922+ ["debug_mode", False],
3923+ ["follow_website_redirects", True],
3924+ ["pop_toast", True],
3925+ ["show_deactivated_watches", True],
3926+ ["show_in_windowlist", True],
3927+ ["show_notifier", True],
3928+ ["show_toolbar", True],
3929+ ["sort_function", "name"],
3930+ ["sort_order", "asc"],
3931+ ["changed_sound", changed_sound],
3932+ ["use_changed_sound", False],
3933+ ["window_notifier_height", 500],
3934+ ["window_notifier_width", 500],
3935+ ["use_keyring", True])
3936+ for default_setting in self.default_settings:
3937+ if self.specto_gconf.get_entry(default_setting[0]) == None:
3938+ self.specto_gconf.set_entry(default_setting[0], \
3939+ default_setting[1])
3940+
3941+ def check_instance(self):
3942+ """ Check if specto is already running. """
3943+ pidfile = self.SPECTO_DIR + "/" + "specto.pid"
3944+ if not os.path.exists(pidfile):
3945+ f = open(pidfile, "w")
3946+ f.close()
3947+ os.chmod(pidfile, 0600)
3948+
3949+ #see if specto is already running
3950+ with open(pidfile, "r") as f:
3951+ pid = f.readline()
3952+ if pid:
3953+ p = os.system("ps --no-heading --pid " + pid)
3954+ p_name = os.popen("ps -f --pid " + pid).read()
3955+ if p == 0 and "specto" in p_name:
3956+ if self.GTK:
3957+ # Save our pid and prepare a 'pong' system
3958+ f = open(pidfile + ".boot", "w")
3959+ f.write(str(os.getpid()))
3960+ f.close()
3961+
3962+ def not_responding(signum, frame):
3963+ """ Launch the already running dialog if the
3964+ other instance doesn't respond """
3965+ os.unlink(pidfile + ".boot")
3966+ self.already_running_dialog()
3967+
3968+ def response_received(signum, frame):
3969+ """ Kill this specto if the other one answers """
3970+ signal.alarm(0)
3971+ os.unlink(pidfile + ".boot")
3972+ self.logger.log("Specto is already running! The old instance will be brought to front.", "debug", "specto")
3973+ sys.exit(0)
3974+
3975+ signal.signal(signal.SIGALRM, not_responding)
3976+ signal.signal(signal.SIGUSR1, response_received)
3977+ signal.alarm(5)
3978+
3979+ # Send signal to raise window
3980+ os.kill(int(pid), signal.SIGUSR1)
3981+
3982+ # Wait for signals
3983+ signal.pause()
3984+
3985+ return True
3986+ elif DEBUG:
3987+ self.logger.log(_("Specto is already running!"), "critical", "specto")
3988+ sys.exit(0)
3989+ else:
3990+ print _("Specto is already running!")
3991+ sys.exit(0)
3992+
3993+ #write the pid file
3994+ with open(pidfile, "w") as f:
3995+ f.write(str(os.getpid()))
3996+
3997+ def mark_watch_status(self, status, id):
3998+ """ get the watch status (checking, changed, idle) """
3999+ if self.GTK:
4000+ self.notifier.mark_watch_status(status, id)
4001+ elif self.CONSOLE:
4002+ self.console.mark_watch_status(status, id)
4003+
4004+ def toggle_notifier(self, *args):
4005+ """
4006+ Toggle the state of the notifier, hidden or shown.
4007+ It will save the size, position,
4008+ and the last state when you closed Specto.
4009+ """
4010+ #Creating the notifier window, but keeping it hidden
4011+ if self.notifier.get_state() == True and not self.notifier_hide:
4012+ self.specto_gconf.set_entry("show_notifier", True)
4013+ self.notifier.restore_size_and_position()
4014+ self.notifier.notifier.show()
4015+ self.notifier_hide = True
4016+ elif self.notifier.get_state()==True and self.notifier_hide:
4017+ self.notifier.save_size_and_position()
4018+ self.specto_gconf.set_entry("show_notifier", False)
4019+ self.notifier.notifier.hide()
4020+ self.notifier_hide = False
4021+ else:
4022+ self.specto_gconf.set_entry("show_notifier", True)
4023+ self.notifier.restore_size_and_position()
4024+ self.notifier.notifier.show()
4025+ self.notifier_hide = True
4026+
4027+ def quit(self, *args):
4028+ """ Save the save and position from the notifier and quit Specto. """
4029+ if self.notifier.get_state() == True and self.notifier_hide:
4030+ self.notifier.save_size_and_position()
4031+ try:
4032+ gtk.main_quit()
4033+ except:
4034+ #create a close dialog
4035+ self.dialog = gtk.Dialog(_("Cannot quit yet"), None, gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None)
4036+ self.dialog.set_modal(False) # Needed to prevent the notifier UI and refresh process from blocking. Also, do not use dialog.run(), because it automatically sets modal to true.
4037+
4038+ #HIG tricks
4039+ self.dialog.set_has_separator(False)
4040+
4041+ self.dialog.add_button(_("Murder!"), 3)
4042+ self.dialog.add_button(gtk.STOCK_CANCEL, -1)
4043+
4044+ self.dialog.label_hbox = gtk.HBox(spacing=6)
4045+
4046+ icon = gtk.Image()
4047+ icon.set_from_pixbuf(self.icon_theme.\
4048+ load_icon("dialog-warning", 64, 0))
4049+ self.dialog.label_hbox.pack_start(icon, True, True, 6)
4050+ icon.show()
4051+
4052+ label = gtk.Label(_('<b><big>Specto is currently busy and cannot quit yet.</big></b>\n\nThis may be because it is checking for watch changes.\nHowever, you can try forcing it to quit by clicking the murder button.'))
4053+ label.set_use_markup(True)
4054+ self.dialog.label_hbox.pack_start(label, True, True, 6)
4055+ label.show()
4056+
4057+ self.dialog.vbox.pack_start(self.dialog.label_hbox, True, True, 12)
4058+ self.dialog.label_hbox.show()
4059+
4060+ icon = gtk.gdk.pixbuf_new_from_file(self.PATH + \
4061+ 'icons/specto_window_icon.svg')
4062+ self.dialog.set_icon(icon)
4063+ self.dialog.connect("delete_event", self.quit_dialog_response)
4064+ self.dialog.connect("response", self.quit_dialog_response)
4065+ self.dialog.show_all()
4066+
4067+ def quit_dialog_response(self, widget, answer):
4068+ if answer == 3:
4069+ try:#go figure, it never works!
4070+ self.notifier.stop_refresh = True
4071+ sys.exit(0)
4072+ except:
4073+ #kill the specto process with killall
4074+ os.system('killall specto')
4075+ else:
4076+ self.dialog.hide()
4077+
4078+ def already_running_dialog(self, *args):
4079+ """ Save the save and position from the notifier and quit Specto. """
4080+ #create a dialog
4081+ self.dialog = gtk.Dialog(_("Error"), None, gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None)
4082+ self.dialog.set_modal(False) # Needed to prevent the notifier UI and refresh process from blocking. Also, do not use dialog.run(), because it automatically sets modal to true.
4083+
4084+ #HIG tricks
4085+ self.dialog.set_has_separator(False)
4086+
4087+ #self.dialog.add_button(_("Murder!"), 3)
4088+ self.dialog.add_button(gtk.STOCK_OK, 3)
4089+
4090+ self.dialog.label_hbox = gtk.HBox(spacing=6)
4091+
4092+ icon = gtk.Image()
4093+ icon.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG)
4094+ self.dialog.label_hbox.pack_start(icon, True, True, 6)
4095+ icon.show()
4096+
4097+ label = gtk.Label(_('Specto is already running!'))
4098+ label.set_use_markup(True)
4099+ self.dialog.label_hbox.pack_start(label, True, True, 6)
4100+ label.show()
4101+
4102+ self.dialog.vbox.pack_start(self.dialog.label_hbox, True, True, 12)
4103+ self.dialog.label_hbox.show()
4104+
4105+ icon = gtk.gdk.pixbuf_new_from_file(self.PATH + 'icons/specto_window_icon.svg')
4106+ self.dialog.set_icon(icon)
4107+ self.dialog.connect("delete_event", self.running_dialog_response)
4108+ self.dialog.connect("response", self.running_dialog_response)
4109+ self.dialog.show_all()
4110+
4111+ def running_dialog_response(self, widget, answer):
4112+ if answer == 3:
4113+ sys.exit(0)
4114
4115=== added file 'build/lib.linux-i686-2.6/spectlib/notifier.py'
4116--- build/lib.linux-i686-2.6/spectlib/notifier.py 1970-01-01 00:00:00 +0000
4117+++ build/lib.linux-i686-2.6/spectlib/notifier.py 2012-03-14 09:03:18 +0000
4118@@ -0,0 +1,1080 @@
4119+# -*- coding: utf-8 -*-
4120+
4121+# Specto , Unobtrusive event notifier
4122+#
4123+# notifier.py
4124+#
4125+# See the AUTHORS file for copyright ownership information
4126+
4127+# This program is free software; you can redistribute it and/or
4128+# modify it under the terms of the GNU General Public
4129+# License as published by the Free Software Foundation; either
4130+# version 2 of the License, or (at your option) any later version.
4131+#
4132+# This program is distributed in the hope that it will be useful,
4133+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4134+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4135+# General Public License for more details.
4136+#
4137+# You should have received a copy of the GNU General Public
4138+# License along with this program; if not, write to the
4139+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
4140+# Boston, MA 02111-1307, USA.
4141+
4142+import os
4143+from random import randrange
4144+from datetime import datetime
4145+
4146+from spectlib.contact import Contact
4147+from spectlib.preferences import Preferences
4148+from spectlib.add_watch import Add_watch
4149+from spectlib.about import About
4150+from spectlib.edit_watch import Edit_watch
4151+from spectlib.logger import Log_dialog
4152+from spectlib.balloons import NotificationToast
4153+from spectlib.import_watch import Import_watch
4154+from spectlib.export_watch import Export_watch
4155+from spectlib.trayicon import Tray
4156+from spectlib.crawl import Crawler
4157+
4158+INDICATOR = True
4159+try:
4160+ from spectlib.tools.indicator import Indicator
4161+except:
4162+ INDICATOR = False
4163+
4164+SOUND = True
4165+try:
4166+ from spectlib.tools.sound import Sound
4167+except:
4168+ SOUND = False
4169+
4170+
4171+from spectlib.util import show_webpage
4172+from spectlib.gtkconfig import ErrorDialog, RemoveDialog, create_menu_item
4173+
4174+try:
4175+ import pygtk
4176+ pygtk.require("2.0")
4177+except:
4178+ pass
4179+
4180+try:
4181+ import gtk
4182+ import gobject
4183+ import pango
4184+except:
4185+ pass
4186+
4187+
4188+class Notifier:
4189+ """
4190+ Class to create the main specto window
4191+ """
4192+ add_w = ""
4193+ edit_w = ""
4194+ error_l = ""
4195+ about = ""
4196+ export_watch = ""
4197+ import_watch = ""
4198+
4199+ def __init__(self, specto):
4200+ """
4201+ In this init we are going to display the main notifier window.
4202+ """
4203+ self.specto = specto
4204+ uifile = os.path.join(self.specto.PATH, "uis/notifier.ui")
4205+ windowname = "notifier"
4206+ self.builder = gtk.Builder()
4207+ self.builder.set_translation_domain("specto")
4208+ self.builder.add_from_file(uifile)
4209+ self.notifier = self.builder.get_object("notifier")
4210+ if INDICATOR:
4211+ self.indicator = Indicator(specto)
4212+ self.tray = None
4213+ else:
4214+ self.tray = Tray(specto, self)
4215+ self.indicator = None
4216+ if SOUND:
4217+ self.sound = Sound()
4218+ else:
4219+ self.sound = None
4220+ self.balloon = NotificationToast(specto, self)
4221+ self.preferences_initialized = False
4222+ self.contact_initialized = False
4223+
4224+ #create tree
4225+ self.iter = {}
4226+ self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING, pango.Weight)
4227+
4228+ #catch some events
4229+ dic = {
4230+ "on_add_activate": self.show_add_watch_menu,
4231+ "on_edit_activate": self.show_edit_watch,
4232+ "on_clear_all_activate": self.mark_all_as_read,
4233+ "on_preferences_activate": self.show_preferences,
4234+ "on_contact_activate":self.show_contact,
4235+ "on_refresh_activate": self.refresh_all_watches,
4236+ "on_close_activate": self.close_event,
4237+ "on_quit_activate": self.delete_event,
4238+ "on_import_watches_activate": self.import_watches,
4239+ "on_export_watches_activate": self.export_watches,
4240+ "on_error_log_activate": self.show_error_log,
4241+ "on_display_all_watches_activate": self.toggle_show_deactivated_watches,
4242+ "on_display_toolbar_activate": self.toggle_display_toolbar,
4243+ "on_help_activate": self.show_help,
4244+ "on_about_activate": self.show_about,
4245+ "on_treeview_row_activated": self.open_watch_callback,
4246+ "on_btnOpen_clicked": self.open_watch_callback,
4247+ "on_btnClear_clicked": self.mark_watch_as_read,
4248+ "on_treeview_cursor_changed": self.show_watch_info,
4249+ "on_btnEdit_clicked": self.show_edit_watch,
4250+ "on_by_watch_type_activate": self.sort_type,
4251+ "on_by_name_activate": self.sort_name,
4252+ "on_by_watch_active_activate": self.sort_active,
4253+ "on_remove_clicked": self.remove_watch,
4254+ "on_clear_activate": self._mark_watch_as_read,
4255+ "on_remove_activate": self.remove_watch}
4256+ self.builder.connect_signals(dic)
4257+
4258+ icon = gtk.gdk.pixbuf_new_from_file(os.path.join(self.specto.PATH, "icons/specto_window_icon.svg"))
4259+ self.notifier.set_icon(icon)
4260+ self.specto.notifier_initialized = True
4261+ self.create_notifier_gui()
4262+ self.stop_refresh = False
4263+
4264+ def mark_watch_as_read(self, widget, *id):
4265+ """
4266+ Call the main function to mark the watch as read and reset the name in the notifier.
4267+ If widget == '' then id will be used to mark the watch as read else the selected watch will be marked as read.
4268+ """
4269+ try:
4270+ id = id[0]
4271+ except:
4272+ model, iter = self.treeview.get_selection().get_selected()
4273+ id = int(model.get_value(iter, 3))
4274+ watch = self.specto.watch_db[id]
4275+ watch.mark_as_read()
4276+ self.model.set(self.iter[id], 2, watch.name, 5, pango.WEIGHT_NORMAL)
4277+ if self.model.iter_is_valid(self.iter[id]) and not watch.error:
4278+ self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 50, False))
4279+ if watch.changed == False:
4280+ self.builder.get_object("btnClear").set_sensitive(False)
4281+ else:
4282+ self.builder.get_object("btnClear").set_sensitive(True)
4283+ #check if all watches has been marked as read
4284+ changed_watches = False
4285+ changes = self.specto.watch_db.count_changed_watches()
4286+ for changed in changes.values():
4287+ if changed > 0:
4288+ changed_watches = True
4289+ if changed_watches == False:
4290+ self.builder.get_object("button_clear_all").set_sensitive(False)
4291+
4292+ def mark_all_as_read(self, widget):
4293+ """ Call the main function to mark all watches as read and reset the name in the notifier. """
4294+ self.builder.get_object("btnClear").set_sensitive(False)
4295+ self.builder.get_object("button_clear_all").set_sensitive(False)
4296+ self.builder.get_object("clear_all1").set_sensitive(False)
4297+ for watch in self.specto.watch_db:
4298+ if self.model.iter_is_valid(self.iter[watch.id]):
4299+ self.mark_watch_as_read("", watch.id)
4300+
4301+ def refresh_all_watches(self, *widget):
4302+ """ Call the main funcion to refresh all active watches and change refresh icon to stop. """
4303+ if self.builder.get_object("button_refresh").get_stock_id() == "gtk-refresh":
4304+ self.builder.get_object("button_refresh").set_stock_id("gtk-stop") #menu item, does not allow changing label
4305+ self.builder.get_object("button_refresh").set_label(_("Stop"))
4306+ self.builder.get_object("button_add").set_sensitive(False)
4307+ self.builder.get_object("btnEdit").set_sensitive(False)
4308+ for i in self.iter:
4309+ if self.stop_refresh == True:
4310+ self.stop_refresh = False
4311+ break
4312+ try:
4313+ iter = self.model.get_iter(i)
4314+ if self.model.iter_is_valid(iter):
4315+ model = self.model
4316+ id = int(model.get_value(iter, 3))
4317+ except:
4318+ break
4319+ if self.specto.watch_db[id].active == True:
4320+ try:
4321+ self.specto.watch_db[id].stop()
4322+ except:
4323+ pass
4324+ self.specto.watch_db[id].start()
4325+ self.builder.get_object("button_refresh").set_stock_id("gtk-refresh") #menu item, does not allow changing label
4326+ self.builder.get_object("button_refresh").set_label(_("Refresh All"))
4327+ self.builder.get_object("button_add").set_sensitive(True)
4328+ self.builder.get_object("btnEdit").set_sensitive(True)
4329+ else:
4330+ self.stop_refresh = True
4331+
4332+ def mark_error(self, error_message):
4333+ error_dialog = ErrorDialog(self.specto, error_message)
4334+
4335+ def mark_watch_status(self, status, id):
4336+ """ show the right icon for the status from the watch. """
4337+ watch = self.specto.watch_db[id]
4338+ statusbar = self.builder.get_object("statusbar1")
4339+ icon = self.get_icon("error", 50, False)
4340+
4341+ try:
4342+ if status == "checking":
4343+ icon = self.get_icon("reload", 0, False)
4344+ statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" is checking.') % watch.name))
4345+
4346+ elif status == "idle":
4347+ if self.tray:
4348+ self.tray.show_tooltip() #check if all watches are cleared
4349+ if watch.changed == True:
4350+ self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_BOLD)
4351+ self.builder.get_object("button_clear_all").set_sensitive(True)
4352+ self.builder.get_object("clear_all1").set_sensitive(True)
4353+ icon = self.get_icon(watch.icon, 0, False)
4354+ else:
4355+ self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_NORMAL)
4356+ self.builder.get_object("clear_all1").set_sensitive(False)
4357+ icon = self.get_icon(watch.icon, 50, False)
4358+ statusbar.push(0, "") # As per HIG, make the status bar empty when nothing is happening
4359+
4360+ elif status == "no-network":
4361+ statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The network connection seems to be down, networked watches will not check until then.')))
4362+ if self.tray:
4363+ self.tray.show_tooltip()
4364+ icon = self.get_icon(watch.icon, 50, False)
4365+
4366+ elif status == "error":
4367+ statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" has a problem.') % watch.name))
4368+ balloon_icon = self.get_icon("error", 0, True)
4369+ icon = self.get_icon("error", 50, False)
4370+ if self.specto.specto_gconf.get_entry("pop_toast") == True:
4371+ body = watch.escape(watch.error_message)
4372+ self.balloon.show_toast(body, balloon_icon, urgency="critical", summary=(_("%s encountered a problem") % watch.name))
4373+ if self.specto.specto_gconf.get_entry("use_problem_sound") and self.sound:
4374+ problem_sound = self.specto.specto_gconf.get_entry("problem_sound")
4375+ self.sound.play(problem_sound)
4376+
4377+ elif status == "changed":
4378+ if self.indicator:
4379+ self.indicator.add_indicator(watch)
4380+ statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" has changed.') % watch.name))
4381+
4382+ self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_BOLD)
4383+
4384+ self.builder.get_object("button_clear_all").set_sensitive(True)
4385+ self.builder.get_object("clear_all1").set_sensitive(True)
4386+
4387+ if self.model.iter_is_valid(self.iter[id]):
4388+ icon = self.get_icon(watch.icon, 0, False)
4389+
4390+ if self.tray:
4391+ self.tray.show_tooltip()
4392+
4393+ balloon_icon = self.get_icon(watch.icon, 0, True)
4394+ if self.specto.specto_gconf.get_entry("pop_toast") == True:
4395+ self.balloon.show_toast(watch.get_balloon_text(), balloon_icon, summary=(_("%s has changed") % watch.name), name=watch.name)
4396+
4397+ icon = self.get_icon(watch.icon, 0, False)
4398+ if self.specto.specto_gconf.get_entry("use_changed_sound") and self.sound:
4399+ changed_sound = self.specto.specto_gconf.get_entry("changed_sound")
4400+ self.sound.play(changed_sound)
4401+
4402+ elif status == "read":
4403+ if self.indicator:
4404+ self.indicator.remove_indicator(id)
4405+
4406+ self.model.set_value(self.iter[id], 1, icon)
4407+
4408+ try:
4409+ model, iter = self.treeview.get_selection().get_selected()
4410+ id2 = int(model.get_value(iter, 3))
4411+ if id == id2:
4412+ self.show_watch_info()
4413+ except:
4414+ pass
4415+ except:
4416+ self.specto.logger.log(_("There was an error marking the watch status"), "error", watch.name)
4417+
4418+ def deactivate(self, id):
4419+ """ Disable the checkbox from the watch. """
4420+ watch = self.specto.watch_db[id]
4421+ self.model.set_value(self.iter[id], 0, 0)#TODO: make the text label in the "Name" column and the buttons insensitive
4422+
4423+ def activate(self, id):
4424+ """ enable the checkbox from the watch. """
4425+ watch = self.specto.watch_db[id]
4426+ self.model.set_value(self.iter[id], 0, 1)#TODO: make the text label in the "Name" column and the buttons insensitive
4427+
4428+ def get_icon(self, icon, percent, size):
4429+ """ Calculate the alpha and return a transparent pixbuf. The input percentage is the 'transparency' percentage. 0 means no transparency. """
4430+ if icon == "":
4431+ icon = "dialog-information"
4432+
4433+ if size == True:
4434+ size = 64
4435+ else:
4436+ size = 22
4437+
4438+ try:
4439+ icon = self.specto.icon_theme.load_icon(icon, size, 0)
4440+ except gobject.GError:
4441+ try:
4442+ icon = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(self.specto.PATH, ("icons/" + icon + ".svg")), size, size)
4443+ except:
4444+ try:
4445+ icon = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(self.specto.PATH, ("icons/" + icon + ".png")), size, size)
4446+ except:
4447+ return None
4448+
4449+ icon = icon.add_alpha(False, '0', '0', '0')
4450+ for row in icon.get_pixels_array():
4451+ for pix in row:
4452+ pix[3] = min(int(pix[3]), 255 - (percent * 0.01 * 255))#note: we must *0.01, NOT /100, otherwise it won't work
4453+ return icon
4454+
4455+ def add_notifier_entry(self, id):
4456+ """ Add an entry to the notifier list. """
4457+ watch = self.specto.watch_db[id]
4458+ if watch.active == True:
4459+ active = 1
4460+ else:
4461+ active = 0
4462+
4463+ self.iter[id] = self.model.insert_before(None, None)
4464+ self.model.set_value(self.iter[id], 0, active)
4465+ if watch.changed == True:
4466+ self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 0, False))
4467+ self.model.set(self.iter[id], 5, pango.WEIGHT_BOLD)
4468+ else:
4469+ self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 50, False))
4470+ self.model.set(self.iter[id], 5, pango.WEIGHT_NORMAL)
4471+ self.model.set_value(self.iter[id], 2, watch.name)
4472+ self.model.set_value(self.iter[id], 3, watch.id)
4473+ self.model.set_value(self.iter[id], 4, watch.type)
4474+
4475+ if not self.builder.get_object("display_all_watches").active and active == 0: #dont creat the entry
4476+ self.remove_notifier_entry(id)
4477+
4478+ def remove_notifier_entry(self, id):
4479+ path = self.model.get_path(self.iter[id])
4480+ iter = self.model.get_iter(path)
4481+ id = int(self.model.get_value(iter, 3))
4482+ self.model.remove(iter)
4483+
4484+ def check_clicked(self, object, path, model):
4485+ """ Call the main function to start/stop the selected watch. """
4486+ sel = self.treeview.get_selection()
4487+ sel.select_path(path)
4488+
4489+ model, iter = self.treeview.get_selection().get_selected()
4490+ id = int(model.get_value(iter, 3))
4491+ watch = self.specto.watch_db[id]
4492+
4493+ if model.get_value(iter, 0):
4494+ model.set_value(iter, 0, 0)
4495+ if watch.changed:
4496+ self.mark_watch_as_read("", id)
4497+ self.mark_watch_status("idle", id)
4498+ self.mark_watch_status("idle", id)
4499+ watch.stop()
4500+ if not self.builder.get_object("display_all_watches").active:
4501+ self.remove_notifier_entry(id)
4502+ else:
4503+ model.set_value(iter, 0, 1)
4504+ watch.start()
4505+
4506+ def connected_message(self, connected):
4507+ return
4508+ if not connected:
4509+ self.builder.get_object("statusbar1").push(0, _("The network connection seems to be down, networked watches will not check until then."))
4510+ self.builder.get_object("statusbar1").show()
4511+ else:
4512+ self.builder.get_object("statusbar1").hide()
4513+
4514+ def show_watch_info(self, *args):
4515+ """ Show the watch information in the notifier window. """
4516+ model, iter = self.treeview.get_selection().get_selected()
4517+
4518+ if iter != None and self.model.iter_is_valid(iter):
4519+ self.builder.get_object("edit").set_sensitive(True)
4520+ self.builder.get_object("remove").set_sensitive(True)
4521+
4522+ if not self.info_table.flags() & gtk.VISIBLE:
4523+ #hide the tip of the day and show the buttons
4524+ self.quicktip.hide()
4525+ self.quicktip_image.hide()
4526+ self.builder.get_object("vbox_panel_buttons").show()
4527+ self.builder.get_object("notebook1").show()
4528+ self.info_table.show()
4529+
4530+ id = int(model.get_value(iter, 3))
4531+
4532+ watch = self.specto.watch_db[id]
4533+ watch_values = watch.get_gui_info()
4534+
4535+ #set the error log field
4536+ if not self.specto.DEBUG:
4537+ self.builder.get_object("notebook1").remove_page(2)
4538+ else:
4539+ if self.builder.get_object("notebook1").get_n_pages() == 2:
4540+ self.builder.get_object("notebook1").append_page(self.error_log_window, self.label_error_log)
4541+ log_text = self.specto.logger.watch_log(watch.name)
4542+
4543+ start = self.log_buffer.get_start_iter()
4544+ end = self.log_buffer.get_end_iter()
4545+ self.log_buffer.delete(start, end)
4546+
4547+ iter = self.log_buffer.get_iter_at_offset(0)
4548+ for line in log_text:
4549+ self.log_buffer.insert_with_tags_by_name(iter, line[1], line[0])
4550+
4551+ if watch.changed == False:
4552+ self.builder.get_object("clear").set_sensitive(False)
4553+ self.builder.get_object("btnClear").set_sensitive(False)
4554+ self.builder.get_object("lblExtraInfo").set_label(_("No extra information available."))
4555+ else:
4556+ self.builder.get_object("clear").set_sensitive(True)
4557+ self.builder.get_object("btnClear").set_sensitive(True)
4558+ try:
4559+ self.extra_info = watch.get_extra_information()
4560+ if self.extra_info != "":
4561+ try:
4562+ self.builder.get_object("lblExtraInfo").set_label(self.extra_info)
4563+ except:
4564+ self.specto.logger.log(_("Extra information could not be set"), "error", self.specto.watch_db[id].name)
4565+ except:
4566+ self.specto.logger.log(_("Extra information could not be set"), "error", self.specto.watch_db[id].name)
4567+
4568+ i = 0
4569+ while i < 4:
4570+ if i >= len(watch_values):
4571+ self.info_labels[i][0].set_label("")
4572+ self.info_labels[i][1].set_label("")
4573+ else:
4574+ #create label
4575+ self.info_labels[i][0].set_label("<b>" + str(watch_values[i][0]) + ":</b>")
4576+ label = watch.escape(str(watch_values[i][1]))
4577+ self.info_labels[i][1].set_label(label)
4578+
4579+ i += 1
4580+
4581+ image = self.builder.get_object("watch_icon")
4582+ image.set_from_pixbuf(self.get_icon(watch.icon, 0, True))
4583+
4584+ def open_watch(self, id):
4585+ """
4586+ Open the selected watch.
4587+ Returns False if the watch failed to open
4588+ """
4589+ return self.specto.watch_db[id].open_watch()
4590+
4591+ def open_watch_callback(self, *args):
4592+ """
4593+ Opens the selected watch and mark it as unchanged
4594+ """
4595+ model, iter = self.treeview.get_selection().get_selected()
4596+ id = int(model.get_value(iter, 3))
4597+ self.open_watch(id)
4598+ if self.specto.watch_db[id].changed == True:
4599+ self.mark_watch_as_read(None, id)
4600+
4601+ def show_watch_popup(self, treeview, event, data=None):
4602+ if event.button == 3:
4603+ x = int(event.x)
4604+ y = int(event.y)
4605+ time = event.time
4606+ pthinfo = treeview.get_path_at_pos(x, y)
4607+ if pthinfo is not None:
4608+ path, col, cellx, celly = pthinfo
4609+ treeview.grab_focus()
4610+ treeview.set_cursor(path, col, 0)
4611+ menu = self.create_menu(self, self.notifier, None)
4612+ menu.popup(None, None, None, 3, time)
4613+ return 1
4614+
4615+ def _mark_watch_as_read(self, *widget):
4616+ try:
4617+ model, iter = self.treeview.get_selection().get_selected()
4618+ id = int(model.get_value(iter, 3))
4619+
4620+ self.mark_watch_as_read(id)
4621+ except:
4622+ pass
4623+
4624+ def refresh_watch(self, widget):
4625+ model, iter = self.treeview.get_selection().get_selected()
4626+ id = int(model.get_value(iter, 3))
4627+ watch = self.specto.watch_db[id]
4628+ watch.restart()
4629+
4630+ def edit_watch(self, widget):
4631+ model, iter = self.treeview.get_selection().get_selected()
4632+ id = int(model.get_value(iter, 3))
4633+ self.show_edit_watch(self, widget, id)
4634+
4635+ def create_menu(self, window, event, data=None):
4636+ model, iter = self.treeview.get_selection().get_selected()
4637+ id = int(model.get_value(iter, 3))
4638+ watch = self.specto.watch_db[id]
4639+ menu = gtk.Menu()
4640+ menuItem = None
4641+
4642+ menuItem = create_menu_item(_("Refresh"), self.refresh_watch,
4643+ gtk.STOCK_REFRESH)
4644+ if not watch.active:
4645+ menuItem.set_sensitive(False)
4646+ menu.append(menuItem)
4647+
4648+ menuItem = create_menu_item(_("Mark as read"), self._mark_watch_as_read,
4649+ gtk.STOCK_CLEAR)
4650+ if not watch.changed:
4651+ menuItem.set_sensitive(False)
4652+ menu.append(menuItem)
4653+
4654+ menuItem = create_menu_item(_("Crawl"), self.crawl_watch, gtk.STOCK_EDIT)
4655+ menu.append(menuItem)
4656+
4657+ separator = gtk.SeparatorMenuItem()
4658+ menu.append(separator)
4659+
4660+ menuItem = create_menu_item(_("Edit"), self.edit_watch, gtk.STOCK_EDIT)
4661+ menu.append(menuItem)
4662+
4663+ menuItem = create_menu_item(_("Remove"), self.remove_watch,
4664+ gtk.STOCK_REMOVE)
4665+ menu.append(menuItem)
4666+
4667+ menu.show_all()
4668+ return menu
4669+
4670+ def change_entry_name(self, *args):
4671+ """ Edit the name from the watch in the notifier window. """
4672+ # Change the name in the treeview
4673+ model, iter = self.treeview.get_selection().get_selected()
4674+ id = int(model.get_value(iter, 3))
4675+ self.change_name(args[2], id)
4676+
4677+ def change_name(self, new_name, id):
4678+ if self.specto.watch_db[id].changed == True:
4679+ weight = pango.WEIGHT_BOLD
4680+ else:
4681+ weight = pango.WEIGHT_NORMAL
4682+ self.model.set(self.iter[id], 2, new_name, 5, weight)
4683+
4684+ # Write the new name in watches.list
4685+ self.specto.watch_io.replace_name(self.specto.watch_db[id].name, new_name)
4686+ # Change the name in the database
4687+ self.specto.watch_db[id].name = new_name
4688+ self.show_watch_info()
4689+
4690+### GUI FUNCTIONS ###
4691+ def get_quick_tip(self):
4692+ """Return a random tip of the day to be shown on startup"""
4693+ tips = [_("You can add all kinds of websites as watches. Static pages, RSS or Atom feeds, etc. Specto will automatically handle them."),
4694+ _("Website watches can use an error margin that allows you to set a minimum difference percentage. This allows you to adapt to websites that change constantly or have lots of advertising."),
4695+ _("Single-click an existing watch to display information, and double-click it to open the content."),
4696+ _("Please set a reasonable refresh interval in order to save bandwidth and prevent you from being blocked from content providers.")]
4697+ chosen_tip = tips[randrange(len(tips))]
4698+ return chosen_tip
4699+
4700+ def toggle_display_toolbar(self, *args):
4701+ """ Show or hide the toolbar. """
4702+ if self.builder.get_object("display_toolbar").active:
4703+ self.builder.get_object("toolbar").show()
4704+ self.specto.specto_gconf.set_entry("hide_toolbar", False)
4705+ else:
4706+ self.builder.get_object("toolbar").hide()
4707+ self.specto.specto_gconf.set_entry("hide_toolbar", True)
4708+
4709+ def toggle_show_deactivated_watches(self, *widget):
4710+ """ Display only active watches or all watches. """
4711+ if self.startup != True:
4712+ self.startup = False # This is important to prevent *widget from messing with us. If you don't believe me, print startup ;)
4713+ if self.startup == True:
4714+ self.startup = False
4715+ else:
4716+ if self.builder.get_object("display_all_watches").active:
4717+ for watch in self.specto.watch_db:
4718+ if watch.active == False: # For each watch that is supposed to be inactive, show it in the notifier but don't activate it
4719+ if self.startup == False: # Recreate the item because it was deleted
4720+ self.add_notifier_entry(watch.id)
4721+ self.specto.specto_gconf.set_entry("show_deactivated_watches", True)
4722+ else: # Hide the deactivated watches
4723+ for i in self.iter:
4724+ if self.model.iter_is_valid(self.iter[i]):
4725+ path = self.model.get_path(self.iter[i])
4726+ iter = self.model.get_iter(path)
4727+ model = self.model
4728+ id = int(model.get_value(iter, 3))
4729+
4730+ if self.specto.watch_db[id].active == False:
4731+ model.remove(iter)
4732+ self.specto.specto_gconf.set_entry("show_deactivated_watches", False)
4733+
4734+ def remove_watch(self, *widget):
4735+ try:
4736+ model, iter = self.treeview.get_selection().get_selected()
4737+ id = int(model.get_value(iter, 3))
4738+ except:
4739+ pass
4740+ else:
4741+ dialog = RemoveDialog(_("Remove a watch"),
4742+ (_('<big>Remove the watch "%s"?</big>\nThis operation cannot be undone.') % self.specto.watch_db[id].name))
4743+ answer = dialog.show()
4744+ if answer == True:
4745+ self.remove_notifier_entry(id)
4746+ self.specto.watch_db.remove(id) #remove the watch
4747+ self.specto.watch_io.remove_watch(self.specto.watch_db[id].name)
4748+ if self.tray:
4749+ self.tray.show_tooltip()
4750+
4751+ def delete_event(self, *args):
4752+ """
4753+ quit specto
4754+ """
4755+ self.save_size_and_position()
4756+ self.specto.quit()
4757+ return True
4758+
4759+
4760+ def close_event(self, *args):
4761+ """
4762+ if the trayicon and the indicator or not available then quit specto else hide the notifier window
4763+ """
4764+ if self.specto.specto_gconf.get_entry("always_show_icon") == True or self.indicator:
4765+ self.notifier.hide()
4766+ self.specto.specto_gconf.set_entry("show_notifier", False)#save the window state for the next time specto starts
4767+ return True
4768+ else:
4769+ self.specto.quit()
4770+ return True
4771+
4772+ def restore_size_and_position(self):
4773+ """
4774+ Restore the size and the postition from the notifier window.
4775+ """
4776+ saved_window_width = self.specto.specto_gconf.get_entry("window_notifier_width")
4777+ saved_window_height = self.specto.specto_gconf.get_entry("window_notifier_height")
4778+ saved_window_x = self.specto.specto_gconf.get_entry("window_notifier_x")
4779+ saved_window_y = self.specto.specto_gconf.get_entry("window_notifier_y")
4780+ if self.specto.specto_gconf.get_entry("hide_from_windowlist")==True:
4781+ self.notifier.set_skip_taskbar_hint(True) # Hide from the window list applet
4782+
4783+ if saved_window_width != None and saved_window_height != None: # Check if the size is not 0
4784+ self.builder.get_object("notifier").resize(saved_window_width, saved_window_height)
4785+
4786+ if saved_window_x != None and saved_window_y != None: # Check if the position is not 0
4787+ self.builder.get_object("notifier").move(saved_window_x, saved_window_y)
4788+
4789+ def save_size_and_position(self):
4790+ """
4791+ Save the size and position from the notifier in gconf when the window is closed.
4792+ """
4793+ # Save the size in gconf
4794+ current_window_size = self.builder.get_object("notifier").get_size()
4795+ current_window_width = current_window_size[0]
4796+ current_window_height = current_window_size[1]
4797+ self.specto.specto_gconf.set_entry("window_notifier_width", current_window_width)
4798+ self.specto.specto_gconf.set_entry("window_notifier_height", current_window_height)
4799+
4800+ # Save the window position in gconf when the window is closed
4801+ current_window_xy = self.builder.get_object("notifier").get_position()
4802+ current_window_x = current_window_xy[0]
4803+ current_window_y = current_window_xy[1]
4804+ self.specto.specto_gconf.set_entry("window_notifier_x", current_window_x)
4805+ self.specto.specto_gconf.set_entry("window_notifier_y", current_window_y)
4806+
4807+ def get_state(self):
4808+ """ Return True if the notifier window is visible. """
4809+ return bool(self.notifier.flags() & gtk.VISIBLE)
4810+
4811+ def create_notifier_gui(self):
4812+ """ Create the gui from the notifier. """
4813+ self.treeview = self.builder.get_object("treeview")
4814+ self.treeview.set_model(self.model)
4815+ self.treeview.set_flags(gtk.TREE_MODEL_ITERS_PERSIST)
4816+ self.treeview.connect("button_press_event", self.show_watch_popup, None)
4817+ self.builder.get_object("button_clear_all").set_sensitive(False)
4818+ self.builder.get_object("clear_all1").set_sensitive(False)
4819+
4820+ if self.specto.specto_gconf.get_entry("always_show_icon") == False and not self.indicator:
4821+ self.builder.get_object("close").set_sensitive(False)
4822+
4823+ if self.specto.specto_gconf.get_entry("show_in_windowlist") == False:
4824+ self.notifier.set_skip_taskbar_hint(True)
4825+
4826+
4827+ ### Initiate the window
4828+ self.restore_size_and_position()
4829+ self.show_toolbar = self.specto.specto_gconf.get_entry("show_toolbar")
4830+ if self.show_toolbar == False:
4831+ self.builder.get_object("display_toolbar").set_active(False)
4832+ self.toggle_display_toolbar()
4833+ else:
4834+ self.builder.get_object("display_toolbar").set_active(True)
4835+ self.toggle_display_toolbar()
4836+
4837+ self.startup = True
4838+ if self.specto.specto_gconf.get_entry("show_deactivated_watches") == True:
4839+ self.builder.get_object("display_all_watches").set_active(True)
4840+ else:
4841+ self.builder.get_object("display_all_watches").set_active(False)
4842+ self.startup = False
4843+
4844+ if not self.specto.notifier_hide:
4845+ self.notifier.show()
4846+
4847+ ### Checkbox
4848+ self.columnCheck_renderer = gtk.CellRendererToggle()
4849+ self.columnCheck_renderer.set_property("activatable", True)
4850+ self.columnCheck_renderer.connect("toggled", self.check_clicked, self.model)
4851+ self.columnCheck = gtk.TreeViewColumn(_("Active"), self.columnCheck_renderer, active=0)
4852+ self.columnCheck.connect("clicked", self.sort_active_from_treeview_headers)
4853+ self.columnCheck.set_sort_column_id(0)
4854+ self.treeview.append_column(self.columnCheck)
4855+
4856+ ### Icon
4857+ self.columnIcon_renderer = gtk.CellRendererPixbuf()
4858+ self.columnIcon = gtk.TreeViewColumn(_("Type"), self.columnIcon_renderer, pixbuf=1)
4859+ self.columnIcon.set_clickable(True)
4860+ self.columnIcon.connect("clicked", self.sort_type_from_treeview_headers)
4861+ self.treeview.append_column(self.columnIcon)
4862+
4863+ ### Titre
4864+ self.columnTitle_renderer = gtk.CellRendererText()
4865+ #self.columnTitle_renderer.set_property("editable", True)
4866+ #self.columnTitle_renderer.connect('edited', self.change_entry_name)
4867+ self.columnTitle = gtk.TreeViewColumn(_("Name"), self.columnTitle_renderer, text=2, weight=5)
4868+ self.columnTitle.connect("clicked", self.sort_name_from_treeview_headers)
4869+ self.columnTitle.set_expand(True)
4870+ self.columnTitle.set_resizable(True)
4871+ self.columnTitle.set_sort_column_id(2)
4872+ self.treeview.append_column(self.columnTitle)
4873+
4874+ ### ID
4875+ self.columnID_renderer = gtk.CellRendererText()
4876+ self.columnID = gtk.TreeViewColumn(_("ID"), self.columnID_renderer, markup=3)
4877+ self.columnID.set_visible(False)
4878+ self.columnID.set_sort_column_id(3)
4879+ self.treeview.append_column(self.columnID)
4880+
4881+ ### type
4882+ self.renderer = gtk.CellRendererText()
4883+ self.columnType = gtk.TreeViewColumn(_("TYPE"), self.renderer, markup=4)
4884+ self.columnType.set_visible(False)
4885+ self.columnType.set_sort_column_id(4)
4886+ self.treeview.append_column(self.columnType)
4887+
4888+ self.get_startup_sort_order()
4889+
4890+
4891+ ###Create info-panel
4892+ vbox_info = self.builder.get_object("vbox_info")
4893+
4894+ #show tip of the day
4895+ self.quicktip = self.get_quick_tip()
4896+ self.quicktip_image = gtk.Image()
4897+ self.quicktip_image.set_from_pixbuf(self.get_icon("dialog-information", 0, True))
4898+ self.quicktip_image.show()
4899+ vbox_info.pack_start(self.quicktip_image, False, False, 0)
4900+ self.quicktip = gtk.Label(("<big>" + _("Tip of the Day:") + "</big> "+ self.quicktip))
4901+ self.quicktip.set_line_wrap(True)
4902+ self.quicktip.set_use_markup(True)
4903+ self.quicktip.set_alignment(xalign=0.0, yalign=0.5)
4904+ self.quicktip.show()
4905+ vbox_info.pack_start(self.quicktip, False, False, 0)
4906+
4907+ #create the info table
4908+ self.info_table = gtk.Table(rows=4, columns=2, homogeneous=True)
4909+ self.info_table.set_row_spacings(6)
4910+ self.info_table.set_col_spacings(6)
4911+ vbox_watch_info = self.builder.get_object("vbox_watch_info")
4912+ vbox_watch_info.pack_start(self.info_table, False, False, 0) #show the image
4913+
4914+ i = 0
4915+ self.info_labels = []
4916+ while i < 4:
4917+ gtk_label = gtk.Label()
4918+ gtk_label.set_alignment(xalign=0.0, yalign=0.5)
4919+ gtk_label.set_use_markup(True)
4920+ gtk_label.set_ellipsize(pango.ELLIPSIZE_END)
4921+ gtk_label.show()
4922+
4923+ #create value
4924+ gtk_label1 = gtk.Label()
4925+ gtk_label1.set_alignment(xalign=0.0, yalign=0.5)
4926+ gtk_label1.set_use_markup(True)
4927+ gtk_label1.set_ellipsize(pango.ELLIPSIZE_END)
4928+ gtk_label1.show()
4929+
4930+ self.info_labels.extend([(gtk_label, gtk_label1)])
4931+ self.info_table.attach(self.info_labels[i][1], 1, 2, i, i + 1)
4932+ self.info_table.attach(self.info_labels[i][0], 0, 1, i, i + 1)
4933+
4934+ i += 1
4935+
4936+ #create the error log textview and notebook label
4937+ self.error_log = gtk.TextView()
4938+ self.log_buffer = self.error_log.get_buffer()
4939+ self.log_buffer.create_tag("ERROR", foreground="#a40000")
4940+ self.log_buffer.create_tag("INFO", foreground="#4e9a06")
4941+ self.log_buffer.create_tag("WARNING", foreground="#c4a000")
4942+ self.error_log_window = gtk.ScrolledWindow()
4943+ self.error_log_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
4944+ self.error_log_window.add_with_viewport(self.error_log)
4945+ self.error_log_window.show()
4946+ self.label_error_log = gtk.Label(_("Error log"))
4947+ self.error_log.show()
4948+ self.label_error_log.show()
4949+
4950+ #hide the buttons
4951+ self.builder.get_object("vbox_panel_buttons").hide()
4952+
4953+ self.builder.get_object("edit").set_sensitive(False)
4954+ self.builder.get_object("clear").set_sensitive(False)
4955+ self.builder.get_object("remove").set_sensitive(False)
4956+
4957+ self.builder.get_object("statusbar1").show()
4958+
4959+ self.builder.get_object("notebook1").hide()
4960+
4961+ self.generate_add_menu()
4962+
4963+### Sort functions ###
4964+ def get_startup_sort_order(self):
4965+ order = self.get_gconf_sort_order()
4966+ sort_function = self.specto.specto_gconf.get_entry("sort_function")
4967+ if sort_function == "name":
4968+ self.builder.get_object("by_name").set_active(True)
4969+ self.model.set_sort_column_id(2, order)
4970+ elif sort_function == "type":
4971+ self.builder.get_object("by_watch_type").set_active(True)
4972+ self.model.set_sort_column_id(4, order)
4973+ elif sort_function == "active":
4974+ self.builder.get_object("by_watch_active").set_active(True)
4975+ self.model.set_sort_column_id(0, order)
4976+
4977+ def get_gconf_sort_order(self):
4978+ """ Get the order (asc, desc) from a gconf key. """
4979+ order = self.specto.specto_gconf.get_entry("sort_order")
4980+ if order == "asc":
4981+ sort_order = gtk.SORT_ASCENDING
4982+ else:
4983+ sort_order = gtk.SORT_DESCENDING
4984+ return sort_order
4985+
4986+ def set_gconf_sort_order(self, order):
4987+ """ Set the order (asc, desc) for a gconf keys. """
4988+ if order == gtk.SORT_ASCENDING:
4989+ sort_order = "asc"
4990+ else:
4991+ sort_order = "desc"
4992+ return sort_order
4993+
4994+ def sort_name(self, *args):
4995+ """ Sort by watch name. """
4996+ self.model.set_sort_column_id(2, not self.columnTitle.get_sort_order())
4997+ self.specto.specto_gconf.set_entry("sort_function", "name")
4998+
4999+ def sort_type(self, *args):
5000+ """ Sort by watch type. """
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches