diff browser_side/richtext.py @ 254:28d3315a8003

browser_side: isolate the basic stuff of RecipientManager in a new class ListManager: - renamed most occurences of "recipient" to "contact" and "recipient type" to "contact key" or "list" - data to represent the lists and autocomplete values are parametrized - UI elements styles are set by default but can be ovewritten by a sub-class - popup menu for the list Button element has to be set with registerPopupMenuPanel - richtext UI uses the definitions from sat.tool.frontends.composition Know issues: - drag and drop AutoCompleteTextBox corrupts the list of remaining autocomplete values - selecting an autocomplete value with the mouse and not keybord is not working properly
author souliane <souliane@mailoo.org>
date Sat, 09 Nov 2013 09:38:17 +0100
parents d4e73d9140af
children d3c734669577
line wrap: on
line diff
--- a/browser_side/richtext.py	Sat Nov 09 08:53:03 2013 +0100
+++ b/browser_side/richtext.py	Sat Nov 09 09:38:17 2013 +0100
@@ -27,73 +27,14 @@
 from pyjamas.ui.Label import Label
 from pyjamas.ui.FlexTable import FlexTable
 from pyjamas.ui.HorizontalPanel import HorizontalPanel
-from recipients import RECIPIENT_TYPES, RecipientManager
-
-BUTTONS = {
-    "bold": {"tip": "Bold", "icon": "media/icons/dokuwiki/toolbar/16/bold.png"},
-    "italic": {"tip": "Italic", "icon": "media/icons/dokuwiki/toolbar/16/italic.png"},
-    "underline": {"tip": "Underline", "icon": "media/icons/dokuwiki/toolbar/16/underline.png"},
-    "code": {"tip": "Code", "icon": "media/icons/dokuwiki/toolbar/16/mono.png"},
-    "strikethrough": {"tip": "Strikethrough", "icon": "media/icons/dokuwiki/toolbar/16/strike.png"},
-    "heading": {"tip": "Heading", "icon": "media/icons/dokuwiki/toolbar/16/hequal.png"},
-    "numberedlist": {"tip": "Numbered List", "icon": "media/icons/dokuwiki/toolbar/16/ol.png"},
-    "list": {"tip": "List", "icon": "media/icons/dokuwiki/toolbar/16/ul.png"},
-    "link": {"tip": "Link", "icon": "media/icons/dokuwiki/toolbar/16/linkextern.png"},
-    "horizontalrule": {"tip": "Horizontal rule", "icon": "media/icons/dokuwiki/toolbar/16/hr.png"}
-    }
-
-# Define here your formats, the key must match the ones used in button.
-# Tupples values must have 3 elements : prefix to the selection or cursor
-# position, sample text to write if the marker is not applied on a selection,
-# suffix to the selection or cursor position.
-# FIXME: must be moved in backend and not harcoded like this
-FORMATS = {"markdown": {"bold": ("**", "bold", "**"),
-                        "italic": ("*", "italic", "*"),
-                        "code": ("`", "code", "`"),
-                        "heading": ("\n# ", "Heading 1", "\n## Heading 2\n"),
-                        "list": ("\n* ", "item", "\n    + subitem\n"),
-                        "link": ("[desc](", "link", ")"),
-                        "horizontalrule": ("\n***\n", "", "")
-                        },
-           "bbcode": {"bold": ("[b]", "bold", "[/b]"),
-                      "italic": ("[i]", "italic", "[/i]"),
-                      "underline": ("[u]", "underline", "[/u]"),
-                      "strikethrough": ("[s]", "strikethrough", "[/s]"),
-                      "code": ("[code]", "code", "[/code]"),
-                      "link": ("[url=", "link", "]desc[/url]"),
-                      "list": ("\n[list] [*]", "item 1", " [*]item 2 [/list]\n")
-                     },
-           "dokuwiki": {"bold": ("**", "bold", "**"),
-                        "italic": ("//", "italic", "//"),
-                        "underline": ("__", "underline", "__"),
-                        "strikethrough": ("<del>", "strikethrough", "</del>"),
-                        "code": ("<code>", "code", "</code>"),
-                        "heading": ("\n==== ", "Heading 1", " ====\n=== Heading 2 ===\n"),
-                        "link": ("[[", "link", "|desc]]"),
-                        "list": ("\n  * ", "item\n", "\n    * subitem\n"),
-                        "horizontalrule": ("\n----\n", "", "")
-                        },
-           "XHTML": {"bold": ("<b>", "bold", "</b>"),
-                        "italic": ("<i>", "italic", "</i>"),
-                        "underline": ("<u>", "underline", "</u>"),
-                        "strikethrough": ("<s>", "strikethrough", "</s>"),
-                        "code": ("<pre>", "code", "</pre>"),
-                        "heading": ("\n<h3>", "Heading 1", "</h3>\n<h4>Heading 2</h4>\n"),
-                        "link": ("<a href=\"", "link", "\">desc</a>"),
-                        "list": ("\n<ul><li>", "item 1", "</li><li>item 2</li></ul>\n"),
-                        "horizontalrule": ("\n<hr/>\n", "", "")
-                        }
-
-           }
-
-PARAM_KEY = "Composition"
-PARAM_NAME = "Syntax"
+from list_manager import ListManager
+from sat.tools.frontends import composition
 
 
 class RichTextEditor(FlexTable):
     """Panel for the rich text editor."""
 
-    def __init__(self, host, parent=None, onCloseCallback=None):
+    def __init__(self, host, parent, onCloseCallback=None):
         """Fill the editor with recipients panel, toolbar, text area..."""
 
         # TODO: don't forget to comment this before commit
@@ -102,8 +43,8 @@
         # This must be done before FlexTable.__init__ because it is used by setVisible
         self.host = host
 
-        offset1 = len(RECIPIENT_TYPES)
-        offset2 = len(FORMATS) if self._debug else 1
+        offset1 = len(composition.RECIPIENT_TYPES)
+        offset2 = len(composition.RICH_FORMATS) if self._debug else 1
         FlexTable.__init__(self, offset1 + offset2 + 2, 2)
         self.addStyleName('richTextEditor')
 
@@ -112,7 +53,7 @@
 
         # recipient types sub-panels are automatically added by the manager
         self.recipient = RecipientManager(self)
-        self.recipient.createWidgets()
+        self.recipient.createWidgets(title_format="%s: ")
 
         # Rich text tool bar is automatically added by setVisible
 
@@ -138,9 +79,9 @@
         to be also automatically removed from its parent, or the
         popup to be closed.
         @param host: the host
-        @popup parent: parent panel (in a popup if parent == None) .
-        @return: the RichTextEditor instance if popup is False, otherwise
-        a popup DialogBox containing the RichTextEditor.
+        @param parent: parent panel (or None to display in a popup).
+        @return: the RichTextEditor instance if parent is not None,
+        otherwise a popup DialogBox containing the RichTextEditor.
         """
         if not hasattr(host, 'richtext'):
             host.richtext = RichTextEditor(host, parent, onCloseCallback)
@@ -168,7 +109,7 @@
 
     def setVisible(self, kwargs):
         """Called each time the widget is displayed, after creation or after having been hidden."""
-        self.host.bridge.call('asyncGetParamA', self.setToolBar, PARAM_NAME, PARAM_KEY) or self.setToolBar(None)
+        self.host.bridge.call('asyncGetParamA', self.setToolBar, composition.PARAM_NAME_SYNTAX, composition.PARAM_KEY_COMPOSITION) or self.setToolBar(None)
         FlexTable.setVisible(self, kwargs)
 
     def __close(self):
@@ -185,17 +126,17 @@
         holding the rich text format is retrieved. It is called at
         each opening of the rich text editor because the user may
         have change his setting since the last time."""
-        if _format is None or _format not in FORMATS.keys():
-            _format = FORMATS.keys()[0]
+        if _format is None or _format not in composition.RICH_FORMATS.keys():
+            _format = composition.RICH_FORMATS.keys()[0]
         if hasattr(self, "_format") and self._format == _format:
             return
         self._format = _format
-        offset1 = len(RECIPIENT_TYPES)
+        offset1 = len(composition.RECIPIENT_TYPES)
         count = 0
-        for _format in FORMATS.keys() if self._debug else [self._format]:
+        for _format in composition.RICH_FORMATS.keys() if self._debug else [self._format]:
             toolbar = HorizontalPanel()
             toolbar.addStyleName('richTextToolbar')
-            for key in FORMATS[_format].keys():
+            for key in composition.RICH_FORMATS[_format].keys():
                 self.addToolbarButton(toolbar, _format, key)
             label = Label("Format: %s" % _format)
             label.addStyleName("richTextFormatLabel")
@@ -207,8 +148,8 @@
     def addToolbarButton(self, toolbar, _format, key):
         """Add a button with the defined parameters."""
         button = Button('<img src="%s" class="richTextIcon" />' %
-                        BUTTONS[key]["icon"])
-        button.setTitle(BUTTONS[key]["tip"])
+                        composition.RICH_BUTTONS[key]["icon"])
+        button.setTitle(composition.RICH_BUTTONS[key]["tip"])
         button.addStyleName('richTextToolButton')
         toolbar.add(button)
 
@@ -217,7 +158,7 @@
             text = self.textarea.getText()
             cursor_pos = self.textarea.getCursorPos()
             selection_length = self.textarea.getSelectionLength()
-            infos = FORMATS[_format][key]
+            infos = composition.RICH_FORMATS[_format][key]
             if selection_length == 0:
                 middle_text = infos[1]
             else:
@@ -235,7 +176,7 @@
     def syncFromUniBox(self):
         """Synchronize from unibox."""
         data, target = self.host.uni_box.getTargetAndData()
-        self.recipient.setRecipients({"To": [target]} if target else {})
+        self.recipient.setContacts({"To": [target]} if target else {})
         self.textarea.setText(data if data else "")
 
     def syncToUniBox(self, recipients=None):
@@ -245,7 +186,7 @@
         or if a recipient is set to an optional type (Cc, Bcc).
         @return True if the sync could be done, False otherwise"""
         if recipients is None:
-            recipients = self.recipient.getRecipients()
+            recipients = self.recipient.getContacts()
         target = ""
         # we could eventually allow more in the future
         allowed = 1
@@ -254,7 +195,7 @@
             if count == 0:
                 continue
             allowed -= count
-            if allowed < 0 or RECIPIENT_TYPES[key]["optional"]:
+            if allowed < 0 or composition.RECIPIENT_TYPES[key]["optional"]:
                 return False
             # TODO: change this if later more then one recipients are allowed
             target = recipients[key][0]
@@ -294,7 +235,7 @@
 
     def sendMessage(self):
         """Send the message."""
-        recipients = self.recipient.getRecipients()
+        recipients = self.recipient.getContacts()
         if self.syncToUniBox(recipients):
             # also check that we actually have a message target and data
             if len(recipients["To"]) > 0 and self.textarea.getText() != "":
@@ -309,3 +250,19 @@
         InfoDialog("Feature in development",
                    "Sending a message to more the one recipient," +
                    " to Cc or Bcc is not implemented yet!", Width="400px").center()
+
+
+class RecipientManager(ListManager):
+    """A manager for sub-panels to set the recipients for each recipient type."""
+
+    def __init__(self, parent):
+        # TODO: be sure we also display empty groups and disconnected contacts + their groups
+        # store the full list of potential recipients (groups and contacts)
+        list_ = []
+        list_.extend("@%s" % group for group in parent.host.contact_panel.getGroups())
+        list_.extend(contact for contact in parent.host.contact_panel.getContacts())
+        ListManager.__init__(self, parent, composition.RECIPIENT_TYPES, list_)
+
+        self.registerPopupMenuPanel(entries=composition.RECIPIENT_TYPES,
+                                    hide=lambda sender, key: self.__children[key]["panel"].isVisible(),
+                                    callback=self.setContactPanelVisible)