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 BrandingChangeView(LaunchpadEditFormView): """This is a base class that MUST be subclassed for each object, because each object will have a different description for its branding that is part of its own interface. For each subclass, specify the schema ("IPerson") and the field_names (some subset of icon, logo, mugshot). """ @property def label(self): return ('Change the images used to represent %s in Launchpad' % self.context.displayname) page_title = "Change branding" custom_widget_icon = CustomWidgetFactory(ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) custom_widget_logo = CustomWidgetFactory(ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) custom_widget_mugshot = CustomWidgetFactory(ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) @action("Change Branding", name='change') def change_action(self, action, data): self.updateContextFromData(data) @property def next_url(self): return canonical_url(self.context) cancel_url = next_url
def __init__(self, context, request): SimpleInputWidget.__init__(self, context, request) fields = form.Fields( Choice(__name__='action', source=self._getActionsVocabulary(), title=_('Action')), Datetime(__name__='announcement_date', title=_('Date'), required=False, default=None)) fields['action'].custom_widget = CustomWidgetFactory( LaunchpadRadioWidget) fields['announcement_date'].custom_widget = CustomWidgetFactory( DateTimeWidget) if IAnnouncement.providedBy(self.context.context): # we are editing an existing announcement data = {} date_announced = self.context.context.date_announced data['announcement_date'] = date_announced if date_announced is None: data['action'] = 'sometime' else: data['action'] = 'specific' else: data = {'action': 'immediately'} widgets = form.setUpWidgets(fields, self.name, context, request, ignore_request=False, data=data) self.action_widget = widgets['action'] self.announcement_date_widget = widgets['announcement_date']
class ProductReleaseEditView(LaunchpadEditFormView): """Edit view for ProductRelease objects""" schema = IProductRelease field_names = [ "datereleased", "release_notes", "changelog", ] custom_widget_datereleased = DateTimeWidget custom_widget_release_notes = CustomWidgetFactory( TextAreaWidget, height=7, width=62) custom_widget_changelog = CustomWidgetFactory( TextAreaWidget, height=7, width=62) @property def label(self): """The form label.""" return smartquote('Edit %s release details' % self.context.title) page_title = label @action('Change', name='change') def change_action(self, action, data): self.updateContextFromData(data) self.next_url = canonical_url(self.context) @property def cancel_url(self): return canonical_url(self.context)
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
class BugSubscriptionFilterEditViewBase(LaunchpadEditFormView, AdvancedSubscriptionMixin): """Base class for edit or create views of `IBugSubscriptionFilter`.""" schema = IBugSubscriptionFilter field_names = ( "description", "statuses", "importances", "information_types", "tags", "find_all_tags", ) custom_widget_description = CustomWidgetFactory( TextWidget, displayWidth=50) custom_widget_statuses = LabeledMultiCheckBoxWidget custom_widget_importances = LabeledMultiCheckBoxWidget custom_widget_information_types = LabeledMultiCheckBoxWidget custom_widget_tags = CustomWidgetFactory( BugTagsFrozenSetWidget, displayWidth=35) # Define in concrete subclass to be the target of the # structural subscription that we are modifying. target = None # This is used by the AdvancedSubscriptionMixin. current_user_subscription = None @cachedproperty def _bug_notification_level_descriptions(self): return bug_notification_level_description_mapping( 'a bug in %s' % self.target.displayname) def setUpFields(self): """Set up fields for form. Overrides the usual implementation to also set up bug notification.""" super(BugSubscriptionFilterEditViewBase, self).setUpFields() self._setUpBugNotificationLevelField() @property def next_url(self): """Return to the user's structural subscriptions page.""" return canonical_url( self.user, view_name="+structural-subscriptions") cancel_url = next_url
class ProductReleaseAddViewBase(LaunchpadFormView): """Base class for creating a release from an existing or new milestone. Subclasses need to define the field_names a form action. """ schema = IProductRelease custom_widget_datereleased = DateTimeWidget custom_widget_release_notes = CustomWidgetFactory( TextAreaWidget, height=7, width=62) custom_widget_changelog = CustomWidgetFactory( TextAreaWidget, height=7, width=62) def _prependKeepMilestoneActiveField(self): keep_milestone_active_checkbox = FormFields( Bool( __name__='keep_milestone_active', title=_("Keep the %s milestone active." % self.context.name), description=_( "Only select this if bugs or blueprints still need " "to be targeted to this project release's milestone.")), render_context=self.render_context) self.form_fields = keep_milestone_active_checkbox + self.form_fields def _createRelease(self, milestone, data): """Create product release for this milestone.""" newrelease = milestone.createProductRelease( self.user, changelog=data['changelog'], release_notes=data['release_notes'], datereleased=data['datereleased']) # Set Milestone.active to false, since bugs & blueprints # should not be targeted to a milestone in the past. if data.get('keep_milestone_active') is False: milestone.active = False self.next_url = canonical_url(newrelease.milestone) notify(ObjectCreatedEvent(newrelease)) @property def label(self): """The form label.""" return smartquote('Create a new release for %s' % self.context.product.displayname) page_title = label @property def cancel_url(self): return canonical_url(self.context)
class ProductSeriesReviewView(LaunchpadEditFormView): """A view to review and change the series `IProduct` and name.""" schema = IProductSeries field_names = ['product', 'name'] custom_widget_name = CustomWidgetFactory(TextWidget, displayWidth=20) @property def label(self): """The form label.""" return 'Administer %s %s series' % (self.context.product.displayname, self.context.name) page_title = label @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) @action(_('Change'), name='change') def change_action(self, action, data): """Update the series.""" self.updateContextFromData(data) self.request.response.addInfoNotification( _('This Series has been changed')) self.next_url = canonical_url(self.context)
def __init__(self, field, vocabulary, request): super(LicenseWidget, self).__init__(field, vocabulary, request) # We want to put the license_info widget inside the licences widget's # HTML, for better alignment and JavaScript dynamism. This is # accomplished by ghosting the form's license_info widget (see # lp/registry/browser/product.py and the GhostWidget implementation # below) and creating a custom widget here. It's a pretty simple text # widget so create that now. The fun part is that it's all within the # same form, so posts work correctly. self.license_info = Text(__name__='license_info') self.license_info_widget = CustomWidgetFactory(DescriptionWidget) # The initial value of the license_info widget will be taken from the # field's context when available. This will be the IProduct when # we're editing an existing project, but when we're creating a new # one, it'll be an IProductSet, which does not have license_info. initial_value = getattr(field.context, 'license_info', None) setUpWidget(self, 'license_info', self.license_info, IInputWidget, prefix='field', value=initial_value, context=field.context) self.source_package_release = None # These will get filled in by _categorize(). They are the number of # selected licences in the category. The actual count doesn't matter, # since if it's greater than 0 it will start opened. Note that we # always want the recommended licences to be opened, so we initialize # its value to 1. self.recommended_count = 1 self.more_count = 0 self.deprecated_count = 0 self.special_count = 0
def _setUpBugNotificationLevelField(self): """Set up the bug_notification_level field.""" self.form_fields = self.form_fields.omit('bug_notification_level') self.form_fields += formlib.form.Fields( self._bug_notification_level_field) self.form_fields['bug_notification_level'].custom_widget = ( CustomWidgetFactory(RadioWidget))
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 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__='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=package_vocab), ] self.distribution_widget = CustomWidgetFactory(LaunchpadDropdownWidget) for field in fields: setUpWidget(self, field.__name__, field, IInputWidget, prefix=self.name) self._widgets_set_up = True
class LanguageAdminView(LaunchpadEditFormView): """Handle an admin form submission.""" rootsite = 'translations' schema = ILanguage custom_widget_countries = CustomWidgetFactory(LabeledMultiCheckBoxWidget, orientation='vertical') field_names = [ 'code', 'englishname', 'nativename', 'pluralforms', 'pluralexpression', 'visible', 'direction', 'countries' ] page_title = "Change details" @property def label(self): """The form label""" return "Edit %s in Launchpad" % describe_language(self.context) @property def cancel_url(self): """See LaunchpadFormView.""" return canonical_url(self.context, rootsite=self.rootsite) @property def next_url(self): return canonical_url(self.context, rootsite=self.rootsite) @action("Admin Language", name="admin") def admin_action(self, action, data): self.updateContextFromData(data) def _validateCode(self, new_code): """Validate a change in language code.""" language_set = getUtility(ILanguageSet) if language_set.getLanguageByCode(new_code) is not None: self.setFieldError('code', 'There is already a language with that code.') def _validatePluralData(self, pluralforms, pluralexpression): """Validate plural expression and number of plural forms.""" try: make_friendly_plural_forms(pluralexpression, pluralforms) except BadPluralExpression as e: self.setFieldError('pluralexpression', str(e)) def validate(self, data): new_code = data.get('code') if new_code != self.context.code: self._validateCode(new_code) pluralexpression = data.get('pluralexpression') pluralforms = data.get('pluralforms') if pluralexpression is not None: self._validatePluralData(pluralforms, pluralexpression)
def setUpFields(self): """See `LaunchpadFormView`.""" super(BugSubscriptionSubscribeSelfView, self).setUpFields() if self.user is None: return self.form_fields += formlib.form.Fields(self._subscription_field) self._setUpBugNotificationLevelField() self.form_fields['subscription'].custom_widget = CustomWidgetFactory( RadioWidget)
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)
class ProductSeriesEditView(LaunchpadEditFormView): """A View to edit the attributes of a series.""" schema = IProductSeries field_names = ['name', 'summary', 'status', 'branch', 'releasefileglob'] custom_widget_summary = CustomWidgetFactory(TextAreaWidget, height=7, width=62) custom_widget_releasefileglob = CustomWidgetFactory(StrippedTextWidget, displayWidth=40) @property def label(self): """The form label.""" return 'Edit %s %s series' % (self.context.product.displayname, self.context.name) page_title = label def validate(self, data): """See `LaunchpadFormView`.""" branch = data.get('branch') if branch is not None: message = get_series_branch_error(self.context.product, branch) if message: self.setFieldError('branch', message) @action(_('Change'), name='change') def change_action(self, action, data): """Update the series.""" self.updateContextFromData(data) @property def next_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) cancel_url = next_url