GTG

Merge lp:~izidor/gtg/bug1074140 into lp:~gtg/gtg/old-trunk

Proposed by Izidor Matušov
Status: Merged
Merged at revision: 1239
Proposed branch: lp:~izidor/gtg/bug1074140
Merge into: lp:~gtg/gtg/old-trunk
Diff against target: 346 lines (+123/-99)
1 file modified
GTG/plugins/notification_area/notification_area.py (+123/-99)
To merge this branch: bzr merge lp:~izidor/gtg/bug1074140
Reviewer Review Type Date Requested Status
Bertrand Rousseau (community) Approve
Review via email: mp+132654@code.launchpad.net

Description of the change

A patch to run notification area plugin even for systems without appindicator, e.g. Archlinux's XFCE4.

To post a comment you must log in.
Revision history for this message
Bertrand Rousseau (bertrand-rousseau) wrote :

I ran your code under Ubuntu 12.10/GNOME Shell, and could see the notification icon when activating the notification area plugin. So everything ok from that PoV.

Did you test it against Unity?

review: Needs Information
Revision history for this message
Bertrand Rousseau (bertrand-rousseau) wrote :

following discussion on IRC, it appears to have been tested on unity/xfce, so I approve

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed directory 'GTG/plugins/notification_area/data'
=== removed directory 'GTG/plugins/notification_area/data/icons'
=== removed directory 'GTG/plugins/notification_area/data/icons/hicolor'
=== removed directory 'GTG/plugins/notification_area/data/icons/hicolor/22x22'
=== removed directory 'GTG/plugins/notification_area/data/icons/hicolor/22x22/apps'
=== modified file 'GTG/plugins/notification_area/notification_area.py'
--- GTG/plugins/notification_area/notification_area.py 2012-07-18 12:09:41 +0000
+++ GTG/plugins/notification_area/notification_area.py 2012-11-02 07:54:58 +0000
@@ -24,11 +24,109 @@
24 pass24 pass
2525
26from GTG import _26from GTG import _
27from GTG import PLUGIN_DIR
28from GTG.tools.borg import Borg27from GTG.tools.borg import Borg
29from GTG.tools.dates import Date28from GTG.tools.dates import Date
3029
3130
31class TheIndicator(Borg):
32 """
33 Application indicator can be instantiated only once. The
34 plugin api, when toggling the activation state of a plugin,
35 instantiates different objects from the plugin class. Therefore,
36 we need to keep a reference to the indicator object. This class
37 does that.
38 """
39
40 def __init__(self):
41 super(TheIndicator, self).__init__()
42 if not hasattr(self, "_indicator"):
43 try:
44 self._indicator = appindicator.Indicator( \
45 "gtg",
46 "indicator-messages",
47 appindicator.CATEGORY_APPLICATION_STATUS)
48 except:
49 self._indicator = None
50
51 def get_indicator(self):
52 return self._indicator
53
54
55class IconIndicator:
56 """
57 A common interface to an app indicator and a status icon
58 """
59
60 NORMAL_ICON = "gtg"
61 ATTENTION_ICON = "gtg_need_attention"
62
63 def __init__(self):
64 self._indicator = TheIndicator().get_indicator()
65 self._icon = None
66 self._menu = None
67 self._attention = False
68
69 def activate(self, leftbtn_callback, menu):
70 """ Setup the icon / the indicator """
71
72 self._menu = menu
73
74 if self._indicator:
75 self._indicator.set_icon("gtg-panel")
76 self._indicator.set_attention_icon(self.ATTENTION_ICON)
77 self._indicator.set_menu(menu)
78 self._indicator.set_status(appindicator.STATUS_ACTIVE)
79 else:
80 self._icon = gtk.StatusIcon()
81 self._icon.set_from_icon_name(self.NORMAL_ICON)
82 self._icon.set_tooltip("Getting Things GNOME!")
83 self._icon.set_visible(True)
84 self._icon.connect('activate', leftbtn_callback)
85 self._icon.connect('popup-menu', self._on_icon_popup)
86
87 def deactivate(self):
88 """ Hide the icon """
89 if self._indicator:
90 self._indicator.set_status(appindicator.STATUS_PASSIVE)
91 else:
92 self._icon.set_visible(False)
93
94 def update_menu(self):
95 """ Force indicator to update menu """
96 if self._indicator:
97 self._indicator.set_menu(self._menu)
98
99 def set_attention(self, attention):
100 """ Show a special icon when the indicator needs attention """
101 # Change icon only when the attention change
102 if self._attention == attention:
103 return
104
105 if self._indicator:
106 if attention:
107 status = appindicator.STATUS_ATTENTION
108 else:
109 status = appindicator.STATUS_ACTIVE
110
111 self._indicator.set_status(status)
112 else:
113 if attention:
114 icon = self.ATTENTION_ICON
115 else:
116 icon = self.NORMAL_ICON
117
118 self._icon.set_from_icon_name(icon)
119
120 self._attention = attention
121
122 def _on_icon_popup(self, icon, button, timestamp):
123 """ Show the menu on right click on the icon """
124 if not self._indicator:
125 self._menu.popup(None, None, gtk.status_icon_position_menu,
126 button, timestamp, icon)
127
128
129
32def _due_within(task, danger_zone):130def _due_within(task, danger_zone):
33 """131 """
34 Determine if a task is the danger zone.132 Determine if a task is the danger zone.
@@ -55,16 +153,10 @@
55 than time span (in days) defined by danger_zone.153 than time span (in days) defined by danger_zone.
56 """154 """
57155
58 STATUS = {'normal': appindicator.STATUS_ACTIVE,
59 'high': appindicator.STATUS_ATTENTION}
60
61 ICON = {'normal': 'gtg-panel',
62 'high': 'gtg_need_attention'}
63
64 def __init__(self, danger_zone, indicator, tree, req):156 def __init__(self, danger_zone, indicator, tree, req):
65 self.__tree = tree157 self.__tree = tree
66 self.__req = req158 self.__req = req
67 self.__indicator = indicator159 self._indicator = indicator
68 self.danger_zone = danger_zone160 self.danger_zone = danger_zone
69161
70 # Setup list of tasks in danger zone162 # Setup list of tasks in danger zone
@@ -76,27 +168,13 @@
76 self.tasks_danger.append(tid)168 self.tasks_danger.append(tid)
77169
78 # Set initial status170 # Set initial status
79 self.__update_indicator(self.level())171 self._update_indicator()
80172
81 def level(self):173 def _update_indicator(self):
82 """ Two states only: attention is either needed or not """174 """ Set the proper icon for the indicator """
83 return 'high' if len(self.tasks_danger)>0 else 'normal'175 self._indicator.set_attention(len(self.tasks_danger) > 0)
84
85 def __update_indicator(self, new, old=None):
86 """ Reset indicator status or update upon change in status """
87 if old is None or not old == new:
88 try:
89 # This works if __indicator implements the appindicator api
90 self.__indicator.set_status(self.STATUS[new])
91 except AttributeError:
92 # If we passed a status icon instead try this
93 self.__indicator.set_from_icon_name(self.ICON[new])
94 except:
95 raise
96176
97 def update_on_task_modified(self, tid):177 def update_on_task_modified(self, tid):
98 # Store current attention level
99 old_lev = self.level()
100 task = self.__req.get_task(tid)178 task = self.__req.get_task(tid)
101 if tid in self.tasks_danger:179 if tid in self.tasks_danger:
102 if not _due_within(task, self.danger_zone):180 if not _due_within(task, self.danger_zone):
@@ -104,19 +182,14 @@
104 else:182 else:
105 if _due_within(task, self.danger_zone):183 if _due_within(task, self.danger_zone):
106 self.tasks_danger.append(tid)184 self.tasks_danger.append(tid)
107 185
108 # Update icon only if attention level has changed186 self._update_indicator()
109 self.__update_indicator(self.level(), old_lev)
110187
111 def update_on_task_deleted(self, tid):188 def update_on_task_deleted(self, tid):
112 # Store current attention level
113 old_lev = self.level()
114
115 if tid in self.tasks_danger:189 if tid in self.tasks_danger:
116 self.tasks_danger.remove(tid)190 self.tasks_danger.remove(tid)
117191
118 # Update icon only if attention level has changed192 self._update_indicator()
119 self.__update_indicator(self.level(), old_lev)
120193
121194
122class NotificationArea:195class NotificationArea:
@@ -131,31 +204,9 @@
131 MAX_TITLE_LEN = 30204 MAX_TITLE_LEN = 30
132 MAX_ITEMS = 10205 MAX_ITEMS = 10
133206
134 class TheIndicator(Borg):
135 """
136 Application indicator can be instantiated only once. The
137 plugin api, when toggling the activation state of a plugin,
138 instantiates different objects from the plugin class. Therefore,
139 we need to keep a reference to the indicator object. This class
140 does that.
141 """
142
143 def __init__(self):
144 super(NotificationArea.TheIndicator, self).__init__()
145 if not hasattr(self, "_indicator"):
146 try:
147 self._indicator = appindicator.Indicator( \
148 "gtg",
149 "indicator-messages",
150 appindicator.CATEGORY_APPLICATION_STATUS)
151 except:
152 self._indicator = None
153
154 def get_indicator(self):
155 return self._indicator
156207
157 def __init__(self):208 def __init__(self):
158 self.__indicator = NotificationArea.TheIndicator().get_indicator()209 self._indicator = IconIndicator()
159 self.__browser_handler = None210 self.__browser_handler = None
160 self.__liblarch_callbacks = []211 self.__liblarch_callbacks = []
161212
@@ -203,10 +254,7 @@
203254
204 def deactivate(self, plugin_api):255 def deactivate(self, plugin_api):
205 """ Set everything back to normal """256 """ Set everything back to normal """
206 if self.__indicator:257 self._indicator.deactivate()
207 self.__indicator.set_status(appindicator.STATUS_PASSIVE)
208 else:
209 self.status_icon.set_visible(False)
210258
211 # Allow to close browser after deactivation259 # Allow to close browser after deactivation
212 self.__set_browser_close_callback(None)260 self.__set_browser_close_callback(None)
@@ -224,13 +272,13 @@
224 def __init_gtk(self):272 def __init_gtk(self):
225 browser = self.__view_manager.get_browser()273 browser = self.__view_manager.get_browser()
226274
227 self.__menu = gtk.Menu()275 menu = gtk.Menu()
228276
229 #add "new task"277 #add "new task"
230 menuItem = gtk.ImageMenuItem(gtk.STOCK_ADD)278 menuItem = gtk.ImageMenuItem(gtk.STOCK_ADD)
231 menuItem.get_children()[0].set_label(_('Add _New Task'))279 menuItem.get_children()[0].set_label(_('Add _New Task'))
232 menuItem.connect('activate', self.__open_task)280 menuItem.connect('activate', self.__open_task)
233 self.__menu.append(menuItem)281 menu.append(menuItem)
234282
235 #view in main window checkbox283 #view in main window checkbox
236 view_browser_checkbox = gtk.CheckMenuItem(_("_View Main Window"))284 view_browser_checkbox = gtk.CheckMenuItem(_("_View Main Window"))
@@ -239,48 +287,29 @@
239 self.__toggle_browser)287 self.__toggle_browser)
240 browser.connect('visibility-toggled', self.__on_browser_toggled,288 browser.connect('visibility-toggled', self.__on_browser_toggled,
241 view_browser_checkbox)289 view_browser_checkbox)
242 self.__menu.append(view_browser_checkbox)290 menu.append(view_browser_checkbox)
243 self.checkbox = view_browser_checkbox291 self.checkbox = view_browser_checkbox
244292
245 #separator (it's intended to be after show_all)293 #separator (it's intended to be after show_all)
246 # separator should be shown only when having tasks294 # separator should be shown only when having tasks
247 self.__task_separator = gtk.SeparatorMenuItem()295 self.__task_separator = gtk.SeparatorMenuItem()
248 self.__menu.append(self.__task_separator)296 menu.append(self.__task_separator)
249 self.__menu_top_length = len(self.__menu)297 menu_top_length = len(menu)
250298
251 self.__menu.append(gtk.SeparatorMenuItem())299 menu.append(gtk.SeparatorMenuItem())
252300
253 #quit item301 #quit item
254 menuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)302 menuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
255 menuItem.connect('activate', self.__view_manager.close_browser)303 menuItem.connect('activate', self.__view_manager.close_browser)
256 self.__menu.append(menuItem)304 menu.append(menuItem)
257305
258 self.__menu.show_all()306 menu.show_all()
259 self.__task_separator.hide()307 self.__task_separator.hide()
260308
261 self.__tasks_menu = SortedLimitedMenu(self.MAX_ITEMS,309 self.__tasks_menu = SortedLimitedMenu(self.MAX_ITEMS,
262 self.__menu, self.__menu_top_length)310 menu, menu_top_length)
263311
264 # Update the icon theme312 self._indicator.activate(self.__toggle_browser, menu)
265 icon_theme = os.path.join('notification_area', 'data', 'icons')
266 abs_theme_path = os.path.join(PLUGIN_DIR[0], icon_theme)
267 theme = gtk.icon_theme_get_default()
268 theme.append_search_path(abs_theme_path)
269
270 if self.__indicator:
271 self.__indicator.set_icon_theme_path(abs_theme_path)
272 self.__indicator.set_icon("gtg-panel")
273 self.__indicator.set_attention_icon("gtg_need_attention")
274 self.__indicator.set_menu(self.__menu)
275 self.__indicator.set_status(appindicator.STATUS_ACTIVE)
276 else:
277 self.status_icon = gtk.StatusIcon()
278 self.status_icon.set_from_icon_name("gtg-panel")
279 self.status_icon.set_tooltip("Getting Things Gnome!")
280 self.status_icon.set_visible(True)
281 self.status_icon.connect('activate', self.__toggle_browser)
282 self.status_icon.connect('popup-menu',
283 self.__on_icon_popup, self.__menu)
284313
285 def __init_attention(self):314 def __init_attention(self):
286 # Use two different viewtree for attention and menu315 # Use two different viewtree for attention and menu
@@ -290,7 +319,7 @@
290 if self.preferences['danger_zone'] > 0:319 if self.preferences['danger_zone'] > 0:
291 self.__attention = _Attention( \320 self.__attention = _Attention( \
292 self.preferences['danger_zone'],321 self.preferences['danger_zone'],
293 self.__indicator if self.__indicator else self.status_icon,322 self._indicator,
294 self.__tree_att,323 self.__tree_att,
295 self.__requester)324 self.__requester)
296 else:325 else:
@@ -340,8 +369,7 @@
340 menu_item.connect('activate', self.__open_task, tid)369 menu_item.connect('activate', self.__open_task, tid)
341 self.__tasks_menu.add(tid, (task.get_due_date(), title), menu_item)370 self.__tasks_menu.add(tid, (task.get_due_date(), title), menu_item)
342371
343 if self.__indicator:372 self._indicator.update_menu()
344 self.__indicator.set_menu(self.__menu)
345373
346 def __on_task_deleted_att(self, tid, path):374 def __on_task_deleted_att(self, tid, path):
347 # Update icon on deletion375 # Update icon on deletion
@@ -362,10 +390,6 @@
362 short_title = short_title.strip() + "..."390 short_title = short_title.strip() + "..."
363 return short_title391 return short_title
364392
365 def __on_icon_popup(self, icon, button, timestamp, menu=None):
366 if not self.__indicator:
367 menu.popup(None, None, gtk.status_icon_position_menu, \
368 button, timestamp, icon)
369393
370### Preferences methods #######################################################394### Preferences methods #######################################################
371 def preferences_load(self):395 def preferences_load(self):
372396
=== renamed file 'GTG/plugins/notification_area/data/icons/hicolor/22x22/apps/gtg_need_attention.png' => 'data/icons/hicolor/22x22/apps/gtg_need_attention.png'
=== renamed directory 'GTG/plugins/notification_area/data/icons/ubuntu-mono-dark' => 'data/icons/ubuntu-mono-dark'
=== renamed directory 'GTG/plugins/notification_area/data/icons/ubuntu-mono-light' => 'data/icons/ubuntu-mono-light'

Subscribers

People subscribed via source and target branches

to status/vote changes: