| 
									
										
										
										
											2007-04-17 21:53:34 +02:00
										 |  |  | import shutil | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | import logging | 
					
						
							| 
									
										
										
										
											2007-04-17 21:53:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | import hippo | 
					
						
							|  |  |  | import gtk | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | from sugar import util | 
					
						
							|  |  |  | from view.clipboardicon import ClipboardIcon | 
					
						
							|  |  |  | from sugar.clipboard import clipboardservice | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _ContextMap: | 
					
						
							|  |  |  |     """Maps a drag context to the clipboard object involved in the dragging.""" | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self._context_map = {} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def add_context(self, context, object_id, data_types): | 
					
						
							|  |  |  |         """Establishes the mapping. data_types will serve us for reference-
 | 
					
						
							|  |  |  |         counting this mapping. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self._context_map[context] = [object_id, data_types] | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def get_object_id(self, context): | 
					
						
							|  |  |  |         """Retrieves the object_id associated with context.
 | 
					
						
							|  |  |  |         Will release the association when this function was called as many times | 
					
						
							|  |  |  |         as the number of data_types that this clipboard object contains. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         [object_id, data_types_left] = self._context_map[context] | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         data_types_left = data_types_left - 1 | 
					
						
							|  |  |  |         if data_types_left == 0: | 
					
						
							|  |  |  |             del self._context_map[context] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self._context_map[context] = [object_id, data_types_left] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return object_id | 
					
						
							| 
									
										
										
										
											2006-12-16 23:55:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def has_context(self, context): | 
					
						
							|  |  |  |         return context in self._context_map | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |   | 
					
						
							|  |  |  | class ClipboardBox(hippo.CanvasBox): | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2007-02-21 21:12:27 +01:00
										 |  |  |     def __init__(self, popup_context): | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         hippo.CanvasBox.__init__(self) | 
					
						
							| 
									
										
										
										
											2007-02-21 21:12:27 +01:00
										 |  |  |         self._popup_context = popup_context | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         self._icons = {} | 
					
						
							|  |  |  |         self._context_map = _ContextMap() | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |         self._selected_icon = None | 
					
						
							|  |  |  |         self._owns_clipboard = False | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self._pressed_button = None | 
					
						
							|  |  |  |         self._press_start_x = None | 
					
						
							|  |  |  |         self._press_start_y = None | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         cb_service = clipboardservice.get_instance() | 
					
						
							|  |  |  |         cb_service.connect('object-added', self._object_added_cb) | 
					
						
							|  |  |  |         cb_service.connect('object-deleted', self._object_deleted_cb) | 
					
						
							|  |  |  |         cb_service.connect('object-state-changed', self._object_state_changed_cb) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |     def owns_clipboard(self): | 
					
						
							|  |  |  |         return self._owns_clipboard | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |     def _get_icon_at_coords(self, x, y): | 
					
						
							|  |  |  |         for object_id, icon in self._icons.iteritems(): | 
					
						
							|  |  |  |             [icon_x, icon_y] = self.get_position(icon) | 
					
						
							|  |  |  |             [icon_width, icon_height] = icon.get_allocation() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (x >= icon_x ) and (x <= icon_x + icon_width) and        \ | 
					
						
							|  |  |  |                     (y >= icon_y ) and (y <= icon_y + icon_height): | 
					
						
							|  |  |  |                 return icon | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _add_selection(self, object_id, selection): | 
					
						
							| 
									
										
										
										
											2007-03-14 05:50:06 +01:00
										 |  |  |         if not selection.data: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-17 21:53:34 +02:00
										 |  |  |         logging.debug('ClipboardBox: adding type ' + selection.type + ' ' + selection.data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-14 05:50:06 +01:00
										 |  |  |         cb_service = clipboardservice.get_instance() | 
					
						
							| 
									
										
										
										
											2007-04-17 21:53:34 +02:00
										 |  |  |         if selection.type == 'text/uri-list': | 
					
						
							|  |  |  |             # Copy the file, as it will be deleted when the dnd operation finishes. | 
					
						
							|  |  |  |             file_path = selection.data.replace('file://', '') | 
					
						
							|  |  |  |             new_file_path = os.path.join(os.path.split(file_path)[0], | 
					
						
							|  |  |  |                                          "cb" + os.path.split(file_path)[1]) | 
					
						
							|  |  |  |             shutil.copyfile(file_path, new_file_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             cb_service.add_object_format(object_id,  | 
					
						
							|  |  |  |                                          selection.type, | 
					
						
							|  |  |  |                                          'file://' + new_file_path, | 
					
						
							|  |  |  |                                          on_disk=True) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             cb_service.add_object_format(object_id,  | 
					
						
							|  |  |  |                                          selection.type, | 
					
						
							|  |  |  |                                          selection.data, | 
					
						
							|  |  |  |                                          on_disk=False) | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |      | 
					
						
							|  |  |  |     def _object_added_cb(self, cb_service, object_id, name): | 
					
						
							| 
									
										
										
										
											2007-02-21 21:12:27 +01:00
										 |  |  |         icon = ClipboardIcon(self._popup_context, object_id, name) | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |         icon.connect('activated', self._icon_activated_cb) | 
					
						
							|  |  |  |         self._set_icon_selected(icon) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.prepend(icon) | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         self._icons[object_id] = icon | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         logging.debug('ClipboardBox: ' + object_id + ' was added.') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |     def _set_icon_selected(self, icon): | 
					
						
							|  |  |  |         logging.debug('_set_icon_selected') | 
					
						
							|  |  |  |         icon.props.selected = True | 
					
						
							|  |  |  |         if self._selected_icon: | 
					
						
							|  |  |  |             self._selected_icon.props.selected = False | 
					
						
							|  |  |  |         self._selected_icon = icon | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _put_in_clipboard(self, object_id): | 
					
						
							|  |  |  |         logging.debug('ClipboardBox._put_in_clipboard') | 
					
						
							|  |  |  |         targets = self._get_object_targets(object_id) | 
					
						
							|  |  |  |         if targets: | 
					
						
							|  |  |  |             clipboard = gtk.Clipboard() | 
					
						
							|  |  |  |             if not clipboard.set_with_data(targets, | 
					
						
							|  |  |  |                                            self._clipboard_data_get_cb, | 
					
						
							|  |  |  |                                            self._clipboard_clear_cb): | 
					
						
							|  |  |  |                 logging.error('GtkClipboard.set_with_data failed!') | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self._owns_clipboard = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _clipboard_data_get_cb(self, clipboard, selection, info, data): | 
					
						
							|  |  |  |         object_id = self._selected_icon.get_object_id() | 
					
						
							|  |  |  |         cb_service = clipboardservice.get_instance() | 
					
						
							|  |  |  |         data = cb_service.get_object_data(object_id, selection.target) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         selection.set(selection.target, 8, data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _clipboard_clear_cb(self, clipboard, data): | 
					
						
							|  |  |  |         logging.debug('ClipboardBox._clipboard_clear_cb') | 
					
						
							|  |  |  |         self._owns_clipboard = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _icon_activated_cb(self, icon): | 
					
						
							|  |  |  |         logging.debug('ClipboardBox._icon_activated_cb') | 
					
						
							|  |  |  |         if not icon.props.selected: | 
					
						
							|  |  |  |             self._set_icon_selected(icon) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |     def _object_deleted_cb(self, cb_service, object_id): | 
					
						
							|  |  |  |         icon = self._icons[object_id] | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |         position = self.get_children().index(icon) | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         self.remove(icon) | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2007-03-20 12:58:52 +01:00
										 |  |  |         if icon.props.selected and self.get_children(): | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |             self._set_icon_selected(self.get_children()[position]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         del self._icons[object_id] | 
					
						
							|  |  |  |         logging.debug('ClipboardBox: ' + object_id + ' was deleted.') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-11 18:22:52 +02:00
										 |  |  |     def _object_state_changed_cb(self, cb_service, object_id, name, percent, | 
					
						
							|  |  |  |                                  icon_name, preview, activity): | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         icon = self._icons[object_id] | 
					
						
							| 
									
										
										
										
											2007-04-11 18:22:52 +02:00
										 |  |  |         icon.set_state(name, percent, icon_name, preview, activity) | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |         if icon.props.selected and percent == 100: | 
					
						
							|  |  |  |             self._put_in_clipboard(object_id) | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def drag_motion_cb(self, widget, context, x, y, time): | 
					
						
							| 
									
										
										
										
											2006-12-16 23:55:22 +01:00
										 |  |  |         logging.debug('ClipboardBox._drag_motion_cb') | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         context.drag_status(gtk.gdk.ACTION_COPY, time) | 
					
						
							| 
									
										
										
										
											2007-04-05 17:22:27 +02:00
										 |  |  |         return True; | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def drag_drop_cb(self, widget, context, x, y, time): | 
					
						
							| 
									
										
										
										
											2006-12-16 23:55:22 +01:00
										 |  |  |         logging.debug('ClipboardBox._drag_drop_cb') | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         cb_service = clipboardservice.get_instance() | 
					
						
							| 
									
										
										
										
											2007-03-14 05:50:06 +01:00
										 |  |  |         object_id = cb_service.add_object(name="") | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-14 05:50:06 +01:00
										 |  |  |         self._context_map.add_context(context, object_id, len(context.targets)) | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         for target in context.targets: | 
					
						
							|  |  |  |             if str(target) not in ('TIMESTAMP', 'TARGETS', 'MULTIPLE'): | 
					
						
							|  |  |  |                 widget.drag_get_data(context, target, time) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-05 21:13:46 +01:00
										 |  |  |         cb_service.set_object_percent(object_id, percent = 100) | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |          | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def drag_data_received_cb(self, widget, context, x, y, selection, targetType, time): | 
					
						
							|  |  |  |         logging.debug('ClipboardBox: got data for target ' + selection.target) | 
					
						
							| 
									
										
										
										
											2007-04-17 21:53:34 +02:00
										 |  |  |         try: | 
					
						
							|  |  |  |             if selection: | 
					
						
							|  |  |  |                 object_id = self._context_map.get_object_id(context) | 
					
						
							|  |  |  |                 self._add_selection(object_id, selection) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 logging.warn('ClipboardBox: empty selection for target ' + selection.target) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             # If it's the last target to be processed, finish the dnd transaction | 
					
						
							|  |  |  |             if not self._context_map.has_context(context): | 
					
						
							|  |  |  |                 context.drop_finish(True, gtk.get_current_event_time()) | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def drag_data_get_cb(self, widget, context, selection, targetType, eventTime): | 
					
						
							|  |  |  |         logging.debug("drag_data_get_cb: requested target " + selection.target) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         object_id = self._last_clicked_icon.get_object_id() | 
					
						
							|  |  |  |         cb_service = clipboardservice.get_instance() | 
					
						
							|  |  |  |         data = cb_service.get_object_data(object_id, selection.target) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         selection.set(selection.target, 8, data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def button_press_event_cb(self, widget, event): | 
					
						
							|  |  |  |         logging.debug("button_press_event_cb") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS: | 
					
						
							|  |  |  |             self._last_clicked_icon = self._get_icon_at_coords(event.x, event.y) | 
					
						
							|  |  |  |             if self._last_clicked_icon: | 
					
						
							|  |  |  |                 self._pressed_button = event.button | 
					
						
							|  |  |  |                 self._press_start_x = event.x | 
					
						
							|  |  |  |                 self._press_start_y = event.y | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return True; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def motion_notify_event_cb(self, widget, event): | 
					
						
							| 
									
										
										
										
											2006-12-14 13:50:42 +01:00
										 |  |  |         | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         if not self._pressed_button: | 
					
						
							|  |  |  |             return True | 
					
						
							| 
									
										
										
										
											2006-12-14 13:50:42 +01:00
										 |  |  |          | 
					
						
							|  |  |  |         # if the mouse button is not pressed, no drag should occurr | 
					
						
							|  |  |  |         if not event.state & gtk.gdk.BUTTON1_MASK: | 
					
						
							|  |  |  |             self._pressed_button = None | 
					
						
							|  |  |  |             return True | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         logging.debug("motion_notify_event_cb") | 
					
						
							|  |  |  |                          | 
					
						
							|  |  |  |         if event.is_hint: | 
					
						
							|  |  |  |             x, y, state = event.window.get_pointer() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             x = event.x | 
					
						
							|  |  |  |             y = event.y | 
					
						
							|  |  |  |             state = event.state | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-14 13:50:42 +01:00
										 |  |  |         if widget.drag_check_threshold(int(self._press_start_x), | 
					
						
							|  |  |  |                                        int(self._press_start_y), | 
					
						
							|  |  |  |                                        int(x), | 
					
						
							|  |  |  |                                        int(y)): | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |             targets = self._get_object_targets( | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |                 self._last_clicked_icon.get_object_id()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             context = widget.drag_begin(targets, | 
					
						
							|  |  |  |                                         gtk.gdk.ACTION_COPY, | 
					
						
							|  |  |  |                                         1, | 
					
						
							|  |  |  |                                         event); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def drag_end_cb(self, widget, drag_context): | 
					
						
							|  |  |  |         logging.debug("drag_end_cb") | 
					
						
							|  |  |  |         self._pressed_button = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-14 13:32:05 +01:00
										 |  |  |     def _get_object_targets(self, object_id): | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         cb_service = clipboardservice.get_instance() | 
					
						
							| 
									
										
										
										
											2007-01-05 21:13:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-14 05:50:06 +01:00
										 |  |  |         attrs = cb_service.get_object(object_id) | 
					
						
							|  |  |  |         format_types = attrs[clipboardservice.FORMATS_KEY] | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2007-01-05 21:13:46 +01:00
										 |  |  |         targets = []         | 
					
						
							| 
									
										
										
										
											2006-12-13 22:36:05 +01:00
										 |  |  |         for format_type in format_types: | 
					
						
							|  |  |  |             targets.append((format_type, 0, 0)) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return targets |