class GitRepositoryTargetWidgetBase(BrowserWidget):

    template = ViewPageTemplateFile("templates/gitrepository-target.pt")
    default_option = "project"
    _widgets_set_up = False

    def setUpSubWidgets(self):
        if self._widgets_set_up:
            return
        if bool(getFeatureFlag("disclosure.dsp_picker.enabled")):
            # Replace the default field with a field that uses the better
            # vocabulary.
            package_vocab = "DistributionSourcePackage"
        else:
            package_vocab = "BinaryAndSourcePackageName"
        fields = [
            Choice(__name__="project",
                   title=u"Project",
                   required=True,
                   vocabulary="Product"),
            Choice(__name__="distribution",
                   title=u"Distribution",
                   required=True,
                   vocabulary="Distribution",
                   default=getUtility(ILaunchpadCelebrities).ubuntu),
            Choice(__name__="package",
                   title=u"Package",
                   required=False,
                   vocabulary=package_vocab),
        ]
        if not self._read_only:
            self.distribution_widget = CustomWidgetFactory(
                LaunchpadDropdownWidget)
        for field in fields:
            setUpWidget(self,
                        field.__name__,
                        field,
                        self._sub_widget_interface,
                        prefix=self.name)
        self._widgets_set_up = True

    def setUpOptions(self):
        """Set up options to be rendered."""
        self.options = {}
        for option in ["personal", "package", "project"]:
            attributes = dict(type="radio",
                              name=self.name,
                              value=option,
                              id="%s.option.%s" % (self.name, option))
            if self.request.form_ng.getOne(self.name,
                                           self.default_option) == option:
                attributes["checked"] = "checked"
            if self._read_only:
                attributes["disabled"] = "disabled"
            self.options[option] = renderElement("input", **attributes)

    @property
    def show_options(self):
        return {
            option: not self._read_only or self.default_option == option
            for option in ["personal", "package", "project"]
        }

    def setRenderedValue(self, value):
        """See `IWidget`."""
        self.setUpSubWidgets()
        if value is None or IPerson.providedBy(value):
            self.default_option = "personal"
            return
        elif IProduct.providedBy(value):
            self.default_option = "project"
            self.project_widget.setRenderedValue(value)
            return
        elif IDistributionSourcePackage.providedBy(value):
            self.default_option = "package"
            self.distribution_widget.setRenderedValue(value.distribution)
            self.package_widget.setRenderedValue(value.sourcepackagename)
        else:
            raise AssertionError("Not a valid value: %r" % value)

    def __call__(self):
        """See `zope.formlib.interfaces.IBrowserWidget`."""
        self.setUpSubWidgets()
        self.setUpOptions()
        return self.template()
class LaunchpadTargetWidget(BrowserWidget, InputWidget):
    """Widget for selecting a product, distribution or package target."""

    implements(IAlwaysSubmittedWidget, IMultiLineWidgetLayout, IInputWidget)

    template = ViewPageTemplateFile('templates/launchpad-target.pt')
    default_option = "package"
    _widgets_set_up = False

    def getDistributionVocabulary(self):
        return 'Distribution'
    
    def getProductVocabulary(self):
        return 'Product'

    def setUpSubWidgets(self):
        if self._widgets_set_up:
            return
        fields = [
            Choice(
                __name__='product', title=u'Project',
                required=True, vocabulary=self.getProductVocabulary()),
            Choice(
                __name__='distribution', title=u"Distribution",
                required=True, vocabulary=self.getDistributionVocabulary(),
                default=getUtility(ILaunchpadCelebrities).ubuntu),
            Choice(
                __name__='package', title=u"Package",
                required=False, vocabulary='BinaryAndSourcePackageName'),
            ]
        self.distribution_widget = CustomWidgetFactory(
            LaunchpadDropdownWidget)
        for field in fields:
            setUpWidget(
                self, field.__name__, field, IInputWidget, prefix=self.name)
        self._widgets_set_up = True

    def setUpOptions(self):
        """Set up options to be rendered."""
        self.options = {}
        for option in ['package', 'product']:
            attributes = dict(
                type='radio', name=self.name, value=option,
                id='%s.option.%s' % (self.name, option))
            if self.request.form_ng.getOne(
                     self.name, self.default_option) == option:
                attributes['checked'] = 'checked'
            self.options[option] = renderElement('input', **attributes)
        self.package_widget.onKeyPress = (
            "selectWidget('%s.option.package', event)" % self.name)
        self.product_widget.onKeyPress = (
            "selectWidget('%s.option.product', event)" % self.name)

    def hasInput(self):
        return self.name in self.request.form

    def hasValidInput(self):
        """See zope.formlib.interfaces.IInputWidget."""
        try:
            self.getInputValue()
            return True
        except (InputErrors, UnexpectedFormData):
            return False

    def getInputValue(self):
        """See zope.formlib.interfaces.IInputWidget."""
        self.setUpSubWidgets()
        form_value = self.request.form_ng.getOne(self.name)
        if form_value == 'product':
            try:
                return self.product_widget.getInputValue()
            except MissingInputError:
                self._error = WidgetInputError(
                    self.name, self.label,
                    LaunchpadValidationError('Please enter a project name'))
                raise self._error
            except ConversionError:
                entered_name = self.request.form_ng.getOne(
                    "%s.product" % self.name)
                self._error = WidgetInputError(
                    self.name, self.label,
                    LaunchpadValidationError(
                        "There is no project named '%s' registered in"
                        " Launchpad" % entered_name))
                raise self._error
        elif form_value == 'package':
            try:
                distribution = self.distribution_widget.getInputValue()
            except ConversionError:
                entered_name = self.request.form_ng.getOne(
                    "%s.distribution" % self.name)
                self._error = WidgetInputError(
                    self.name, self.label,
                    LaunchpadValidationError(
                        "There is no distribution named '%s' registered in"
                        " Launchpad" % entered_name))
                raise self._error
            if self.package_widget.hasInput():
                try:
                    package_name = self.package_widget.getInputValue()
                    if package_name is None:
                        return distribution
                    if IDistributionSourcePackage.providedBy(package_name):
                        dsp = package_name
                    else:
                        source_name = (
                            distribution.guessPublishedSourcePackageName(
                                package_name.name))
                        dsp = distribution.getSourcePackage(source_name)
                except (ConversionError, NotFoundError):
                    entered_name = self.request.form_ng.getOne(
                        '%s.package' % self.name)
                    self._error = WidgetInputError(
                        self.name, self.label,
                        LaunchpadValidationError(
                            "There is no package named '%s' published in %s."
                            % (entered_name, distribution.displayname)))
                    raise self._error
                return dsp
            else:
                return distribution
        else:
            raise UnexpectedFormData("No valid option was selected.")

    def setRenderedValue(self, value):
        """See IWidget."""
        self.setUpSubWidgets()
        if IProduct.providedBy(value):
            self.default_option = 'product'
            self.product_widget.setRenderedValue(value)
        elif IDistribution.providedBy(value):
            self.default_option = 'package'
            self.distribution_widget.setRenderedValue(value)
        elif IDistributionSourcePackage.providedBy(value):
            self.default_option = 'package'
            self.distribution_widget.setRenderedValue(value.distribution)
            self.package_widget.setRenderedValue(value.sourcepackagename)
        else:
            raise AssertionError('Not a valid value: %r' % value)

    def __call__(self):
        """See zope.formlib.interfaces.IBrowserWidget."""
        self.setUpSubWidgets()
        self.setUpOptions()
        return self.template()
示例#3
0
class StoreChannelsWidget(BrowserWidget, InputWidget):

    template = ViewPageTemplateFile("templates/storechannels.pt")
    _separator = channel_components_delimiter
    _default_track = 'latest'
    _widgets_set_up = False

    def __init__(self, field, value_type, request):
        # We don't use value_type.
        super(StoreChannelsWidget, self).__init__(field, request)
        # disable help_text for the global widget
        self.hint = None

    def setUpSubWidgets(self):
        if self._widgets_set_up:
            return
        fields = [
            TextLine(__name__="track",
                     title=u"Track",
                     required=False,
                     description=_(
                         "Track defines a series for your software. "
                         "If not specified, the default track ('latest') is "
                         "assumed.")),
            List(
                __name__="risks",
                title=u"Risk",
                required=False,
                value_type=Choice(vocabulary="SnapStoreChannel"),
                description=_("Risks denote the stability of your software.")),
            TextLine(
                __name__="branch",
                title=u"Branch",
                required=False,
                description=_(
                    "Branches provide users with an easy way to test bug "
                    "fixes.  They are temporary and created on demand.  If "
                    "not specified, no branch is used.")),
        ]

        self.risks_widget = CustomWidgetFactory(LabeledMultiCheckBoxWidget)
        for field in fields:
            setUpWidget(self,
                        field.__name__,
                        field,
                        IInputWidget,
                        prefix=self.name)
        self.risks_widget.orientation = 'horizontal'
        self._widgets_set_up = True

    @property
    def has_risks_vocabulary(self):
        risks_widget = getattr(self, 'risks_widget', None)
        return risks_widget and bool(risks_widget.vocabulary)

    def buildChannelName(self, track, risk, branch):
        """Return channel name composed from given track, risk, and branch."""
        channel = risk
        if track and track != self._default_track:
            channel = self._separator.join((track, channel))
        if branch:
            channel = self._separator.join((channel, branch))
        return channel

    def splitChannelName(self, channel):
        """Return extracted track, risk, and branch from given channel name."""
        try:
            track, risk, branch = split_channel_name(channel)
        except ValueError:
            raise AssertionError("Not a valid value: %r" % channel)
        return track, risk, branch

    def setRenderedValue(self, value):
        """See `IWidget`."""
        self.setUpSubWidgets()
        if value:
            # NOTE: atm target channels must belong to the same track and
            # branch
            tracks = set()
            branches = set()
            risks = []
            for channel in value:
                track, risk, branch = self.splitChannelName(channel)
                tracks.add(track)
                risks.append(risk)
                branches.add(branch)
            if len(tracks) != 1 or len(branches) != 1:
                raise AssertionError("Not a valid value: %r" % value)
            track = tracks.pop()
            self.track_widget.setRenderedValue(track)
            self.risks_widget.setRenderedValue(risks)
            branch = branches.pop()
            self.branch_widget.setRenderedValue(branch)
        else:
            self.track_widget.setRenderedValue(None)
            self.risks_widget.setRenderedValue(None)
            self.branch_widget.setRenderedValue(None)

    def hasInput(self):
        """See `IInputWidget`."""
        return ("%s.risks" % self.name) in self.request.form

    def hasValidInput(self):
        """See `IInputWidget`."""
        try:
            self.getInputValue()
            return True
        except (InputErrors, UnexpectedFormData):
            return False

    def getInputValue(self):
        """See `IInputWidget`."""
        self.setUpSubWidgets()
        track = self.track_widget.getInputValue()
        risks = self.risks_widget.getInputValue()
        branch = self.branch_widget.getInputValue()
        if track and self._separator in track:
            error_msg = "Track name cannot include '%s'." % self._separator
            raise WidgetInputError(self.name, self.label,
                                   LaunchpadValidationError(error_msg))
        if branch and self._separator in branch:
            error_msg = "Branch name cannot include '%s'." % self._separator
            raise WidgetInputError(self.name, self.label,
                                   LaunchpadValidationError(error_msg))
        channels = [
            self.buildChannelName(track, risk, branch) for risk in risks
        ]
        return channels

    def error(self):
        """See `IBrowserWidget`."""
        try:
            if self.hasInput():
                self.getInputValue()
        except InputErrors as error:
            self._error = error
        return super(StoreChannelsWidget, self).error()

    def __call__(self):
        """See `IBrowserWidget`."""
        self.setUpSubWidgets()
        return self.template()
示例#4
0
class ProductBugTrackerWidget(LaunchpadRadioWidget):
    """Widget for selecting a product bug tracker."""

    _joinButtonToMessageTemplate = u'%s %s'
    template = ViewPageTemplateFile('templates/product-bug-tracker.pt')

    def __init__(self, field, vocabulary, request):
        LaunchpadRadioWidget.__init__(self, field, vocabulary, request)

        # Bug tracker widget.
        self.bugtracker = Choice(vocabulary="WebBugTracker",
                                 __name__='bugtracker')
        self.bugtracker_widget = CustomWidgetFactory(BugTrackerPickerWidget)
        setUpWidget(self,
                    'bugtracker',
                    self.bugtracker,
                    IInputWidget,
                    prefix=self.name,
                    value=field.context.bugtracker,
                    context=field.context)
        self.bugtracker_widget.onKeyPress = ("selectWidget('%s.2', event);" %
                                             self.name)

        # Upstream email address field and widget.
        ## This is to make email address bug trackers appear
        ## separately from the main bug tracker list.
        self.upstream_email_address = StrippedTextLine(
            required=False,
            constraint=email_validator,
            __name__='upstream_email_address')
        self.upstream_email_address_widget = (
            CustomWidgetFactory(StrippedTextWidget))
        setUpWidget(self,
                    'upstream_email_address',
                    self.upstream_email_address,
                    IInputWidget,
                    prefix=self.name,
                    value='',
                    context=self.upstream_email_address.context)
        ## Select the corresponding radio option automatically if
        ## the user starts typing.
        if self.upstream_email_address_widget.extra is None:
            self.upstream_email_address_widget.extra = ''
        self.upstream_email_address_widget.extra += (
            ''' onkeypress="selectWidget('%s.3', event);"\n''' % self.name)

    def _renderItem(self, index, text, value, name, cssClass, checked=False):
        # This form has a custom need to render their labels separately,
        # because of a Firefox problem: see comment in renderItems.
        kw = {}
        if checked:
            kw['checked'] = 'checked'
        id = '%s.%s' % (name, index)
        elem = renderElement(u'input',
                             value=value,
                             name=name,
                             id=id,
                             cssClass=cssClass,
                             type='radio',
                             **kw)
        return '%s %s' % (elem, text)

    def _toFieldValue(self, form_value):
        if form_value == "malone":
            return self.context.malone_marker
        elif form_value == "external":
            return self.bugtracker_widget.getInputValue()
        elif form_value == "external-email":
            email_address = self.upstream_email_address_widget.getInputValue()
            if email_address is None or len(email_address) == 0:
                self.upstream_email_address_widget._error = (
                    LaunchpadValidationError('Please enter an email address.'))
                raise self.upstream_email_address_widget._error
            bugtracker = getUtility(IBugTrackerSet).ensureBugTracker(
                'mailto:%s' % email_address,
                getUtility(ILaunchBag).user, BugTrackerType.EMAILADDRESS)
            return bugtracker
        elif form_value == "project":
            return None

    def getInputValue(self):
        return self._toFieldValue(self._getFormInput())

    def setRenderedValue(self, value):
        self._data = value
        if value is not self.context.malone_marker:
            self.bugtracker_widget.setRenderedValue(value)

    def _renderLabel(self, text, index):
        """Render a label for the option with the specified index."""
        option_id = '%s.%s' % (self.name, index)
        return u'<label for="%s" style="font-weight: normal">%s</label>' % (
            option_id, text)

    def error(self):
        """Concatenate errors from this widget and sub-widgets."""
        errors = [
            super(ProductBugTrackerWidget, self).error(),
            self.upstream_email_address_widget.error()
        ]
        return '; '.join(err for err in errors if len(err) > 0)

    def renderItems(self, value):
        """Custom-render the radio-buttons and dependent widgets.

        Some of the radio options have dependent widgets: the bug
        tracker drop-down box, and the email address text field. To
        render these in the correct place we must override the default
        rendering of `LaunchpadRadioWidget`.

        We must also make sure that these dependent widgets are
        populated with the correct information, specifically the bug
        tracker selected, or the email address where bugs must be
        reported.
        """
        field = self.context
        product = field.context
        if value == self._missing:
            value = field.missing_value

        # Bugs tracked in Launchpad Bugs.
        malone_item_arguments = dict(index=0,
                                     text=self._renderLabel("In Launchpad", 0),
                                     value="malone",
                                     name=self.name,
                                     cssClass=self.cssClass)

        # Project or somewhere else.
        project = product.project
        if project is None or project.bugtracker is None:
            project_bugtracker_caption = "Somewhere else"
        else:
            project_bugtracker_caption = structured(
                'In the %s bug tracker (<a href="%s">%s</a>)</label>',
                project.displayname, canonical_url(project.bugtracker),
                project.bugtracker.title).escapedtext
        project_bugtracker_arguments = dict(index=1,
                                            text=self._renderLabel(
                                                project_bugtracker_caption, 1),
                                            value="project",
                                            name=self.name,
                                            cssClass=self.cssClass)

        # External bug tracker.
        ## The bugtracker widget can't be within the <label> tag,
        ## since Firefox doesn't cope with it well.
        external_bugtracker_text = "%s %s" % (self._renderLabel(
            "In a registered bug tracker:", 2), self.bugtracker_widget())
        external_bugtracker_arguments = dict(index=2,
                                             text=external_bugtracker_text,
                                             value="external",
                                             name=self.name,
                                             cssClass=self.cssClass)

        # Upstream email address (special-case bug tracker).
        if (IBugTracker.providedBy(value)
                and value.bugtrackertype == BugTrackerType.EMAILADDRESS):
            self.upstream_email_address_widget.setRenderedValue(
                value.baseurl.lstrip('mailto:'))
        external_bugtracker_email_text = "%s %s" % (self._renderLabel(
            "By emailing an upstream bug contact:\n",
            3), self.upstream_email_address_widget())
        external_bugtracker_email_arguments = dict(
            index=3,
            text=external_bugtracker_email_text,
            value="external-email",
            name=self.name,
            cssClass=self.cssClass)

        # All the choices arguments in order.
        all_arguments = {
            'launchpad': malone_item_arguments,
            'external_bugtracker': external_bugtracker_arguments,
            'external_email': external_bugtracker_email_arguments,
            'unknown': project_bugtracker_arguments,
        }

        # Figure out the selected choice.
        if value == field.malone_marker:
            selected = malone_item_arguments
        elif value != self.context.missing_value:
            # value will be 'external-email' if there was an error on
            # upstream_email_address_widget.
            if (value == 'external-email' or
                (IBugTracker.providedBy(value)
                 and value.bugtrackertype == BugTrackerType.EMAILADDRESS)):
                selected = external_bugtracker_email_arguments
            else:
                selected = external_bugtracker_arguments
        else:
            selected = project_bugtracker_arguments

        # Render.
        for name, arguments in all_arguments.items():
            if arguments is selected:
                render = self.renderSelectedItem
            else:
                render = self.renderItem
            yield (name, render(**arguments))

    def renderValue(self, value):
        # Render the items with subordinate fields and support markup.
        self.bug_trackers = dict(self.renderItems(value))
        self.product = self.context.context
        # The view must also use GhostWidget for the 'remote_product' field.
        self.remote_product = copy_field(IProduct['remote_product'])
        self.remote_product_widget = CustomWidgetFactory(TextWidget)
        setUpWidget(self,
                    'remote_product',
                    self.remote_product,
                    IInputWidget,
                    prefix='field',
                    value=self.product.remote_product,
                    context=self.product)
        # The view must also use GhostWidget for the 'enable_bug_expiration'
        # field.
        self.enable_bug_expiration = copy_field(
            IProduct['enable_bug_expiration'])
        self.enable_bug_expiration_widget = CustomWidgetFactory(CheckBoxWidget)
        setUpWidget(self,
                    'enable_bug_expiration',
                    self.enable_bug_expiration,
                    IInputWidget,
                    prefix='field',
                    value=self.product.enable_bug_expiration,
                    context=self.product)
        return self.template()
示例#5
0
class ProductBugTrackerWidget(LaunchpadRadioWidget):
    """Widget for selecting a product bug tracker."""

    _joinButtonToMessageTemplate = u'%s&nbsp;%s'
    template = ViewPageTemplateFile('templates/product-bug-tracker.pt')

    def __init__(self, field, vocabulary, request):
        LaunchpadRadioWidget.__init__(self, field, vocabulary, request)

        # Bug tracker widget.
        self.bugtracker = Choice(
            vocabulary="WebBugTracker",
            __name__='bugtracker')
        self.bugtracker_widget = CustomWidgetFactory(BugTrackerPickerWidget)
        setUpWidget(
            self, 'bugtracker', self.bugtracker, IInputWidget,
            prefix=self.name, value=field.context.bugtracker,
            context=field.context)
        self.bugtracker_widget.onKeyPress = (
            "selectWidget('%s.2', event);" % self.name)

        # Upstream email address field and widget.
        ## This is to make email address bug trackers appear
        ## separately from the main bug tracker list.
        self.upstream_email_address = StrippedTextLine(
            required=False, constraint=email_validator,
            __name__='upstream_email_address')
        self.upstream_email_address_widget = (
            CustomWidgetFactory(StrippedTextWidget))
        setUpWidget(
            self, 'upstream_email_address', self.upstream_email_address,
            IInputWidget, prefix=self.name, value='',
            context=self.upstream_email_address.context)
        ## Select the corresponding radio option automatically if
        ## the user starts typing.
        if self.upstream_email_address_widget.extra is None:
            self.upstream_email_address_widget.extra = ''
        self.upstream_email_address_widget.extra += (
            ''' onkeypress="selectWidget('%s.3', event);"\n''' % self.name)

    def _renderItem(self, index, text, value, name, cssClass, checked=False):
        # This form has a custom need to render their labels separately,
        # because of a Firefox problem: see comment in renderItems.
        kw = {}
        if checked:
            kw['checked'] = 'checked'
        id = '%s.%s' % (name, index)
        elem = renderElement(u'input',
                             value=value,
                             name=name,
                             id=id,
                             cssClass=cssClass,
                             type='radio',
                             **kw)
        return '%s&nbsp;%s' % (elem, text)

    def _toFieldValue(self, form_value):
        if form_value == "malone":
            return self.context.malone_marker
        elif form_value == "external":
            return self.bugtracker_widget.getInputValue()
        elif form_value == "external-email":
            email_address = self.upstream_email_address_widget.getInputValue()
            if email_address is None or len(email_address) == 0:
                self.upstream_email_address_widget._error = (
                    LaunchpadValidationError(
                        'Please enter an email address.'))
                raise self.upstream_email_address_widget._error
            bugtracker = getUtility(IBugTrackerSet).ensureBugTracker(
                'mailto:%s' % email_address, getUtility(ILaunchBag).user,
                BugTrackerType.EMAILADDRESS)
            return bugtracker
        elif form_value == "project":
            return None

    def getInputValue(self):
        return self._toFieldValue(self._getFormInput())

    def setRenderedValue(self, value):
        self._data = value
        if value is not self.context.malone_marker:
            self.bugtracker_widget.setRenderedValue(value)

    def _renderLabel(self, text, index):
        """Render a label for the option with the specified index."""
        option_id = '%s.%s' % (self.name, index)
        return u'<label for="%s" style="font-weight: normal">%s</label>' % (
            option_id, text)

    def error(self):
        """Concatenate errors from this widget and sub-widgets."""
        errors = [super(ProductBugTrackerWidget, self).error(),
                  self.upstream_email_address_widget.error()]
        return '; '.join(err for err in errors if len(err) > 0)

    def renderItems(self, value):
        """Custom-render the radio-buttons and dependent widgets.

        Some of the radio options have dependent widgets: the bug
        tracker drop-down box, and the email address text field. To
        render these in the correct place we must override the default
        rendering of `LaunchpadRadioWidget`.

        We must also make sure that these dependent widgets are
        populated with the correct information, specifically the bug
        tracker selected, or the email address where bugs must be
        reported.
        """
        field = self.context
        product = field.context
        if value == self._missing:
            value = field.missing_value

        # Bugs tracked in Launchpad Bugs.
        malone_item_arguments = dict(
            index=0, text=self._renderLabel("In Launchpad", 0),
            value="malone", name=self.name, cssClass=self.cssClass)

        # Project or somewhere else.
        project = product.project
        if project is None or project.bugtracker is None:
            project_bugtracker_caption = "Somewhere else"
        else:
            project_bugtracker_caption = structured(
                'In the %s bug tracker (<a href="%s">%s</a>)</label>',
                project.displayname, canonical_url(project.bugtracker),
                project.bugtracker.title).escapedtext
        project_bugtracker_arguments = dict(
            index=1, text=self._renderLabel(project_bugtracker_caption, 1),
            value="project", name=self.name, cssClass=self.cssClass)

        # External bug tracker.
        ## The bugtracker widget can't be within the <label> tag,
        ## since Firefox doesn't cope with it well.
        external_bugtracker_text = "%s %s" % (
            self._renderLabel("In a registered bug tracker:", 2),
            self.bugtracker_widget())
        external_bugtracker_arguments = dict(
            index=2, text=external_bugtracker_text,
            value="external", name=self.name, cssClass=self.cssClass)

        # Upstream email address (special-case bug tracker).
        if (IBugTracker.providedBy(value) and
            value.bugtrackertype == BugTrackerType.EMAILADDRESS):
            self.upstream_email_address_widget.setRenderedValue(
                value.baseurl.lstrip('mailto:'))
        external_bugtracker_email_text = "%s %s" % (
            self._renderLabel("By emailing an upstream bug contact:\n", 3),
            self.upstream_email_address_widget())
        external_bugtracker_email_arguments = dict(
            index=3, text=external_bugtracker_email_text,
            value="external-email", name=self.name, cssClass=self.cssClass)

        # All the choices arguments in order.
        all_arguments = {
            'launchpad': malone_item_arguments,
            'external_bugtracker': external_bugtracker_arguments,
            'external_email': external_bugtracker_email_arguments,
            'unknown': project_bugtracker_arguments,
            }

        # Figure out the selected choice.
        if value == field.malone_marker:
            selected = malone_item_arguments
        elif value != self.context.missing_value:
            # value will be 'external-email' if there was an error on
            # upstream_email_address_widget.
            if (value == 'external-email' or (
                    IBugTracker.providedBy(value) and
                    value.bugtrackertype == BugTrackerType.EMAILADDRESS)):
                selected = external_bugtracker_email_arguments
            else:
                selected = external_bugtracker_arguments
        else:
            selected = project_bugtracker_arguments

        # Render.
        for name, arguments in all_arguments.items():
            if arguments is selected:
                render = self.renderSelectedItem
            else:
                render = self.renderItem
            yield (name, render(**arguments))

    def renderValue(self, value):
        # Render the items with subordinate fields and support markup.
        self.bug_trackers = dict(self.renderItems(value))
        self.product = self.context.context
        # The view must also use GhostWidget for the 'remote_product' field.
        self.remote_product = copy_field(IProduct['remote_product'])
        self.remote_product_widget = CustomWidgetFactory(TextWidget)
        setUpWidget(
            self, 'remote_product', self.remote_product, IInputWidget,
            prefix='field', value=self.product.remote_product,
            context=self.product)
        # The view must also use GhostWidget for the 'enable_bug_expiration'
        # field.
        self.enable_bug_expiration = copy_field(
            IProduct['enable_bug_expiration'])
        self.enable_bug_expiration_widget = CustomWidgetFactory(
            CheckBoxWidget)
        setUpWidget(
            self, 'enable_bug_expiration', self.enable_bug_expiration,
            IInputWidget, prefix='field',
            value=self.product.enable_bug_expiration, context=self.product)
        return self.template()
class LaunchpadTargetWidget(BrowserWidget, InputWidget):
    """Widget for selecting a product, distribution or package target."""

    implements(IAlwaysSubmittedWidget, IMultiLineWidgetLayout, IInputWidget)

    template = ViewPageTemplateFile('templates/launchpad-target.pt')
    default_option = "package"
    _widgets_set_up = False

    def getDistributionVocabulary(self):
        return 'Distribution'

    def getProductVocabulary(self):
        return 'Product'

    def setUpSubWidgets(self):
        if self._widgets_set_up:
            return
        fields = [
            Choice(__name__='product',
                   title=u'Project',
                   required=True,
                   vocabulary=self.getProductVocabulary()),
            Choice(__name__='distribution',
                   title=u"Distribution",
                   required=True,
                   vocabulary=self.getDistributionVocabulary(),
                   default=getUtility(ILaunchpadCelebrities).ubuntu),
            Choice(__name__='package',
                   title=u"Package",
                   required=False,
                   vocabulary='BinaryAndSourcePackageName'),
        ]
        self.distribution_widget = CustomWidgetFactory(LaunchpadDropdownWidget)
        for field in fields:
            setUpWidget(self,
                        field.__name__,
                        field,
                        IInputWidget,
                        prefix=self.name)
        self._widgets_set_up = True

    def setUpOptions(self):
        """Set up options to be rendered."""
        self.options = {}
        for option in ['package', 'product']:
            attributes = dict(type='radio',
                              name=self.name,
                              value=option,
                              id='%s.option.%s' % (self.name, option))
            if self.request.form_ng.getOne(self.name,
                                           self.default_option) == option:
                attributes['checked'] = 'checked'
            self.options[option] = renderElement('input', **attributes)
        self.package_widget.onKeyPress = (
            "selectWidget('%s.option.package', event)" % self.name)
        self.product_widget.onKeyPress = (
            "selectWidget('%s.option.product', event)" % self.name)

    def hasInput(self):
        return self.name in self.request.form

    def hasValidInput(self):
        """See zope.formlib.interfaces.IInputWidget."""
        try:
            self.getInputValue()
            return True
        except (InputErrors, UnexpectedFormData):
            return False

    def getInputValue(self):
        """See zope.formlib.interfaces.IInputWidget."""
        self.setUpSubWidgets()
        form_value = self.request.form_ng.getOne(self.name)
        if form_value == 'product':
            try:
                return self.product_widget.getInputValue()
            except MissingInputError:
                self._error = WidgetInputError(
                    self.name, self.label,
                    LaunchpadValidationError('Please enter a project name'))
                raise self._error
            except ConversionError:
                entered_name = self.request.form_ng.getOne("%s.product" %
                                                           self.name)
                self._error = WidgetInputError(
                    self.name, self.label,
                    LaunchpadValidationError(
                        "There is no project named '%s' registered in"
                        " Launchpad" % entered_name))
                raise self._error
        elif form_value == 'package':
            try:
                distribution = self.distribution_widget.getInputValue()
            except ConversionError:
                entered_name = self.request.form_ng.getOne("%s.distribution" %
                                                           self.name)
                self._error = WidgetInputError(
                    self.name, self.label,
                    LaunchpadValidationError(
                        "There is no distribution named '%s' registered in"
                        " Launchpad" % entered_name))
                raise self._error
            if self.package_widget.hasInput():
                try:
                    package_name = self.package_widget.getInputValue()
                    if package_name is None:
                        return distribution
                    if IDistributionSourcePackage.providedBy(package_name):
                        dsp = package_name
                    else:
                        source_name = (
                            distribution.guessPublishedSourcePackageName(
                                package_name.name))
                        dsp = distribution.getSourcePackage(source_name)
                except (ConversionError, NotFoundError):
                    entered_name = self.request.form_ng.getOne('%s.package' %
                                                               self.name)
                    self._error = WidgetInputError(
                        self.name, self.label,
                        LaunchpadValidationError(
                            "There is no package named '%s' published in %s." %
                            (entered_name, distribution.displayname)))
                    raise self._error
                return dsp
            else:
                return distribution
        else:
            raise UnexpectedFormData("No valid option was selected.")

    def setRenderedValue(self, value):
        """See IWidget."""
        self.setUpSubWidgets()
        if IProduct.providedBy(value):
            self.default_option = 'product'
            self.product_widget.setRenderedValue(value)
        elif IDistribution.providedBy(value):
            self.default_option = 'package'
            self.distribution_widget.setRenderedValue(value)
        elif IDistributionSourcePackage.providedBy(value):
            self.default_option = 'package'
            self.distribution_widget.setRenderedValue(value.distribution)
            self.package_widget.setRenderedValue(value.sourcepackagename)
        else:
            raise AssertionError('Not a valid value: %r' % value)

    def __call__(self):
        """See zope.formlib.interfaces.IBrowserWidget."""
        self.setUpSubWidgets()
        self.setUpOptions()
        return self.template()
示例#7
0
class GitGranteeWidgetBase(BrowserWidget):

    template = ViewPageTemplateFile("templates/gitgrantee.pt")
    default_option = "person"
    _widgets_set_up = False

    def setUpSubWidgets(self):
        if self._widgets_set_up:
            return
        fields = [
            Choice(__name__="person",
                   title=u"Person",
                   required=False,
                   vocabulary="ValidPersonOrTeam"),
        ]
        if self._read_only:
            self.person_widget = CustomWidgetFactory(
                GitGranteePersonDisplayWidget)
        else:
            self.person_widget = CustomWidgetFactory(
                PersonPickerWidget,
                # XXX cjwatson 2018-10-18: This is a little unfortunate, but
                # otherwise there's no spacing at all between the
                # (deliberately unlabelled) radio button and the text box.
                style="margin-left: 4px;")
        for field in fields:
            setUpWidget(self,
                        field.__name__,
                        field,
                        self._sub_widget_interface,
                        prefix=self.name)
        self._widgets_set_up = True

    def setUpOptions(self):
        """Set up options to be rendered."""
        self.options = {}
        for option in ("repository_owner", "person"):
            attributes = {
                "type": "radio",
                "name": self.name,
                "value": option,
                "id": "%s.option.%s" % (self.name, option),
                # XXX cjwatson 2018-10-18: Ugly, but it's worse without
                # this, especially in a permissions table where this widget
                # is normally used.
                "style": "margin-left: 0;",
            }
            if self.request.form_ng.getOne(self.name,
                                           self.default_option) == option:
                attributes["checked"] = "checked"
            if self._read_only:
                attributes["disabled"] = "disabled"
            self.options[option] = renderElement("input", **attributes)

    @property
    def show_options(self):
        return {
            option: not self._read_only or self.default_option == option
            for option in ("repository_owner", "person")
        }

    def setRenderedValue(self, value):
        """See `IWidget`."""
        self.setUpSubWidgets()
        if value == GitGranteeType.REPOSITORY_OWNER:
            self.default_option = "repository_owner"
            return
        elif value is None or IPerson.providedBy(value):
            self.default_option = "person"
            self.person_widget.setRenderedValue(value)
            return
        else:
            raise AssertionError("Not a valid value: %r" % value)

    def __call__(self):
        """See `zope.formlib.interfaces.IBrowserWidget`."""
        self.setUpSubWidgets()
        self.setUpOptions()
        return self.template()