Package conduit :: Package hildonui :: Module Canvas
[hide private]

Source Code for Module conduit.hildonui.Canvas

  1  """ 
  2  Manages adding, removing, resizing and drawing the canvas 
  3   
  4  The Canvas is the main area in Conduit, the area to which DataProviders are  
  5  dragged onto. 
  6   
  7  Copyright: John Stowers, 2006 
  8  Copyright: Thomas Van Machelen, 2007 
  9  License: GPLv2 
 10  """ 
 11  import gobject 
 12  import gtk 
 13  import logging 
 14  log = logging.getLogger("hildonui.Canvas") 
 15   
 16  import conduit.gtkui.Canvas 
 17  import conduit.gtkui.Util as GtkUtil  
 18   
 19  LINE_WIDTH = 3.0 
 20   
21 -class Canvas(conduit.gtkui.Canvas.Canvas, gobject.GObject):
22 """ 23 This class manages many objects 24 """ 25 26 __gsignals__ = { 27 "position-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []) # The canvas 28 } 29
30 - def __init__(self, parentWindow, typeConverter, syncManager):
31 """ 32 Draws an empty canvas of the appropriate size 33 """ 34 #setup the canvas 35 conduit.gtkui.Canvas.Canvas.__init__(self, 36 parentWindow,typeConverter,syncManager, 37 None,None, #menus are set in _setup_popup_menus 38 None #no message hints in hildon 39 ) 40 self.position = -1
41
42 - def _update_for_theme(self, *args):
43 pass
44
45 - def _setup_popup_menus(self, dataproviderPopupXML, conduitPopupXML):
46 # dp context menu 47 self.dataproviderMenu = DataProviderMenu(self) 48 # conduit context menu 49 self.conduitMenu = ConduitMenu(self)
50
51 - def _create_welcome(self):
52 c_x,c_y,c_w,c_h = self.get_bounds() 53 self.welcome = goocanvas.Text( 54 x=c_w/2, 55 y=c_w/3, 56 width=3*c_w/5, 57 text=self.WELCOME_MESSAGE, 58 anchor=gtk.ANCHOR_CENTER, 59 alignment=pango.ALIGN_CENTER, 60 font="Sans 10", 61 fill_color="black", 62 ) 63 self.root.add_child(self.welcome,-1)
64
65 - def _on_conduit_button_press(self, view, target, event):
66 log.debug("Clicked View: %s" % view.model) 67 68 #single left click 69 if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: 70 if not view.model.is_busy(): 71 self.conduitMenu.popup(None, None, 72 None, event.button, event.time) 73 74 #dont propogate the event 75 return True
76
77 - def _on_dataprovider_button_press(self, view, target, event):
78 """ 79 Handle button clicks 80 81 @param user_data_dataprovider_wrapper: The dpw that was clicked 82 @type user_data_dataprovider_wrapper: L{conduit.Module.ModuleWrapper} 83 """ 84 log.debug("Clicked View: %s" % view.model) 85 self.selectedDataproviderItem = view 86 87 #single left click 88 if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: 89 if view.model.enabled and not view.model.module.is_busy(): 90 self.dataproviderMenu.configureMenuItem.set_property("sensitive", view.model.configurable) 91 self.dataproviderMenu.popup(None, None, 92 None, event.button, event.time) 93 94 #dont propogate the event 95 return True
96
97 - def on_conduit_added(self, sender, conduitAdded):
98 """ 99 Creates a ConduitCanvasItem for the new conduit 100 """ 101 log.debug("Conduit added %s" % conduitAdded) 102 self.set_position(self.model.index(conduitAdded))
103
104 - def on_conduit_removed(self, sender, conduitRemoved):
105 self.move_previous ()
106
107 - def on_dataprovider_removed(self, sender, dataproviderRemoved, conduitCanvasItem):
108 for item in self._get_child_dataprovider_canvas_items(): 109 if item.model == dataproviderRemoved: 110 conduitCanvasItem.delete_dataprovider_canvas_item(item) 111 self._remove_overlap()
112
113 - def on_dataprovider_added(self, sender, dataproviderAdded, conduitCanvasItem):
114 #check for duplicates to eliminate race condition in set_sync_set 115 if dataproviderAdded in [i.model for i in self._get_child_dataprovider_canvas_items()]: 116 return 117 118 item = DataProviderCanvasItem( 119 parent=conduitCanvasItem, 120 model=dataproviderAdded 121 ) 122 item.connect('button-press-event', self._on_dataprovider_button_press) 123 conduitCanvasItem.add_dataprovider_canvas_item(item) 124 self._remove_overlap()
125
126 - def set_sync_set(self, syncSet):
127 conduit.gtkui.Canvas.Canvas.set_sync_set(self, syncSet) 128 if len(self.model.get_all_conduits()) > 0: 129 self.set_position(0)
130
131 - def move_next(self):
132 """ 133 Moves the canvas to the next conduit 134 """ 135 self.set_position(self.position + 1)
136
137 - def move_previous(self):
138 """ 139 Moves the canvas to the previous conduit 140 """ 141 self.set_position(self.position - 1)
142
143 - def set_position (self, index):
144 """ 145 Sets the Canvas position to the index provided 146 """ 147 nr_of_conduits = self.model.num_conduits() 148 149 if index > nr_of_conduits: 150 return 151 152 # get the old one 153 if self.position == index: 154 return 155 156 # set new index 157 self.position = index 158 159 log.debug("Current position %d, Lenght: %d" % (self.position, nr_of_conduits)) 160 161 # position cycling 162 if self.position == nr_of_conduits: 163 self.position = 0 164 elif self.position < 0: 165 self.position = nr_of_conduits - 1 166 167 self._refresh_current_item() 168 169 self.emit("position-changed")
170
171 - def get_position (self):
172 """ 173 Gets the position 174 """ 175 return self.position
176
177 - def get_position_str(self):
178 """ 179 Gets the position representation 180 """ 181 return "%s/%s" % (self.position + 1, self.model.num_conduits())
182
183 - def _refresh_current_item(self):
184 """ 185 Refreshes the current item; only in drawing, not the conduit 186 """ 187 self._remove_current_item() 188 189 try: 190 conduit = self.model.get_conduit(self.position) 191 self._create_item_for_conduit (conduit) 192 except: 193 self._show_welcome_message()
194
195 - def _remove_current_item (self):
196 """ 197 Clears the current conduit from the Canvas 198 """ 199 currentItem = self._get_child_conduit_canvas_item() 200 201 if not currentItem: 202 return 203 204 #remove the canvas item 205 idx = self.root.find_child(currentItem) 206 if idx != -1: 207 self.root.remove_child(idx) 208 else: 209 log.warn("Error finding item") 210 211 self._remove_overlap() 212 self._show_welcome_message()
213
214 - def _create_item_for_conduit (self, conduit):
215 c_x,c_y,c_w,c_h = self.get_bounds() 216 #Create the item and move it into position 217 bottom = self._get_bottom_of_conduits_coord() 218 conduitCanvasItem = ConduitCanvasItem( 219 parent=self.root, 220 model=conduit, 221 width=c_w) 222 conduitCanvasItem.translate( 223 LINE_WIDTH/2.0, 224 bottom+(LINE_WIDTH/2.0) 225 ) 226 227 # keep ref 228 self.selectedConduitItem = conduitCanvasItem 229 230 #FIXME Evilness to fix ConduitCanvasItems ending up too big (scrollbars suck!) 231 #self.set_size_request(self.CANVAS_WIDTH, self.CANVAS_HEIGHT) 232 #self.set_size_request(self.CANVAS_WIDTH, self.CANVAS_HEIGHT) 233 234 conduitCanvasItem.connect('button-press-event', self._on_conduit_button_press) 235 236 for dp in conduit.get_all_dataproviders(): 237 self.on_dataprovider_added(None, dp, conduitCanvasItem) 238 239 conduit.connect("dataprovider-added", self.on_dataprovider_added, conduitCanvasItem) 240 conduit.connect("dataprovider-removed", self.on_dataprovider_removed, conduitCanvasItem) 241 242 self._show_welcome_message()
243
244 - def _get_child_conduit_canvas_items(self):
245 items = [] 246 for i in range(0, self.root.get_n_children()): 247 condItem = self.root.get_child(i) 248 if isinstance(condItem, ConduitCanvasItem): 249 items.append(condItem) 250 return items
251
252 - def _get_child_conduit_canvas_item(self):
253 for i in range(0, self.root.get_n_children()): 254 condItem = self.root.get_child(i) 255 if isinstance(condItem, ConduitCanvasItem): 256 return condItem 257 258 return None
259
260 - def _get_child_dataprovider_canvas_items(self):
261 items = [] 262 263 conduitItem = self._get_child_conduit_canvas_item() 264 265 if conduitItem: 266 for i in range(0, conduitItem.get_n_children()): 267 dpItem = conduitItem.get_child(i) 268 if isinstance(dpItem, DataProviderCanvasItem): 269 items.append(dpItem) 270 return items
271 272 # def on_two_way_sync_toggle(self, widget): 273 # """ 274 # Enables or disables two way sync on dataproviders. 275 # """ 276 # if widget.get_active(): 277 # self.selectedConduitItem.model.enable_two_way_sync() 278 # else: 279 # self.selectedConduitItem.model.disable_two_way_sync() 280 281 # def on_slow_sync_toggle(self, widget): 282 # """ 283 # Enables or disables slow sync of dataproviders. 284 # """ 285 # if widget.get_active(): 286 # self.selectedConduitItem.model.enable_slow_sync() 287 # else: 288 # self.selectedConduitItem.model.disable_slow_sync() 289
290 -class DataProviderCanvasItem(conduit.gtkui.Canvas.DataProviderCanvasItem):
291 292 WIDGET_WIDTH = 160 293 WIDGET_HEIGHT = 85 294 LINE_WIDTH = 3.0 295
296 - def get_styled_item_names(self):
297 return ()
298
299 - def get_style_properties(self, specifier):
300 if specifier == "box": 301 #color the box differently if it is pending 302 if self.model.module == None: 303 color = GtkUtil.TANGO_COLOR_BUTTER_LIGHT 304 else: 305 if self.model.module_type == "source": 306 color = GtkUtil.TANGO_COLOR_ALUMINIUM1_MID 307 elif self.model.module_type == "sink": 308 color = GtkUtil.TANGO_COLOR_SKYBLUE_LIGHT 309 elif self.model.module_type == "twoway": 310 color = GtkUtil.TANGO_COLOR_BUTTER_MID 311 else: 312 color = None 313 314 kwargs = { 315 "line_width":LINE_WIDTH, 316 "stroke_color":"black", 317 "fill_color_rgba":color 318 } 319 elif specifier == "name": 320 kwargs = { 321 "font":"Sans 8" 322 } 323 elif specifier == "statusText": 324 kwargs = { 325 "font":"Sans 7", 326 "fill_color_rgba":GtkUtil.TANGO_COLOR_ALUMINIUM2_MID 327 } 328 329 return kwargs
330
331 -class ConduitCanvasItem(conduit.gtkui.Canvas.ConduitCanvasItem):
332 333 FLAT_BOX = False 334 DIVIDER = False 335 LINE_WIDTH = 3.0 336
337 - def get_styled_item_names(self):
338 return ()
339
340 - def get_style_properties(self, specifier):
341 if specifier == "boundingBox": 342 kwargs = { 343 "line_width":LINE_WIDTH, 344 "fill_color_rgba":GtkUtil.TANGO_COLOR_ALUMINIUM1_LIGHT, 345 "stroke_color":"black" 346 } 347 elif specifier == "progressText": 348 kwargs = { 349 "font":"Sans 7", 350 "fill_color":"black" 351 } 352 else: 353 kwargs = {} 354 355 return kwargs
356
357 -class ConnectorCanvasItem(conduit.gtkui.Canvas.ConnectorCanvasItem):
358
359 - def get_styled_item_names(self):
360 return ()
361
362 - def get_style_properties(self, specifier):
363 if specifier == "left_end_round": 364 kwargs = { 365 "fill_color":"black" 366 } 367 elif specifier in ("left_end_arrow", "right_end", "path"): 368 kwargs = { 369 "stroke_color":"black" 370 } 371 else: 372 kwargs = {} 373 374 return kwargs
375
376 -class ContextMenu(gtk.Menu):
377 - def __init__(self):
378 gtk.Menu.__init__(self)
379
380 - def _add_menu_item (self, text, activate_cb):
381 item = gtk.MenuItem(text) 382 item.connect("activate", activate_cb) 383 self.append(item) 384 return item
385
386 -class ConduitMenu(ContextMenu):
387 - def __init__(self, canvas):
388 ContextMenu.__init__(self) 389 self.canvas = canvas 390 391 self._add_menu_item("Refresh", self._on_conduit_refresh) 392 self._add_menu_item("Synchronize", self._on_conduit_sync) 393 394 self.show_all()
395
396 - def _on_conduit_refresh(self, menuItem):
397 conduit = self.canvas.selectedConduitItem.model 398 conduit.refresh()
399
400 - def _on_conduit_sync(self, menuItem):
401 conduit = self.canvas.selectedConduitItem.model 402 conduit.sync()
403
404 -class DataProviderMenu(ContextMenu):
405 - def __init__(self, canvas):
406 ContextMenu.__init__(self) 407 self.canvas = canvas 408 409 self.configureMenuItem = self._add_menu_item("Configure", self._on_configure_activate) 410 self._add_menu_item("Refresh", self._on_refresh_activate) 411 self.append(gtk.SeparatorMenuItem()) 412 self._add_menu_item("Delete", self._on_delete_activate) 413 414 self.show_all()
415
416 - def _on_configure_activate(self, menuItem):
417 dp = self.canvas.selectedDataproviderItem.model.module 418 419 log.debug("Configuring %s " % dp) 420 dp.configure(self.canvas.parentWindow)
421
422 - def _on_refresh_activate(self, menuItem):
423 dp = self.canvas.selectedDataproviderItem.model 424 cond = self.canvas.selectedConduitItem.model 425 cond.refresh_dataprovider(dp)
426
427 - def _on_delete_activate(self, menuItem):
428 dp = self.canvas.selectedDataproviderItem.model 429 cond = self.canvas.selectedConduitItem.model 430 cond.delete_dataprovider(dp)
431