diff src/browser/sat_browser/main_panel.py @ 679:a90cc8fc9605

merged branch frontends_multi_profiles
author Goffi <goffi@goffi.org>
date Wed, 18 Mar 2015 16:15:18 +0100
parents src/browser/sat_browser/panels.py@3eb3a2c0c011 src/browser/sat_browser/panels.py@849ffb24d5bf
children e876f493dccc
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/browser/sat_browser/main_panel.py	Wed Mar 18 16:15:18 2015 +0100
@@ -0,0 +1,297 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Libervia: a Salut à Toi frontend
+# Copyright (C) 2011, 2012, 2013, 2014 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/>.
+
+"""Panels used as main basis"""
+
+import pyjd  # this is dummy in pyjs
+from sat.core.log import getLogger
+log = getLogger(__name__)
+
+from sat.core.i18n import _
+from sat_frontends.tools.strings import addURLToText
+
+from pyjamas.ui.DockPanel import DockPanel
+from pyjamas.ui.HorizontalPanel import HorizontalPanel
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.Button import Button
+from pyjamas.ui.HTML import HTML
+from pyjamas.ui.ClickListener import ClickHandler
+from pyjamas.Timer import Timer
+from pyjamas.ui import HasVerticalAlignment
+
+
+import menu
+import dialog
+import base_widget
+import base_menu
+import libervia_widget
+import editor_widget
+import contact_list
+from constants import Const as C
+
+
+### Warning notification (visibility of message, and other warning data) ###
+
+
+class WarningPopup():
+
+    def __init__(self):
+        self._popup = None
+        self._timer = Timer(notify=self._timeCb)
+
+    def showWarning(self, type_=None, msg=None, duration=2000):
+        """Display a popup information message, e.g. to notify the recipient of a message being composed.
+        If type_ is None, a popup being currently displayed will be hidden.
+        @type_: a type determining the CSS style to be applied (see _showWarning)
+        @msg: message to be displayed
+        """
+        if type_ is None:
+            self.__removeWarning()
+            return
+        if not self._popup:
+            self._showWarning(type_, msg)
+        elif (type_, msg) != self._popup.target_data:
+            self._timeCb(None)  # we remove the popup
+            self._showWarning(type_, msg)
+
+        self._timer.schedule(duration)
+
+    def _showWarning(self, type_, msg):
+        """Display a popup information message, e.g. to notify the recipient of a message being composed.
+        @type_: a type determining the CSS style to be applied. For now the defined styles are
+        "NONE" (will do nothing), "PUBLIC", "GROUP", "STATUS" and "ONE2ONE".
+        @msg: message to be displayed
+        """
+        if type_ == "NONE":
+            return
+        if not msg:
+            log.warning("no msg set uniBox warning")
+            return
+        if type_ == "PUBLIC":
+            style = "targetPublic"
+        elif type_ == "GROUP":
+            style = "targetGroup"
+        elif type_ == "STATUS":
+            style = "targetStatus"
+        elif type_ == "ONE2ONE":
+            style = "targetOne2One"
+        else:
+            log.error("unknown message type")
+            return
+        contents = HTML(msg)
+
+        self._popup = dialog.PopupPanelWrapper(autoHide=False, modal=False)
+        self._popup.target_data = (type_, msg)
+        self._popup.add(contents)
+        self._popup.setStyleName("warningPopup")
+        if style:
+            self._popup.addStyleName(style)
+
+        left = 0
+        top = 0  # max(0, self.getAbsoluteTop() - contents.getOffsetHeight() - 2)
+        self._popup.setPopupPosition(left, top)
+        self._popup.show()
+
+    def _timeCb(self, timer):
+        if self._popup:
+            self._popup.hide()
+            del self._popup
+            self._popup = None
+
+    def __removeWarning(self):
+        """Remove the popup"""
+        self._timeCb(None)
+
+
+### Status ###
+
+
+class StatusPanel(editor_widget.HTMLTextEditor):
+
+    EMPTY_STATUS = '&lt;click to set a status&gt;'
+
+    def __init__(self, host, status=''):
+        self.host = host
+        modifiedCb = lambda content: self.host.bridge.call('setStatus', None, self.host.presence_status_panel.presence, content['text']) or True
+        editor_widget.HTMLTextEditor.__init__(self, {'text': status}, modifiedCb, options={'no_xhtml': True, 'listen_focus': True, 'listen_click': True})
+        self.edit(False)
+        self.setStyleName('marginAuto')
+
+    @property
+    def status(self):
+        return self._original_content['text']
+
+    def __cleanContent(self, content):
+        status = content['text']
+        if status == self.EMPTY_STATUS or status in C.PRESENCE.values():
+            content['text'] = ''
+        return content
+
+    def getContent(self):
+        return self.__cleanContent(editor_widget.HTMLTextEditor.getContent(self))
+
+    def setContent(self, content):
+        content = self.__cleanContent(content)
+        editor_widget.BaseTextEditor.setContent(self, content)
+
+    def setDisplayContent(self):
+        status = self._original_content['text']
+        try:
+            presence = self.host.presence_status_panel.presence
+        except AttributeError:  # during initialization
+            presence = None
+        if not status:
+            if presence and presence in C.PRESENCE:
+                status = C.PRESENCE[presence]
+            else:
+                status = self.EMPTY_STATUS
+        self.display.setHTML(addURLToText(status))
+
+
+class PresenceStatusMenuBar(base_widget.WidgetMenuBar):
+    def __init__(self, parent):
+        styles = {'menu_bar': 'presence-button'}
+        base_widget.WidgetMenuBar.__init__(self, parent, parent.host, styles=styles)
+        self.button = self.addCategory(u"◉")
+        presence_menu = self.button.getSubMenu()
+        for presence, presence_i18n in C.PRESENCE.items():
+            html = u'<span class="%s">◉</span> %s' % (contact_list.buildPresenceStyle(presence), presence_i18n)
+            presence_menu.addItem(html, True, base_menu.SimpleCmd(lambda presence=presence: self.changePresenceCb(presence)))
+        self.parent_panel = parent
+
+    def changePresenceCb(self, presence=''):
+        """Callback to notice the backend of a new presence set by the user.
+        @param presence (unicode): the new presence is a value in ('', 'chat', 'away', 'dnd', 'xa')
+        """
+        self.host.bridge.call('setStatus', None, presence, self.parent_panel.status_panel.status)
+
+    @classmethod
+    def getCategoryHTML(cls, menu_name_i18n, type_):
+        return menu_name_i18n
+
+
+class PresenceStatusPanel(HorizontalPanel, ClickHandler):
+
+    def __init__(self, host, presence="", status=""):
+        self.host = host
+        self.plugin_menu_context = []
+        HorizontalPanel.__init__(self, Width='100%')
+        self.presence_bar = PresenceStatusMenuBar(self)
+        self.status_panel = StatusPanel(host, status=status)
+        self.setPresence(presence)
+
+        panel = HorizontalPanel()
+        panel.add(self.presence_bar)
+        panel.add(self.status_panel)
+        panel.setCellVerticalAlignment(self.presence_bar, 'baseline')
+        panel.setCellVerticalAlignment(self.status_panel, 'baseline')
+        panel.setStyleName("presenceStatusPanel")
+        self.add(panel)
+
+        self.status_panel.edit(False)
+
+        ClickHandler.__init__(self)
+        self.addClickListener(self)
+
+    @property
+    def presence(self):
+        return self._presence
+
+    @property
+    def status(self):
+        return self.status_panel._original_content['text']
+
+    def setPresence(self, presence):
+        self._presence = presence
+        contact_list.setPresenceStyle(self.presence_bar.button, self._presence)
+
+    def setStatus(self, status):
+        self.status_panel.setContent({'text': status})
+        self.status_panel.setDisplayContent()
+
+    def onClick(self, sender):
+        # As status is the default target of uniBar, we don't want to select anything if click on it
+        self.host.setSelected(None)
+
+
+### Panels managing the main area ###
+
+
+class MainPanel(DockPanel):
+    """The panel which take the whole screen"""
+
+    def __init__(self, host):
+        self.host = host
+        DockPanel.__init__(self, StyleName="mainPanel liberviaTabPanel")
+
+        # menu and status panel
+        self.header = VerticalPanel(StyleName="header")
+        self.menu = menu.MainMenuBar(host)
+        self.header.add(self.menu)
+
+        # contacts
+        self.contacts_switch = Button(u'«', self._contactsSwitch)
+        self.contacts_switch.addStyleName('contactsSwitch')
+
+        # tab panel
+        self.tab_panel = libervia_widget.MainTabPanel(host)
+        self.tab_panel.addWidgetsTab(_(u"Discussions"), select=True, locked=True)
+
+        # XXX: widget's addition order is important!
+        self.add(self.header, DockPanel.NORTH)
+        self.add(self.tab_panel, DockPanel.CENTER)
+        self.setCellWidth(self.tab_panel, '100%')
+        self.setCellHeight(self.tab_panel, '100%')
+        self.add(self.tab_panel.getTabBar(), DockPanel.SOUTH)
+
+    def addContactList(self, contact_list):
+        self.add(self.contacts_switch, DockPanel.WEST)
+        self.add(contact_list, DockPanel.WEST)
+
+    def addPresenceStatusPanel(self, panel):
+        self.header.add(panel)
+        self.header.setCellHeight(panel, '100%')
+        self.header.setCellVerticalAlignment(panel, HasVerticalAlignment.ALIGN_BOTTOM)
+
+    def _contactsSwitch(self, btn=None):
+        """ (Un)hide contacts panel """
+        if btn is None:
+            btn = self.contacts_switch
+        clist = self.host.contact_list
+        clist.setVisible(not clist.getVisible())
+        btn.setText(u"«" if clist.getVisible() else u"»")
+        self.host.resize()
+
+    def _contactsMove(self, parent):
+        """Move the contacts container (containing the contact list and
+        the "hide/show" button) to another parent, but always as the
+        first child position (insert at index 0).
+        """
+        if self._contacts.getParent():
+            if self._contacts.getParent() == parent:
+                return
+            self._contacts.removeFromParent()
+        parent.insert(self._contacts, 0)
+
+    def refresh(self):
+        """Refresh the main panel"""
+        self.unibox_panel.refresh()
+        self.host.contact_panel.refresh()
+
+