<filename>src/annalist_root/annalist/views/form_utils/fieldchoice.py
"""
This module defines a class used to represent a choice for an 
enumerated-value field.
"""

from __future__ import unicode_literals
from __future__ import absolute_import, division, print_function

__author__      = "<NAME> (<EMAIL>)"
__copyright__   = "Copyright 2015, <NAME>"
__license__     = "MIT (http://opensource.org/licenses/MIT)"

import re
import logging
log = logging.getLogger(__name__)

from collections            import namedtuple

from utils.py3porting       import to_unicode

from django.utils.html      import format_html, mark_safe, escape

_FieldChoice_tuple = namedtuple("FieldChoice", ("id", "value", "label", "link", "choice_value"))

class FieldChoice(_FieldChoice_tuple):
    """
    Class representing a choice for an enumerated field.

    >>> c1 = FieldChoice('id1', 'value1', 'label1', 'link1', choice_value=True)
    >>> c1 == FieldChoice(id='id1', value='value1', label='label1', link='link1', choice_value=True)
    True
    >>> c1.id == 'id1'
    True
    >>> c1.value == 'value1'
    True
    >>> c1.label == 'label1'
    True
    >>> c1.link == 'link1'
    True
    >>> c1.choice_html() == u'label1&nbsp;&nbsp;&nbsp;(value1)'
    True
    >>> c2 = FieldChoice('id2', 'value2', 'label2', 'link2', choice_value=False)
    >>> c2 == FieldChoice(id='id2', value='value2', label='label2', link='link2', choice_value=False)
    True
    >>> c2.id == 'id2'
    True
    >>> c2.value == 'value2'
    True
    >>> c2.label == 'label2'
    True
    >>> c2.link == 'link2'
    True
    >>> c2.choice() == u'label2'
    True
    >>> c3 = FieldChoice(id='id3', value='value3', link='link3')
    >>> c3 == FieldChoice(id='id3', value='value3', label='value3', link='link3', choice_value=False)
    True
    >>> c3.id == 'id3'
    True
    >>> c3.value == 'value3'
    True
    >>> c3.label == 'value3'
    True
    >>> c3.link == 'link3'
    True
    >>> c4 = FieldChoice('id4', link='link4')
    >>> c4 == FieldChoice(id='id4', value='id4', label='id4', link='link4', choice_value=False)
    True
    >>> c4.id == 'id4'
    True
    >>> c4.value == 'id4'
    True
    >>> c4.label == 'id4'
    True
    >>> c4.link == 'link4'
    True
    >>> c5 = FieldChoice('')
    >>> c5 == FieldChoice(id='', value='', label='', link=None, choice_value=False)
    True
    """

    def __new__(_cls, id=None, value=None, label=None, link=None, choice_value=False):
        if value is None: value = id
        if label is None: label = value
        result = super(FieldChoice, _cls).__new__(_cls, id, value, label, link, choice_value)
        return result

    def __eq__(self, other):
        """
        Returns True if self == other for sorting and equivalence purposes
        """
        return self.id.__eq__(other.id)

    def __ne__(self, other):
        """
        Returns True if self != other for sorting and equivalence purposes

        Note: required for Python2.
        """
        return self.id.__ne__(other.id)

    def __lt__(self, other):
        """
        Returns True if self < other for sorting purposes
        """
        return self.id.__lt__(other.id)

    def __hash__(self):
        """
        pylint says this should be defined if __eq__ is defined.
        Something to do with sets?
        """
        return hash(self.id)

    def choice(self, sep=u"\xa0\xa0\xa0"):
        """
        Return choice string
        """
        if self.choice_value:
            choice_text = self.option_label(sep=sep)
        else:
            choice_text = to_unicode(self.label)
        return choice_text

    def choice_html(self, sep=u"&nbsp;&nbsp;&nbsp;"):
        """
        Return choice string HTML for option in drop-down list.
        """
        return self.choice(sep=sep)

    def add_link(self, link=None):
        return FieldChoice(self.id, self.value, self.label, link)

    def option_label(self, sep=u"\xa0\xa0\xa0"):
        """
        Returns string used for displayed option label.

        This function is used mainly for testing, to isolate details of 
        option presentation from the majority of test cases.
        """
        if self.label:
            return format_html(u"{}{}({})", self.label, mark_safe(sep), self.value)
        else:
            return escape(self.value)

    def option_label_html(self, sep=u"&nbsp;&nbsp;&nbsp;"):
        """
        Variation of option_label returns HTML-encoded form of label text
        """
        return self.option_label(sep=sep)


def update_choice_labels(fieldchoices):
    """
    Update choice labels in supplied list of FieldChoice values so that duplicate labels can
    be distinguished.

    Returns an updated list of options.
    """
    # Detect non-unique labels
    labels = {}
    for o in fieldchoices:
        l = o.label
        labels[l] = labels.get(l, 0) + 1
    # Generate updated choice values
    new_choices = []
    for o in fieldchoices:
        if labels[o.label] > 1:
            new_choices.append(
                FieldChoice(id=o.id, value=o.value, label=o.label, link=o.link, choice_value=True)
                )
        else:
            new_choices.append(o)
    return new_choices

def get_choice_labels(fieldchoices):
    """
    Return a list of choice labels based on the supplied list of FieldChoice values

    >>> c1  = FieldChoice('id1',  'value1',  'label1', 'link1')
    >>> c2a = FieldChoice('id2a', 'value2a', 'label2', 'link2')
    >>> c2b = FieldChoice('id2b', 'value2b', 'label2', 'link2')
    >>> labels = get_choice_labels([c1,c2a,c2b])
    >>> labels == ['label1', u'label2\\xa0\\xa0\\xa0(value2a)', u'label2\\xa0\\xa0\\xa0(value2b)']
    True
    """
    return [ fc.choice() for fc in update_choice_labels(fieldchoices) ]

if __name__ == "__main__":
    import doctest
    doctest.testmod()

# End.

<filename>src/annalist_root/annalist/views/form_utils/fieldchoice.py
"""
This module defines a class used to represent a choice for an 
enumerated-value field.
"""

from __future__ import unicode_literals
from __future__ import absolute_import, division, print_function

__author__      = "<NAME> (<EMAIL>)"
__copyright__   = "Copyright 2015, <NAME>"
__license__     = "MIT (http://opensource.org/licenses/MIT)"

import re
import logging
log = logging.getLogger(__name__)

from collections            import namedtuple

from utils.py3porting       import to_unicode

from django.utils.html      import format_html, mark_safe, escape

_FieldChoice_tuple = namedtuple("FieldChoice", ("id", "value", "label", "link", "choice_value"))

class FieldChoice(_FieldChoice_tuple):
    """
    Class representing a choice for an enumerated field.

    >>> c1 = FieldChoice('id1', 'value1', 'label1', 'link1', choice_value=True)
    >>> c1 == FieldChoice(id='id1', value='value1', label='label1', link='link1', choice_value=True)
    True
    >>> c1.id == 'id1'
    True
    >>> c1.value == 'value1'
    True
    >>> c1.label == 'label1'
    True
    >>> c1.link == 'link1'
    True
    >>> c1.choice_html() == u'label1&nbsp;&nbsp;&nbsp;(value1)'
    True
    >>> c2 = FieldChoice('id2', 'value2', 'label2', 'link2', choice_value=False)
    >>> c2 == FieldChoice(id='id2', value='value2', label='label2', link='link2', choice_value=False)
    True
    >>> c2.id == 'id2'
    True
    >>> c2.value == 'value2'
    True
    >>> c2.label == 'label2'
    True
    >>> c2.link == 'link2'
    True
    >>> c2.choice() == u'label2'
    True
    >>> c3 = FieldChoice(id='id3', value='value3', link='link3')
    >>> c3 == FieldChoice(id='id3', value='value3', label='value3', link='link3', choice_value=False)
    True
    >>> c3.id == 'id3'
    True
    >>> c3.value == 'value3'
    True
    >>> c3.label == 'value3'
    True
    >>> c3.link == 'link3'
    True
    >>> c4 = FieldChoice('id4', link='link4')
    >>> c4 == FieldChoice(id='id4', value='id4', label='id4', link='link4', choice_value=False)
    True
    >>> c4.id == 'id4'
    True
    >>> c4.value == 'id4'
    True
    >>> c4.label == 'id4'
    True
    >>> c4.link == 'link4'
    True
    >>> c5 = FieldChoice('')
    >>> c5 == FieldChoice(id='', value='', label='', link=None, choice_value=False)
    True
    """

    def __new__(_cls, id=None, value=None, label=None, link=None, choice_value=False):
        if value is None: value = id
        if label is None: label = value
        result = super(FieldChoice, _cls).__new__(_cls, id, value, label, link, choice_value)
        return result

    def __eq__(self, other):
        """
        Returns True if self == other for sorting and equivalence purposes
        """
        return self.id.__eq__(other.id)

    def __ne__(self, other):
        """
        Returns True if self != other for sorting and equivalence purposes

        Note: required for Python2.
        """
        return self.id.__ne__(other.id)

    def __lt__(self, other):
        """
        Returns True if self < other for sorting purposes
        """
        return self.id.__lt__(other.id)

    def __hash__(self):
        """
        pylint says this should be defined if __eq__ is defined.
        Something to do with sets?
        """
        return hash(self.id)

    def choice(self, sep=u"\xa0\xa0\xa0"):
        """
        Return choice string
        """
        if self.choice_value:
            choice_text = self.option_label(sep=sep)
        else:
            choice_text = to_unicode(self.label)
        return choice_text

    def choice_html(self, sep=u"&nbsp;&nbsp;&nbsp;"):
        """
        Return choice string HTML for option in drop-down list.
        """
        return self.choice(sep=sep)

    def add_link(self, link=None):
        return FieldChoice(self.id, self.value, self.label, link)

    def option_label(self, sep=u"\xa0\xa0\xa0"):
        """
        Returns string used for displayed option label.

        This function is used mainly for testing, to isolate details of 
        option presentation from the majority of test cases.
        """
        if self.label:
            return format_html(u"{}{}({})", self.label, mark_safe(sep), self.value)
        else:
            return escape(self.value)

    def option_label_html(self, sep=u"&nbsp;&nbsp;&nbsp;"):
        """
        Variation of option_label returns HTML-encoded form of label text
        """
        return self.option_label(sep=sep)


def update_choice_labels(fieldchoices):
    """
    Update choice labels in supplied list of FieldChoice values so that duplicate labels can
    be distinguished.

    Returns an updated list of options.
    """
    # Detect non-unique labels
    labels = {}
    for o in fieldchoices:
        l = o.label
        labels[l] = labels.get(l, 0) + 1
    # Generate updated choice values
    new_choices = []
    for o in fieldchoices:
        if labels[o.label] > 1:
            new_choices.append(
                FieldChoice(id=o.id, value=o.value, label=o.label, link=o.link, choice_value=True)
                )
        else:
            new_choices.append(o)
    return new_choices

def get_choice_labels(fieldchoices):
    """
    Return a list of choice labels based on the supplied list of FieldChoice values

    >>> c1  = FieldChoice('id1',  'value1',  'label1', 'link1')
    >>> c2a = FieldChoice('id2a', 'value2a', 'label2', 'link2')
    >>> c2b = FieldChoice('id2b', 'value2b', 'label2', 'link2')
    >>> labels = get_choice_labels([c1,c2a,c2b])
    >>> labels == ['label1', u'label2\\xa0\\xa0\\xa0(value2a)', u'label2\\xa0\\xa0\\xa0(value2b)']
    True
    """
    return [ fc.choice() for fc in update_choice_labels(fieldchoices) ]

if __name__ == "__main__":
    import doctest
    doctest.testmod()

# End.

This module defines a class used to represent a choice for an  enumerated-value field. Class representing a choice for an enumerated field.      >>> c1 = FieldChoice('id1', 'value1', 'label1', 'link1', choice_value=True)     >>> c1 == FieldChoice(id='id1', value='value1', label='label1', link='link1', choice_value=True)     True     >>> c1.id == 'id1'     True     >>> c1.value == 'value1'     True     >>> c1.label == 'label1'     True     >>> c1.link == 'link1'     True     >>> c1.choice_html() == u'label1&nbsp;&nbsp;&nbsp;(value1)'     True     >>> c2 = FieldChoice('id2', 'value2', 'label2', 'link2', choice_value=False)     >>> c2 == FieldChoice(id='id2', value='value2', label='label2', link='link2', choice_value=False)     True     >>> c2.id == 'id2'     True     >>> c2.value == 'value2'     True     >>> c2.label == 'label2'     True     >>> c2.link == 'link2'     True     >>> c2.choice() == u'label2'     True     >>> c3 = FieldChoice(id='id3', value='value3', link='link3')     >>> c3 == FieldChoice(id='id3', value='value3', label='value3', link='link3', choice_value=False)     True     >>> c3.id == 'id3'     True     >>> c3.value == 'value3'     True     >>> c3.label == 'value3'     True     >>> c3.link == 'link3'     True     >>> c4 = FieldChoice('id4', link='link4')     >>> c4 == FieldChoice(id='id4', value='id4', label='id4', link='link4', choice_value=False)     True     >>> c4.id == 'id4'     True     >>> c4.value == 'id4'     True     >>> c4.label == 'id4'     True     >>> c4.link == 'link4'     True     >>> c5 = FieldChoice('')     >>> c5 == FieldChoice(id='', value='', label='', link=None, choice_value=False)     True Returns True if self == other for sorting and equivalence purposes Returns True if self != other for sorting and equivalence purposes          Note: required for Python2. Returns True if self < other for sorting purposes pylint says this should be defined if __eq__ is defined.         Something to do with sets? Return choice string Return choice string HTML for option in drop-down list. Returns string used for displayed option label.          This function is used mainly for testing, to isolate details of          option presentation from the majority of test cases. Variation of option_label returns HTML-encoded form of label text Update choice labels in supplied list of FieldChoice values so that duplicate labels can     be distinguished.      Returns an updated list of options. # Detect non-unique labels # Generate updated choice values Return a list of choice labels based on the supplied list of FieldChoice values      >>> c1  = FieldChoice('id1',  'value1',  'label1', 'link1')     >>> c2a = FieldChoice('id2a', 'value2a', 'label2', 'link2')     >>> c2b = FieldChoice('id2b', 'value2b', 'label2', 'link2')     >>> labels = get_choice_labels([c1,c2a,c2b])     >>> labels == ['label1', u'label2\\xa0\\xa0\\xa0(value2a)', u'label2\\xa0\\xa0\\xa0(value2b)']     True # End.