def edit(self): """ Open an editor to edit the filter """ if len(self._constraints) != 0: Out.warn('Editing filters that already have constraints is not yet supported') # create initial content initial_content = '# FILTER EDITOR\n' initial_content += '# - an asterisk (*) indicates "dont-care" fields\n' initial_content += '# - you may either\n' initial_content += '# - simply specify a field such as value = 100n, or\n' initial_content += '# - you can use regular expressiong i.e. ^R for getting all resistors\n\n' for field_name in Field.known_names: initial_content += '\'' + field_name + '\' = *\n' # run editor editor = Editor(initial_content) filter_file_content = editor.run() # parse content and add fields fields_dict = editor.parse(filter_file_content) for name, value in fields_dict.items(): self.add_constraint(name, value)
class Component(object): """ Represents a component and offers methods to modify fields """ def __init__(self, content): """ Take a list of lines to init component """ self._editor = Editor() # lists containing lines of eeschema syntax including $Comp and $EndComp self._original_content = content self._new_content = [] # lists containing parts of the original content list self._header = [] self._trailer = [] self._fields = [] self._x_pos = -1 self._y_pos = -1 self._parse() def __repr__(self): return self.__str__() def __str__(self): return '%-5s: %s' %(self.get_field('Designator').value, self.get_field('Value').value) def _parse(self): line_number = 0 # store header self._header = [] while not re.match('^F 0 "', self._original_content[line_number]): self._header.append(self._original_content[line_number]) line_number += 1 # create fields while re.match('^F [0-9]', self._original_content[line_number]): line = self._original_content[line_number] # obtain position of the value if re.match('^F 1 "', line): tokens = line.split('"') tokens2 = tokens[2].split(' ') self._x_pos = int(tokens2[2]) self._y_pos = int(tokens2[3]) Out.fine('Detected component position [' + str(self._x_pos) + '|' + str(self._y_pos) + ']') # parse fields new_field = FieldParser.parse(line) self._fields.append(new_field) line_number += 1 # store trailer last_line = '$EndComp' line = '' while line != last_line: line = self._original_content[line_number] self._trailer.append(line) line_number += 1 def serialize(self): # create new_content new_content = list(self._header) for field in self._fields: new_content.append(field.serialize()) new_content.extend(self._trailer) # assign new content to member self._new_content = new_content # return a string with new_content line_separator = '\n' return line_separator.join(self._new_content) def edit(self): """ Run an editor to let the user modify the fields """ # prepare initial content initial_content = '# COMPONENT EDITOR\n' initial_content += '# [' + self.get_field('Designator').value + ']\n\n' # add existing fields for field in self._fields: if field.name != 'Designator': initial_content += '\'' + field.name + '\' = ' + field.value + '\n' # add proposed fields as comments for field_name in Field.known_names: if self.get_field(field_name) is None: initial_content += '#\'' + field_name + '\' = \n' # run editor self._editor.initial_content = initial_content new_content = self._editor.run() # parse fields from editor and reset own fields new_fields_dict = self._editor.parse(new_content) self.reset_fields() # modify all fields for name, value in new_fields_dict.items(): self.add_or_update_field(name, value) def reset_fields(self): """ Keep designator, reset native field values, remove all custom fields """ new_fields = [] designator_field = self.get_field('Designator') # reset values for field_name in ['Value', 'Footprint', 'Datasheet']: field = self.get_field(field_name) field.value = '' new_fields.append(field) # prepend designator new_fields.insert(0, designator_field) self._fields = new_fields def get_template(self): """ Return a copy of this component with no fields (except designator) """ template = copy.deepcopy(self) template.reset_fields() return template def merge(self, source_component): """ Merges all fields from a given component into self """ for field in source_component._fields: if field.name != 'Designator': self.add_or_update_field(field.name, field.value) def add_or_update_field(self, name, value): """ Add a new (custom) field or replace an existing field """ # warn and return if name is empty if name == '': Out.warn('Will not add or update field in ' + self.get_field('Designator').value + ' due to empty name') return # log when clearing a value elif value == '': Out.log('Clearing value of field "' + name + '" in ' + self.get_field('Designator').value + '.') # change value of name-matching fields Out.fine('Changing value of fields matching the name "' + name + '"') for index, field in enumerate(self._fields): if field.name == name: Out.fine('Overwriting value of field #' + str(index) + ' with ' + name + ':' + value) self._fields[index].value = value # only designator and value should be visible if name == 'Designator' or name == 'Value': self._fields[index].set_visible(True) else: self._fields[index].set_visible(False) return # Construct and add new custom field new_field = CustomField.copy(self.get_field('Designator')) new_field.name = name new_field.value = value new_field.number = len(self._fields) new_field.set_visible(False) Out.fine('Adding new custom field:' + new_field.serialize()) self._fields.append(new_field) def get_field(self, name): """ Return field instance with a given name """ matching_fields = list(filter(lambda field: field.name == name, self._fields)) if len(matching_fields) == 1: return matching_fields[0] elif len(matching_fields) > 1: Out.warn('More than one field with name ' + name + ' defined!') return None else: Out.fine('No field with name ' + name) return None