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()
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()
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()
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()
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()
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()