From bf477466db711b7758b9cd8f8b8d989379bf9d63 Mon Sep 17 00:00:00 2001 From: AbrahmAB Date: Tue, 19 Apr 2016 04:35:13 +0530 Subject: [PATCH] Send a file to multiple friends: Fixes #1471 pop-up window with the listview of the friends online is displayed, multiple friends cn be selected and pressing the send toolbutton sends the file to selected friends. Note: used the PopWindow class of sugar3.graphics as implemented in commit-> sugar-toolkit-gtk3:3d61134 --- src/jarabe/journal/palettes.py | 98 ++++++++++++---------- src/jarabe/view/Makefile.am | 2 + src/jarabe/view/friendlistmodel.py | 67 +++++++++++++++ src/jarabe/view/friendlistview.py | 130 +++++++++++++++++++++++++++++ 4 files changed, 252 insertions(+), 45 deletions(-) create mode 100644 src/jarabe/view/friendlistmodel.py create mode 100644 src/jarabe/view/friendlistview.py diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py index ce128a74ed..6542dd528e 100644 --- a/src/jarabe/journal/palettes.py +++ b/src/jarabe/journal/palettes.py @@ -34,8 +34,9 @@ from sugar3.graphics.alert import Alert from sugar3 import mime from sugar3 import profile +from sugar3.graphics.popwindow import PopWindow +from sugar3.graphics.toolbutton import ToolButton -from jarabe.model import friends from jarabe.model import filetransfer from jarabe.model import mimeregistry from jarabe.journal import misc @@ -43,6 +44,7 @@ from jarabe.journal import journalwindow from jarabe.webservice import accountsmanager from jarabe.journal.misc import get_mount_color +from jarabe.view.friendlistview import FriendListView class ObjectPalette(Palette): @@ -125,9 +127,7 @@ def __init__(self, journalactivity, metadata, detail=False): self.menu.append(menu_item) menu_item.show() - friends_menu = FriendsMenu() - friends_menu.connect('friend-selected', self.__friend_selected_cb) - menu_item.set_submenu(friends_menu) + menu_item.connect('activate', self.__friendlist_popup_cb) if detail is True: menu_item = MenuItem(_('View Details'), 'go-right') @@ -143,6 +143,9 @@ def __init__(self, journalactivity, metadata, detail=False): def __get_uid_list_cb(self): return [self._metadata['uid']] + def __friend_activate_cb(self, menu_item): + FriendListView() + def __start_activate_cb(self, menu_item): misc.resume(self._metadata, alert_window=journalwindow.get_journal_window()) @@ -183,7 +186,7 @@ def __detail_activate_cb(self, menu_item): def __volume_error_cb(self, menu_item, message, severity): self.emit('volume-error', message, severity) - def __friend_selected_cb(self, menu_item, buddy): + def __friend_selected_cb(self, menu_item, buddies): logging.debug('__friend_selected_cb') file_name = model.get_file(self._metadata['uid']) @@ -201,8 +204,9 @@ def __friend_selected_cb(self, menu_item, buddy): if not mime_type: mime_type = mime.get_for_file(file_name) - filetransfer.start_transfer(buddy, file_name, title, description, - mime_type) + for buddy in buddies: + filetransfer.start_transfer(buddy, file_name, title, description, + mime_type) def popup(self, immediate=False, state=None): if self._journalactivity.get_list_view().is_dragging(): @@ -210,6 +214,48 @@ def popup(self, immediate=False, state=None): Palette.popup(self, immediate) + def __friendlist_popup_cb(self, menu_item): + pop_up = FriendListPopup() + pop_up.connect('friend-selected', self.__friend_selected_cb) + + +class FriendListPopup(PopWindow): + __gtype_name__ = 'FriendListPopup' + + __gsignals__ = { + 'friend-selected': (GObject.SignalFlags.RUN_FIRST, None, + ([object])), + } + + def __init__(self): + PopWindow.__init__(self, True) + self.view = FriendListView() + self._scrolled_window = Gtk.ScrolledWindow() + self._scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, + Gtk.PolicyType.AUTOMATIC) + + self._scrolled_window.add(self.view) + width, height = PopWindow.FULLSCREEN + self.set_size_request(width*1/3, height*2/3) + self.modify_fg(Gtk.StateType.NORMAL, + style.COLOR_BLACK.get_gdk_color()) + self.get_vbox().pack_start(self._scrolled_window, True, True, 0) + self.get_title_box().props.title = 'Send to' + self._scrolled_window.show() + self.view.show() + self.show() + + ok_button = ToolButton(icon_name='document-send') + self.get_title_box().add_widget(ok_button, False, -1) + ok_button.connect('clicked', self.__send_clicked_cb) + ok_button.show() + + def __send_clicked_cb(self, button): + model = self.view.get_model() + selected = model.get_selected() + self.emit('friend-selected', selected) + self.destroy() + class CopyMenu(Gtk.Menu): __gtype_name__ = 'JournalCopyMenu' @@ -451,44 +497,6 @@ def __clipboard_clear_func_cb(self, clipboard, data): self._temp_file_path = None -class FriendsMenu(Gtk.Menu): - __gtype_name__ = 'JournalFriendsMenu' - - __gsignals__ = { - 'friend-selected': (GObject.SignalFlags.RUN_FIRST, None, - ([object])), - } - - def __init__(self): - Gtk.Menu.__init__(self) - - if filetransfer.file_transfer_available(): - friends_model = friends.get_model() - for friend in friends_model: - if friend.is_present(): - menu_item = MenuItem(text_label=friend.get_nick(), - icon_name='computer-xo', - xo_color=friend.get_color()) - menu_item.connect('activate', self.__item_activate_cb, - friend) - self.append(menu_item) - menu_item.show() - - if not self.get_children(): - menu_item = MenuItem(_('No friends present')) - menu_item.set_sensitive(False) - self.append(menu_item) - menu_item.show() - else: - menu_item = MenuItem(_('No valid connection found')) - menu_item.set_sensitive(False) - self.append(menu_item) - menu_item.show() - - def __item_activate_cb(self, menu_item, friend): - self.emit('friend-selected', friend) - - class StartWithMenu(Gtk.Menu): __gtype_name__ = 'JournalStartWithMenu' diff --git a/src/jarabe/view/Makefile.am b/src/jarabe/view/Makefile.am index 94c50ecafc..c858a378d7 100644 --- a/src/jarabe/view/Makefile.am +++ b/src/jarabe/view/Makefile.am @@ -6,6 +6,8 @@ sugar_PYTHON = \ buddymenu.py \ cursortracker.py \ customizebundle.py \ + friendlistmodel.py \ + friendlistview.py \ gesturehandler.py \ keyhandler.py \ launcher.py \ diff --git a/src/jarabe/view/friendlistmodel.py b/src/jarabe/view/friendlistmodel.py new file mode 100644 index 0000000000..4a1bb2ae85 --- /dev/null +++ b/src/jarabe/view/friendlistmodel.py @@ -0,0 +1,67 @@ +# Copyright (C) 2016, Abhijit Patel +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import logging + +from gi.repository import GObject +from gi.repository import Gtk +from jarabe.model import friends + + +class FriendListModel(GObject.GObject): + __gtype_name__ = 'FriendListModel' + + COLUMN_SELECT = 0 + COLUMN_XO_COLOR = 1 + COLUMN_NICK = 2 + COLUMN_FRIEND = 3 + + _COLUMN_TYPES = { + COLUMN_SELECT: bool, + COLUMN_XO_COLOR: object, + COLUMN_NICK: str, + COLUMN_FRIEND: object + } + + def __init__(self): + GObject.GObject.__init__(self) + + self.friend_list = friends.get_model() + self._selected = [] + + self._list_store = Gtk.ListStore(bool, object, str, object) + + for friend in self.friend_list: + if friend.get_handle() is not None: + nick = friend.get_nick() + color = friend.get_color() + row = (False, color, nick, friend) + self._list_store.append(row) + + def get_selected(self): + return self._selected + + def get_liststore(self): + return self._list_store + + def is_selected(self, friend): + return friend in self._selected + + def set_selected(self, friend, value): + if value: + self._selected.append(friend) + else: + self._selected.remove(friend) diff --git a/src/jarabe/view/friendlistview.py b/src/jarabe/view/friendlistview.py new file mode 100644 index 0000000000..830bb262a8 --- /dev/null +++ b/src/jarabe/view/friendlistview.py @@ -0,0 +1,130 @@ +# Copyright (C) 2016, Abhijit Patel +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import logging + +from gi.repository import GObject +from gi.repository import Gtk + +from sugar3.graphics import style +from sugar3.graphics.icon import CellRendererIcon + +from jarabe.view.friendlistmodel import FriendListModel + + +class FriendListView(Gtk.TreeView): + __gtype_name__ = 'FriendListView' + + def __init__(self): + Gtk.TreeView.__init__(self) + + self._model = FriendListModel() + self.set_model(self._model.get_liststore()) + selection = self.get_selection() + selection.set_mode(Gtk.SelectionMode.NONE) + + cell_select = Gtk.CellRendererToggle() + cell_select.connect('toggled', self.__cell_select_toggled_cb) + cell_select.props.activatable = True + cell_select.props.xpad = style.DEFAULT_PADDING + cell_select.props.indicator_size = style.zoom(26) + + column = Gtk.TreeViewColumn() + column.props.sizing = Gtk.TreeViewColumnSizing.FIXED + column.props.fixed_width = style.GRID_CELL_SIZE + column.pack_start(cell_select, True) + column.set_cell_data_func(cell_select, self.__select_set_data_cb) + self.append_column(column) + + buddies_column = Gtk.TreeViewColumn() + buddies_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED + self.append_column(buddies_column) + + cell_icon = CellRendererBuddy() + cell_icon.props.sensitive = False + buddies_column.pack_start(cell_icon, True) + buddies_column.props.fixed_width += cell_icon.props.width + buddies_column.add_attribute(cell_icon, + 'xo-color', + FriendListModel.COLUMN_XO_COLOR) + buddies_column.set_cell_data_func(cell_icon, + self.__buddies_set_data_cb) + self.append_column(buddies_column) + + self.cell_title = Gtk.CellRendererText() + self.cell_title.props.ellipsize = style.ELLIPSIZE_MODE_DEFAULT + self.cell_title.props.ellipsize_set = True + + self._title_column = Gtk.TreeViewColumn() + self._title_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED + self._title_column.props.expand = True + self._title_column.props.clickable = False + self._title_column.pack_start(self.cell_title, True) + self._title_column.add_attribute(self.cell_title, 'markup', + FriendListModel.COLUMN_NICK) + self.append_column(self._title_column) + + def get_model(self): + return self._model + + def __select_set_data_cb(self, column, cell, tree_model, tree_iter, + data): + logging.debug('select_set_data_cb') + friend = tree_model[tree_iter] + + if friend is None: + return + cell.props.active = \ + self._model.is_selected(friend[FriendListModel.COLUMN_FRIEND]) + + def __cell_select_toggled_cb(self, cell, path): + logging.debug('cell_select_toggled_cb') + friend = self._model.get_liststore()[path] + if friend is None: + return + self._model.set_selected(friend[FriendListModel.COLUMN_FRIEND], + not cell.get_active()) + cell.props.active = \ + self._model.is_selected(friend[FriendListModel.COLUMN_FRIEND]) + + def __buddies_set_data_cb(self, column, cell, tree_model, tree_iter, + data): + friend = tree_model[tree_iter] + cell.props.xo_color = friend[FriendListModel.COLUMN_XO_COLOR] + + +class CellRendererBuddy(CellRendererIcon): + __gtype_name__ = 'CellRendererBuddy' + + def __init__(self): + CellRendererIcon.__init__(self) + + self.props.width = style.STANDARD_ICON_SIZE + self.props.height = style.STANDARD_ICON_SIZE + self.props.size = style.STANDARD_ICON_SIZE + self.props.mode = Gtk.CellRendererMode.ACTIVATABLE + self.props.icon_name = 'computer-xo' + self.nick = None + + def set_buddy(self, buddy): + if buddy is None: + self.props.icon_name = None + self.nick = None + else: + self.nick, xo_color = buddy + self.props.xo_color = xo_color + + buddy = GObject.property(type=object, setter=set_buddy)