@@ -0,0 +1,2880 @@
+# This file is part of Indico.%0A# Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).%0A#%0A# Indico is free software; you can redistribute it and/or%0A# modify it under the terms of the GNU General Public License as%0A# published by the Free Software Foundation; either version 3 of the%0A# License, or (at your option) any later version.%0A#%0A# Indico is distributed in the hope that it will be useful, but%0A# WITHOUT ANY WARRANTY; without even the implied warranty of%0A# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU%0A# General Public License for more details.%0A#%0A# You should have received a copy of the GNU General Public License%0A# along with Indico; if not, see %3Chttp://www.gnu.org/licenses/%3E.%0A%0Afrom __future__ import unicode_literals%0A%0Aimport string%0A%0Afrom collections import namedtuple%0A%0Afrom indico.core.db import db%0A%0A%0Aclass ColorTuple(namedtuple('ColorTuple', ('text', 'background'))):%0A    %22%22%22A tuple that contains text and background color.%0A%0A    Both colors are unified to 'rrggbb' notation (in case 'rgb' is%0A    passed) and leading %60%60#%60%60 is stripped.%0A%0A    When a text/background color is specifie, the other color needs%0A    to be specified too.  If no color is specified, the ColorTuple%0A    is falsy.%0A    %22%22%22%0A%0A    def __new__(cls, text, background):%0A        colors = %5Btext, background%5D%0A        for i, color in enumerate(colors):%0A            if color.startswith('#'):%0A                color = color%5B1:%5D%0A            if len(color) == 3:%0A                color = ''.join(x * 2 for x in color)%0A            colors%5Bi%5D = color.lower()%0A        if any(colors):%0A            if not all(colors):%0A                raise ValueError('Both colors must be specified')%0A            if not all(len(x) == 6 for x in colors):%0A                raise ValueError('Colors must be be %60rgb%60 or %60rrggbb%60')%0A            if not all(c in string.hexdigits for color in colors for c in color):%0A                raise ValueError('Colors must only use hex digits')%0A        return super(ColorTuple, cls).__new__(cls, *colors)%0A%0A    def __nonzero__(self):%0A        return all(self)%0A%0A%0Aclass ColorMixin(object):%0A    %22%22%22Mixin to store text+background colors in a model.%0A%0A    For convenience (e.g. for WTForms integrations when selecting both%0A    colors at the same time from a palette or in a compound field) it%0A    provides a %60colors%60 property which returns/accepts a %60ColorTuple%60%0A    holding text color and background color.%0A    %22%22%22%0A%0A    text_color = db.Column(%0A        db.String,%0A        nullable=False,%0A        default=''%0A    )%0A    background_color = db.Column(%0A        db.String,%0A        nullable=False,%0A        default=''%0A    )%0A%0A    @property%0A    def colors(self):%0A        return ColorTuple(self.text_color, self.background_color)%0A%0A    @colors.setter%0A    def colors(self, value):%0A        if value is None:%0A            value = '', ''%0A        self.text_color, self.background_color = value%0A

Add ColorMixin and ColorTuple