<commit_before>import copy

from django import forms
from django.db.models.fields import FieldDoesNotExist
from django.utils.translation import ugettext_lazy as _
from django.contrib.gis.db.models.fields import GeometryField

import floppyforms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Button, HTML
from crispy_forms.bootstrap import FormActions
from tinymce.widgets import TinyMCE
from modeltranslation.translator import translator, NotRegistered


from . import app_settings
from .widgets import MapWidget


class TranslatedModelForm(forms.ModelForm):
    """
    Auto-expand translatable fields.
    Expand means replace native (e.g. `name`) by translated (e.g. `name_fr`, `name_en`)
    """

    def __init__(self, *args, **kwargs):
        super(TranslatedModelForm, self).__init__(*args, **kwargs)
        # Track translated fields
        self._translated = {}
        self.replace_orig_fields()
        self.populate_fields()

    def replace_orig_fields(self):
        # Expand i18n fields
        try:
            # Obtain model translation options
            mto = translator.get_options_for_model(self._meta.model)
        except NotRegistered:
            # No translation field on this model, nothing to do
            return
        # For each translated model field
        for modelfield in mto.fields:
            # Remove form native field (e.g. `name`)
            native = self.fields.pop(modelfield)
            # Add translated fields (e.g. `name_fr`, `name_en`...)
            for l in app_settings['TRANSLATED_LANGUAGES']:
                lang = l[0]
                name = '%s_%s' % (modelfield, lang)
                # Add to form.fields{}
                translated = copy.deepcopy(native)
                translated.required = native.required and (lang == app_settings['LANGUAGE_CODE'])
                translated.label = u"%s [%s]" % (unicode(translated.label), lang)
                self.fields[name] = translated
                # Keep track of replacements
                self._translated.setdefault(modelfield, []).append(name)

    def save(self, *args, **kwargs):
        """ Manually saves translated fields on instance.
        """
        # Save translated fields
        for fields in self._translated.values():
            for field in fields:
                value = self.cleaned_data.get(field)
                if value:
                    setattr(self.instance, field, value)
        return super(TranslatedModelForm, self).save(*args, **kwargs)

    def populate_fields(self):
        """ Manually loads translated fields from instance.
        """
        if self.instance:
            for fields in self._translated.values():
                for field in fields:
                    self.fields[field].initial = getattr(self.instance, field)


class SubmitButton(HTML):

    def __init__(self, divid, label):
        content = ("""
            <a id="%s" class="btn btn-success pull-right offset1" onclick="javascript:$(this).parents('form').submit();">
                <i class="icon-white icon-ok-sign"></i> %s
            </a>""" % (divid, unicode(label)))
        super(SubmitButton, self).__init__(content)


class MapEntityForm(TranslatedModelForm):

    fieldslayout = None
    geomfields = []
    leftpanel_scrollable = True

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        self.can_delete = kwargs.pop('can_delete', True)
        super(MapEntityForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.form_tag = True

        self.fields['pk'] = forms.Field(required=False, widget=forms.Field.hidden_widget,
                                        initial=self.instance.pk)
        self.fields['model'] = forms.Field(required=False, widget=forms.Field.hidden_widget,
                                           initial=self.instance._meta.module_name)

        # Default widgets
        for fieldname, formfield in self.fields.items():
            # Custom code because formfield_callback does not work with inherited forms
            if formfield:
                # Assign map widget to all geometry fields
                try:
                    formmodel = self._meta.model
                    modelfield = formmodel._meta.get_field(fieldname)
                    needs_replace_widget = (isinstance(modelfield, GeometryField)
                                            and not isinstance(formfield.widget, MapWidget))
                    if needs_replace_widget:
                        formfield.widget = MapWidget()
                        formfield.widget.attrs['geom_type'] = formfield.geom_type
                except FieldDoesNotExist:
                    pass

                # Bypass widgets that inherit textareas, such as geometry fields
                if formfield.widget.__class__ in (forms.widgets.Textarea,
                                                  floppyforms.widgets.Textarea):
                    formfield.widget = TinyMCE()

        self._init_layout()

    def _init_layout(self):
        """ Setup form buttons, submit URL, layout
        """
        is_creation = self.instance.pk is None

        actions = [
            SubmitButton('save_changes', _('Create') if is_creation else _('Save changes')),
            Button('cancel', _('Cancel'), css_class="pull-right offset1"),
        ]

        # Generic behaviour
        if not is_creation:
            self.helper.form_action = self.instance.get_update_url()
            # Put delete url in Delete button
            actions.insert(0, HTML('<a class="btn %s delete" href="%s"><i class="icon-white icon-trash"></i> %s</a>' % (
                'btn-danger' if self.can_delete else 'disabled',
                self.instance.get_delete_url() if self.can_delete else '#',
                unicode(_("Delete")))))
        else:
            self.helper.form_action = self.instance.get_add_url()

        # Check if fieldslayout is defined, otherwise use Meta.fields
        fieldslayout = self.fieldslayout
        if not fieldslayout:
            # Remove geomfields from left part
            fieldslayout = [fl for fl in self.fields.keys() if fl not in self.geomfields]
        # Replace native fields in Crispy layout by translated fields
        fieldslayout = self.__replace_translatable_fields(fieldslayout)

        has_geomfield = len(self.geomfields) > 0
        leftpanel_css = "span" + ('4' if has_geomfield else '12')
        if self.leftpanel_scrollable:
            leftpanel_css += " scrollable"

        leftpanel = Div(
            *fieldslayout,
            css_class=leftpanel_css,
            css_id="modelfields"
        )

        rightpanel = tuple()
        if has_geomfield:
            rightpanel = (Div(
                *self.geomfields,
                css_class="span8",
                css_id="geomfield"
            ),)

        # Main form layout
        self.helper.help_text_inline = True
        self.helper.form_class = 'form-horizontal'
        self.helper.layout = Layout(
            Div(
                Div(
                    leftpanel,<commit_msg>Create tabs for translatable fields when crispy form layout is not specified<commit_after>import copy

from django import forms
from django.db.models.fields import FieldDoesNotExist
from django.utils.translation import ugettext_lazy as _
from django.contrib.gis.db.models.fields import GeometryField

import floppyforms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Button, HTML
from crispy_forms.bootstrap import FormActions
from tinymce.widgets import TinyMCE
from modeltranslation.translator import translator, NotRegistered


from . import app_settings
from .widgets import MapWidget


class TranslatedModelForm(forms.ModelForm):
    """
    Auto-expand translatable fields.
    Expand means replace native (e.g. `name`) by translated (e.g. `name_fr`, `name_en`)
    """

    def __init__(self, *args, **kwargs):
        super(TranslatedModelForm, self).__init__(*args, **kwargs)
        # Track translated fields
        self._translated = {}
        self.replace_orig_fields()
        self.populate_fields()

    def replace_orig_fields(self):
        self.orig_fields = self.fields.keys()
        # Expand i18n fields
        try:
            # Obtain model translation options
            mto = translator.get_options_for_model(self._meta.model)
        except NotRegistered:
            # No translation field on this model, nothing to do
            return
        # For each translated model field
        for modelfield in mto.fields:
            # Remove form native field (e.g. `name`)
            native = self.fields.pop(modelfield)
            # Add translated fields (e.g. `name_fr`, `name_en`...)
            for l in app_settings['TRANSLATED_LANGUAGES']:
                lang = l[0]
                name = '%s_%s' % (modelfield, lang)
                # Add to form.fields{}
                translated = copy.deepcopy(native)
                translated.required = native.required and (lang == app_settings['LANGUAGE_CODE'])
                translated.label = u"%s [%s]" % (unicode(translated.label), lang)
                self.fields[name] = translated
                # Keep track of replacements
                self._translated.setdefault(modelfield, []).append(name)

    def save(self, *args, **kwargs):
        """ Manually saves translated fields on instance.
        """
        # Save translated fields
        for fields in self._translated.values():
            for field in fields:
                value = self.cleaned_data.get(field)
                if value:
                    setattr(self.instance, field, value)
        return super(TranslatedModelForm, self).save(*args, **kwargs)

    def populate_fields(self):
        """ Manually loads translated fields from instance.
        """
        if self.instance:
            for fields in self._translated.values():
                for field in fields:
                    self.fields[field].initial = getattr(self.instance, field)


class SubmitButton(HTML):

    def __init__(self, divid, label):
        content = ("""
            <a id="%s" class="btn btn-success pull-right offset1" onclick="javascript:$(this).parents('form').submit();">
                <i class="icon-white icon-ok-sign"></i> %s
            </a>""" % (divid, unicode(label)))
        super(SubmitButton, self).__init__(content)


class MapEntityForm(TranslatedModelForm):

    fieldslayout = None
    geomfields = []
    leftpanel_scrollable = True

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        self.can_delete = kwargs.pop('can_delete', True)
        super(MapEntityForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.form_tag = True

        self.fields['pk'] = forms.Field(required=False, widget=forms.Field.hidden_widget,
                                        initial=self.instance.pk)
        self.fields['model'] = forms.Field(required=False, widget=forms.Field.hidden_widget,
                                           initial=self.instance._meta.module_name)

        # Default widgets
        for fieldname, formfield in self.fields.items():
            # Custom code because formfield_callback does not work with inherited forms
            if formfield:
                # Assign map widget to all geometry fields
                try:
                    formmodel = self._meta.model
                    modelfield = formmodel._meta.get_field(fieldname)
                    needs_replace_widget = (isinstance(modelfield, GeometryField)
                                            and not isinstance(formfield.widget, MapWidget))
                    if needs_replace_widget:
                        formfield.widget = MapWidget()
                        formfield.widget.attrs['geom_type'] = formfield.geom_type
                except FieldDoesNotExist:
                    pass

                # Bypass widgets that inherit textareas, such as geometry fields
                if formfield.widget.__class__ in (forms.widgets.Textarea,
                                                  floppyforms.widgets.Textarea):
                    formfield.widget = TinyMCE()

        self._init_layout()

    def _init_layout(self):
        """ Setup form buttons, submit URL, layout
        """
        is_creation = self.instance.pk is None

        actions = [
            SubmitButton('save_changes', _('Create') if is_creation else _('Save changes')),
            Button('cancel', _('Cancel'), css_class="pull-right offset1"),
        ]

        # Generic behaviour
        if not is_creation:
            self.helper.form_action = self.instance.get_update_url()
            # Put delete url in Delete button
            actions.insert(0, HTML('<a class="btn %s delete" href="%s"><i class="icon-white icon-trash"></i> %s</a>' % (
                'btn-danger' if self.can_delete else 'disabled',
                self.instance.get_delete_url() if self.can_delete else '#',
                unicode(_("Delete")))))
        else:
            self.helper.form_action = self.instance.get_add_url()

        # Check if fieldslayout is defined, otherwise use Meta.fields
        fieldslayout = self.fieldslayout
        if not fieldslayout:
            # Remove geomfields from left part
            fieldslayout = [fl for fl in self.orig_fields if fl not in self.geomfields]
        # Replace native fields in Crispy layout by translated fields
        fieldslayout = self.__replace_translatable_fields(fieldslayout)

        has_geomfield = len(self.geomfields) > 0
        leftpanel_css = "span" + ('4' if has_geomfield else '12')
        if self.leftpanel_scrollable:
            leftpanel_css += " scrollable"

        leftpanel = Div(
            *fieldslayout,
            css_class=leftpanel_css,
            css_id="modelfields"
        )

        rightpanel = tuple()
        if has_geomfield:
            rightpanel = (Div(
                *self.geomfields,
                css_class="span8",
                css_id="geomfield"
            ),)

        # Main form layout
        self.helper.help_text_inline = True
        self.helper.form_class = 'form-horizontal'
        self.helper.layout = Layout(
            Div(
                Div(
                    leftpanel,
{'fraction_non_alphanumeric': 0.09536671514647829, 'fraction_numerical': 0.0015236512223838216, 'mean_word_length': 2.0127268933861884, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5029514', 'n_tokens_mistral': 3912, 'n_tokens_neox': 3716, 'n_words': 956}