Ejemplo n.º 1
0
def get_available_skins(selected=None):
    """selected is a name of preferred skin
    if it's None, then information about all skins will be returned
    otherwise, only data about selected and default skins
    will be returned

    selected skin is guaranteed to be the first item in the dictionary
    """
    skins = SortedDict()
    if hasattr(django_settings, 'ASKBOT_EXTRA_SKINS_DIR'):
        skins.update(get_skins_from_dir(django_settings.ASKBOT_EXTRA_SKINS_DIR))

    stock_dir = os.path.normpath(os.path.dirname(__file__))
    stock_skins = get_skins_from_dir(stock_dir)
    default_dir = stock_skins.pop('default')

    skins.update(stock_skins)

    if selected:
        if selected in skins:
            selected_dir = skins[selected]
            skins.clear()
            skins[selected] = selected_dir
        else:
            assert(selected == 'default')
            skins = SortedDict()

    #re-insert default as a last item
    skins['default'] = default_dir
    return skins
Ejemplo n.º 2
0
def get_available_skins(selected=None):
    """Returns a dictionary of skin name --> directory where
    "templates" and "media" subdirectories can be found.

    selected is a name of preferred skin
    if it's None, then information about all skins will be returned
    otherwise, only data about selected and default skins
    will be returned

    selected skin is guaranteed to be the first item in the dictionary
    """
    skins = SortedDict()
    if hasattr(django_settings, 'ASKBOT_EXTRA_SKINS_DIR'):
        skins.update(get_skins_from_dir(django_settings.ASKBOT_EXTRA_SKINS_DIR))

    if 'default' in skins:
        raise ValueError('"default" is not an acceptable name for a custom skin')

    if selected in skins:
        selected_dir = skins[selected]
        skins.clear()
        skins[selected] = selected_dir
    elif selected == 'default':
        skins = SortedDict()
    elif selected:
        raise ValueError(
            'skin ' + str(selected) + \
            ' not found, please check ASKBOT_EXTRA_SKINS_DIR setting ' + \
            'or in the corresponding directory'
        )

    #insert default as a last item
    skins['default'] = askbot.get_install_directory()
    return skins
Ejemplo n.º 3
0
def get_available_skins(selected=None):
    """selected is a name of preferred skin
    if it's None, then information about all skins will be returned
    otherwise, only data about selected and default skins
    will be returned

    selected skin is guaranteed to be the first item in the dictionary
    """
    skins = SortedDict()
    if hasattr(django_settings, 'ASKBOT_EXTRA_SKINS_DIR'):
        skins.update(get_skins_from_dir(
            django_settings.ASKBOT_EXTRA_SKINS_DIR))

    stock_dir = os.path.normpath(os.path.dirname(__file__))
    stock_skins = get_skins_from_dir(stock_dir)
    default_dir = stock_skins.pop('default')

    skins.update(stock_skins)

    if selected:
        if selected in skins:
            selected_dir = skins[selected]
            skins.clear()
            skins[selected] = selected_dir
        else:
            assert (selected == 'default')
            skins = SortedDict()

    #re-insert default as a last item
    skins['default'] = default_dir
    return skins
Ejemplo n.º 4
0
class Cart(models.Model):
    user = models.OneToOneField(User, null=True, blank=True)
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

    objects = CartManager()

    def __init__(self, *args, **kwargs):
        super(Cart, self).__init__(*args, **kwargs)
        self.modifiers = SortedDict()

    def reset_cached_items(self):
        key = self.cachekey()
        l = list(self.items.all())
        cache.set(key, l, 60 * 60 * 24 * 7 * 4)
        return l

    def cachekey(self, append=''):
        return 'fastcart_items:%s%s' % (self.pk, append)

    def get_items(self):
        key = self.cachekey()
        l = cache.get(key, '!')
        if l is '!':
            return self.reset_cached_items()
        elif l:
            return l
        else:
            return []

    def get_price(self):
        price = Decimal('0.00')
        for item in self.get_items():
            price += item.get_total_price()
        return price

    def get_count(self):
        c = 0
        for item in self.get_items():
            c = c + item.quantity
        return c

    def get_total_price(self):
        total_price = self.get_price()
        for modifier in get_cart_modifiers():
            total_price = modifier(self, total_price)
        return total_price

    def add(self, product, quantity=1):
        item, created = self.items.get_or_create(product=product)
        if not created:
            item.quantity += quantity
        else:
            item.quantity = quantity
        item.save()
        return item

    def clear(self):
        self.items.all().delete()
        self.modifiers.clear()
Ejemplo n.º 5
0
class SortedDictTests(SimpleTestCase):
    def setUp(self):
        self.d1 = SortedDict()
        self.d1[7] = 'seven'
        self.d1[1] = 'one'
        self.d1[9] = 'nine'

        self.d2 = SortedDict()
        self.d2[1] = 'one'
        self.d2[9] = 'nine'
        self.d2[0] = 'nil'
        self.d2[7] = 'seven'

    def test_basic_methods(self):
        self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9])
        self.assertEqual(list(six.itervalues(self.d1)), ['seven', 'one', 'nine'])
        self.assertEqual(list(six.iteritems(self.d1)), [(7, 'seven'), (1, 'one'), (9, 'nine')])

    def test_overwrite_ordering(self):
        """ Overwriting an item keeps its place. """
        self.d1[1] = 'ONE'
        self.assertEqual(list(six.itervalues(self.d1)), ['seven', 'ONE', 'nine'])

    def test_append_items(self):
        """ New items go to the end. """
        self.d1[0] = 'nil'
        self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9, 0])

    def test_delete_and_insert(self):
        """
        Deleting an item, then inserting the same key again will place it
        at the end.
        """
        del self.d2[7]
        self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0])
        self.d2[7] = 'lucky number 7'
        self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0, 7])

    if six.PY2:
        def test_change_keys(self):
            """
            Changing the keys won't do anything, it's only a copy of the
            keys dict.

            This test doesn't make sense under Python 3 because keys is
            an iterator.
            """
            k = self.d2.keys()
            k.remove(9)
            self.assertEqual(self.d2.keys(), [1, 9, 0, 7])

    def test_init_keys(self):
        """
        Initialising a SortedDict with two keys will just take the first one.

        A real dict will actually take the second value so we will too, but
        we'll keep the ordering from the first key found.
        """
        tuples = ((2, 'two'), (1, 'one'), (2, 'second-two'))
        d = SortedDict(tuples)

        self.assertEqual(list(six.iterkeys(d)), [2, 1])

        real_dict = dict(tuples)
        self.assertEqual(sorted(six.itervalues(real_dict)), ['one', 'second-two'])

        # Here the order of SortedDict values *is* what we are testing
        self.assertEqual(list(six.itervalues(d)), ['second-two', 'one'])

    def test_overwrite(self):
        self.d1[1] = 'not one'
        self.assertEqual(self.d1[1], 'not one')
        self.assertEqual(list(six.iterkeys(self.d1)), list(six.iterkeys(self.d1.copy())))

    def test_append(self):
        self.d1[13] = 'thirteen'
        self.assertEqual(
            repr(self.d1),
            "{7: 'seven', 1: 'one', 9: 'nine', 13: 'thirteen'}"
        )

    def test_pop(self):
        self.assertEqual(self.d1.pop(1, 'missing'), 'one')
        self.assertEqual(self.d1.pop(1, 'missing'), 'missing')

        # We don't know which item will be popped in popitem(), so we'll
        # just check that the number of keys has decreased.
        l = len(self.d1)
        self.d1.popitem()
        self.assertEqual(l - len(self.d1), 1)

    def test_dict_equality(self):
        d = SortedDict((i, i) for i in range(3))
        self.assertEqual(d, {0: 0, 1: 1, 2: 2})

    def test_tuple_init(self):
        d = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
        self.assertEqual(repr(d), "{1: 'one', 0: 'zero', 2: 'two'}")

    def test_pickle(self):
        self.assertEqual(
            pickle.loads(pickle.dumps(self.d1, 2)),
            {7: 'seven', 1: 'one', 9: 'nine'}
        )

    def test_copy(self):
        orig = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
        copied = copy.copy(orig)
        self.assertEqual(list(six.iterkeys(orig)), [1, 0, 2])
        self.assertEqual(list(six.iterkeys(copied)), [1, 0, 2])

    def test_clear(self):
        self.d1.clear()
        self.assertEqual(self.d1, {})
        self.assertEqual(self.d1.keyOrder, [])

    def test_reversed(self):
        self.assertEqual(list(self.d1), [7, 1, 9])
        self.assertEqual(list(self.d2), [1, 9, 0, 7])
        self.assertEqual(list(reversed(self.d1)), [9, 1, 7])
        self.assertEqual(list(reversed(self.d2)), [7, 0, 9, 1])

    def test_insert(self):
        d = SortedDict()
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            d.insert(0, "hello", "world")
        assert w[0].category is DeprecationWarning

    def test_value_for_index(self):
        d = SortedDict({"a": 3})
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            self.assertEqual(d.value_for_index(0), 3)
        assert w[0].category is DeprecationWarning
Ejemplo n.º 6
0
class SortedDictTests(IgnoreDeprecationWarningsMixin, SimpleTestCase):
    def setUp(self):
        super(SortedDictTests, self).setUp()
        self.d1 = SortedDict()
        self.d1[7] = 'seven'
        self.d1[1] = 'one'
        self.d1[9] = 'nine'

        self.d2 = SortedDict()
        self.d2[1] = 'one'
        self.d2[9] = 'nine'
        self.d2[0] = 'nil'
        self.d2[7] = 'seven'

    def test_basic_methods(self):
        self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9])
        self.assertEqual(list(six.itervalues(self.d1)),
                         ['seven', 'one', 'nine'])
        self.assertEqual(list(six.iteritems(self.d1)),
                         [(7, 'seven'), (1, 'one'), (9, 'nine')])

    def test_overwrite_ordering(self):
        """ Overwriting an item keeps its place. """
        self.d1[1] = 'ONE'
        self.assertEqual(list(six.itervalues(self.d1)),
                         ['seven', 'ONE', 'nine'])

    def test_append_items(self):
        """ New items go to the end. """
        self.d1[0] = 'nil'
        self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9, 0])

    def test_delete_and_insert(self):
        """
        Deleting an item, then inserting the same key again will place it
        at the end.
        """
        del self.d2[7]
        self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0])
        self.d2[7] = 'lucky number 7'
        self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0, 7])

    if six.PY2:

        def test_change_keys(self):
            """
            Changing the keys won't do anything, it's only a copy of the
            keys dict.

            This test doesn't make sense under Python 3 because keys is
            an iterator.
            """
            k = self.d2.keys()
            k.remove(9)
            self.assertEqual(self.d2.keys(), [1, 9, 0, 7])

    def test_init_keys(self):
        """
        Initialising a SortedDict with two keys will just take the first one.

        A real dict will actually take the second value so we will too, but
        we'll keep the ordering from the first key found.
        """
        tuples = ((2, 'two'), (1, 'one'), (2, 'second-two'))
        d = SortedDict(tuples)

        self.assertEqual(list(six.iterkeys(d)), [2, 1])

        real_dict = dict(tuples)
        self.assertEqual(sorted(six.itervalues(real_dict)),
                         ['one', 'second-two'])

        # Here the order of SortedDict values *is* what we are testing
        self.assertEqual(list(six.itervalues(d)), ['second-two', 'one'])

    def test_overwrite(self):
        self.d1[1] = 'not one'
        self.assertEqual(self.d1[1], 'not one')
        self.assertEqual(list(six.iterkeys(self.d1)),
                         list(six.iterkeys(self.d1.copy())))

    def test_append(self):
        self.d1[13] = 'thirteen'
        self.assertEqual(repr(self.d1),
                         "{7: 'seven', 1: 'one', 9: 'nine', 13: 'thirteen'}")

    def test_pop(self):
        self.assertEqual(self.d1.pop(1, 'missing'), 'one')
        self.assertEqual(self.d1.pop(1, 'missing'), 'missing')

        # We don't know which item will be popped in popitem(), so we'll
        # just check that the number of keys has decreased.
        l = len(self.d1)
        self.d1.popitem()
        self.assertEqual(l - len(self.d1), 1)

    def test_dict_equality(self):
        d = SortedDict((i, i) for i in range(3))
        self.assertEqual(d, {0: 0, 1: 1, 2: 2})

    def test_tuple_init(self):
        d = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
        self.assertEqual(repr(d), "{1: 'one', 0: 'zero', 2: 'two'}")

    def test_pickle(self):
        self.assertEqual(pickle.loads(pickle.dumps(self.d1, 2)), {
            7: 'seven',
            1: 'one',
            9: 'nine'
        })

    def test_copy(self):
        orig = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
        copied = copy.copy(orig)
        self.assertEqual(list(six.iterkeys(orig)), [1, 0, 2])
        self.assertEqual(list(six.iterkeys(copied)), [1, 0, 2])

    def test_clear(self):
        self.d1.clear()
        self.assertEqual(self.d1, {})
        self.assertEqual(self.d1.keyOrder, [])

    def test_reversed(self):
        self.assertEqual(list(self.d1), [7, 1, 9])
        self.assertEqual(list(self.d2), [1, 9, 0, 7])
        self.assertEqual(list(reversed(self.d1)), [9, 1, 7])
        self.assertEqual(list(reversed(self.d2)), [7, 0, 9, 1])
Ejemplo n.º 7
0
class SortedDictTests(SimpleTestCase):
    def setUp(self):
        self.d1 = SortedDict()
        self.d1[7] = 'seven'
        self.d1[1] = 'one'
        self.d1[9] = 'nine'

        self.d2 = SortedDict()
        self.d2[1] = 'one'
        self.d2[9] = 'nine'
        self.d2[0] = 'nil'
        self.d2[7] = 'seven'

    def test_basic_methods(self):
        self.assertEqual(self.d1.keys(), [7, 1, 9])
        self.assertEqual(self.d1.values(), ['seven', 'one', 'nine'])
        self.assertEqual(self.d1.items(), [(7, 'seven'), (1, 'one'), (9, 'nine')])

    def test_overwrite_ordering(self):
        """ Overwriting an item keeps it's place. """
        self.d1[1] = 'ONE'
        self.assertEqual(self.d1.values(), ['seven', 'ONE', 'nine'])

    def test_append_items(self):
        """ New items go to the end. """
        self.d1[0] = 'nil'
        self.assertEqual(self.d1.keys(), [7, 1, 9, 0])

    def test_delete_and_insert(self):
        """
        Deleting an item, then inserting the same key again will place it
        at the end.
        """
        del self.d2[7]
        self.assertEqual(self.d2.keys(), [1, 9, 0])
        self.d2[7] = 'lucky number 7'
        self.assertEqual(self.d2.keys(), [1, 9, 0, 7])

    def test_change_keys(self):
        """
        Changing the keys won't do anything, it's only a copy of the
        keys dict.
        """
        k = self.d2.keys()
        k.remove(9)
        self.assertEqual(self.d2.keys(), [1, 9, 0, 7])

    def test_init_keys(self):
        """
        Initialising a SortedDict with two keys will just take the first one.

        A real dict will actually take the second value so we will too, but
        we'll keep the ordering from the first key found.
        """
        tuples = ((2, 'two'), (1, 'one'), (2, 'second-two'))
        d = SortedDict(tuples)

        self.assertEqual(d.keys(), [2, 1])

        real_dict = dict(tuples)
        self.assertEqual(sorted(real_dict.values()), ['one', 'second-two'])

        # Here the order of SortedDict values *is* what we are testing
        self.assertEqual(d.values(), ['second-two', 'one'])

    def test_overwrite(self):
        self.d1[1] = 'not one'
        self.assertEqual(self.d1[1], 'not one')
        self.assertEqual(self.d1.keys(), self.d1.copy().keys())

    def test_append(self):
        self.d1[13] = 'thirteen'
        self.assertEqual(
            repr(self.d1),
            "{7: 'seven', 1: 'one', 9: 'nine', 13: 'thirteen'}"
        )

    def test_pop(self):
        self.assertEqual(self.d1.pop(1, 'missing'), 'one')
        self.assertEqual(self.d1.pop(1, 'missing'), 'missing')

        # We don't know which item will be popped in popitem(), so we'll
        # just check that the number of keys has decreased.
        l = len(self.d1)
        self.d1.popitem()
        self.assertEqual(l - len(self.d1), 1)

    def test_dict_equality(self):
        d = SortedDict((i, i) for i in xrange(3))
        self.assertEqual(d, {0: 0, 1: 1, 2: 2})

    def test_tuple_init(self):
        d = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
        self.assertEqual(repr(d), "{1: 'one', 0: 'zero', 2: 'two'}")

    def test_pickle(self):
        self.assertEqual(
            pickle.loads(pickle.dumps(self.d1, 2)),
            {7: 'seven', 1: 'one', 9: 'nine'}
        )

    def test_clear(self):
        self.d1.clear()
        self.assertEqual(self.d1, {})
        self.assertEqual(self.d1.keyOrder, [])
Ejemplo n.º 8
0
class Cart(models.Model):
    user = models.OneToOneField(User,
                                null=True,
                                blank=True)
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

    objects = CartManager()

    def __init__(self, *args, **kwargs):
        super(Cart, self).__init__(*args, **kwargs)
        self.modifiers = SortedDict()

    def reset_cached_items(self):
        key = self.cachekey()
        l = list(self.items.all())
        cache.set(key, l, 60 * 60 * 24 * 7 * 4)
        return l

    def cachekey(self, append=''):
        return 'fastcart_items:%s%s' % (self.pk, append)

    def get_items(self):
        key = self.cachekey()
        l = cache.get(key, '!')
        if l is '!':
            return self.reset_cached_items()
        elif l:
            return l
        else:
            return []

    def get_price(self):
        price = Decimal('0.00')
        for item in self.get_items():
            price += item.get_total_price()
        return price

    def get_count(self):
        c = 0
        for item in self.get_items():
            c = c + item.quantity
        return c

    def get_total_price(self):
        total_price = self.get_price()
        for modifier in get_cart_modifiers():
            total_price = modifier(self, total_price)
        return total_price

    def add(self, product, quantity=1, price=None):
        item_qry = self.items.filter(product=product)
        item = None
        # import pdb;pdb.set_trace()

        if item_qry.exists():
            item = item_qry[0]
            item.quantity += quantity
        else:
            item = CartItem()
            item.product = product
            item.cart = self
            if price:
                item.price = price
            else:
                price_qry = Price.objects.filter(product=product)
                if price_qry.exists():
                    item.price = price_qry[0]

            item.quantity = quantity
        item.save()
        return item

    def clear(self):
        self.items.all().delete()
        self.modifiers.clear()
Ejemplo n.º 9
0
class SortedDictTests(SimpleTestCase):
    def setUp(self):
        super(SortedDictTests, self).setUp()
        self.d1 = SortedDict()
        self.d1[7] = "seven"
        self.d1[1] = "one"
        self.d1[9] = "nine"

        self.d2 = SortedDict()
        self.d2[1] = "one"
        self.d2[9] = "nine"
        self.d2[0] = "nil"
        self.d2[7] = "seven"

    def test_basic_methods(self):
        self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9])
        self.assertEqual(list(six.itervalues(self.d1)), ["seven", "one", "nine"])
        self.assertEqual(list(six.iteritems(self.d1)), [(7, "seven"), (1, "one"), (9, "nine")])

    def test_overwrite_ordering(self):
        """ Overwriting an item keeps its place. """
        self.d1[1] = "ONE"
        self.assertEqual(list(six.itervalues(self.d1)), ["seven", "ONE", "nine"])

    def test_append_items(self):
        """ New items go to the end. """
        self.d1[0] = "nil"
        self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9, 0])

    def test_delete_and_insert(self):
        """
        Deleting an item, then inserting the same key again will place it
        at the end.
        """
        del self.d2[7]
        self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0])
        self.d2[7] = "lucky number 7"
        self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0, 7])

    if six.PY2:

        def test_change_keys(self):
            """
            Changing the keys won't do anything, it's only a copy of the
            keys dict.

            This test doesn't make sense under Python 3 because keys is
            an iterator.
            """
            k = self.d2.keys()
            k.remove(9)
            self.assertEqual(self.d2.keys(), [1, 9, 0, 7])

    def test_init_keys(self):
        """
        Initialising a SortedDict with two keys will just take the first one.

        A real dict will actually take the second value so we will too, but
        we'll keep the ordering from the first key found.
        """
        tuples = ((2, "two"), (1, "one"), (2, "second-two"))
        d = SortedDict(tuples)

        self.assertEqual(list(six.iterkeys(d)), [2, 1])

        real_dict = dict(tuples)
        self.assertEqual(sorted(six.itervalues(real_dict)), ["one", "second-two"])

        # Here the order of SortedDict values *is* what we are testing
        self.assertEqual(list(six.itervalues(d)), ["second-two", "one"])

    def test_overwrite(self):
        self.d1[1] = "not one"
        self.assertEqual(self.d1[1], "not one")
        self.assertEqual(list(six.iterkeys(self.d1)), list(six.iterkeys(self.d1.copy())))

    def test_append(self):
        self.d1[13] = "thirteen"
        self.assertEqual(repr(self.d1), "{7: 'seven', 1: 'one', 9: 'nine', 13: 'thirteen'}")

    def test_pop(self):
        self.assertEqual(self.d1.pop(1, "missing"), "one")
        self.assertEqual(self.d1.pop(1, "missing"), "missing")

        # We don't know which item will be popped in popitem(), so we'll
        # just check that the number of keys has decreased.
        l = len(self.d1)
        self.d1.popitem()
        self.assertEqual(l - len(self.d1), 1)

    def test_dict_equality(self):
        d = SortedDict((i, i) for i in range(3))
        self.assertEqual(d, {0: 0, 1: 1, 2: 2})

    def test_tuple_init(self):
        d = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
        self.assertEqual(repr(d), "{1: 'one', 0: 'zero', 2: 'two'}")

    def test_pickle(self):
        self.assertEqual(pickle.loads(pickle.dumps(self.d1, 2)), {7: "seven", 1: "one", 9: "nine"})

    def test_copy(self):
        orig = SortedDict(((1, "one"), (0, "zero"), (2, "two")))
        copied = copy.copy(orig)
        self.assertEqual(list(six.iterkeys(orig)), [1, 0, 2])
        self.assertEqual(list(six.iterkeys(copied)), [1, 0, 2])

    def test_clear(self):
        self.d1.clear()
        self.assertEqual(self.d1, {})
        self.assertEqual(self.d1.keyOrder, [])

    def test_reversed(self):
        self.assertEqual(list(self.d1), [7, 1, 9])
        self.assertEqual(list(self.d2), [1, 9, 0, 7])
        self.assertEqual(list(reversed(self.d1)), [9, 1, 7])
        self.assertEqual(list(reversed(self.d2)), [7, 0, 9, 1])
Ejemplo n.º 10
0
class ExtGrid(BaseExtPanel):
    """
    Таблица (Grid)
    Внимание! Грид реализует двуличное поведение
    в зависимости от атрибута editor.
    Порождающая его функция createGridPanel может вернуть экземпляр
    Ext.m3.GridPanel (False) или Ext.m3.EditorGridPanel (True),
    поэтому некоторые атрибуты могут действовать в одном,
    но не действовать в другом гриде.
    """

    manageable_listeners = ("dblclick",)

    # TODO: Реализовать человеческий MVC грид

    def __init__(self, *args, **kwargs):
        super(ExtGrid, self).__init__(*args, **kwargs)
        self._items = []
        self.__store = None

        # Будет ли редактироваться
        self.editor = False

        # Объект маскирования, который будет отображаться при загрузке
        self.load_mask = False

        # Сколько раз нужно щелкнуть для редактирования ячейки.
        # Только для EditorGridPanel
        self.clicks_to_edit = 2

        self.drag_drop = False
        self.drag_drop_group = None

        # Разворачивать колонки грида по всей ширине (True)
        self.force_fit = True

        # selection model
        self.__sm = None

        self.__view = None

        # Колонка для авторасширения
        self.auto_expand_column = None

        # устанавливается True, если sm=CheckBoxSelectionModel. Этот флаг нужен
        # чтобы знать когда нужен дополнительный column
        self.__checkbox = False

        # перечень плагинов
        self.plugins = []

        # модель колонок
        self.__cm = None

        self.col_model = ExtGridDefaultColumnModel()

        # Конфигурация для уровня view
        self._view_config = {}
        self.show_preview = False
        self.enable_row_body = False
        self.get_row_class = None

        # признак отображения вертикальных линий в гриде
        self.column_lines = True

        # Если True не рендерим drag and drop, выключаем editor
        self.read_only = False

        # Метка. Использовать только если задан layout=form
        self.label = None

        self.init_component(*args, **kwargs)

        # protected
        self.show_banded_columns = False
        self.banded_columns = SortedDict()

    def t_render_plugins(self):
        """
        Рендеринг плагинов
        """
        res = []
        for plugin in self.plugins:
            res.append(plugin.render() if hasattr(plugin, "render") else plugin)

        return "[%s]" % ",".join(res)

    def t_render_banded_columns(self):
        """
        Возвращает JS массив состоящий из массивов с описанием объединенных
        колонок. Каждый вложенный массив соответствует уровню шапки грида от
        верхней к нижней.
        """
        result = []
        for level_list in self.banded_columns.values():
            result.append("[%s]" % ",".join([column.render() for column in level_list]))
        return "[%s]" % ",".join(result)

    def t_render_columns(self):
        return self.t_render_items()

    def t_render_store(self):
        assert self.__store, "Store is not define"
        return self.__store.render(self.columns)

    def t_render_col_model(self):
        return self.__cm.render()

    def add_column(self, **kwargs):
        """
        Добавляет стандартную колонку
        """
        self.columns.append(ExtGridColumn(**kwargs))

    def add_bool_column(self, **kwargs):
        """
        Добавляет булевую колонку
        """
        self.columns.append(ExtGridBooleanColumn(**kwargs))

    def add_check_column(self, **kwargs):
        """
        Добавляет колонку для выбора значения
        """
        self.columns.append(ExtGridCheckColumn(**kwargs))

    def add_number_column(self, **kwargs):
        """
        Добавляет числовую колонку
        """
        self.columns.append(ExtGridNumberColumn(**kwargs))

    def add_date_column(self, **kwargs):
        """
        Добавляет колонку с датой
        """
        self.columns.append(ExtGridDateColumn(**kwargs))

    def add_banded_column(self, column, level, colspan):
        """
        Добавляет в грид объединенную ячейку.
        :param column: Колонка грида
        :type column: ExtGridColumn или None
        :param colspan: Количество колонок, кот-е находятся под данной колонкой
        :type colspan: int
        :param level: Уровень ячейки (0 - самый верхний, 1-ниже, и т.д)
        :type level: int

        .. note ::
            upd:26.10.2010 kirov
            колонка может быть не указана, т.е. None,
            в этом случае на указанном уровне будет "дырка"
        """

        class BlankBandColumn:
            colspan = 0

            def render(self):
                return "{%s}" % (("colspan:%s" % self.colspan) if self.colspan else "")

        assert isinstance(level, int)
        assert isinstance(colspan, int)
        assert isinstance(column, ExtGridColumn) or not column
        if not column:
            column = BlankBandColumn()
        # Колонки хранятся в списках внутки сортированного словаря,
        # чтобы их можно было
        # извечь по возрастанию уровней
        column.colspan = colspan
        level_list = self.banded_columns.get(level, [])
        level_list.append(column)
        self.banded_columns[level] = level_list
        self.show_banded_columns = True

    def clear_banded_columns(self):
        """
        Удаляет все объединенные колонки из грида
        """
        self.banded_columns.clear()
        self.show_banded_columns = False

    def set_store(self, store):
        self.__store = store

    def get_store(self):
        return self.__store

    store = property(get_store, set_store)

    def _make_read_only(self, access_off=True, exclude_list=(), *args, **kwargs):
        super(ExtGrid, self)._make_read_only(access_off, exclude_list, *args, **kwargs)
        self.read_only = access_off
        if self.columns:
            for column in self.columns:
                column.make_read_only(self.read_only, exclude_list, *args, **kwargs)

        # контекстное меню.
        context_menu_items = [self.handler_contextmenu, self.handler_rowcontextmenu]
        for context_menu in context_menu_items:
            if (
                context_menu
                and hasattr(context_menu, "items")
                and context_menu.items
                and hasattr(context_menu.items, "__iter__")
            ):
                for item in context_menu.items:
                    if isinstance(item, ExtUIComponent):
                        item.make_read_only(self.read_only, exclude_list, *args, **kwargs)

    @property
    def columns(self):
        return self._items

    @property
    def sm(self):
        return self.__sm

    @sm.setter
    def sm(self, value):
        self.__sm = value
        self.checkbox_model = isinstance(self.__sm, ExtGridCheckBoxSelModel)

    @property
    def view(self):
        return self.__view

    @view.setter
    def view(self, value):
        self.__view = value

    def t_render_view(self):
        return self.view.render()

    def pre_render(self):
        super(ExtGrid, self).pre_render()
        if self.store:
            self.store.action_context = self.action_context

    @property
    def col_model(self):
        return self.__cm

    @col_model.setter
    def col_model(self, value):
        self.__cm = value
        self.__cm.grid = self

    @property
    def handler_click(self):
        return self._listeners.get("click")

    @handler_click.setter
    def handler_click(self, function):
        self._listeners["click"] = function

    @property
    def handler_dblclick(self):
        if self.read_only:
            # Если грид работает в режиме "чтения"
            # выключаем двойной клик, заменяя пустой функцией
            return "Ext.emptyFn"
        return self._listeners.get("dblclick")

    @handler_dblclick.setter
    def handler_dblclick(self, function):
        self._listeners["dblclick"] = function

    @property
    def handler_contextmenu(self):
        return self._listeners.get("contextmenu")

    @handler_contextmenu.setter
    def handler_contextmenu(self, menu):
        menu.container = self
        self._listeners["contextmenu"] = menu

    @property
    def handler_rowcontextmenu(self):
        return self._listeners.get("rowcontextmenu")

    @handler_rowcontextmenu.setter
    def handler_rowcontextmenu(self, menu):
        menu.container = self
        self._listeners["rowcontextmenu"] = menu

    def render_base_config(self):
        super(ExtGrid, self).render_base_config()
        if self.force_fit:
            self._view_config["forceFit"] = self.force_fit
        if self.show_preview:
            self._view_config["showPreview"] = self.show_preview
        if self.enable_row_body:
            self._view_config["enableRowBody"] = self.enable_row_body
        if self.get_row_class:
            self._view_config["getRowClass"] = self.get_row_class

        for args in (
            ("stripeRows", True),
            ("stateful", True),
            ("loadMask", self.load_mask),
            ("autoExpandColumn", self.auto_expand_column),
            ("editor", self.editor),
            ("view", self.t_render_view, self.view),
            ("store", self.t_render_store, self.get_store()),
            ("viewConfig", self._view_config),
            ("columnLines", self.column_lines, self.column_lines),
            ("enableDragDrop", self.drag_drop) if self.read_only else (),
            ("ddGroup", self.drag_drop_group) if self.read_only else (),
            ("fieldLabel", self.label) if self.label else (),
            ("clicksToEdit", self.clicks_to_edit, self.clicks_to_edit != 2) if self.editor else (),
        ):
            if args:
                self._put_config_value(*args)

    def render_params(self):
        super(ExtGrid, self).render_params()

        handler_cont_menu = self.handler_contextmenu.render if self.handler_contextmenu else ""
        handler_rowcontextmenu = self.handler_rowcontextmenu.render if self.handler_rowcontextmenu else ""

        self._put_params_value("menus", {"contextMenu": handler_cont_menu, "rowContextMenu": handler_rowcontextmenu})
        if self.sm:
            self._put_params_value("selModel", self.sm.render)

        self._put_params_value("colModel", self.col_model.render)
        # проверим набор колонок на наличие фильтров,
        # если есть, то добавим плагин с фильтрами
        for col in self.columns:
            if col.filter:
                self.plugins.append(u"new Ext.ux.grid.GridFilters({menuFilterText:'Фильтр'})")
                break
        self._put_params_value("plugins", self.t_render_plugins)

        if self.show_banded_columns:
            self._put_params_value("bundedColumns", self.t_render_banded_columns)

    def render(self):
        try:
            self.pre_render()

            self.render_base_config()
            self.render_params()
        except UnicodeDecodeError as msg:
            raise Exception(msg)

        config = self._get_config_str()
        params = self._get_params_str()
        return "createGridPanel({%s}, {%s})" % (config, params)
Ejemplo n.º 11
0
class ExtGrid(BaseExtPanel):
    """
    Таблица (Grid)
    Внимание! Грид реализует двуличное поведение
    в зависимости от атрибута editor.
    Порождающая его функция createGridPanel может вернуть экземпляр
    Ext.m3.GridPanel (False) или Ext.m3.EditorGridPanel (True),
    поэтому некоторые атрибуты могут действовать в одном,
    но не действовать в другом гриде.
    """
    manageable_listeners = ('dblclick', )

    # TODO: Реализовать человеческий MVC грид

    def __init__(self, *args, **kwargs):
        super(ExtGrid, self).__init__(*args, **kwargs)
        self._items = []
        self.__store = None

        # Будет ли редактироваться
        self.editor = False

        # Объект маскирования, который будет отображаться при загрузке
        self.load_mask = False

        # Сколько раз нужно щелкнуть для редактирования ячейки.
        # Только для EditorGridPanel
        self.clicks_to_edit = 2

        self.drag_drop = False
        self.drag_drop_group = None

        # Разворачивать колонки грида по всей ширине (True)
        self.force_fit = True

        # selection model
        self.__sm = None

        self.__view = None

        # Колонка для авторасширения
        self.auto_expand_column = None

        # устанавливается True, если sm=CheckBoxSelectionModel. Этот флаг нужен
        # чтобы знать когда нужен дополнительный column
        self.__checkbox = False

        # перечень плагинов
        self.plugins = []

        # модель колонок
        self.__cm = None

        self.col_model = ExtGridDefaultColumnModel()

        # Конфигурация для уровня view
        self._view_config = {}
        self.show_preview = False
        self.enable_row_body = False
        self.get_row_class = None

        # признак отображения вертикальных линий в гриде
        self.column_lines = True

        #Если True не рендерим drag and drop, выключаем editor
        self.read_only = False

        # Метка. Использовать только если задан layout=form
        self.label = None

        self.init_component(*args, **kwargs)

        # protected
        self.show_banded_columns = False
        self.banded_columns = SortedDict()

    def t_render_plugins(self):
        """
        Рендеринг плагинов
        """
        res = []
        for plugin in self.plugins:
            res.append(
                plugin.render() if hasattr(plugin, 'render') else plugin)

        return '[%s]' % ','.join(res)

    def t_render_banded_columns(self):
        """
        Возвращает JS массив состоящий из массивов с описанием объединенных
        колонок. Каждый вложенный массив соответствует уровню шапки грида от
        верхней к нижней.
        """
        result = []
        for level_list in self.banded_columns.values():
            result.append('[%s]' %
                          ','.join([column.render() for column in level_list]))
        return '[%s]' % ','.join(result)

    def t_render_columns(self):
        return self.t_render_items()

    def t_render_store(self):
        assert self.__store, 'Store is not define'
        return self.__store.render(self.columns)

    def t_render_col_model(self):
        return self.__cm.render()

    def add_column(self, **kwargs):
        """
        Добавляет стандартную колонку
        """
        self.columns.append(ExtGridColumn(**kwargs))

    def add_bool_column(self, **kwargs):
        """
        Добавляет булевую колонку
        """
        self.columns.append(ExtGridBooleanColumn(**kwargs))

    def add_check_column(self, **kwargs):
        """
        Добавляет колонку для выбора значения
        """
        self.columns.append(ExtGridCheckColumn(**kwargs))

    def add_number_column(self, **kwargs):
        """
        Добавляет числовую колонку
        """
        self.columns.append(ExtGridNumberColumn(**kwargs))

    def add_date_column(self, **kwargs):
        """
        Добавляет колонку с датой
        """
        self.columns.append(ExtGridDateColumn(**kwargs))

    def add_banded_column(self, column, level, colspan):
        """
        Добавляет в грид объединенную ячейку.
        :param column: Колонка грида
        :type column: ExtGridColumn или None
        :param colspan: Количество колонок, кот-е находятся под данной колонкой
        :type colspan: int
        :param level: Уровень ячейки (0 - самый верхний, 1-ниже, и т.д)
        :type level: int

        .. note ::
            upd:26.10.2010 kirov
            колонка может быть не указана, т.е. None,
            в этом случае на указанном уровне будет "дырка"
        """
        class BlankBandColumn():
            colspan = 0

            def render(self):
                return '{%s}' % (
                    ('colspan:%s' % self.colspan) if self.colspan else '')

        assert isinstance(level, int)
        assert isinstance(colspan, int)
        assert isinstance(column, ExtGridColumn) or not column
        if not column:
            column = BlankBandColumn()
        # Колонки хранятся в списках внутки сортированного словаря,
        #чтобы их можно было
        # извечь по возрастанию уровней
        column.colspan = colspan
        level_list = self.banded_columns.get(level, [])
        level_list.append(column)
        self.banded_columns[level] = level_list
        self.show_banded_columns = True

    def clear_banded_columns(self):
        """
        Удаляет все объединенные колонки из грида
        """
        self.banded_columns.clear()
        self.show_banded_columns = False

    def set_store(self, store):
        self.__store = store

    def get_store(self):
        return self.__store

    store = property(get_store, set_store)

    def _make_read_only(self,
                        access_off=True,
                        exclude_list=(),
                        *args,
                        **kwargs):
        super(ExtGrid, self)._make_read_only(access_off, exclude_list, *args,
                                             **kwargs)
        self.read_only = access_off
        if self.columns:
            for column in self.columns:
                column.make_read_only(self.read_only, exclude_list, *args,
                                      **kwargs)

        # контекстное меню.
        context_menu_items = [
            self.handler_contextmenu, self.handler_rowcontextmenu
        ]
        for context_menu in context_menu_items:
            if (context_menu and hasattr(context_menu, 'items')
                    and context_menu.items
                    and hasattr(context_menu.items, '__iter__')):
                for item in context_menu.items:
                    if isinstance(item, ExtUIComponent):
                        item.make_read_only(self.read_only, exclude_list,
                                            *args, **kwargs)

    @property
    def columns(self):
        return self._items

    @property
    def sm(self):
        return self.__sm

    @sm.setter
    def sm(self, value):
        self.__sm = value
        self.checkbox_model = isinstance(self.__sm, ExtGridCheckBoxSelModel)

    @property
    def view(self):
        return self.__view

    @view.setter
    def view(self, value):
        self.__view = value

    def t_render_view(self):
        return self.view.render()

    def pre_render(self):
        super(ExtGrid, self).pre_render()
        if self.store:
            self.store.action_context = self.action_context

    @property
    def col_model(self):
        return self.__cm

    @col_model.setter
    def col_model(self, value):
        self.__cm = value
        self.__cm.grid = self

    @property
    def handler_click(self):
        return self._listeners.get('click')

    @handler_click.setter
    def handler_click(self, function):
        self._listeners['click'] = function

    @property
    def handler_dblclick(self):
        if self.read_only:
            # Если грид работает в режиме "чтения"
            # выключаем двойной клик, заменяя пустой функцией
            return 'Ext.emptyFn'
        return self._listeners.get('dblclick')

    @handler_dblclick.setter
    def handler_dblclick(self, function):
        self._listeners['dblclick'] = function

    @property
    def handler_contextmenu(self):
        return self._listeners.get('contextmenu')

    @handler_contextmenu.setter
    def handler_contextmenu(self, menu):
        menu.container = self
        self._listeners['contextmenu'] = menu

    @property
    def handler_rowcontextmenu(self):
        return self._listeners.get('rowcontextmenu')

    @handler_rowcontextmenu.setter
    def handler_rowcontextmenu(self, menu):
        menu.container = self
        self._listeners['rowcontextmenu'] = menu

    def render_base_config(self):
        super(ExtGrid, self).render_base_config()
        if self.force_fit:
            self._view_config['forceFit'] = self.force_fit
        if self.show_preview:
            self._view_config['showPreview'] = self.show_preview
        if self.enable_row_body:
            self._view_config['enableRowBody'] = self.enable_row_body
        if self.get_row_class:
            self._view_config['getRowClass'] = self.get_row_class

        for args in (
            ('stripeRows', True),
            ('stateful', True),
            ('loadMask', self.load_mask),
            ('autoExpandColumn', self.auto_expand_column),
            ('editor', self.editor),
            ('view', self.t_render_view, self.view),
            ('store', self.t_render_store, self.get_store()),
            ('viewConfig', self._view_config),
            ('columnLines', self.column_lines, self.column_lines),
            ('enableDragDrop', self.drag_drop) if self.read_only else (),
            ('ddGroup', self.drag_drop_group) if self.read_only else (),
            ('fieldLabel', self.label) if self.label else (),
            ('clicksToEdit', self.clicks_to_edit,
             self.clicks_to_edit != 2) if self.editor else (),
        ):
            if args:
                self._put_config_value(*args)

    def render_params(self):
        super(ExtGrid, self).render_params()

        handler_cont_menu = (self.handler_contextmenu.render
                             if self.handler_contextmenu else '')
        handler_rowcontextmenu = (self.handler_rowcontextmenu.render
                                  if self.handler_rowcontextmenu else '')

        self._put_params_value(
            'menus', {
                'contextMenu': handler_cont_menu,
                'rowContextMenu': handler_rowcontextmenu
            })
        if self.sm:
            self._put_params_value('selModel', self.sm.render)

        self._put_params_value('colModel', self.col_model.render)
        # проверим набор колонок на наличие фильтров,
        # если есть, то добавим плагин с фильтрами
        for col in self.columns:
            if col.filter:
                self.plugins.append(
                    u"new Ext.ux.grid.GridFilters({menuFilterText:'Фильтр'})")
                break
        self._put_params_value('plugins', self.t_render_plugins)

        if self.show_banded_columns:
            self._put_params_value('bundedColumns',
                                   self.t_render_banded_columns)

    def render(self):
        try:
            self.pre_render()

            self.render_base_config()
            self.render_params()
        except UnicodeDecodeError as msg:
            raise Exception(msg)

        config = self._get_config_str()
        params = self._get_params_str()
        return 'createGridPanel({%s}, {%s})' % (config, params)