Mercurial > libervia-desktop-kivy
diff cagou/core/menu.py @ 126:cd99f70ea592
global file reorganisation:
- follow common convention by puttin cagou in "cagou" instead of "src/cagou"
- added VERSION in cagou with current version
- updated dates
- moved main executable in /bin
- moved buildozer files in root directory
- temporary moved platform to assets/platform
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 05 Apr 2018 17:11:21 +0200 |
parents | src/cagou/core/menu.py@4d8c122b86a6 |
children | 397f2fb67aab |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cagou/core/menu.py Thu Apr 05 17:11:21 2018 +0200 @@ -0,0 +1,239 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Cagou: desktop/mobile frontend for Salut à Toi XMPP client +# Copyright (C) 2016-2018 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +from sat.core.i18n import _ +from sat.core import log as logging +log = logging.getLogger(__name__) +from cagou.core.constants import Const as C +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.label import Label +from kivy.uix.popup import Popup +from kivy import properties +from kivy.garden import contextmenu +from sat_frontends.quick_frontend import quick_menus +from cagou import G +import webbrowser + +ABOUT_TITLE = _(u"About {}".format(C.APP_NAME)) +ABOUT_CONTENT = _(u"""Cagou (Salut à Toi) v{} + +Cagou is a libre communication tool based on libre standard XMPP. + +Cagou is part of the "Salut à Toi" project +more informations at [color=5500ff][ref=website]salut-a-toi.org[/ref][/color] +""").format(C.APP_VERSION) + + +class AboutContent(Label): + + def on_ref_press(self, value): + if value == "website": + webbrowser.open("https://salut-a-toi.org") + + +class AboutPopup(Popup): + + def on_touch_down(self, touch): + if self.collide_point(*touch.pos): + self.dismiss() + return super(AboutPopup, self).on_touch_down(touch) + + +class MainMenu(contextmenu.AppMenu): + pass + + +class MenuItem(contextmenu.ContextMenuTextItem): + item = properties.ObjectProperty() + + def on_item(self, instance, item): + self.text = item.name + + def on_release(self): + super(MenuItem, self).on_release() + self.parent.hide() + selected = G.host.selected_widget + profile = None + if selected is not None: + try: + profile = selected.profile + except AttributeError: + pass + + if profile is None: + try: + profile = list(selected.profiles)[0] + except (AttributeError, IndexError): + try: + profile = list(G.host.profiles)[0] + except IndexError: + log.warning(u"Can't find profile") + self.item.call(selected, profile) + + +class MenuSeparator(contextmenu.ContextMenuDivider): + pass + + +class RootMenuContainer(contextmenu.AppMenuTextItem): + pass + + +class MenuContainer(contextmenu.ContextMenuTextItem): + pass + + +class MenusWidget(BoxLayout): + + def update(self, type_, caller=None): + """Method to call when menus have changed + + @param type_(unicode): menu type like in sat.core.sat_main.importMenu + @param caller(Widget): instance linked to the menus + """ + self.menus_container = G.host.menus.getMainContainer(type_) + self.createMenus(caller) + + def _buildMenus(self, container, caller=None): + """Recursively build menus of the container + + @param container(quick_menus.MenuContainer): menu container + @param caller(Widget): instance linked to the menus + """ + if caller is None: + main_menu = MainMenu() + self.add_widget(main_menu) + caller = main_menu + else: + context_menu = contextmenu.ContextMenu() + caller.add_widget(context_menu) + # FIXME: next line is needed after parent is set to avoid a display bug in contextmenu + # TODO: fix this upstream + context_menu._on_visible(False) + + caller = context_menu + + for child in container.getActiveMenus(): + if isinstance(child, quick_menus.MenuContainer): + if isinstance(caller, MainMenu): + menu_container = RootMenuContainer() + else: + menu_container = MenuContainer() + menu_container.text = child.name + caller.add_widget(menu_container) + self._buildMenus(child, caller=menu_container) + elif isinstance(child, quick_menus.MenuSeparator): + wid = MenuSeparator() + caller.add_widget(wid) + elif isinstance(child, quick_menus.MenuItem): + wid = MenuItem(item=child) + caller.add_widget(wid) + else: + log.error(u"Unknown child type: {}".format(child)) + + def createMenus(self, caller): + self.clear_widgets() + self._buildMenus(self.menus_container, caller) + + def onAbout(self): + about = AboutPopup() + about.title = ABOUT_TITLE + about.content = AboutContent(text=ABOUT_CONTENT, markup=True) + about.open() + + +class TransferItem(BoxLayout): + plug_info = properties.DictProperty() + + def on_touch_up(self, touch): + if not self.collide_point(*touch.pos): + return super(TransferItem, self).on_touch_up(touch) + else: + transfer_menu = self.parent + while not isinstance(transfer_menu, TransferMenu): + transfer_menu = transfer_menu.parent + transfer_menu.do_callback(self.plug_info) + return True + + +class TransferMenu(BoxLayout): + """transfer menu which handle display and callbacks""" + # callback will be called with path to file to transfer + callback = properties.ObjectProperty() + # cancel callback need to remove the widget for UI + # will be called with the widget to remove as argument + cancel_cb = properties.ObjectProperty() + # profiles if set will be sent to transfer widget, may be used to get specific files + profiles = properties.ObjectProperty() + transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted there\nServer admin(s) can see the file, and they choose how, when and if it will be deleted") + send_txt = _(u"The file will be sent unencrypted directly to your contact (without transiting by the server), except in some cases") + items_layout = properties.ObjectProperty() + + def __init__(self, **kwargs): + super(TransferMenu, self).__init__(**kwargs) + if self.cancel_cb is None: + self.cancel_cb = self.onTransferCancelled + if self.profiles is None: + self.profiles = iter(G.host.profiles) + for plug_info in G.host.getPluggedWidgets(type_=C.PLUG_TYPE_TRANSFER): + item = TransferItem( + plug_info = plug_info + ) + self.items_layout.add_widget(item) + + def show(self, caller_wid=None): + self.visible = True + G.host.app.root.add_widget(self) + + def on_touch_down(self, touch): + # we remove the menu if we click outside + # else we want to handle the event, but not + # transmit it to parents + if not self.collide_point(*touch.pos): + self.parent.remove_widget(self) + else: + return super(TransferMenu, self).on_touch_down(touch) + return True + + def _closeUI(self, wid): + G.host.closeUI() + + def onTransferCancelled(self, wid, cleaning_cb=None): + self._closeUI(wid) + if cleaning_cb is not None: + cleaning_cb() + + def do_callback(self, plug_info): + self.parent.remove_widget(self) + if self.callback is None: + log.warning(u"TransferMenu callback is not set") + else: + wid = None + external = plug_info.get('external', False) + def onTransferCb(file_path, cleaning_cb=None): + if not external: + self._closeUI(wid) + self.callback( + file_path, + cleaning_cb, + transfer_type = C.TRANSFER_UPLOAD if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND) + wid = plug_info['factory'](plug_info, onTransferCb, self.cancel_cb, self.profiles) + if not external: + G.host.showExtraUI(wid)