def load():
def save():
def _test(): class Filter(db.Object):
	"""Filters set and options."""
	
	__slots__ = ('_idx_', '_name', '_bg_color', '_ephe_type', '_ephe_path',
		'_hsys', '_sid_mode', '_sid_t0', '_sid_ayan_t0', '_true_pos',
		'_xcentric', '_calc_midp', '_draw_midp', '_comment',
		# sub-filters:
		'_planets', '_aspects', '_orbs', '_asprestr', '_orbrestr',
		'_midpoints')
	
	def _get_name(self):
		"""Get filter name.
		
		:rtype: str
		"""
		return self._name
	
	def _set_name(self, name):
		"""Set filter name.
		
		:type name: str
		"""
		self._name = name
	
	def _get_bg_color(self):
		"""Get background color.
		
		:rtype: str
		"""
		return self._bg_color
	
	def _set_bg_color(self, clr):
		"""Set background color ('black', 'white').
		
		:type clr: str
		:raise ValueError: invalid color
		"""
		if clr not in ('black', 'white'):
			raise ValueError('Invalid background color %s.' % clr)
		self._bg_color = clr
	
	def _get_ephe_type(self):
		"""Get ephemeris type.
		
		:rtype: str
		"""
		return self._ephe_type
	
	def _set_ephe_type(self, ephe='swiss'):
		"""Set ephemeris type ('swiss', 'jpl', 'moshier').
		
		:type ephe: str
		:raise ValueError: invalid ephemeris type
		"""
		if ephe not in ('swiss', 'jpl', 'moshier'):
			raise ValueError('Invalid ephemeris type %s.' % ephe)
		self._ephe_type = ephe
	
	def _get_ephe_path(self):
		"""Get ephemeris files directory (or file for jpl) path.
		
		:rtype: str
		"""
		return self._ephe_path
	
	def _set_ephe_path(self, path):
		"""Set ephemeris directory/file.
		
		:type path: str
		"""
		self._ephe_path = str(path) # str() till pyswisseph accepts unicode!
	
	def _get_hsys(self):
		"""Get house system.
		
		:rtype: str
		"""
		return self._hsys
	
	def _set_hsys(self, hsys='P'):
		"""Set house system.
		
		One in 'PKORCAEVXHTBG'. See swisseph docs.
		
		:type hsys: str
		"""
		if hsys not in 'PKRCBOAEHVXGU':
			raise ValueError('Invalid house system %s.' % hsys)
		self._hsys = str(hsys) ## till pyswisseph accepts unicode
	
	def _get_sid_mode(self):
		return self._sid_mode
	
	def _set_sid_mode(self, sidmode=-1):
		"""Set sidereal mode.
		
			- -1 -> western tropical zodiac
			- 0+ -> sidereal modes
			- 255 -> user-defined sidereal (see sid_t0 and sid_ayan_t0)
		
		:type sidmode: int
		:raise ValueError: invalid sidereal mode
		"""
		if sidmode < -1 or sidmode > 255:
			raise ValueError('Invalid sidereal mode %s.' % sidmode)
		self._sid_mode = sidmode
	
	def _get_sid_t0(self):
		"""Get sidereal time 0.
		
		:rtype: float
		"""
		return self._sid_t0
	
	def _set_sid_t0(self, sidt0):
		"""Set sidereal time 0.
		
		:type sidt0: numeric
		"""
		self._sid_t0 = float(sidt0)
	
	def _get_sid_ayan_t0(self):
		"""Get sidereal ayanamsa at t0.
		
		:rtype: float
		"""
		return self._sid_ayan_t0
	
	def _set_sid_ayan_t0(self, ayan_t0):
		"""Set sidereal ayanamsa at t0.
		
		:type ayan_t0: numeric
		"""
		self._sid_ayan_t0 = float(ayan_t0)
	
	def _get_true_pos(self):
		"""Get true positions flag.
		
		:rtype: bool
		"""
		return self._true_pos
	
	def _set_true_pos(self, boolean=False):
		"""Set true positions flag
		
		:type boolean: bool
		"""
		self._true_pos = bool(boolean)
	
	def _get_xcentric(self):
		"""Get observer mode.
		
		:rtype: str
		"""
		return self._xcentric
	
	def _set_xcentric(self, xcentric='geo'):
		"""Set geo/topo/helio/bary centric mode.
		
		:type xcentric: str
		:raise ValueError: invalid mode
		"""
		if xcentric not in ('geo', 'topo', 'helio', 'bary'):
			raise ValueError('Invalid xcentric mode %s.' % xcentric)
		self._xcentric = xcentric
	
	def _get_calc_midp(self):
		"""Calculate mid-points or not (boolean).
		
		:rtype: bool
		"""
		return self._calc_midp
	
	def _set_calc_midp(self, boolean):
		"""Set midpoints flag.
		
		:type boolean: bool
		"""
		if boolean in (True, 1, 'True', '1', 'yes'):
			self._calc_midp = True
		else:
			self._calc_midp = False
	
	def _get_draw_midp(self):
		"""Draw mid-points aspects or not (boolean).
		
		:rtype: bool
		"""
		return self._draw_midp
	
	def _set_draw_midp(self, boolean):
		"""Set mid-points drawing flag.
		
		:type boolean: bool
		"""
		if boolean in (True, 1, 'True', '1', 'yes'):
			self._draw_midp = True
		else:
			self._draw_midp = False
	
	def _get_comment(self):
		"""Get comment
		
		:rtype: str
		"""
		return self._comment
	
	def _set_comment(self, comment):
		"""Set comment.
		
		:type comment: str
		"""
		self._comment = comment
	
	# sub filters
	
	def _get_planets(self):
		"""Get planets filter.
		
		:rtype: PlanetsFilter
		"""
		return self._planets
	
	def _set_planets(self, filt):
		"""Set planets filter.
		
		:type filt: PlanetsFilter, str or int
		"""
		if not isinstance(filt, PlanetsFilter):
			self._planets = PlanetsFilter(filt)
		else:
			self._planets = filt
	
	def _get_aspects(self):
		"""Get aspects filter.
		
		:rtype: AspectsFilter
		"""
		return self._aspects
	
	def _set_aspects(self, filt):
		"""Set aspects filter.
		
		:type filt: AspectsFilter, str or int
		"""
		if not isinstance(filt, AspectsFilter):
			self._aspects = AspectsFilter(filt)
		else:
			self._aspects = filt
	
	def _get_orbs(self):
		"""Get orbs filter.
		
		:rtype: OrbsFilter
		"""
		return self._orbs
	
	def _set_orbs(self, filt):
		"""Set orbs filter.
		
		:type filt: OrbsFilter, str or int
		"""
		if not isinstance(filt, OrbsFilter):
			self._orbs = OrbsFilter(filt)
		else:
			self._orbs = filt
	
	def _get_asprestr(self):
		"""Get aspects restrictions.
		
		:rtype: AspectsRestrictions
		"""
		return self._asprestr
	
	def _set_asprestr(self, filt):
		"""Set aspects restrictions.
		
		:type filt: AspectsRestrictions, str or int
		"""
		if not isinstance(filt, AspectsRestrictions):
			self._asprestr = AspectsRestrictions(filt)
		else:
			self._asprestr = filt
	
	def _get_orbrestr(self):
		"""Get orbs restrictions.
		
		:rtype: OrbsRestrictions
		"""
		return self._orbrestr
	
	def _set_orbrestr(self, filt):
		"""Set orbs restrictions.
		
		:type filt: OrbsRestrictions, str or int
		"""
		if not isinstance(filt, OrbsRestrictions):
			self._orbrestr = OrbsRestrictions(filt)
		else:
			self._orbrestr = filt
	
	def _get_midpoints(self):
		"""Get midpoints filters.
		
		:rtype: MidPointsFilter
		"""
		return self._midpoints
	
	def _set_midpoints(self, filt):
		"""Set mid-points filters.
		
		:type filt: MidPointsFilter, str or int
		"""
		if not isinstance(filt, MidPointsFilter):
			self._midpoints = MidPointsFilter(filt)
		else:
			self._midpoints = filt
	
	_idx = property(db.Object._get_idx, db.Object._set_idx,
		doc='Filter db index value.')
	name = property(_get_name, _set_name,
		doc='Filter name.')
	bg_color = property(_get_bg_color, _set_bg_color,
		doc='Background color (black|white).')
	ephe_type = property(_get_ephe_type, _set_ephe_type,
		doc='Ephemeris type (swiss|jpl|moshier).')
	ephe_path = property(_get_ephe_path, _set_ephe_path,
		doc='Ephemeris directory/files path.')
	hsys = property(_get_hsys, _set_hsys,
		doc='House system (PKORCAEVXHTBG). See swisseph docs.')
	sid_mode = property(_get_sid_mode, _set_sid_mode,
		doc='Sidereal mode (-1=tropical). See swisseph docs.')
	sid_t0 = property(_get_sid_t0, _set_sid_t0,
		doc='Sidereal mode reference time.')
	sid_ayan_t0 = property(_get_sid_ayan_t0, _set_sid_ayan_t0,
		doc='Sidereal mode ayanmsa.')
	true_pos = property(_get_true_pos, _set_true_pos,
		doc='True positions mode (boolean).')
	xcentric = property(_get_xcentric, _set_xcentric,
		doc='geo/topo/helio/bary centric mode.')
	calc_midp = property(_get_calc_midp, _set_calc_midp,
		doc='Calculate mid-points.')
	draw_midp = property(_get_draw_midp, _set_draw_midp,
		doc='Draw mid-points.')
	planets = property(_get_planets, _set_planets,
		doc='Planets filter.')
	aspects = property(_get_aspects, _set_aspects,
		doc='Aspects filter.')
	orbs = property(_get_orbs, _set_orbs,
		doc='Orbs filter.')
	asprestr = property(_get_asprestr, _set_asprestr,
		doc='Aspects restrictions.')
	orbrestr = property(_get_orbrestr, _set_orbrestr,
		doc='Orbs restrictions.')
	midpoints = property(_get_midpoints, _set_midpoints,
		doc='Mid-points filter.')
	comment = property(_get_comment, _set_comment,
		doc='Filter comment.')
	
	def set(self, _idx=None, name=None, bg_color=None, ephe_type=None,
		ephe_path=None, hsys=None, sid_mode=None, sid_t0=None,
		sid_ayan_t0=None, true_pos=None, xcentric=None, calc_midp=None,
		draw_midp=None, planets=None, aspects=None, orbs=None, asprestr=None,
		orbrestr=None, midpoints=None, comment=None):
		"""Set filter properties."""
		if _idx != None:
			self._idx = _idx
		if name != None:
			self.name = name
		if bg_color != None:
			self.bg_color = bg_color
		if ephe_type != None:
			self.ephe_type = ephe_type
		if ephe_path != None:
			self.ephe_path = ephe_path
		if hsys != None:
			self.hsys = hsys
		if sid_mode != None:
			self.sid_mode = sid_mode
		if sid_t0 != None:
			self.sid_t0 = sid_t0
		if sid_ayan_t0 != None:
			self.sid_ayan_t0 = sid_ayan_t0
		if true_pos != None:
			self.true_pos = true_pos
		if xcentric != None:
			self.xcentric = xcentric
		if calc_midp != None:
			self.calc_midp = calc_midp
		if draw_midp != None:
			self.draw_midp = draw_midp
		if planets != None:
			self.planets = planets
		if aspects != None:
			self.aspects = aspects
		if orbs != None:
			self.orbs = orbs
		if asprestr != None:
			self.asprestr = asprestr
		if orbrestr != None:
			self.orbrestr = orbrestr
		if midpoints != None:
			self.midpoints = midpoints
		if comment != None:
			self.comment = comment
	
	def __init__(self, filt=None, set_default=True):
		"""Init filter.
		
		:type filt: str or int
		:type set_default: bool
		"""
		if filt != None:
			return self._select(filt)
		if set_default:
			self.set_default()
	
	def set_default(self):
		"""Set filter to default values."""
		sql = 'select dft_filter from Config;'
		idx = int(db.execute(sql).fetchone()[0])
		self._select_by_idx(idx)
	
	def reset(self):
		"""Reset filter when database is updated.
		
		Filter may have been deleted, then load the default one.
		
		"""
		try:
			self._select_by_idx(self._idx_)
		except ValueError: # filter deleted
			self.set_default()
	
	def _select(self, filt):
		"""Select filter in database.
		
		:raise TypeError: invalid filter
		"""
		if isinstance(filt, int):
			return self._select_by_idx(filt)
		elif isinstance(filt, basestring): ## not py3
			return self._select_by_name(filt)
		raise TypeError('Invalid filter %s.' % filt)
	
	def _select_by_idx(self, idx):
		"""Select filter in database, by idx.
		
		:type idx: int
		:raise ValueError: not found
		"""
		sql = "select * from Filters where _idx = ?;"
		res = db.execute(sql, (idx,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid idx %s.' % idx)
		self.set(*res[0])
	
	def _select_by_name(self, filt):
		"""Select filter in database, by name.
		
		:type filt: str
		:raise ValueError: not found
		"""
		sql = "select * from Filters where name = ?;"
		res = db.execute(sql, (filt,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid filter %s.' % filt)
		self.set(*res[0])
	
	def save(self, recursive=False):
		"""Save filter in database.
		
		If recursive is True, save all sub-filters.
		Else raise TypeError if a sub-filter is not saved.
		
		:type recursive: bool
		"""
		if self._idx_ == None:
			self._insert(recursive)
		else:
			self._update(recursive)
	
	def _insert(self, recursive=False):
		"""Insert filter in database.
		
		:type recursive: bool
		:raise ValueError: duplicate
		"""
		self._save_filters(recursive)
		sql1 = """insert into Filters (name, bg_color, ephe_type, ephe_path,
			hsys, sid_mode, sid_t0, sid_ayan_t0, true_pos, xcentric, calc_midp,
			draw_midp, planets, aspects, orbs, asprestr, orbrestr, midpoints,
			comment) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
			?, ?);"""
		var = (self._name, self._bg_color, self._ephe_type, self._ephe_path,
			self._hsys, self._sid_mode, self._sid_t0, self._sid_ayan_t0,
			self._true_pos, self._xcentric, self._calc_midp, self._draw_midp,
			self._planets._idx_, self._aspects._idx_, self._orbs._idx_,
			self._asprestr._idx_, self._orbrestr._idx_, self._midpoints._idx_,
			self._comment)
		sql2 = "select _idx from Filters where name = ?;"
		try:
			db.execute(sql1, var)
		except: # sqlite3.IntegrityError
			raise ValueError('Duplicate filter %s.' % self._name)
		self._idx = db.execute(sql2,(self._name,)).fetchone()[0]
	
	def _update(self, recursive=False):
		"""Update filter in database.
		
		:raise ValueError: duplicate
		"""
		self._save_filters(recursive)
		sql = """update Filters set name = ?, bg_color = ?, ephe_type = ?,
			ephe_path = ?, hsys = ?, sid_mode = ?, sid_t0 = ?, sid_ayan_t0 = ?,
			true_pos = ?, xcentric = ?, calc_midp = ?, draw_midp = ?,
			planets = ?, aspects = ?, orbs = ?, asprestr = ?, orbrestr = ?,
			midpoints = ?, comment = ? where _idx = ?;"""
		var = (self._name, self._bg_color, self._ephe_type, self._ephe_path,
			self._hsys, self._sid_mode, self._sid_t0, self._sid_ayan_t0,
			self._true_pos, self._xcentric, self._calc_midp, self._draw_midp,
			self._planets._idx_, self._aspects._idx_, self._orbs._idx_,
			self._asprestr._idx_, self._orbrestr._idx_, self._midpoints._idx_,
			self._comment, self._idx_)
		try:
			db.execute(sql, var)
		except: ## integrity error
			raise ValueError('Duplicate filter %s.' % self._name)
	
	def _save_filters(self, recursive):
		"""Save sub-filters if recursive is True, else check they are saved.
		
		Raise TypeError if recursive is False and sub-filter is not saved.
		
		:type recursive: bool
		"""
		for f in (self.planets, self.aspects, self.orbs, self.asprestr,
			self.orbrestr, self.midpoints):
			if recursive:
				f.save()
			else:
				if f._idx_ == None:
					raise TypeError('Sub filter %s is not saved.' % f._name)
	
	def delete(self):
		"""Delete filter in database.
		
		:raise TypeError: invalid index
		:raise ValueError: integrity error
		"""
		if self._idx_ == None:
			raise TypeError('Missing idx')
		sql = "delete from Filters where _idx = ?;"
		try:
			db.execute(sql, (self._idx_,))
		except: # sqlite3 integrity error
			raise ValueError('Cannot delete default filter.')
		self._idx_ = None
	
	def get_calcflag(self):
		"""Return swisseph calculation flag.
		
		:rtype: int
		"""
		flag = 0
		# speed
		flag += swe.FLG_SPEED
		# ephemeris type
		if self._ephe_type == 'swiss':
			flag += swe.FLG_SWIEPH
		elif self._ephe_type == 'jpl':
			flag += swe.FLG_JPLEPH
		elif self._ephe_type == 'moshier':
			flag += swe.FLG_MOSEPH
		# sidereal mode
		if self._sid_mode > -1:
			flag += swe.FLG_SIDEREAL
		# true positions
		if self._true_pos:
			flag += swe.FLG_TRUEPOS
		# xcentric
		if self._xcentric == 'topo':
			flag += swe.FLG_TOPOCTR
		elif self._xcentric == 'helio':
			flag += swe.FLG_HELCTR
		elif self._xcentric == 'bary':
			flag += swe.FLG_BARYCTR
		return flag
	
	def __iter__(self):
		"""Iterate over filter internals.
		
		:rtype: iterator
		"""
		return (x for x in (self._idx_, self._name, self._bg_color,
			self._ephe_type, self._ephe_path, self._hsys, self._sid_mode,
			self._sid_t0, self._sid_ayan_t0, self._true_pos, self._xcentric,
			self._calc_midp, self._draw_midp, self._planets, self._aspects,
			self._orbs, self._asprestr, self._orbrestr, self._midpoints,
			self._comment))
	
	def __str__(self):
		"""Show filter internals."""
		return str(tuple(self))
	
	def __repr__(self):
		if self._idx_ == None:
			return repr(tuple(repr(x) for x in self))
		return "Filter('''%s''')" % self._name
	
	def __getstate__(self):
		"""TODO."""
		pass
	
	def _to_xml(self, with_idx=False):
		"""TODO."""
		pass
	
	def _from_xml(self, elem, with_idx=False):
		"""TODO."""
		pass
	
	def __eq__(self, other):
		"""Return True if other is the same filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return False
		if not isinstance(other, Filter):
			return False
		if other._idx_ == self._idx_:
			return True
		return False
	
	def __ne__(self, other):
		"""Return True if other is not the same filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return True
		if not isinstance(other, Filter):
			return True
		if other._idx_ != self._idx_:
			return True
		return False class AspectsFilter(db.Object):
	"""Aspects filter type."""
	
	__slots__ = ('_idx_', '_name', '_comment', '_dict_')
	
	def _get_name(self):
		"""Get aspects filter name."""
		return self._name
	
	def _set_name(self, name):
		"""Set aspects filter name."""
		self._name = name
	
	def _get_comment(self):
		"""Get aspects filter comment."""
		return self._comment
	
	def _set_comment(self, comment):
		"""Set aspects filter comment."""
		self._comment = comment
	
	def _get_dict(self):
		"""Get internal dict of aspects."""
		return self._dict_
	
	def _set_dict(self, res):
		"""Set internal dict of aspects (with db result rows)."""
		self._dict_.clear()
		for x, y in res:
			if y in (True, '1', 1, 'True', 'true', 'yes'):
				y = True
			else:
				y = False
			self._dict_[x] = y
	
	_idx = property(db.Object._get_idx, db.Object._set_idx,
		doc="Aspects filter db index value.")
	name = property(_get_name, _set_name,
		doc="Aspects filter name.")
	comment = property(_get_comment, _set_comment,
		doc="Aspects filter comment.")
	_dict = property(_get_dict, _set_dict,
		doc="Aspects filter internal dict.")
	
	def set(self, _idx=None, name=None, comment=None):
		"""Set aspects filter properties.
		
		:type name: str
		:type comment: str
		"""
		if _idx != None:
			self._idx = _idx
		if name != None:
			self.name = name
		if comment != None:
			self.comment = comment
	
	def __init__(self, filt=None, set_default=True):
		"""Aspects filter initialization."""
		self._dict_ = dict()
		if filt != None:
			return self._select(filt)
		else:
			self._idx_ = None
			self._name = ''
			self._comment = ''
			if set_default:
				self.set_default()
	
	def set_default(self):
		"""Reset aspects filter to default values."""
		sql = "select name, bool_use from Aspects;"
		res = db.execute(sql)
		self._set_dict(res)
	
	def reset(self):
		"""Reset filter when database is updated.
		
		The filter may have been deleted, then load the default one.
		
		"""
		try:
			self._select_by_idx(self._idx_)
		except ValueError: # filter deleted
			sql = '''select aspects from Filters
				where _idx = (select dft_filter from Config);'''
			idx = int(db.execute(sql).fetchone()[0])
			self._select_by_idx(idx)
	
	def _select(self, filt):
		"""Select aspects filter in database.
		
		:raise TypeError: invalid filter
		"""
		if isinstance(filt, int):
			return self._select_by_idx(filt)
		elif isinstance(filt, basestring):
			return self._select_by_name(filt)
		raise TypeError('Invalid filter %s.' % filt)
	
	def _select_by_idx(self, idx):
		"""Select aspects filter in database, by idx.
		
		:raise ValueError: not found
		"""
		sql = "select * from AspectsFilters where _idx = ?;"
		res = db.execute(sql, (idx,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid idx %s.' % idx)
		self.set(*res[0])
		self._select_dict()
	
	def _select_by_name(self, filt):
		"""Select aspects filter in database, by name.
		
		:raise ValueError: not found
		"""
		sql = "select * from AspectsFilters where name = ?;"
		res = db.execute(sql, (filt,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid filter %s.' % filt)
		self.set(*res[0])
		self._select_dict()
	
	def _select_dict(self):
		"""Select aspects filters dict in database, with filter idx."""
		sql = """select A.name, B.bool_use from Aspects as A, _AspectsFilters
			as B where B.filter_idx = ? and A._idx = B.aspect_idx;"""
		res = db.execute(sql, (self._idx_,)).fetchall()
		self._set_dict(res)
	
	def save(self):
		"""Save aspects filter in database."""
		if self._idx_ == None:
			self._insert()
		else:
			self._update()
	
	def _insert(self):
		"""Insert aspects filter in database.
		
		:raise ValueError: duplicate
		"""
		sql1 = "insert into AspectsFilters (name, comment) values (?, ?);"
		sql2 = "select _idx from AspectsFilters where name = ?;"
		try:
			db.execute(sql1, (self._name, self._comment))
		except: # sqlite3.IntegrityError
			raise ValueError('Duplicate filter %s.' % self._name)
		self._idx = db.execute(sql2,(self._name,)).fetchone()[0]
		self._save_dict()
	
	def _update(self):
		"""Update aspects filter in database."""
		sql = "update AspectsFilters set name = ?, comment = ? where _idx = ?;"
		db.execute(sql, (self._name, self._comment, self._idx_))
		self._save_dict()
	
	def _save_dict(self):
		"""Save aspects filter dict in database (with filter idx)."""
		self._delete_dict()
		sql = """insert into _AspectsFilters select ?, _idx, ? from Aspects
			where name = ?;"""
		for asp, val in self._dict_.items():
			db.execute(sql, (self._idx_, int(val), asp))
	
	def delete(self):
		"""Delete aspects filter in database.
		
		:raise TypeError: invalid index
		:raise ValueError: integrity error
		"""
		if self._idx_ == None:
			raise TypeError('Missing idx.')
		sql = "delete from AspectsFilters where _idx = ?;"
		try:
			db.execute(sql, (self._idx_,))
		except: # integrity error
			raise ValueError('Cannot delete default filter.')
		self._idx_ = None
	
	def _delete_dict(self):
		"""Delete aspects filter dict in database."""
		sql = "delete from _AspectsFilters where filter_idx = ?;"
		db.execute(sql, (self._idx_,))
	
	def __len__(self):
		"""Return number of elements in aspects filter.
		
		:rtype: int
		"""
		return len(self._dict_)
	
	def __getitem__(self, key):
		"""Return boolean (aspect usage) identified by aspect name.
		
		:raise KeyError: not found
		:rtype: bool
		"""
		return self._dict_[key]
	
	def __setitem__(self, key, value=False):
		"""Set aspect usage (boolean), identified by aspect name.
		
		:raise KeyError: not found
		"""
		for asp in self._dict_:
			if asp == key:
				if value in (True, 1, 'True', '1', 'true'):
					value = True
				else:
					value = False
				self._dict_[asp] = value
				return
		raise KeyError(key)
	
	def __contains__(self, key):
		"""Return True if aspect name is in aspects filter.
		
		:rtype: bool
		"""
		return self._dict_.__contains__(key)
	
	def __iter__(self):
		"""Return iterator over aspects filter keys.
		
		:rtype: iterator
		"""
		return self._dict_.__iter__()
	
	def keys(self):
		"""Return a list of aspects filter keys.
		
		:rtype: list
		"""
		return self._dict_.keys()
	
	def values(self):
		"""Return a list of aspects filter values.
		
		:rtype: list
		"""
		return self._dict_.values()
	
	def items(self):
		"""Return a list of aspects filter key, value tuples.
		
		:rtype: list
		"""
		return self._dict_.items()
	
	def get(self, key, default=None):
		"""Return boolean (aspect usage), identified by key (aspect name).
		
		Return default (None) if aspect not found.
		
		:rtype: bool
		"""
		got = self.__getitem__(key)
		if got == None:
			return default
		return got
	
	def __str__(self):
		"""Show aspects filter internals.
		
		:rtype: str
		"""
		return str(tuple(x for x in (self._idx_, self._name, self._comment,
			self._dict_)))
	
	def __repr__(self):
		if self._idx_ == None:
			return repr(tuple(repr(x) for x in self))
		return "AspectsFilter('''%s''')" % self._name
	
	def __getstate__(self):
		return {'_idx': None,
			'name': self._name,
			'comment': self._comment,
			'_dict': self._dict_}
	
	def _to_xml(self, with_idx=False):
		"""Return a xmlutils.Element('AspecstFilter').
		
		:type with_idx: bool
		:rtype: xmlutils.Element
		"""
		if with_idx:
			el = xmlutils.Element('AspectsFilter', {'_idx': self._idx_},
				'\n\t', '\n')
		else:
			el = xmlutils.Element('AspectsFilter', {'_id': None}, '\n\t', '\n')
		el.append('name', {}, self._name, '\n\t')
		el.append('comment', {}, self._comment, '\n\t')
		el2 = xmlutils.Element('Aspects', {}, '\n\t\t', '\n')
		for x, y in self.items():
			el2.append('Aspect', {'name': x, 'value': y}, '', '\n\t\t')
		el.append(el2)
		return el
	
	def _from_xml(self, elem, with_idx=False):
		"""Set aspects filter from a xmlutils.Element('AspectsFilter').
		
		:type elem: xmlutils.Element
		:type with_idx: bool
		"""
		if with_idx:
			_idx = elem.get_attr('_idx')
			if _idx == 'None':
				self._idx_ = None
			else:
				self._idx = _idx
		self.set(name=elem.get_child_text(tag='name').replace('&lt;',
				'<').replace('&gt;', '>'),
			comment=elem.get_child_text(tag='comment').replace('&lt;',
				'<').replace('&gt;', '>'))
		el2 = elem.get_child('Aspects')
		for e in el2.get_iterator(tag='Aspect'):
			self[e.get_attr('name')] = e.get_attr('value')
	
	def __eq__(self, other):
		"""Return True if other is the same aspects filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return False
		if not isinstance(other, AspectsFilter):
			return False
		if other._idx_ == self._idx_:
			return True
		return False
	
	def __ne__(self, other):
		"""Return True if other is not the same aspects filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return True
		if not isinstance(other, AspectsFilter):
			return True
		if other._idx_ != self._idx_:
			return True
		return False def all_aspects_filters_names():
	"""Return a list of all aspects filters names.
	
	:rtype: list
	"""
	ret = list()
	sql = 'select name from AspectsFilters order by name;'
	res = db.execute(sql).fetchall()
	for row in res:
		ret.append(row[0])
	return ret class AspectsRestrictions(db.Object):
	"""Aspects restrictions filter type."""
	
	__slots__ = ('_idx_', '_name', '_comment', '_dict_')
	
	def _get_name(self):
		"""Get filter name.
		
		:rtype: str
		"""
		return self._name
	
	def _set_name(self, name):
		"""Set filter name.
		
		:type name: str
		"""
		self._name = name
	
	def _get_comment(self):
		"""Get filter comment.
		
		:rtype: str
		"""
		return self._comment
	
	def _set_comment(self, comment):
		"""Set filter comment.
		
		:type comment: str
		"""
		self._comment = comment
	
	def _get_dict(self):
		"""Return internal dict of planets.
		
		:rtype: dict
		"""
		return self._dict_
	
	def _set_dict(self, res):
		"""Set internal dict of planets (with db result rows).
		
		:type res: sequence
		"""
		self._dict_.clear()
		for x, y in res:
			if y in (True, '1', 1, 'True', 'true'):
				y = True
			else:
				y = False
			self._dict_[x] = y
	
	_idx = property(db.Object._get_idx, db.Object._set_idx,
		doc="Aspects restrictions filter db index value.")
	name = property(_get_name, _set_name,
		doc="Aspects restrictions filter name.")
	comment = property(_get_comment, _set_comment,
		doc="Aspects restrictions filter comment.")
	_dict = property(_get_dict, _set_dict,
		doc="Aspects restrictions filter internal dict.")
	
	def set(self, _idx=None, name=None, comment=None):
		"""Set filter properties.
		
		Args: 'name', 'comment'
		
		"""
		if _idx != None:
			self._idx = _idx
		if name != None:
			self.name = name
		if comment != None:
			self.comment = comment
	
	def __init__(self, filt=None, set_default=True):
		"""Aspects restrictions initialization.
		
		:type filt: int or str or None
		:type set_default: bool
		"""
		self._dict_ = dict()
		if filt != None:
			return self._select(filt)
		else:
			self._idx_ = None
			self._name = str()
			self._comment = str()
			if set_default:
				self.set_default()
	
	def set_default(self):
		"""Reset restrictions to default values."""
		sql = "select name, bool_aspect from Planets;"
		res = db.execute(sql)
		self._set_dict(res)
	
	def reset(self):
		"""Reset filter when database is updated.
		
		Filter may have been deleted, then load the default one.
		
		"""
		try:
			self._select_by_idx(self._idx_)
		except ValueError: # filter deleted
			sql = '''select asprestr from Filters
				where _idx = (select dft_filter from Config);'''
			idx = int(db.execute(sql).fetchone()[0])
			self._select_by_idx(idx)
	
	def _select(self, filt):
		"""Select aspects restrictions in database.
		
		:raise TypeError: invalid filter
		"""
		if isinstance(filt, int):
			return self._select_by_idx(filt)
		elif isinstance(filt, basestring): # str in py3
			return self._select_by_name(filt)
		raise TypeError('Invalid filter %s.' % filt)
	
	def _select_by_idx(self, idx):
		"""Select aspects restrictions in database, by idx.
		
		:raise ValueError: not found
		"""
		sql = "select * from AspectsRestrictions where _idx = ?;"
		res = db.execute(sql, (idx,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid idx %s.' % idx)
		self.set(*res[0])
		self._select_dict()
	
	def _select_by_name(self, filt):
		"""Select aspects restrictions filter in database, by name.
		
		:raise ValueError: not found
		"""
		sql = "select * from AspectsRestrictions where name = ?;"
		res = db.execute(sql, (filt,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid filter %s.' % filt)
		self.set(*res[0])
		self._select_dict()
	
	def _select_dict(self):
		"""Select filter dict in database, with filter idx."""
		sql = """select A.name, B.bool_asp from Planets as A,
		_AspectsRestrictions as B where B.filter_idx = ? and A._idx =
		B.planet_idx;"""
		res = db.execute(sql, (self._idx_,)).fetchall()
		self._set_dict(res)
	
	def save(self):
		"""Save aspects restrictions in database."""
		if self._idx_ == None:
			self._insert()
		else:
			self._update()
	
	def _insert(self):
		"""Insert aspects restrictions in database.
		
		:raise ValueError: duplicate
		"""
		sql1 = "insert into AspectsRestrictions (name, comment) values (?, ?);"
		sql2 = "select _idx from AspectsRestrictions where name = ?;"
		try:
			db.execute(sql1, (self._name, self._comment))
		except: # sqlite3.IntegrityError
			raise ValueError('Duplicate filter %s.' % self._name)
		self._idx = db.execute(sql2, (self._name,)).fetchone()[0]
		self._save_dict()
	
	def _update(self):
		"""Update aspects restrictions filter in database.
		
		:raise ValueError: duplicate
		"""
		sql = """update AspectsRestrictions set name = ?, comment = ?
			where _idx = ?;"""
		try:
			db.execute(sql, (self._name, self._comment, self._idx_))
		except: # integrity error
			raise ValueError('Duplicate filter %s.' % self._name)
		self._save_dict()
	
	def delete(self):
		"""Delete aspects restrictions in database.
		
		:raise TypeError: invalid index
		:raise ValueError: integrity error
		"""
		if self._idx_ == None:
			raise TypeError('Missing idx.')
		sql = "delete from AspectsRestrictions where _idx = ?;"
		try:
			db.execute(sql, (self._idx_,))
		except: # integrity error
			raise ValueError('Cannot delete default filter')
		self._idx_ = None
	
	def _save_dict(self):
		"""Save aspects restrictions dict in database (with filter idx)."""
		self._delete_dict()
		sql = """insert into _AspectsRestrictions select ?, _idx, ? from
			Planets where name = ?;"""
		for plt, val in self.items():
			db.execute(sql, (self._idx_, int(val), plt))
	
	def _delete_dict(self):
		"""Delete aspects restrictions dict in database."""
		sql = "delete from _AspectsRestrictions where filter_idx = ?;"
		db.execute(sql, (self._idx_,))
	
	def __len__(self):
		"""Return number of planets in aspects restrictions.
		
		:rtype: int
		"""
		return len(self._dict_)
	
	def __getitem__(self, key):
		"""Return boolean (aspected) identified by planet name.
		
		:type key: str
		:rtype: bool
		"""
		return self._dict_[key]
	
	def __setitem__(self, key, value=False):
		"""Set planet aspected, identified by planet name.
		
		:type key: str
		:type value: bool
		:raise KeyError: not found
		"""
		for plt in self._dict_:
			if plt == key:
				if value in (True, 1, 'True', '1', 'true'):
					value = True
				else:
					value = False
				self._dict_[plt] = value
				return
		raise KeyError(key)
	
	def __contains__(self, key):
		"""Return True if planet name is in aspects restrictions.
		
		:rtype: bool
		"""
		return self._dict_.__contains__(key)
	
	def __iter__(self):
		"""Return iterator over aspects restrictions keys.
		
		:rtype: iterator
		"""
		return self._dict_.__iter__()
	
	def keys(self):
		"""Return a list of aspects restrictions keys.
		
		:rtype: list
		"""
		return self._dict_.keys()
	
	def values(self):
		"""Return a list of aspects restrictions values."""
		return self._dict_.values()
	
	def items(self):
		"""Return a list of restrictions key, value tuples.
		
		:rtype: list
		"""
		return self._dict_.items()
	
	def get(self, key, default=None):
		"""Return boolean (aspected), identified by key (planet name).
		
		Return default (None) if aspect not found.
		
		:type key: str
		:type default: any
		:rtype: bool or default
		"""
		got = self.__getitem__(key)
		if got == None:
			return default
		return got
	
	def __str__(self):
		"""Return aspects restrictions as string.
		
		:rtype: str
		"""
		return str(tuple(x for x in (self._idx_, self._name, self._comment,
			self._dict_)))
	
	def __repr__(self):
		if self._idx_ == None:
			return repr(tuple(repr(x) for x in self))
		return "AspectsRestrictions('''%s''')" % self._name
	
	def __getstate__(self):
		return {'_idx': None,
			'name': self._name,
			'comment': self._comment,
			'_dict': self._dict_}
	
	def _to_xml(self, with_idx=False):
		"""Return a xmlutils.Element('AspectsRestrictions').
		
		:type with_idx: bool
		:rtype: xmlutils.Element
		"""
		if with_idx:
			el = xmlutils.Element('PlanetsAspectsFilter', {'_idx': self._idx_},
				'\n\t', '\n')
		else:
			el = xmlutils.Element('PlanetsAspectsFilter', {'_idx': None},
				'\n\t', '\n')
		el.append('name', {}, self._name, '\n\t')
		el.append('comment', {}, self._comment, '\n\t')
		el2 = xmlutils.Element('Planets', {}, '\n\t\t', '\n')
		for x, y in self.items():
			el2.append('Planet', {'name': x, 'value': y}, '', '\n\t\t')
		el.append(el2)
		return el
	
	def _from_xml(self, elem, with_idx=False):
		"""Set restrictions from a xmlutils.Element('AspectsRestrictions').
		
		:type elem: xmlutils.Element
		:type with_idx: bool
		"""
		if with_idx:
			_idx = elem.get_attr('_idx')
			if _idx == 'None':
				self._idx_ = None
			else:
				self._idx = _idx
		self.set(name=elem.get_child_text(
				tag='name').replace('&lt;', '<').replace('&gt;', '>'),
			comment=elem.get_child_text(
				tag='comment').replace('&lt;', '<').replace('&gt;', '>'))
		el2 = elem.get_child('Planets')
		for e in el2.get_iterator(tag='Planet'):
			self[e.get_attr('name')] = e.get_attr('value')
	
	def __eq__(self, other):
		"""Return True if other is the same filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return False
		if not isinstance(other, AspectsRestrictions):
			return False
		if other._idx_ == self._idx_:
			return True
		return False
	
	def __ne__(self, other):
		"""Return True if other is not the same filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return True
		if not isinstance(other, AspectsRestrictions):
			return True
		if other._idx_ != self._idx_:
			return True
		return False def all_aspects_restrictions_names():
	"""Return a list of all aspects restrictions names.
	
	:rtype: list
	"""
	ret = list()
	sql = 'select name from AspectsRestrictions order by name;'
	res = db.execute(sql).fetchall()
	for row in res:
		ret.append(row[0])
	return ret class OrbsRestrictions(db.Object):
	"""Orbs restrictions type."""
	
	__slots__ = ('_idx_', '_name', '_comment', '_dict_')
	
	def _get_name(self):
		"""Return filter name."""
		return self._name
	
	def _set_name(self, name):
		"""Set filter name."""
		self._name = name
	
	def _get_comment(self):
		"""Return filter comment."""
		return self._comment
	
	def _set_comment(self, comment):
		"""Set filter comment."""
		self._comment = comment
	
	def _get_dict(self):
		"""Return internal dict of planets."""
		return self._dict_
	
	def _set_dict(self, res):
		"""Set internal dict of planets (with db result rows)."""
		self._dict_.clear()
		for x, y in res:
			self._dict_[x] = OrbModifier(y)
	
	_idx = property(db.Object._get_idx, db.Object._set_idx,
		doc="Orbs restrictions filter db index value.")
	name = property(_get_name, _set_name,
		doc="Orbs restrictions filter name.")
	comment = property(_get_comment, _set_comment,
		doc="Orbs restrictions filter comment.")
	_dict = property(_get_dict, _set_dict,
		doc="Orbs restrictions filter internal dict.")
	
	def set(self, _idx=None, name=None, comment=None):
		"""Set orbs restrictions properties.
		
		Args: 'name', 'comment'
		
		"""
		if _idx != None:
			self._idx = _idx
		if name != None:
			self.name = name
		if comment != None:
			self.comment = comment
	
	def __init__(self, filt=None, set_default=True):
		"""Orbs restrictions initialization."""
		self._dict_ = dict()
		if filt != None:
			return self._select(filt)
		else:
			self._idx_ = None
			self._name = str()
			self._comment = str()
			if set_default:
				self.set_default()
	
	def set_default(self):
		"""Reset Orbs restrictions to default values."""
		sql = "select name, orb_mod from Planets;"
		res = db.execute(sql)
		self._set_dict(res)
	
	def reset(self):
		"""Reset filter when database is updated.
		
		Filter may have been deleted, then load the default one.
		
		"""
		try:
			self._select_by_idx(self._idx_)
		except ValueError: ## filter deleted
			sql = '''select orbrestr from Filters
				where _idx = (select dft_filter from Config);'''
			idx = int(db.execute(sql).fetchone()[0])
			self._select_by_idx(idx)
	
	def _select(self, filt):
		"""Select orbs restrictions filter in database.
		
		Raise TypeError if invalid filter.
		
		"""
		if isinstance(filt, int):
			return self._select_by_idx(filt)
		elif isinstance(filt, basestring): # str in py3
			return self._select_by_name(filt)
		raise TypeError('Invalid filter %s.' % filt)
	
	def _select_by_idx(self, idx):
		"""Select Orbs restrictions filter by idx.
		
		Raise ValueError if not found.
		
		"""
		sql = "select * from OrbsRestrictions where _idx = ?;"
		res = db.execute(sql, (idx,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid idx %s.' % idx)
		self.set(*res[0])
		self._select_dict()
	
	def _select_by_name(self, filt):
		"""Select orbs restrictions filter by name.
		
		Raise ValueError if not found.
		
		"""
		sql = "select * from OrbsRestrictions where name = ?;"
		res = db.execute(sql, (filt,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid filter %s.' % filt)
		self.set(*res[0])
		self._select_dict()
	
	def _select_dict(self):
		"""Select orbs restrictions dict in database."""
		sql = """select A.name, B.orb_mod from Planets as A, _OrbsRestrictions
			as B where B.filter_idx = ? and A._idx = B.planet_idx;"""
		res = db.execute(sql, (self._idx_,)).fetchall()
		self._set_dict(res)
	
	def save(self):
		"""Save orbs restrictions filter in database."""
		if self._idx_ == None:
			self._insert()
		else:
			self._update()
	
	def _insert(self):
		"""Insert orbs restrictions filter in database.
		
		Raise ValueError if duplicate.
		
		"""
		sql1 = "insert into OrbsRestrictions (name, comment) values (?, ?);"
		sql2 = "select _idx from OrbsRestrictions where name = ?;"
		try:
			db.execute(sql1, (self._name, self._comment))
		except: # sqlite3.IntegrityError?
			raise ValueError('Duplicate filter %s' % self._name)
		self._idx = db.execute(sql2, (self._name,)).fetchone()[0]
		self._save_dict()
	
	def _update(self):
		"""Update orbs restrictions filter in database.
		
		Raise ValueError if duplicate.
		
		"""
		sql = """update OrbsRestrictions set name = ?, comment = ?
			where _idx = ?;"""
		try:
			db.execute(sql, (self._name, self._comment, self._idx_))
		except: ## integrity error
			raise ValueError('Duplicate filter %s.' % self._name)
		self._save_dict()
	
	def delete(self):
		"""Delete orbs restrictions in database (by idx).
		
		Raise TypeError if idx is None.
		Raise ValueError if filter is required by default filter.
		
		"""
		if self._idx_ == None:
			raise TypeError('Missing idx.')
		sql = "delete from OrbsRestrictions where _idx = ?;"
		try:
			db.execute(sql, (self._idx_,))
		except:
			raise ValueError('Cannot delete default filter.')
		self._idx_ = None
	
	def _save_dict(self):
		"""Save orbs restrictions dict in database (with idx)."""
		self._delete_dict()
		sql = """insert into _OrbsRestrictions select ?, _idx, ? from
			Planets where name = ?;"""
		for plt, val in self.items():
			db.execute(sql, (self._idx_, val, plt))
	
	def _delete_dict(self):
		"""Delete orbs restrictions filter dict in database."""
		sql = "delete from _OrbsRestrictions where filter_idx = ?;"
		db.execute(sql, (self._idx_,))
	
	def __len__(self):
		"""Return number of planets in orbs restrictions."""
		return len(self._dict_)
	
	def __getitem__(self, key):
		"""Return orb modifier identified by planet name.
		
		Raise KeyError if planet not found.
		
		"""
		return self._dict_[key]
	
	def __setitem__(self, key, value=False):
		"""Set planet orb modifier, identified by planet name.
		
		Raise KeyError if planet not found.
		
		"""
		for plt in self._dict_:
			if plt == key:
				self._dict_[plt] = OrbModifier(value)
				return
		raise KeyError(key)
	
	def __contains__(self, key):
		"""Return True if planet name is in orbs restrictions."""
		return self._dict_.__contains__(key)
	
	def __iter__(self):
		"""Return iterator over orbs restrictions keys."""
		return self._dict_.__iter__()
	
	def keys(self):
		"""Return a list of Orbs restrictions keys."""
		return self._dict_.keys()
	
	def values(self):
		"""Return a list of Orbs restrictions values."""
		return self._dict_.values()
	
	def items(self):
		"""Return a list of Orbs restrictions key, value tuples."""
		return self._dict_.items()
	
	def get(self, key, default=None):
		"""Return orb modifier, identified by key (planet name).
		
		Return default (None) if aspect not found.
		
		"""
		got = self.__getitem__(key)
		if got == None:
			return default
		return got
	
	def __str__(self):
		"""Return orbs restrictions filter as string."""
		return str([x for x in (self._idx_, self._name, self._comment,
			self._dict_)])
	
	def __repr__(self):
		if self._idx_ == None:
			return repr(str(self))
		return """oroboros.orbsrestrictions.OrbsRestrictions('''%s''')""" % self._name
	
	def __getstate__(self):
		return {'_idx': None,
			'name': self._name,
			'comment': self._comment,
			'_dict': self._dict_}
	
	def _to_xml(self, with_idx=False):
		"""Return a xmlutils.Element('OrbsRestrictions')."""
		if with_idx:
			el = xmlutils.Element('OrbsRestrictions', {'_idx': self._idx_},
				'\n\t', '\n')
		else:
			el = xmlutils.Element('OrbsRestrictions', {'_idx': None},
				'\n\t', '\n')
		el.append('name', {}, self._name, '\n\t')
		el.append('comment', {}, self._comment, '\n\t')
		el2 = xmlutils.Element('Planets', {}, '\n\t', '\n')
		for x, y in self.items():
			el2.append('Planet', {'name': x, 'value': y}, '', '\n\t\t')
		el.append(el2)
		return el
	
	def _from_xml(self, elem, with_idx=False):
		"""Set aspects filter from a xmlutils.Element('OrbsRestrictions')."""
		if with_idx:
			_idx = elem.get_attr('_idx')
			if _idx == 'None':
				self._idx_ = None
			else:
				self._idx = _idx
		self.set(name=elem.get_child_text(
				tag='name').replace('&lt;', '<').replace('&gt;', '>'),
			comment=elem.get_child_text(
				tag='comment').replace('&lt;', '<').replace('&gt;', '>'))
		el2 = elem.get_child('Planets')
		for e in el2.get_iterator(tag='Planet'):
			self[e.get_attr('name')] = e.get_attr('value')
	
	def __eq__(self, other):
		"""Return True if other is the same filter in database."""
		if other == None:
			return False
		if not isinstance(other, OrbsRestrictions):
			return False
		if other._idx_ == self._idx_:
			return True
		return False
	
	def __ne__(self, other):
		"""Return True if other is not the same filter in database."""
		if other == None:
			return True
		if not isinstance(other, OrbsRestrictions):
			return True
		if other._idx_ != self._idx_:
			return True
		return False def all_orbs_restrictions_names():
	"""Return a list of all orbs restrictions names."""
	ret = list()
	sql = 'select name from OrbsRestrictions order by name;'
	res = db.execute(sql).fetchall()
	for row in res:
		ret.append(row[0])
	return ret class MidPointsFilter(db.Object):
	"""Mid-points settings."""
	
	__slots__ = ('_idx_', '_name', '_planets', '_aspects', '_orbs', '_asprestr',
		'_orbrestr', '_comment')
	
	def _get_name(self):
		"""Get filter name.
		
		:rtype: str
		"""
		return self._name
	
	def _set_name(self, name):
		"""Set filter name.
		
		:type name: str
		"""
		self._name = name
	
	def _get_comment(self):
		"""Get filter comment.
		
		:rtype: str
		"""
		return self._comment
	
	def _set_comment(self, comment):
		"""Set filter comment.
		
		:type comment: str
		"""
		self._comment = comment
	
	# sub filters
	
	def _get_planets(self):
		"""Get planets filter.
		
		:rtype: PlanetsFilter
		"""
		return self._planets
	
	def _set_planets(self, filt):
		"""Set planets filter.
		
		:type filt: PlanetsFilter, str or int
		"""
		if not isinstance(filt, PlanetsFilter):
			self._planets = PlanetsFilter(filt)
		else:
			self._planets = filt
	
	def _get_aspects(self):
		"""Get aspects filter.
		
		:rtype: AspectsFilter
		"""
		return self._aspects
	
	def _set_aspects(self, filt):
		"""Set aspects filter.
		
		:type filt: AspectsFilter, str or int
		"""
		if not isinstance(filt, AspectsFilter):
			self._aspects = AspectsFilter(filt)
		else:
			self._aspects = filt
	
	def _get_orbs(self):
		"""Get orbs filter.
		
		:rtype: OrbsFilter
		"""
		return self._orbs
	
	def _set_orbs(self, filt):
		"""Set orbs filter.
		
		:type filt: OrbsFilter, str or int
		"""
		if not isinstance(filt, OrbsFilter):
			self._orbs = OrbsFilter(filt)
		else:
			self._orbs = filt
	
	def _get_asprestr(self):
		"""Get aspects restrictions.
		
		:rtype: AspectsRestrictions
		"""
		return self._asprestr
	
	def _set_asprestr(self, filt):
		"""Set aspects restrictions.
		
		:type filt: AspectsRestrictions
		"""
		if not isinstance(filt, AspectsRestrictions):
			self._asprestr = AspectsRestrictions(filt)
		else:
			self._asprestr = filt
	
	def _get_orbrestr(self):
		"""Get orbs restrictions.
		
		:rtype: OrbsRestrictions
		"""
		return self._orbrestr
	
	def _set_orbrestr(self, filt):
		"""Set orbs restrictions.
		
		:type filt: OrbsRestrictions, str or int
		"""
		if not isinstance(filt, OrbsRestrictions):
			self._orbrestr = OrbsRestrictions(filt)
		else:
			self._orbrestr = filt
	
	_idx = property(db.Object._get_idx, db.Object._set_idx,
		doc='Filter db index value.')
	name = property(_get_name, _set_name,
		doc='Filter name.')
	planets = property(_get_planets, _set_planets,
		doc='Planets filter.')
	aspects = property(_get_aspects, _set_aspects,
		doc='Aspects filter.')
	orbs = property(_get_orbs, _set_orbs,
		doc='Orbs filter.')
	asprestr = property(_get_asprestr, _set_asprestr,
		doc='Aspects restrictions.')
	orbrestr = property(_get_orbrestr, _set_orbrestr,
		doc='Orbs restrictions.')
	comment = property(_get_comment, _set_comment,
		doc='Filter comment.')
	
	def set(self, _idx=None, name=None, planets=None, aspects=None, orbs=None,
		asprestr=None, orbrestr=None, comment=None):
		"""Set filter properties."""
		if _idx != None:
			self._idx = _idx
		if name != None:
			self.name = name
		if planets != None:
			self.planets = planets
		if aspects != None:
			self.aspects = aspects
		if orbs != None:
			self.orbs = orbs
		if asprestr != None:
			self.asprestr = asprestr
		if orbrestr != None:
			self.orbrestr = orbrestr
		if comment != None:
			self.comment = comment
	
	def __init__(self, filt=None, set_default=True):
		"""Init midpoints filters.
		
		:type filt: str or int or None
		:type set_default: bool
		"""
		if filt != None:
			return self._select(filt)
		elif set_default:
			self.set_default()
	
	def set_default(self):
		"""Set filter to default values."""
		sql = '''select midpoints from Filters
			where _idx = (select dft_filter from Config);'''
		idx = int(db.execute(sql).fetchone()[0])
		self._select_by_idx(idx)
	
	def reset(self):
		"""Reset filter when database is updated.
		
		Filter may have been deleted, then load the default one.
		
		"""
		try:
			self._select_by_idx(self._idx_)
		except ValueError: # filter deleted
			self.set_default()
	
	def _select(self, filt):
		"""Select filter in database.
		
		:type filt: str or int
		:raise TypeError: invalid filter
		"""
		if isinstance(filt, int):
			return self._select_by_idx(filt)
		elif isinstance(filt, basestring): ## not py3
			return self._select_by_name(filt)
		raise TypeError('Invalid filter %s.' % filt)
	
	def _select_by_idx(self, idx):
		"""Select filter in database, by idx.
		
		:type idx: int
		:raise ValueError: not found
		"""
		sql = "select * from MidPointsFilters where _idx = ?;"
		res = db.execute(sql, (idx,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid idx %s.' % idx)
		self.set(*res[0])
	
	def _select_by_name(self, filt):
		"""Select filter in database, by name.
		
		:type filt: name
		:raise ValueError: not found
		"""
		sql = "select * from MidPointsFilters where name = ?;"
		res = db.execute(sql, (filt,)).fetchall()
		if len(res) == 0:
			raise ValueError('Invalid filter %s.' % filt)
		self.set(*res[0])
	
	def save(self, recursive=False):
		"""Save filter in database.
		
		If recursive is True, save all sub-filters.
		Else raise TypeError if a sub-filter is not saved.
		
		:type recursive: bool
		"""
		if self._idx_ == None:
			self._insert(recursive)
		else:
			self._update(recursive)
	
	def _insert(self, recursive=False):
		"""Insert filter in database.
		
		:type recursive: bool
		:raise ValueError: duplicate
		"""
		self._save_filters(recursive)
		sql1 = """insert into MidPointsFilters (name, planets,
			aspects, orbs, asprestr, orbrestr, comment) values (?, ?, ?, ?, ?,
			?, ?);"""
		var = (self._name, self._planets._idx_, self._aspects._idx_,
			self._orbs._idx_, self._asprestr._idx_, self._orbrestr._idx_,
			self._comment)
		sql2 = "select _idx from MidPointsFilters where name = ?;"
		try:
			db.execute(sql1, var)
		except: # sqlite3.IntegrityError
			raise ValueError('Duplicate filter %s.' % self._name)
		self._idx = db.execute(sql2,(self._name,)).fetchone()[0]
	
	def _update(self, recursive=False):
		"""Update filter in database.
		
		:type recursive: bool
		:raise ValueError: duplicate
		"""
		self._save_filters(recursive)
		sql = """update MidPointsFilters set name = ?, planets = ?, aspects = ?,
			orbs = ?, asprestr = ?, orbrestr = ?, comment = ? where _idx = ?;"""
		var = (self._name, self._planets._idx_, self._aspects._idx_,
			self._orbs._idx_, self._asprestr._idx_, self._orbrestr._idx_,
			self._comment, self._idx_)
		try:
			db.execute(sql, var)
		except: # integrity error
			raise ValueError('Duplicate filter %s.' % self._name)
	
	def _save_filters(self, recursive):
		"""Save sub-filters if recursive is True, else check they are saved.
		
		Raise TypeError if recursive is False and sub-filter is not saved.
		
		:type recursive: bool
		"""
		for f in (self._planets, self._aspects, self._orbs, self.asprestr,
			self._orbrestr):
			if recursive:
				f.save()
			else:
				if f._idx_ == None:
					raise TypeError('Sub filter %s is not saved.' % f._name)
	
	def delete(self):
		"""Delete filter in database.
		
		:raise TypeError: invalid index
		:raise ValueError: integrity error
		"""
		if self._idx_ == None:
			raise TypeError('Missing idx')
		sql = "delete from MidPointsFilters where _idx = ?;"
		try:
			db.execute(sql, (self._idx_,))
		except: # sqlite3 integrity error 
			raise ValueError('Cannot delete default filter.')
		self._idx_ = None
	
	def __iter__(self):
		"""Return iterator over filter's internals.
		
		:rtype: iterator
		"""
		return (x for x in (self._idx_, self._name,
			self._planets, self._aspects, self._orbs, self._asprestr,
			self._orbrestr, self._comment))
	
	def __str__(self):
		"""Show filter internals.
		
		:rtype: str
		"""
		return str(tuple(self))
	
	def __repr__(self):
		if self._idx_ == None:
			return repr(tuple(repr(x) for x in self))
		return "MidPointsFilter('''%s''')" % self._name
	
	def __getstate__(self):
		"""TODO."""
		pass
	
	def _to_xml(self, with_idx=False):
		"""TODO."""
		pass
	
	def _from_xml(self, elem, with_idx=False):
		"""TODO."""
		pass
	
	def __eq__(self, other):
		"""Return True if other is the same filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return False
		if not isinstance(other, MidPointsFilter):
			return False
		if other._idx_ == self._idx_:
			return True
		return False
	
	def __ne__(self, other):
		"""Return True if other is not the same filter in database.
		
		:rtype: bool
		"""
		if other == None:
			return True
		if not isinstance(other, MidPointsFilter):
			return True
		if other._idx_ != self._idx_:
			return True
		return False def all_midpoints_filters_names():
	"""Return a list of all midpoints filters names.
	
	:rtype: list
	"""
	ret = list()
	sql = 'select name from MidPointsFilters order by name;'
	res = db.execute(sql).fetchall()
	for row in res:
		ret.append(row[0])
	return ret def appendMultiChart(cht):
def insertMultiChart(idx, cht):
def replaceMultiChart(idx, cht):
def removeMultiChart(idx):
def replaceChart(idx, num, cht):
def removeChart(idx, num):
def filterUpdatedEvent(idx):
def planetsFilterUpdatedEvent(idx):
def aspectsFilterUpdatedEvent(idx):
def orbsFilterUpdatedEvent(idx):
def aspectsRestrictionsUpdatedEvent(idx):
def orbsRestrictionsUpdatedEvent(idx):
def midPointsFilterUpdatedEvent(idx): class PlanetsFilterDialog(QDialog):
	
	def __init__(self, parent=None, filt=None):
		QDialog.__init__(self, parent)
		self._parent = parent
		tr = self.tr
		if isinstance(filt, PlanetsFilter):
			self._filt = filt
			title = unicode(tr('Edit Planets Filter \xab %(filter)s \xbb')) % {
				'filter': filt._name}
		else:
			self._filt = PlanetsFilter(cfg.dft_filter._planets._idx_)
			self._filt._idx_ = None # copy dft filter and set idx to None
			title = tr('New Planets Filter')
		self.setWindowTitle(title)
		# size
		self.setMinimumWidth(350)
		self.setMinimumHeight(350)
		self.setSizeGripEnabled(True)
		# layout
		grid = QGridLayout(self)
		self.setLayout(grid)
		# filter name
		grid.addWidget(QLabel(tr('Filter name')), 0, 0)
		self.nameEdit = QLineEdit(self)
		grid.addWidget(self.nameEdit, 0, 1)
		# tab widget
		tabs = QTabWidget(self)
		grid.addWidget(tabs, 1, 0, 1, 2)
		self._cb = dict() ## holds the checkboxes
		
		# ### main planets ###
		mainWidget = QWidget()
		tabs.addTab(mainWidget, tr('Main', 'Main planets'))
		mainGrid = QGridLayout()
		mainWidget.setLayout(mainGrid)
		# sun
		self._cb['Sun'] = QCheckBox(names.planets['Sun'], self)
		mainGrid.addWidget(self._cb['Sun'], 0, 0)
		# moon
		self._cb['Moon'] = QCheckBox(names.planets['Moon'], self)
		mainGrid.addWidget(self._cb['Moon'], 0, 1)
		# mercury
		self._cb['Mercury'] = QCheckBox(names.planets['Mercury'], self)
		mainGrid.addWidget(self._cb['Mercury'], 0, 2)
		# venus
		self._cb['Venus'] = QCheckBox(names.planets['Venus'], self)
		mainGrid.addWidget(self._cb['Venus'], 0, 3)
		# mars
		self._cb['Mars'] = QCheckBox(names.planets['Mars'], self)
		mainGrid.addWidget(self._cb['Mars'], 0, 4)
		# jupiter
		self._cb['Jupiter'] = QCheckBox(names.planets['Jupiter'], self)
		mainGrid.addWidget(self._cb['Jupiter'], 1, 0)
		# saturn
		self._cb['Saturn'] = QCheckBox(names.planets['Saturn'], self)
		mainGrid.addWidget(self._cb['Saturn'], 1, 1)
		# uranus
		self._cb['Uranus'] = QCheckBox(names.planets['Uranus'], self)
		mainGrid.addWidget(self._cb['Uranus'], 1, 2)
		# neptune
		self._cb['Neptune'] = QCheckBox(names.planets['Neptune'], self)
		mainGrid.addWidget(self._cb['Neptune'], 1, 3)
		# pluto
		self._cb['Pluto'] = QCheckBox(names.planets['Pluto'], self)
		mainGrid.addWidget(self._cb['Pluto'], 1, 4)
		# earth
		self._cb['Earth'] = QCheckBox(names.planets['Earth'], self)
		mainGrid.addWidget(self._cb['Earth'], 2, 0)
		# chiron
		self._cb['Chiron'] = QCheckBox(names.planets['Chiron'], self)
		mainGrid.addWidget(self._cb['Chiron'], 2, 1)
		# pholus
		self._cb['Pholus'] = QCheckBox(names.planets['Pholus'], self)
		mainGrid.addWidget(self._cb['Pholus'], 2, 2)
		# ceres
		self._cb['Ceres'] = QCheckBox(names.planets['Ceres'], self)
		mainGrid.addWidget(self._cb['Ceres'], 2, 3)
		# pallas
		self._cb['Pallas'] = QCheckBox(names.planets['Pallas'], self)
		mainGrid.addWidget(self._cb['Pallas'], 2, 4)
		# juno
		self._cb['Juno'] = QCheckBox(names.planets['Juno'], self)
		mainGrid.addWidget(self._cb['Juno'], 3, 0)
		# vesta
		self._cb['Vesta'] = QCheckBox(names.planets['Vesta'], self)
		mainGrid.addWidget(self._cb['Vesta'], 3, 1)
		# rahu (mean)
		self._cb['Rahu (mean)'] = QCheckBox(names.planets['Rahu (mean)'], self)
		mainGrid.addWidget(self._cb['Rahu (mean)'], 3, 2)
		# rahu (true)
		self._cb['Rahu (true)'] = QCheckBox(names.planets['Rahu (true)'], self)
		mainGrid.addWidget(self._cb['Rahu (true)'], 3, 3)
		# ketu (mean)
		self._cb['Ketu (mean)'] = QCheckBox(names.planets['Ketu (mean)'], self)
		mainGrid.addWidget(self._cb['Ketu (mean)'], 3, 4)
		# ketu (true)
		self._cb['Ketu (true)'] = QCheckBox(names.planets['Ketu (true)'], self)
		mainGrid.addWidget(self._cb['Ketu (true)'], 4, 0)
		# lilith (mean)
		self._cb['Lilith (mean)'] = QCheckBox(names.planets['Lilith (mean)'], self)
		mainGrid.addWidget(self._cb['Lilith (mean)'], 4, 1)
		# lilith (true)
		self._cb['Lilith (true)'] = QCheckBox(names.planets['Lilith (true)'], self)
		mainGrid.addWidget(self._cb['Lilith (true)'], 4, 2)
		# priapus (mean)
		self._cb['Priapus (mean)'] = QCheckBox(names.planets['Priapus (mean)'], self)
		mainGrid.addWidget(self._cb['Priapus (mean)'], 4, 3)
		# priapus (true)
		self._cb['Priapus (true)'] = QCheckBox(names.planets['Priapus (true)'], self)
		mainGrid.addWidget(self._cb['Priapus (true)'], 4, 4)
		
		# ### uranians ###
		uranianWidget = QWidget()
		tabs.addTab(uranianWidget, tr('Uranians'))
		uranianGrid = QGridLayout()
		uranianWidget.setLayout(uranianGrid)
		# cupido
		self._cb['Cupido'] = QCheckBox(names.planets['Cupido'], self)
		uranianGrid.addWidget(self._cb['Cupido'], 0, 0)
		# hades
		self._cb['Hades'] = QCheckBox(names.planets['Hades'], self)
		uranianGrid.addWidget(self._cb['Hades'], 0, 1)
		# zeus
		self._cb['Zeus'] = QCheckBox(names.planets['Zeus'], self)
		uranianGrid.addWidget(self._cb['Zeus'], 0, 2)
		# kronos
		self._cb['Kronos'] = QCheckBox(names.planets['Kronos'], self)
		uranianGrid.addWidget(self._cb['Kronos'], 0, 3)
		# apollo
		self._cb['Apollon'] = QCheckBox(names.planets['Apollon'], self)
		uranianGrid.addWidget(self._cb['Apollon'], 1, 0)
		# admetos
		self._cb['Admetos'] = QCheckBox(names.planets['Admetos'], self)
		uranianGrid.addWidget(self._cb['Admetos'], 1, 1)
		# vulkanus
		self._cb['Vulkanus'] = QCheckBox(names.planets['Vulkanus'], self)
		uranianGrid.addWidget(self._cb['Vulkanus'], 1, 2)
		# poseidon
		self._cb['Poseidon'] = QCheckBox(names.planets['Poseidon'], self)
		uranianGrid.addWidget(self._cb['Poseidon'], 1, 3)
		
		# ### others fictitious ###
		othersWidget = QWidget()
		tabs.addTab(othersWidget, tr('Others'))
		othersGrid = QGridLayout()
		othersWidget.setLayout(othersGrid)
		# isis
		self._cb['Isis'] = QCheckBox(names.planets['Isis'], self)
		othersGrid.addWidget(self._cb['Isis'], 0, 0)
		# nibiru
		self._cb['Nibiru'] = QCheckBox(names.planets['Nibiru'], self)
		othersGrid.addWidget(self._cb['Nibiru'], 0, 1)
		# harrington
		self._cb['Harrington'] = QCheckBox(names.planets['Harrington'], self)
		othersGrid.addWidget(self._cb['Harrington'], 0, 2)
		# neptune (leverrier)
		self._cb['Neptune (Leverrier)'] = QCheckBox(names.planets['Neptune (Leverrier)'], self)
		othersGrid.addWidget(self._cb['Neptune (Leverrier)'], 0, 3)
		# neptune (adams)
		self._cb['Neptune (Adams)'] = QCheckBox(names.planets['Neptune (Adams)'], self)
		othersGrid.addWidget(self._cb['Neptune (Adams)'], 1, 0)
		# pluto (lowell)
		self._cb['Pluto (Lowell)'] = QCheckBox(names.planets['Pluto (Lowell)'], self)
		othersGrid.addWidget(self._cb['Pluto (Lowell)'], 1, 1)
		# pluto (pickering)
		self._cb['Pluto (Pickering)'] = QCheckBox(names.planets['Pluto (Pickering)'], self)
		othersGrid.addWidget(self._cb['Pluto (Pickering)'], 1, 2)
		# vulcan
		self._cb['Vulcan'] = QCheckBox(names.planets['Vulcan'], self)
		othersGrid.addWidget(self._cb['Vulcan'], 1, 3)
		# white moon
		self._cb['White Moon'] = QCheckBox(names.planets['White Moon'], self)
		othersGrid.addWidget(self._cb['White Moon'], 2, 0)
		# proserpina
		self._cb['Proserpina'] = QCheckBox(names.planets['Proserpina'], self)
		othersGrid.addWidget(self._cb['Proserpina'], 2, 1)
		# waldemath
		self._cb['Waldemath'] = QCheckBox(names.planets['Waldemath'], self)
		othersGrid.addWidget(self._cb['Waldemath'], 2, 2)
		
		# ### cusps ###
		cuspsWidget = QWidget()
		tabs.addTab(cuspsWidget, tr('Cusps'))
		cuspsGrid = QGridLayout()
		cuspsWidget.setLayout(cuspsGrid)
		# house cusps
		x = (0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2)
		y = (0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3)
		for i in range(12):
			self._cb['Cusp %.2d' % (i+1,)] = QCheckBox(
				names.houses['Cusp %.2d' % (i+1,)], self)
			cuspsGrid.addWidget(self._cb['Cusp %.2d' % (i+1,)], x[i], y[i])
		# asc
		self._cb['Asc'] = QCheckBox(names.planets['Asc'], self)
		cuspsGrid.addWidget(self._cb['Asc'], 3, 0)
		# mc
		self._cb['Mc'] = QCheckBox(names.planets['Mc'], self)
		cuspsGrid.addWidget(self._cb['Mc'], 3, 1)
		# dsc
		self._cb['Dsc'] = QCheckBox(names.planets['Dsc'], self)
		cuspsGrid.addWidget(self._cb['Dsc'], 3, 2)
		# ic
		self._cb['Ic'] = QCheckBox(names.planets['Ic'], self)
		cuspsGrid.addWidget(self._cb['Ic'], 3, 3)
		# armc
		self._cb['Armc'] = QCheckBox(names.planets['Armc'], self)
		cuspsGrid.addWidget(self._cb['Armc'], 4, 0)
		# vertex
		self._cb['Vertex'] = QCheckBox(names.planets['Vertex'], self)
		cuspsGrid.addWidget(self._cb['Vertex'], 4, 1)
		# equatorial asc
		self._cb['Equatorial Ascendant'] = QCheckBox(names.planets['Equatorial Ascendant'], self)
		cuspsGrid.addWidget(self._cb['Equatorial Ascendant'], 4, 2)
		# co-ascendant (koch)
		self._cb['Co-ascendant (Koch)'] = QCheckBox(names.planets['Co-ascendant (Koch)'], self)
		cuspsGrid.addWidget(self._cb['Co-ascendant (Koch)'], 4, 3)
		# co-ascendant (munkasey)
		self._cb['Co-ascendant (Munkasey)'] = QCheckBox(names.planets['Co-ascendant (Munkasey)'], self)
		cuspsGrid.addWidget(self._cb['Co-ascendant (Munkasey)'], 5, 0)
		# polar ascendant
		self._cb['Polar Ascendant (Munkasey)'] = QCheckBox(names.planets['Polar Ascendant (Munkasey)'], self)
		cuspsGrid.addWidget(self._cb['Polar Ascendant (Munkasey)'], 5, 1)
		
		# ### gauquelin ###
		gauquelinWidget = QWidget()
		tabs.addTab(gauquelinWidget, tr('Gauquelin'))
		gauquelinGrid = QGridLayout()
		gauquelinWidget.setLayout(gauquelinGrid)
		# sectors
		x = (0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,5,5)
		y = (0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5)
		for i in range(36):
			self._cb['Sector %.2d' % (i+1,)] = QCheckBox(
				names.houses['Sector %.2d' % (i+1,)], self)
			gauquelinGrid.addWidget(self._cb['Sector %.2d' % (i+1,)], x[i], y[i])
		
		# ### parts ###
		partsWidget = QWidget()
		tabs.addTab(partsWidget, tr('Parts'))
		partsGrid = QGridLayout()
		partsWidget.setLayout(partsGrid)
		# part of fortune (rudhyar)
		self._cb['Part of Fortune (Rudhyar)'] = QCheckBox(
			names.planets['Part of Fortune (Rudhyar)'], self)
		partsGrid.addWidget(self._cb['Part of Fortune (Rudhyar)'], 0, 0)
		
		# ### fixed stars ###
		# get all stars
		sql = 'select name from Planets where family = 2 order by name;'
		res = db.execute(sql).fetchall()
		# stars tab
		starsScroll = QScrollArea()
		starsScroll.setWidgetResizable(True)
		starsWidget = QWidget()
		starsScroll.setWidget(starsWidget)
		tabs.addTab(starsScroll, tr('Stars'))
		starsGrid = QGridLayout()
		starsWidget.setLayout(starsGrid)
		y = 0
		for i, star in enumerate(res):
			s = str(star[0])
			self._cb[s] = QCheckBox(s, self)
			starsGrid.addWidget(self._cb[s], y, i % 6)
			if i % 6 == 5:
				y += 1
		
		# ### asteroids ###
		# get all asteroids
		sql = 'select name from Planets where family = 3 order by name;'
		res = db.execute(sql).fetchall()
		# asteroids tab
		asteroidsScroll = QScrollArea()
		asteroidsScroll.setWidgetResizable(True)
		asteroidsWidget = QWidget()
		asteroidsScroll.setWidget(asteroidsWidget)
		tabs.addTab(asteroidsScroll, tr('Asteroids'))
		asteroidsGrid = QGridLayout()
		asteroidsWidget.setLayout(asteroidsGrid)
		y = 0
		for i, ast in enumerate(res):
			s = str(ast[0])
			self._cb[s] = QCheckBox(s, self)
			asteroidsGrid.addWidget(self._cb[s], y, i % 6)
			if i % 6 == 5:
				y += 1
		
		# ### end planets ###
		
		# comment
		grid.addWidget(QLabel(tr('Comment')), 2, 0, Qt.AlignTop)
		self.commentEdit = QTextEdit('', self)
		grid.addWidget(self.commentEdit, 2, 1)
		# buttons
		buttonsLayout = QHBoxLayout()
		resetButton = QPushButton(tr('Reset'), self)
		self.connect(resetButton, SIGNAL('clicked()'), self.reset)
		buttonsLayout.addWidget(resetButton)
		cancelButton = QPushButton(tr('Cancel'), self)
		self.connect(cancelButton, SIGNAL('clicked()'), self.reject)
		buttonsLayout.addWidget(cancelButton)
		okButton = QPushButton(tr('Ok'), self)
		okButton.setDefault(True)
		self.connect(okButton, SIGNAL('clicked()'), self.accept)
		buttonsLayout.addWidget(okButton)
		grid.addLayout(buttonsLayout, 3, 0, 1, 2)
		# load entries
		self.reset()
		# resize
		self.resize(550, 300)
	
	def reset(self):
		"""Reset entries."""
		# name
		self.nameEdit.setText(self._filt._name)
		# comment
		self.commentEdit.setPlainText(self._filt._comment)
		# values
		for pl, val in self._filt.items():
				self._cb[pl].setChecked(val)
	
	def accept(self):
		"""Set filter new values and save."""
		tr = self.tr
		# name
		name = unicode(self.nameEdit.text())
		if name == '':
			QMessageBox.critical(self, tr('Missing Name'),
				tr('Please set filter name.'))
			self.nameEdit.setFocus()
			return
		# comment
		cmt = unicode(self.commentEdit.toPlainText())
		# set values
		self._filt.set(name=name, comment=cmt)
		for pl, cb in self._cb.items():
			self._filt[pl] = cb.isChecked()
		# save
		try:
			self._filt.save()
		except ValueError: # duplicate filter
			QMessageBox.critical(self, tr('Error'),
				unicode(tr('Duplicate filter name \xab %(filter)s \xbb.')) % {
					'filter': self._filt._name})
			self.nameEdit.setFocus()
			return
		# reload cfg in case filter is default,
		# and opened charts if using this filter
		if __name__ != '__main__':
			app.planetsFilterUpdatedEvent(self._filt._idx_)
		# done
		self.done(QDialog.Accepted) class AspectsFilterDialog(QDialog):
	
	def __init__(self, parent=None, filt=None):
		QDialog.__init__(self, parent)
		self._parent = parent
		tr = self.tr
		if isinstance(filt, AspectsFilter):
			self._filt = filt
			title = unicode(tr('Edit Aspects Filter \xab %(filter)s \xbb')) % {
				'filter': filt._name}
		else:
			self._filt = AspectsFilter(cfg.dft_filter._aspects._idx_)
			self._filt._idx_ = None # copy dft filter and set idx to None
			title = tr('New Aspects Filter')
		self.setWindowTitle(title)
		# size
		self.setMinimumWidth(350)
		self.setMinimumHeight(320)
		self.setSizeGripEnabled(True)
		# layout
		grid = QGridLayout(self)
		self.setLayout(grid)
		# filter name
		grid.addWidget(QLabel(tr('Filter name')), 0, 0)
		self.nameEdit = QLineEdit(self)
		grid.addWidget(self.nameEdit, 0, 1)
		# tab widget
		tabs = QTabWidget(self)
		grid.addWidget(tabs, 1, 0, 1, 2)
		self._cb = dict() ## holds the checkboxes
		
		# ### main aspects ###
		mainWidget = QWidget()
		tabs.addTab(mainWidget, tr('Main', 'Main aspects'))
		mainGrid = QGridLayout()
		mainWidget.setLayout(mainGrid)
		x = (0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3)
		y = (0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3)
		mainAspects = ('Conjunction', 'Opposition', 'Trine', 'Square', 'Sextile',
			'Quincunx', 'SesquiSquare', 'SemiSquare', 'SemiSextile', 'SquiSquare',
			'SquiSextile', 'Quintile', 'BiQuintile', 'SemiQuintile')
		for i, asp in enumerate(mainAspects):
			self._cb[asp] = QCheckBox(names.aspects[asp], self)
			mainGrid.addWidget(self._cb[asp], x[i], y[i])
		
		# ### other aspects ###$
		otherWidget = QWidget()
		tabs.addTab(otherWidget, tr('Others', 'Other aspects'))
		otherGrid = QGridLayout()
		otherWidget.setLayout(otherGrid)
		x = (0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3)
		y = (0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3)
		otherAspects = ('Novile', 'BiNovile', 'QuadriNovile', 'SemiNovile',
			'Septile', 'BiSeptile', 'TriSeptile', 'Undecile', 'BiUndecile',
			'TriUndecile', 'QuadUndecile', 'QuinUndecile')
		for i, asp in enumerate(otherAspects):
			self._cb[asp] = QCheckBox(names.aspects[asp], self)
			otherGrid.addWidget(self._cb[asp], x[i], y[i])
		
		# comment
		grid.addWidget(QLabel(tr('Comment')), 2, 0, Qt.AlignTop)
		self.commentEdit = QTextEdit('', self)
		grid.addWidget(self.commentEdit, 2, 1)
		# buttons
		buttonsLayout = QHBoxLayout()
		resetButton = QPushButton(tr('Reset'), self)
		self.connect(resetButton, SIGNAL('clicked()'), self.reset)
		buttonsLayout.addWidget(resetButton)
		cancelButton = QPushButton(tr('Cancel'), self)
		self.connect(cancelButton, SIGNAL('clicked()'), self.reject)
		buttonsLayout.addWidget(cancelButton)
		okButton = QPushButton(tr('Ok'), self)
		okButton.setDefault(True)
		self.connect(okButton, SIGNAL('clicked()'), self.accept)
		buttonsLayout.addWidget(okButton)
		grid.addLayout(buttonsLayout, 3, 0, 1, 2)
		# load entries
		self.reset()
		# resize
		self.resize(550, 300)
	
	def reset(self):
		"""Reset entries."""
		# name
		self.nameEdit.setText(self._filt._name)
		# comment
		self.commentEdit.setPlainText(self._filt._comment)
		# values
		for asp, val in self._filt.items():
				self._cb[asp].setChecked(val)
	
	def accept(self):
		"""Set filter new values and save."""
		tr = self.tr
		# name
		name = unicode(self.nameEdit.text())
		if name == '':
			QMessageBox.critical(self, tr('Missing Name'),
				tr('Please set filter name.'))
			self.nameEdit.setFocus()
			return
		# comment
		cmt = unicode(self.commentEdit.toPlainText())
		# set values
		self._filt.set(name=name, comment=cmt)
		for asp, cb in self._cb.items():
			self._filt[asp] = cb.isChecked()
		# save
		try:
			self._filt.save()
		except ValueError: # duplicate filter
			QMessageBox.critical(self, tr('Error'),
				unicode(tr('Duplicate filter name \xab %s \xbb.')) % self._filt._name)
			self.nameEdit.setFocus()
			return
		# reload cfg in case filter is default,
		# and opened charts if using this filter
		if __name__ != '__main__':
			app.aspectsFilterUpdatedEvent(self._filt._idx_)
		# done
		self.done(QDialog.Accepted) class OrbsFilterDialog(QDialog):
	
	def __init__(self, parent=None, filt=None):
		QDialog.__init__(self, parent)
		self._parent = parent
		tr = self.tr
		if isinstance(filt, OrbsFilter):
			self._filt = filt
			title = unicode(tr('Edit Orbs Filter \xab %(filter)s \xbb')) % {
				'filter': filt._name}
		else:
			self._filt = OrbsFilter(cfg.dft_filter._orbs._idx_)
			self._filt._idx_ = None # copy dft filter and set idx to None
			title = tr('New Orbs Filter')
		self.setWindowTitle(title)
		# size
		self.setMinimumWidth(500)
		self.setMinimumHeight(320)
		self.setSizeGripEnabled(True)
		# layout
		grid = QGridLayout(self)
		self.setLayout(grid)
		# filter name
		grid.addWidget(QLabel(tr('Filter name')), 0, 0)
		self.nameEdit = QLineEdit(self)
		grid.addWidget(self.nameEdit, 0, 1)
		# tab widget
		tabs = QTabWidget(self)
		grid.addWidget(tabs, 1, 0, 1, 2)
		self._sb = dict() ## holds the spinboxes
		
		# ### main aspects ###
		mainWidget = QWidget()
		tabs.addTab(mainWidget, tr('Main', 'Main aspects'))
		mainGrid = QGridLayout()
		mainWidget.setLayout(mainGrid)
		x = (0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3)
		y = (0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6)
		mainAspects = ('Conjunction', 'Opposition', 'Trine', 'Square', 'Sextile',
			'Quincunx', 'SesquiSquare', 'SemiSquare', 'SemiSextile', 'SquiSquare',
			'SquiSextile', 'Quintile', 'BiQuintile', 'SemiQuintile')
		for i, asp in enumerate(mainAspects):
			mainGrid.addWidget(QLabel(names.aspects[asp]), x[i], y[i])
			self._sb[asp] = QDoubleSpinBox(self)
			self._sb[asp].setRange(0, 30)
			self._sb[asp].setButtonSymbols(QAbstractSpinBox.PlusMinus)
			self._sb[asp].setSuffix(tr('\xb0', 'Degrees'))
			mainGrid.addWidget(self._sb[asp], x[i], y[i]+1)
		
		# ### other aspects ###
		otherWidget = QWidget()
		tabs.addTab(otherWidget, tr('Others', 'Other aspects'))
		otherGrid = QGridLayout()
		otherWidget.setLayout(otherGrid)
		x = (0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3)
		y = (0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6)
		otherAspects = ('Novile', 'BiNovile', 'QuadriNovile', 'SemiNovile',
			'Septile', 'BiSeptile', 'TriSeptile', 'Undecile', 'BiUndecile',
			'TriUndecile', 'QuadUndecile', 'QuinUndecile')
		for i, asp in enumerate(otherAspects):
			otherGrid.addWidget(QLabel(names.aspects[asp]), x[i], y[i])
			self._sb[asp] = QDoubleSpinBox(self)
			self._sb[asp].setRange(0, 30)
			self._sb[asp].setButtonSymbols(QAbstractSpinBox.PlusMinus)
			self._sb[asp].setSuffix(tr('\xb0', 'Degrees'))
			otherGrid.addWidget(self._sb[asp], x[i], y[i]+1)
		
		# comment
		grid.addWidget(QLabel(tr('Comment')), 2, 0, Qt.AlignTop)
		self.commentEdit = QTextEdit('', self)
		grid.addWidget(self.commentEdit, 2, 1)
		# buttons
		buttonsLayout = QHBoxLayout()
		resetButton = QPushButton(tr('Reset'), self)
		self.connect(resetButton, SIGNAL('clicked()'), self.reset)
		buttonsLayout.addWidget(resetButton)
		cancelButton = QPushButton(tr('Cancel'), self)
		self.connect(cancelButton, SIGNAL('clicked()'), self.reject)
		buttonsLayout.addWidget(cancelButton)
		okButton = QPushButton(tr('Ok'), self)
		okButton.setDefault(True)
		self.connect(okButton, SIGNAL('clicked()'), self.accept)
		buttonsLayout.addWidget(okButton)
		grid.addLayout(buttonsLayout, 3, 0, 1, 2)
		# load entries
		self.reset()
		# resize
		self.resize(550, 300)
	
	def reset(self):
		"""Reset entries."""
		# name
		self.nameEdit.setText(self._filt._name)
		# comment
		self.commentEdit.setPlainText(self._filt._comment)
		# values
		for asp, val in self._filt.items():
				self._sb[asp].setValue(val)
	
	def accept(self):
		"""Set filter new values and save."""
		tr = self.tr
		# name
		name = unicode(self.nameEdit.text())
		if name == '':
			QMessageBox.critical(self, tr('Missing Name'),
				tr('Please set filter name.'))
			self.nameEdit.setFocus()
			return
		# comment
		cmt = unicode(self.commentEdit.toPlainText())
		# set values
		self._filt.set(name=name, comment=cmt)
		for asp, sb in self._sb.items():
			self._filt[asp] = sb.value()
		# save
		try:
			self._filt.save()
		except ValueError: # duplicate filter
			QMessageBox.critical(self, tr('Error'),
				unicode(tr('Duplicate filter name \xab %s \xbb.')) % self._filt._name)
			self.nameEdit.setFocus()
			return
		# reload cfg in case filter is default,
		# and opened charts if using this filter
		if __name__ != '__main__':
			app.orbsFilterUpdatedEvent(self._filt._idx_)
		# done
		self.done(QDialog.Accepted) class AspectsRestrictionsDialog(QDialog):
	
	def __init__(self, parent=None, filt=None):
		QDialog.__init__(self, parent)
		self._parent = parent
		tr = self.tr
		if isinstance(filt, AspectsRestrictions):
			self._filt = filt
			title = unicode(tr('Edit Aspects Restrictions \xab %(filter)s \xbb')) % {
				'filter': filt._name}
		else:
			self._filt = AspectsRestrictions(cfg.dft_filter._asprestr._idx_)
			self._filt._idx_ = None # copy dft filter and set idx to None
			title = tr('New Aspects Restrictions')
		self.setWindowTitle(title)
		# size
		self.setMinimumWidth(350)
		self.setMinimumHeight(350)
		self.setSizeGripEnabled(True)
		# layout
		grid = QGridLayout(self)
		self.setLayout(grid)
		# filter name
		grid.addWidget(QLabel(tr('Filter name')), 0, 0)
		self.nameEdit = QLineEdit(self)
		grid.addWidget(self.nameEdit, 0, 1)
		# tab widget
		tabs = QTabWidget(self)
		grid.addWidget(tabs, 1, 0, 1, 2)
		self._cb = dict() ## holds the checkboxes
		
		# ### main planets ###
		mainWidget = QWidget()
		tabs.addTab(mainWidget, tr('Main', 'Main planets'))
		mainGrid = QGridLayout()
		mainWidget.setLayout(mainGrid)
		# sun
		self._cb['Sun'] = QCheckBox(names.planets['Sun'], self)
		mainGrid.addWidget(self._cb['Sun'], 0, 0)
		# moon
		self._cb['Moon'] = QCheckBox(names.planets['Moon'], self)
		mainGrid.addWidget(self._cb['Moon'], 0, 1)
		# mercury
		self._cb['Mercury'] = QCheckBox(names.planets['Mercury'], self)
		mainGrid.addWidget(self._cb['Mercury'], 0, 2)
		# venus
		self._cb['Venus'] = QCheckBox(names.planets['Venus'], self)
		mainGrid.addWidget(self._cb['Venus'], 0, 3)
		# mars
		self._cb['Mars'] = QCheckBox(names.planets['Mars'], self)
		mainGrid.addWidget(self._cb['Mars'], 0, 4)
		# jupiter
		self._cb['Jupiter'] = QCheckBox(names.planets['Jupiter'], self)
		mainGrid.addWidget(self._cb['Jupiter'], 1, 0)
		# saturn
		self._cb['Saturn'] = QCheckBox(names.planets['Saturn'], self)
		mainGrid.addWidget(self._cb['Saturn'], 1, 1)
		# uranus
		self._cb['Uranus'] = QCheckBox(names.planets['Uranus'], self)
		mainGrid.addWidget(self._cb['Uranus'], 1, 2)
		# neptune
		self._cb['Neptune'] = QCheckBox(names.planets['Neptune'], self)
		mainGrid.addWidget(self._cb['Neptune'], 1, 3)
		# pluto
		self._cb['Pluto'] = QCheckBox(names.planets['Pluto'], self)
		mainGrid.addWidget(self._cb['Pluto'], 1, 4)
		# earth
		self._cb['Earth'] = QCheckBox(names.planets['Earth'], self)
		mainGrid.addWidget(self._cb['Earth'], 2, 0)
		# chiron
		self._cb['Chiron'] = QCheckBox(names.planets['Chiron'], self)
		mainGrid.addWidget(self._cb['Chiron'], 2, 1)
		# pholus
		self._cb['Pholus'] = QCheckBox(names.planets['Pholus'], self)
		mainGrid.addWidget(self._cb['Pholus'], 2, 2)
		# ceres
		self._cb['Ceres'] = QCheckBox(names.planets['Ceres'], self)
		mainGrid.addWidget(self._cb['Ceres'], 2, 3)
		# pallas
		self._cb['Pallas'] = QCheckBox(names.planets['Pallas'], self)
		mainGrid.addWidget(self._cb['Pallas'], 2, 4)
		# juno
		self._cb['Juno'] = QCheckBox(names.planets['Juno'], self)
		mainGrid.addWidget(self._cb['Juno'], 3, 0)
		# vesta
		self._cb['Vesta'] = QCheckBox(names.planets['Vesta'], self)
		mainGrid.addWidget(self._cb['Vesta'], 3, 1)
		# rahu (mean)
		self._cb['Rahu (mean)'] = QCheckBox(names.planets['Rahu (mean)'], self)
		mainGrid.addWidget(self._cb['Rahu (mean)'], 3, 2)
		# rahu (true)
		self._cb['Rahu (true)'] = QCheckBox(names.planets['Rahu (true)'], self)
		mainGrid.addWidget(self._cb['Rahu (true)'], 3, 3)
		# ketu (mean)
		self._cb['Ketu (mean)'] = QCheckBox(names.planets['Ketu (mean)'], self)
		mainGrid.addWidget(self._cb['Ketu (mean)'], 3, 4)
		# ketu (true)
		self._cb['Ketu (true)'] = QCheckBox(names.planets['Ketu (true)'], self)
		mainGrid.addWidget(self._cb['Ketu (true)'], 4, 0)
		# lilith (mean)
		self._cb['Lilith (mean)'] = QCheckBox(names.planets['Lilith (mean)'], self)
		mainGrid.addWidget(self._cb['Lilith (mean)'], 4, 1)
		# lilith (true)
		self._cb['Lilith (true)'] = QCheckBox(names.planets['Lilith (true)'], self)
		mainGrid.addWidget(self._cb['Lilith (true)'], 4, 2)
		# priapus (mean)
		self._cb['Priapus (mean)'] = QCheckBox(names.planets['Priapus (mean)'], self)
		mainGrid.addWidget(self._cb['Priapus (mean)'], 4, 3)
		# priapus (true)
		self._cb['Priapus (true)'] = QCheckBox(names.planets['Priapus (true)'], self)
		mainGrid.addWidget(self._cb['Priapus (true)'], 4, 4)
		
		# ### uranians ###
		uranianWidget = QWidget()
		tabs.addTab(uranianWidget, tr('Uranians'))
		uranianGrid = QGridLayout()
		uranianWidget.setLayout(uranianGrid)
		# cupido
		self._cb['Cupido'] = QCheckBox(names.planets['Cupido'], self)
		uranianGrid.addWidget(self._cb['Cupido'], 0, 0)
		# hades
		self._cb['Hades'] = QCheckBox(names.planets['Hades'], self)
		uranianGrid.addWidget(self._cb['Hades'], 0, 1)
		# zeus
		self._cb['Zeus'] = QCheckBox(names.planets['Zeus'], self)
		uranianGrid.addWidget(self._cb['Zeus'], 0, 2)
		# kronos
		self._cb['Kronos'] = QCheckBox(names.planets['Kronos'], self)
		uranianGrid.addWidget(self._cb['Kronos'], 0, 3)
		# apollo
		self._cb['Apollon'] = QCheckBox(names.planets['Apollon'], self)
		uranianGrid.addWidget(self._cb['Apollon'], 1, 0)
		# admetos
		self._cb['Admetos'] = QCheckBox(names.planets['Admetos'], self)
		uranianGrid.addWidget(self._cb['Admetos'], 1, 1)
		# vulkanus
		self._cb['Vulkanus'] = QCheckBox(names.planets['Vulkanus'], self)
		uranianGrid.addWidget(self._cb['Vulkanus'], 1, 2)
		# poseidon
		self._cb['Poseidon'] = QCheckBox(names.planets['Poseidon'], self)
		uranianGrid.addWidget(self._cb['Poseidon'], 1, 3)
		
		# ### others fictitious ###
		othersWidget = QWidget()
		tabs.addTab(othersWidget, tr('Others'))
		othersGrid = QGridLayout()
		othersWidget.setLayout(othersGrid)
		# isis
		self._cb['Isis'] = QCheckBox(names.planets['Isis'], self)
		othersGrid.addWidget(self._cb['Isis'], 0, 0)
		# nibiru
		self._cb['Nibiru'] = QCheckBox(names.planets['Nibiru'], self)
		othersGrid.addWidget(self._cb['Nibiru'], 0, 1)
		# harrington
		self._cb['Harrington'] = QCheckBox(names.planets['Harrington'], self)
		othersGrid.addWidget(self._cb['Harrington'], 0, 2)
		# neptune (leverrier)
		self._cb['Neptune (Leverrier)'] = QCheckBox(names.planets['Neptune (Leverrier)'], self)
		othersGrid.addWidget(self._cb['Neptune (Leverrier)'], 0, 3)
		# neptune (adams)
		self._cb['Neptune (Adams)'] = QCheckBox(names.planets['Neptune (Adams)'], self)
		othersGrid.addWidget(self._cb['Neptune (Adams)'], 1, 0)
		# pluto (lowell)
		self._cb['Pluto (Lowell)'] = QCheckBox(names.planets['Pluto (Lowell)'], self)
		othersGrid.addWidget(self._cb['Pluto (Lowell)'], 1, 1)
		# pluto (pickering)
		self._cb['Pluto (Pickering)'] = QCheckBox(names.planets['Pluto (Pickering)'], self)
		othersGrid.addWidget(self._cb['Pluto (Pickering)'], 1, 2)
		# vulcan
		self._cb['Vulcan'] = QCheckBox(names.planets['Vulcan'], self)
		othersGrid.addWidget(self._cb['Vulcan'], 1, 3)
		# white moon
		self._cb['White Moon'] = QCheckBox(names.planets['White Moon'], self)
		othersGrid.addWidget(self._cb['White Moon'], 2, 0)
		# proserpina
		self._cb['Proserpina'] = QCheckBox(names.planets['Proserpina'], self)
		othersGrid.addWidget(self._cb['Proserpina'], 2, 1)
		# waldemath
		self._cb['Waldemath'] = QCheckBox(names.planets['Waldemath'], self)
		othersGrid.addWidget(self._cb['Waldemath'], 2, 2)
		# ### cusps ###
		cuspsWidget = QWidget()
		tabs.addTab(cuspsWidget, tr('Cusps'))
		cuspsGrid = QGridLayout()
		cuspsWidget.setLayout(cuspsGrid)
		# house cusps
		x = (0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2)
		y = (0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3)
		for i in range(12):
			self._cb['Cusp %.2d' % (i+1,)] = QCheckBox(
				names.houses['Cusp %.2d' % (i+1,)], self)
			cuspsGrid.addWidget(self._cb['Cusp %.2d' % (i+1,)], x[i], y[i])
		# asc
		self._cb['Asc'] = QCheckBox(names.planets['Asc'], self)
		cuspsGrid.addWidget(self._cb['Asc'], 3, 0)
		# mc
		self._cb['Mc'] = QCheckBox(names.planets['Mc'], self)
		cuspsGrid.addWidget(self._cb['Mc'], 3, 1)
		# dsc
		self._cb['Dsc'] = QCheckBox(names.planets['Dsc'], self)
		cuspsGrid.addWidget(self._cb['Dsc'], 3, 2)
		# ic
		self._cb['Ic'] = QCheckBox(names.planets['Ic'], self)
		cuspsGrid.addWidget(self._cb['Ic'], 3, 3)
		# armc
		self._cb['Armc'] = QCheckBox(names.planets['Armc'], self)
		cuspsGrid.addWidget(self._cb['Armc'], 4, 0)
		# vertex
		self._cb['Vertex'] = QCheckBox(names.planets['Vertex'], self)
		cuspsGrid.addWidget(self._cb['Vertex'], 4, 1)
		# equatorial asc
		self._cb['Equatorial Ascendant'] = QCheckBox(names.planets['Equatorial Ascendant'], self)
		cuspsGrid.addWidget(self._cb['Equatorial Ascendant'], 4, 2)
		# co-ascendant (koch)
		self._cb['Co-ascendant (Koch)'] = QCheckBox(names.planets['Co-ascendant (Koch)'], self)
		cuspsGrid.addWidget(self._cb['Co-ascendant (Koch)'], 4, 3)
		# co-ascendant (munkasey)
		self._cb['Co-ascendant (Munkasey)'] = QCheckBox(names.planets['Co-ascendant (Munkasey)'], self)
		cuspsGrid.addWidget(self._cb['Co-ascendant (Munkasey)'], 5, 0)
		# polar ascendant
		self._cb['Polar Ascendant (Munkasey)'] = QCheckBox(names.planets['Polar Ascendant (Munkasey)'], self)
		cuspsGrid.addWidget(self._cb['Polar Ascendant (Munkasey)'], 5, 1)
		
		# ### gauquelin ###
		gauquelinWidget = QWidget()
		tabs.addTab(gauquelinWidget, tr('Gauquelin'))
		gauquelinGrid = QGridLayout()
		gauquelinWidget.setLayout(gauquelinGrid)
		# sectors
		x = (0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,5,5)
		y = (0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5)
		for i in range(36):
			self._cb['Sector %.2d' % (i+1,)] = QCheckBox(
				names.houses['Sector %.2d' % (i+1,)], self)
			gauquelinGrid.addWidget(self._cb['Sector %.2d' % (i+1,)], x[i], y[i])
		
		# ### parts ###
		partsWidget = QWidget()
		tabs.addTab(partsWidget, tr('Parts'))
		partsGrid = QGridLayout()
		partsWidget.setLayout(partsGrid)
		# part of fortune (rudhyar)
		self._cb['Part of Fortune (Rudhyar)'] = QCheckBox(names.planets['Part of Fortune (Rudhyar)'], self)
		partsGrid.addWidget(self._cb['Part of Fortune (Rudhyar)'], 0, 0)
		
		# ### fixed stars ###
		# get all stars
		sql = 'select name from Planets where family = 2 order by name;'
		res = db.execute(sql).fetchall()
		# stars tab
		starsScroll = QScrollArea(self)
		starsScroll.setWidgetResizable(True)
		starsWidget = QWidget()
		starsScroll.setWidget(starsWidget)
		tabs.addTab(starsScroll, tr('Stars'))
		starsGrid = QGridLayout()
		starsWidget.setLayout(starsGrid)
		y = 0
		for i, star in enumerate(res):
			s = str(star[0])
			self._cb[s] = QCheckBox(s, self)
			starsGrid.addWidget(self._cb[s], y, i % 6)
			if i % 6 == 5:
				y += 1
		
		# ### asteroids ###
		# get all asteroids
		sql = 'select name from Planets where family = 3 order by name;'
		res = db.execute(sql).fetchall()
		# asteroids tab
		asteroidsScroll = QScrollArea()
		asteroidsScroll.setWidgetResizable(True)
		asteroidsWidget = QWidget()
		asteroidsScroll.setWidget(asteroidsWidget)
		tabs.addTab(asteroidsScroll, tr('Asteroids'))
		asteroidsGrid = QGridLayout()
		asteroidsWidget.setLayout(asteroidsGrid)
		y = 0
		for i, ast in enumerate(res):
			s = str(ast[0])
			self._cb[s] = QCheckBox(s, self)
			asteroidsGrid.addWidget(self._cb[s], y, i % 6)
			if i % 6 == 5:
				y += 1
		
		# ### end planets ###
		
		# comment
		grid.addWidget(QLabel(tr('Comment')), 2, 0, Qt.AlignTop)
		self.commentEdit = QTextEdit('', self)
		grid.addWidget(self.commentEdit, 2, 1)
		# buttons
		buttonsLayout = QHBoxLayout()
		resetButton = QPushButton(tr('Reset'), self)
		self.connect(resetButton, SIGNAL('clicked()'), self.reset)
		buttonsLayout.addWidget(resetButton)
		cancelButton = QPushButton(tr('Cancel'), self)
		self.connect(cancelButton, SIGNAL('clicked()'), self.reject)
		buttonsLayout.addWidget(cancelButton)
		okButton = QPushButton(tr('Ok'), self)
		okButton.setDefault(True)
		self.connect(okButton, SIGNAL('clicked()'), self.accept)
		buttonsLayout.addWidget(okButton)
		grid.addLayout(buttonsLayout, 3, 0, 1, 2)
		# load entries
		self.reset()
		# resize
		self.resize(550, 300)
	
	def reset(self):
		"""Reset entries."""
		# name
		self.nameEdit.setText(self._filt._name)
		# comment
		self.commentEdit.setPlainText(self._filt._comment)
		# values
		for pl, val in self._filt.items():
				self._cb[pl].setChecked(val)
	
	def accept(self):
		"""Set filter new values and save."""
		tr = self.tr
		# name
		name = unicode(self.nameEdit.text())
		if name == '':
			QMessageBox.critical(self, tr('Missing Name'),
				tr('Please set filter name.'))
			self.nameEdit.setFocus()
			return
		# comment
		cmt = unicode(self.commentEdit.toPlainText())
		# set values
		self._filt.set(name=name, comment=cmt)
		for pl, cb in self._cb.items():
			self._filt[pl] = cb.isChecked()
		# save
		try:
			self._filt.save()
		except ValueError: # duplicate filter
			QMessageBox.critical(self, tr('Error'),
				unicode(tr('Duplicate filter name \xab %(filter)s \xbb.')) % {
					'filter': self._filt._name})
			self.nameEdit.setFocus()
			return
		# reload cfg in case filter is default,
		# and opened charts if using this filter
		if __name__ != '__main__':
			app.aspectsRestrictionsUpdatedEvent(self._filt._idx_)
		# done
		self.done(QDialog.Accepted) class OrbsRestrictionsDialog(QDialog):
	
	def __init__(self, parent=None, filt=None):
		QDialog.__init__(self, parent)
		self._parent = parent
		tr = self.tr
		if isinstance(filt, OrbsRestrictions):
			self._filt = filt
			title = unicode(tr('Edit Orbs Restrictions \xab %(filter)s \xbb')) % {
				'filter': filt._name}
		else:
			self._filt = OrbsRestrictions(cfg.dft_filter._orbrestr._idx_)
			self._filt._idx_ = None # copy dft filter and set idx to None
			title = tr('New Orbs Restrictions')
		self.setWindowTitle(title)
		# size
		self.setMinimumWidth(500)
		self.setMinimumHeight(450)
		self.setSizeGripEnabled(True)
		# layout
		grid = QGridLayout(self)
		self.setLayout(grid)
		# filter name
		grid.addWidget(QLabel(tr('Filter name')), 0, 0)
		self.nameEdit = QLineEdit(self)
		grid.addWidget(self.nameEdit, 0, 1)
		# tab widget
		tabs = QTabWidget(self)
		grid.addWidget(tabs, 1, 0, 1, 2)
		self._sb = dict() ## holds the spinboxes
		
		# ### main planets ###
		mainWidget = QWidget()
		tabs.addTab(mainWidget, tr('Main', 'Main planets'))
		mainGrid = QGridLayout()
		mainWidget.setLayout(mainGrid)
		# sun
		mainGrid.addWidget(QLabel(names.planets['Sun']), 0, 0)
		self._sb['Sun'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Sun'], 0, 1)
		# moon
		mainGrid.addWidget(QLabel(names.planets['Moon']), 0, 2)
		self._sb['Moon'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Moon'], 0, 3)
		# mercury
		mainGrid.addWidget(QLabel(names.planets['Mercury']), 0, 4)
		self._sb['Mercury'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Mercury'], 0, 5)
		# venus
		mainGrid.addWidget(QLabel(names.planets['Venus']), 0, 6)
		self._sb['Venus'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Venus'], 0, 7)
		# mars
		mainGrid.addWidget(QLabel(names.planets['Mars']), 1, 0)
		self._sb['Mars'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Mars'], 1, 1)
		# jupiter
		mainGrid.addWidget(QLabel(names.planets['Jupiter']), 1, 2)
		self._sb['Jupiter'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Jupiter'], 1, 3)
		# saturn
		mainGrid.addWidget(QLabel(names.planets['Saturn']), 1, 4)
		self._sb['Saturn'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Saturn'], 1, 5)
		# uranus
		mainGrid.addWidget(QLabel(names.planets['Uranus']), 1, 6)
		self._sb['Uranus'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Uranus'], 1, 7)
		# neptune
		mainGrid.addWidget(QLabel(names.planets['Neptune']), 2, 0)
		self._sb['Neptune'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Neptune'], 2, 1)
		# pluto
		mainGrid.addWidget(QLabel(names.planets['Pluto']), 2, 2)
		self._sb['Pluto'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Pluto'], 2, 3)
		# earth
		mainGrid.addWidget(QLabel(names.planets['Earth']), 2, 4)
		self._sb['Earth'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Earth'], 2, 5)
		# chiron
		mainGrid.addWidget(QLabel(names.planets['Chiron']), 2, 6)
		self._sb['Chiron'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Chiron'], 2, 7)
		# pholus
		mainGrid.addWidget(QLabel(names.planets['Pholus']), 3, 0)
		self._sb['Pholus'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Pholus'], 3, 1)
		# ceres
		mainGrid.addWidget(QLabel(names.planets['Ceres']), 3, 2)
		self._sb['Ceres'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Ceres'], 3, 3)
		# pallas
		mainGrid.addWidget(QLabel(names.planets['Pallas']), 3, 4)
		self._sb['Pallas'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Pallas'], 3, 5)
		# juno
		mainGrid.addWidget(QLabel(names.planets['Juno']), 3, 6)
		self._sb['Juno'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Juno'], 3, 7)
		# vesta
		mainGrid.addWidget(QLabel(names.planets['Vesta']), 4, 0)
		self._sb['Vesta'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Vesta'], 4, 1)
		# rahu (mean)
		mainGrid.addWidget(QLabel(names.planets['Rahu (mean)']), 4, 2)
		self._sb['Rahu (mean)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Rahu (mean)'], 4, 3)
		# rahu (true)
		mainGrid.addWidget(QLabel(names.planets['Rahu (true)']), 4, 4)
		self._sb['Rahu (true)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Rahu (true)'], 4, 5)
		# ketu (mean)
		mainGrid.addWidget(QLabel(names.planets['Ketu (mean)']), 4, 6)
		self._sb['Ketu (mean)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Ketu (mean)'], 4, 7)
		# ketu (true)
		mainGrid.addWidget(QLabel(names.planets['Ketu (true)']), 5, 0)
		self._sb['Ketu (true)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Ketu (true)'], 5, 1)
		# lilith (mean)
		mainGrid.addWidget(QLabel(names.planets['Lilith (mean)']), 5, 2)
		self._sb['Lilith (mean)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Lilith (mean)'], 5, 3)
		# lilith (true)
		mainGrid.addWidget(QLabel(names.planets['Lilith (true)']), 5, 4)
		self._sb['Lilith (true)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Lilith (true)'], 5, 5)
		# priapus (mean)
		mainGrid.addWidget(QLabel(names.planets['Priapus (mean)']), 5, 6)
		self._sb['Priapus (mean)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Priapus (mean)'], 5, 7)
		# priapus (true)
		mainGrid.addWidget(QLabel(names.planets['Priapus (true)']), 6, 0)
		self._sb['Priapus (true)'] = OrbModifierSpinBox(self)
		mainGrid.addWidget(self._sb['Priapus (true)'], 6, 1)
		
		# ### uranians ###
		uranianWidget = QWidget()
		tabs.addTab(uranianWidget, tr('Uranians'))
		uranianGrid = QGridLayout()
		uranianWidget.setLayout(uranianGrid)
		# cupido
		uranianGrid.addWidget(QLabel(names.planets['Cupido']), 0, 0)
		self._sb['Cupido'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Cupido'], 0, 1)
		# hades
		uranianGrid.addWidget(QLabel(names.planets['Hades']), 0, 2)
		self._sb['Hades'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Hades'], 0, 3)
		# zeus
		uranianGrid.addWidget(QLabel(names.planets['Zeus']), 0, 4)
		self._sb['Zeus'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Zeus'], 0, 5)
		# kronos
		uranianGrid.addWidget(QLabel(names.planets['Kronos']), 0, 6)
		self._sb['Kronos'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Kronos'], 0, 7)
		# apollon
		uranianGrid.addWidget(QLabel(names.planets['Apollon']), 1, 0)
		self._sb['Apollon'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Apollon'], 1, 1)
		# admetos
		uranianGrid.addWidget(QLabel(names.planets['Admetos']), 1, 2)
		self._sb['Admetos'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Admetos'], 1, 3)
		# vulkanus
		uranianGrid.addWidget(QLabel(names.planets['Vulkanus']), 1, 4)
		self._sb['Vulkanus'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Vulkanus'], 1, 5)
		# poseidon
		uranianGrid.addWidget(QLabel(names.planets['Poseidon']), 1, 6)
		self._sb['Poseidon'] = OrbModifierSpinBox(self)
		uranianGrid.addWidget(self._sb['Poseidon'], 1, 7)
		
		# ### others fictitious ###
		othersWidget = QWidget()
		tabs.addTab(othersWidget, tr('Others'))
		othersGrid = QGridLayout()
		othersWidget.setLayout(othersGrid)
		# isis
		othersGrid.addWidget(QLabel(names.planets['Isis']), 0, 0)
		self._sb['Isis'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Isis'], 0, 1)
		# nibiru
		othersGrid.addWidget(QLabel(names.planets['Nibiru']), 0, 2)
		self._sb['Nibiru'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Nibiru'], 0, 3)
		# harrington
		othersGrid.addWidget(QLabel(names.planets['Harrington']), 0, 4)
		self._sb['Harrington'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Harrington'], 0, 5)
		# neptune (leverrier)
		othersGrid.addWidget(QLabel(names.planets['Neptune (Leverrier)']), 0, 6)
		self._sb['Neptune (Leverrier)'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Neptune (Leverrier)'], 0, 7)
		# neptune (adams)
		othersGrid.addWidget(QLabel(names.planets['Neptune (Adams)']), 1, 0)
		self._sb['Neptune (Adams)'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Neptune (Adams)'], 1, 1)
		# pluto (lowell)
		othersGrid.addWidget(QLabel(names.planets['Pluto (Lowell)']), 1, 2)
		self._sb['Pluto (Lowell)'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Pluto (Lowell)'], 1, 3)
		# pluto (pickering)
		othersGrid.addWidget(QLabel(names.planets['Pluto (Pickering)']), 1, 4)
		self._sb['Pluto (Pickering)'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Pluto (Pickering)'], 1, 5)
		# vulcan
		othersGrid.addWidget(QLabel(names.planets['Vulcan']), 1, 6)
		self._sb['Vulcan'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Vulcan'], 1, 7)
		# white moon
		othersGrid.addWidget(QLabel(names.planets['White Moon']), 2, 0)
		self._sb['White Moon'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['White Moon'], 2, 1)
		# proserpina
		othersGrid.addWidget(QLabel(names.planets['Proserpina']), 2, 2)
		self._sb['Proserpina'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Proserpina'], 2, 3)
		# waldemath
		othersGrid.addWidget(QLabel(names.planets['Waldemath']), 2, 4)
		self._sb['Waldemath'] = OrbModifierSpinBox(self)
		othersGrid.addWidget(self._sb['Waldemath'], 2, 5)
		
		# ### cusps ###
		cuspsWidget = QWidget()
		tabs.addTab(cuspsWidget, tr('Cusps'))
		cuspsGrid = QGridLayout()
		cuspsWidget.setLayout(cuspsGrid)
		# house cusps
		x = (0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2)
		y = (0, 2, 4, 6, 0, 2, 4, 6, 0, 2, 4, 6)
		for i in range(12):
			cuspsGrid.addWidget(QLabel(
				names.houses['Cusp %.2d' % (i+1,)]), x[i], y[i])
			self._sb['Cusp %.2d' % (i+1,)] = OrbModifierSpinBox(self)
			cuspsGrid.addWidget(self._sb['Cusp %.2d' % (i+1,)], x[i], y[i]+1)
		# asc
		cuspsGrid.addWidget(QLabel(names.planets['Asc']), 3, 0)
		self._sb['Asc'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Asc'], 3, 1)
		# mc
		cuspsGrid.addWidget(QLabel(names.planets['Mc']), 3, 2)
		self._sb['Mc'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Mc'], 3, 3)
		# dsc
		cuspsGrid.addWidget(QLabel(names.planets['Dsc']), 3, 4)
		self._sb['Dsc'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Dsc'], 3, 5)
		# ic
		cuspsGrid.addWidget(QLabel(names.planets['Ic']), 3, 6)
		self._sb['Ic'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Ic'], 3, 7)
		# armc
		cuspsGrid.addWidget(QLabel(names.planets['Armc']), 4, 0)
		self._sb['Armc'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Armc'], 4, 1)
		# vertex
		cuspsGrid.addWidget(QLabel(names.planets['Vertex']), 4, 2)
		self._sb['Vertex'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Vertex'], 4, 3)
		# equatorial asc
		cuspsGrid.addWidget(QLabel(names.planets['Equatorial Ascendant']), 4, 4)
		self._sb['Equatorial Ascendant'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Equatorial Ascendant'], 4, 5)
		# co-ascendant (koch)
		cuspsGrid.addWidget(QLabel(names.planets['Co-ascendant (Koch)']), 4, 6)
		self._sb['Co-ascendant (Koch)'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Co-ascendant (Koch)'], 4, 7)
		# co-ascendant (munkasey)
		cuspsGrid.addWidget(QLabel(names.planets['Co-ascendant (Munkasey)']), 5, 0)
		self._sb['Co-ascendant (Munkasey)'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Co-ascendant (Munkasey)'], 5, 1)
		# polar ascendant
		cuspsGrid.addWidget(QLabel(names.planets['Polar Ascendant (Munkasey)']), 5, 2)
		self._sb['Polar Ascendant (Munkasey)'] = OrbModifierSpinBox(self)
		cuspsGrid.addWidget(self._sb['Polar Ascendant (Munkasey)'], 5, 3)
		
		# ### gauquelin ###
		gauquelinWidget = QWidget()
		tabs.addTab(gauquelinWidget, tr('Gauquelin'))
		gauquelinGrid = QGridLayout()
		gauquelinWidget.setLayout(gauquelinGrid)
		# sectors
		x = (0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8)
		y = (0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6,0,2,4,6)
		for i in range(36):
			gauquelinGrid.addWidget(QLabel(
				names.houses['Sector %.2d' % (i+1,)]), x[i], y[i])
			self._sb['Sector %.2d' % (i+1,)] = OrbModifierSpinBox(self)
			gauquelinGrid.addWidget(self._sb['Sector %.2d' % (i+1,)], x[i], y[i]+1)
		
		# ### parts ###
		partsWidget = QWidget()
		tabs.addTab(partsWidget, tr('Parts'))
		partsGrid = QGridLayout()
		partsWidget.setLayout(partsGrid)
		# part of fortune (rudhyar)
		partsGrid.addWidget(QLabel(
			names.planets['Part of Fortune (Rudhyar)']), 0, 0)
		self._sb['Part of Fortune (Rudhyar)'] = OrbModifierSpinBox(self)
		partsGrid.addWidget(self._sb['Part of Fortune (Rudhyar)'], 0, 1)
		
		# ### fixed stars ###
		# get all stars
		sql = 'select name from Planets where family = 2 order by name;'
		res = db.execute(sql).fetchall()
		# stars tab
		starsScroll = QScrollArea(self)
		starsScroll.setWidgetResizable(True)
		starsWidget = QWidget()
		starsScroll.setWidget(starsWidget)
		tabs.addTab(starsScroll, tr('Stars'))
		starsGrid = QGridLayout()
		starsWidget.setLayout(starsGrid)
		y = 0
		i = 0
		for star in res:
			s = str(star[0])
			starsGrid.addWidget(QLabel(s), y, i % 10)
			self._sb[s] = OrbModifierSpinBox(self)
			starsGrid.addWidget(self._sb[s], y, (i%10) + 1)
			if i % 10 == 8:
				y += 1
			i += 2
		
		# ### asteroids ###
		# get all asteroids
		sql = 'select name from Planets where family = 3 order by name;'
		res = db.execute(sql).fetchall()
		# asteroids tab
		asteroidsScroll = QScrollArea()
		asteroidsScroll.setWidgetResizable(True)
		asteroidsWidget = QWidget()
		asteroidsScroll.setWidget(asteroidsWidget)
		tabs.addTab(asteroidsScroll, tr('Asteroids'))
		asteroidsGrid = QGridLayout()
		asteroidsWidget.setLayout(asteroidsGrid)
		y = 0
		i = 0
		for ast in res:
			s = str(ast[0])
			asteroidsGrid.addWidget(QLabel(s), y, i % 10)
			self._sb[s] = OrbModifierSpinBox(self)
			asteroidsGrid.addWidget(self._sb[s], y, (i%10) + 1)
			if i % 10 == 8:
				y += 1
			i += 2
		
		# ### end planets ###
		
		# comment
		grid.addWidget(QLabel(tr('Comment')), 2, 0, Qt.AlignTop)
		self.commentEdit = QTextEdit('', self)
		grid.addWidget(self.commentEdit, 2, 1)
		# buttons
		buttonsLayout = QHBoxLayout()
		resetButton = QPushButton(tr('Reset'), self)
		self.connect(resetButton, SIGNAL('clicked()'), self.reset)
		buttonsLayout.addWidget(resetButton)
		cancelButton = QPushButton(tr('Cancel'), self)
		self.connect(cancelButton, SIGNAL('clicked()'), self.reject)
		buttonsLayout.addWidget(cancelButton)
		okButton = QPushButton(tr('Ok'), self)
		okButton.setDefault(True)
		self.connect(okButton, SIGNAL('clicked()'), self.accept)
		buttonsLayout.addWidget(okButton)
		grid.addLayout(buttonsLayout, 3, 0, 1, 2)
		# load entries
		self.reset()
		# resize
		self.resize(550, 300)
	
	def reset(self):
		"""Reset entries."""
		# name
		self.nameEdit.setText(self._filt._name)
		# comment
		self.commentEdit.setPlainText(self._filt._comment)
		# values
		for pl, val in self._filt.items():
				self._sb[pl].setValue(float(val.replace('%', '')))
	
	def accept(self):
		"""Set filter new values and save."""
		tr = self.tr
		# name
		name = unicode(self.nameEdit.text())
		if name == '':
			QMessageBox.critical(self, tr('Missing Name'),
				tr('Please set filter name.'))
			self.nameEdit.setFocus()
			return
		# comment
		cmt = unicode(self.commentEdit.toPlainText())
		# set values
		self._filt.set(name=name, comment=cmt)
		for pl, sb in self._sb.items():
			self._filt[pl] = '%s%%' % sb.value()
		# save
		try:
			self._filt.save()
		except ValueError: # duplicate filter
			QMessageBox.critical(self, tr('Error'),
				unicode(tr('Duplicate filter name \xab %(filter)s \xbb.')) % {
					'filter': self._filt._name})
			self.nameEdit.setFocus()
			return
		# reload cfg in case filter is default,
		# and opened charts if using this filter
		if __name__ != '__main__':
			app.orbsRestrictionsUpdatedEvent(self._filt._idx_)
		# done
		self.done(QDialog.Accepted) class MidPointsFilterDialog(QDialog):
	"""Mid-points filter settings."""
	
	def __init__(self, parent=None, filt=None):
		QDialog.__init__(self, parent)
		self._parent = parent
		tr = self.tr
		if isinstance(filt, MidPointsFilter):
			self._filt = filt
			title = unicode(tr('Edit MidPoints Filter \xab %(filter)s \xbb')) % {
				'filter': filt._name}
		else:
			self._filt = MidPointsFilter(cfg.dft_filter._midpoints._idx_)
			self._filt._idx_ = None # copy dft filter and set idx to None
			title = tr('New MidPoints Filter')
		self.setWindowTitle(title)
		# size
		self.setMinimumWidth(300)
		self.setMaximumHeight(300)
		self.setSizeGripEnabled(True)
		# layout
		grid = QGridLayout(self)
		self.setLayout(grid)
		# filter name
		grid.addWidget(QLabel(tr('Filter name')), 0, 0)
		self.nameEdit = QLineEdit(self)
		grid.addWidget(self.nameEdit, 0, 1)
		# midp planets filter
		grid.addWidget(QLabel(tr('Planets filter')), 1, 0)
		mppfLayout = QHBoxLayout()
		self.planetsEdit = QComboBox(self)
		self.planetsEdit.setEditable(False)
		mppfLayout.addWidget(self.planetsEdit)
		mppfButton = QToolButton(self)
		mppfButton.setIcon(QIcon(os.path.join(_baseDir, 'icons',
			'gtk-execute.png')))
		mppfButton.setToolTip(tr('Edit planets filter'))
		self.connect(mppfButton, SIGNAL('clicked()'), self.editPlanetsFilter)
		mppfLayout.addWidget(mppfButton)
		grid.addLayout(mppfLayout, 1, 1)
		# midp aspects filter
		grid.addWidget(QLabel(tr('Aspects filter')), 2, 0)
		mpafLayout = QHBoxLayout()
		self.aspectsEdit = QComboBox(self)
		self.aspectsEdit.setEditable(False)
		mpafLayout.addWidget(self.aspectsEdit)
		mpafButton = QToolButton(self)
		mpafButton.setIcon(QIcon(os.path.join(_baseDir, 'icons',
			'gtk-execute.png')))
		mpafButton.setToolTip(tr('Edit aspects filter'))
		self.connect(mpafButton, SIGNAL('clicked()'), self.editAspectsFilter)
		mpafLayout.addWidget(mpafButton)
		grid.addLayout(mpafLayout, 2, 1)
		# midp orbs filter
		grid.addWidget(QLabel(tr('Orbs filter')), 3, 0)
		mpofLayout = QHBoxLayout()
		self.orbsEdit = QComboBox(self)
		self.orbsEdit.setEditable(False)
		mpofLayout.addWidget(self.orbsEdit)
		mpofButton = QToolButton(self)
		mpofButton.setIcon(QIcon(os.path.join(_baseDir, 'icons',
			'gtk-execute.png')))
		mpofButton.setToolTip(tr('Edit orbs filter'))
		self.connect(mpofButton, SIGNAL('clicked()'), self.editOrbsFilter)
		mpofLayout.addWidget(mpofButton)
		grid.addLayout(mpofLayout, 3, 1)
		# midp aspects restrictions
		grid.addWidget(QLabel(tr('Aspects restrictions')), 4, 0)
		mparLayout = QHBoxLayout()
		self.asprestrEdit = QComboBox(self)
		self.asprestrEdit.setEditable(False)
		mparLayout.addWidget(self.asprestrEdit)
		mparButton = QToolButton(self)
		mparButton.setIcon(QIcon(os.path.join(_baseDir, 'icons',
			'gtk-execute.png')))
		mparButton.setToolTip(tr('Edit aspects restrictions'))
		self.connect(mparButton, SIGNAL('clicked()'), self.editAspectsRestrictions)
		mparLayout.addWidget(mparButton)
		grid.addLayout(mparLayout, 4, 1)
		# midp orbs restrictions
		grid.addWidget(QLabel(tr('Orbs modifiers')), 5, 0)
		mporLayout = QHBoxLayout()
		self.orbrestrEdit = QComboBox(self)
		self.orbrestrEdit.setEditable(False)
		mporLayout.addWidget(self.orbrestrEdit)
		mporButton = QToolButton(self)
		mporButton.setIcon(QIcon(os.path.join(_baseDir, 'icons',
			'gtk-execute.png')))
		mporButton.setToolTip(tr('Edit orbs restrictions'))
		self.connect(mporButton, SIGNAL('clicked()'), self.editOrbsRestrictions)
		mporLayout.addWidget(mporButton)
		grid.addLayout(mporLayout, 5, 1)
		# comment
		grid.addWidget(QLabel(tr('Comment')), 6, 0, Qt.AlignTop)
		self.commentEdit = QTextEdit('', self)
		grid.addWidget(self.commentEdit, 6, 1)
		
		# ### buttons ###
		buttonsLayout = QHBoxLayout()
		resetButton = QPushButton(tr('Reset'), self)
		self.connect(resetButton, SIGNAL('clicked()'), self.reset)
		buttonsLayout.addWidget(resetButton)
		cancelButton = QPushButton(tr('Cancel'), self)
		self.connect(cancelButton, SIGNAL('clicked()'), self.reject)
		buttonsLayout.addWidget(cancelButton)
		okButton = QPushButton(tr('Ok'), self)
		okButton.setDefault(True)
		self.connect(okButton, SIGNAL('clicked()'), self.accept)
		buttonsLayout.addWidget(okButton)
		grid.addLayout(buttonsLayout, 7, 0, 1, 2)
		# load entries
		self.reset()
	
	
	# ### edit midpoints filters ###
	
	def editPlanetsFilter(self):
		"""Open planets filter edit dialog."""
		pf = PlanetsFilter(
			all_planets_filters_names()[self.planetsEdit.currentIndex()])
		edit = PlanetsFilterDialog(self, pf)
		ok = edit.exec_()
		if ok: ## reset our filters
			if pf == self._filt._planets:
				self._filt._planets.reset()
			self.resetPlanetsFilters()
	
	def editAspectsFilter(self):
		"""Open aspects filter edit dialog."""
		af = AspectsFilter(
			all_aspects_filters_names()[self.aspectsEdit.currentIndex()])
		edit = AspectsFilterDialog(self, af)
		ok = edit.exec_()
		if ok: ## reset our filters
			if af == self._filt._aspects:
				self._filt._aspects.reset()
			self.resetAspectsFilters()
	
	def editOrbsFilter(self):
		of = OrbsFilter(
			all_orbs_filters_names()[self.orbsEdit.currentIndex()])
		edit = OrbsFilterDialog(self, of)
		ok = edit.exec_()
		if ok: ## reset our filters
			if of == self._filt._orbs:
				self._filt._orbs.reset()
			self.resetOrbsFilters()
	
	def editAspectsRestrictions(self):
		ar = AspectsRestrictions(
			all_aspects_restrictions_names()[self.asprestrEdit.currentIndex()])
		edit = AspectsRestrictionsDialog(self, ar)
		ok = edit.exec_()
		if ok: ## reset our filters
			if ar == self._filt._asprestr:
				self._filt._asprestr.reset()
			self.resetAspectsRestrictions()
	
	def editOrbsRestrictions(self):
		orb = OrbsRestrictions(
			all_orbs_restrictions_names()[self.orbrestrEdit.currentIndex()])
		edit = OrbsRestrictionsDialog(self, orb)
		ok = edit.exec_()
		if ok: ## reset our filters
			if orb == self._filt._orbrestr:
				self._filt._orbrestr.reset()
			self.resetOrbsRestrictions()
	
	# ### reset filters boxes ###
	
	def resetPlanetsFilters(self):
		"""Reset planets filter box."""
		self.planetsEdit.clear()
		all = all_planets_filters_names()
		self.planetsEdit.addItems(all)
		i = all.index(self._filt._planets._name)
		self.planetsEdit.setCurrentIndex(i)
	
	def resetAspectsFilters(self):
		"""Reset aspects filters box."""
		self.aspectsEdit.clear()
		all = all_aspects_filters_names()
		self.aspectsEdit.addItems(all)
		i = all.index(self._filt._aspects._name)
		self.aspectsEdit.setCurrentIndex(i)
	
	def resetOrbsFilters(self):
		"""Reset orbs filters box."""
		self.orbsEdit.clear()
		all = all_orbs_filters_names()
		self.orbsEdit.addItems(all)
		i = all.index(self._filt._orbs._name)
		self.orbsEdit.setCurrentIndex(i)
	
	def resetAspectsRestrictions(self):
		"""Reset aspects restrictions box."""
		self.asprestrEdit.clear()
		all = all_aspects_restrictions_names()
		self.asprestrEdit.addItems(all)
		i = all.index(self._filt._asprestr._name)
	
	def resetOrbsRestrictions(self):
		"""Reset orbs restrictions box."""
		self.orbrestrEdit.clear()
		all = all_orbs_restrictions_names()
		self.orbrestrEdit.addItems(all)
		i = all.index(self._filt._orbrestr._name)
		self.orbrestrEdit.setCurrentIndex(i)
	
	def reset(self):
		"""Reset entries."""
		filt = self._filt
		# name
		self.nameEdit.setText(filt._name)
		# planets
		self.resetPlanetsFilters()
		# aspects
		self.resetAspectsFilters()
		# orbs
		self.resetOrbsFilters()
		# aspects restrictions
		self.resetAspectsRestrictions()
		# orbs modifiers
		self.resetOrbsRestrictions()
		# comment
		self.commentEdit.setPlainText(filt._comment)
	
	def accept(self):
		"""Set filter new values and save."""
		tr = self.tr
		# name
		name = unicode(self.nameEdit.text())
		if name == '':
			QMessageBox.critical(self, tr('Missing Name'),
				tr('Please set filter name.'))
			self.nameEdit.setFocus()
			return
		# planets filter
		planets = PlanetsFilter(
			all_planets_filters_names()[self.planetsEdit.currentIndex()])
		# aspects filter
		aspects = AspectsFilter(
			all_aspects_filters_names()[self.aspectsEdit.currentIndex()])
		# orbs filter
		orbs = OrbsFilter(
			all_orbs_filters_names()[self.orbsEdit.currentIndex()])
		# aspects restrictions
		asprestr = AspectsRestrictions(
			all_aspects_restrictions_names()[self.asprestrEdit.currentIndex()])
		# orbs restrictions
		orbrestr = OrbsRestrictions(
			all_orbs_restrictions_names()[self.orbrestrEdit.currentIndex()])
		# comment
		cmt = unicode(self.commentEdit.toPlainText())
		# ### set filter ###
		self._filt.set(name=name, planets=planets, aspects=aspects, orbs=orbs,
			asprestr=asprestr, orbrestr=orbrestr, comment=cmt)
		# save
		try:
			self._filt.save()
		except ValueError: # duplicate filter
			QMessageBox.critical(self, tr('Error'),
				unicode(tr('Duplicate filter name \xab %(filter)s \xbb.')) % {
					'filter': self._filt._name})
			self.nameEdit.setFocus()
			return
		# reload cfg in case filter is default,
		# and opened charts if using this filter
		if __name__ != '__main__':
			app.midPointsFilterUpdatedEvent(self._filt._idx_)
		# done
		self.done(QDialog.Accepted)
import sys
import os.path
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from oroboros.core import cfg
from oroboros.core.filters import Filter
from oroboros.core.planetsfilters import PlanetsFilter, all_planets_filters_names
from oroboros.core.aspectsfilters import AspectsFilter, all_aspects_filters_names
from oroboros.core.orbsfilters import OrbsFilter, all_orbs_filters_names
from oroboros.core.aspectsrestrictions import AspectsRestrictions, all_aspects_restrictions_names
from oroboros.core.orbsrestrictions import OrbsRestrictions, all_orbs_restrictions_names
from oroboros.core.midpfilters import MidPointsFilter, all_midpoints_filters_names
from oroboros.gui import app
from oroboros.gui import names
from oroboros.gui.plntfilterdialog import PlanetsFilterDialog
from oroboros.gui.aspfilterdialog import AspectsFilterDialog
from oroboros.gui.orbfilterdialog import OrbsFilterDialog
from oroboros.gui.asprestrdialog import AspectsRestrictionsDialog
from oroboros.gui.orbrestrdialog import OrbsRestrictionsDialog
from oroboros.gui.midpfilterdialog import MidPointsFilterDialog
			i = 0
		elif xcentric == 'topo':
			i = 1
		elif xcentric == 'helio':
			i = 2
		else: # bary
			i = 3
		self.xcentricEdit.setCurrentIndex(i)
		# planets
		self.resetPlanetsFilters()
		# aspects
		self.resetAspectsFilters()
		# orbs
		self.resetOrbsFilters()
		# aspects restrictions
		self.resetAspectsRestrictions()
		# orbs modifiers
		self.resetOrbsRestrictions()
		# calc midp
		self.calc_midpEdit.setChecked(self._filt._calc_midp)
		# draw midp
		self.draw_midpEdit.setChecked(self._filt._draw_midp)
		# midpoints filter
		self.resetMidPointsFilters()
		# comment
		self.commentEdit.setPlainText(filt._comment)
	
	def accept(self):
		"""Set filter new values and save."""
		tr = self.tr
		# name
		name = unicode(self.nameEdit.text())
		if name == '':
			QMessageBox.critical(self, tr('Missing Name'),
				tr('Please set filter name.'))
			self.nameEdit.setFocus()
			return
		# bg color
		bg = self.bgcolorEdit.currentIndex()
		if bg == 0:
			bg = 'black'
		else:
			bg = 'white'
		# ephe type
		ephetype = self.ephetypeEdit.currentIndex()
		if ephetype == 0:
			ephetype = 'swiss'
		elif ephetype == 1:
			ephetype = 'jpl'
		else:
			ephetype = 'moshier'
		# ephe path
		ephepath = unicode(self.ephepathEdit.text())
		# hsys
		hsys = names.houseSystems[self.hsysEdit.currentIndex()][0]
		# sidereal mode
		sidm = names.sidModes[self.sidmodeEdit.currentIndex()][0]
		# sidereal t0
		sidt0 = self.sidt0Edit.value()
		# sidereal ayanamsa t0
		sidayant0 = self.sidayant0Edit.value()
		# true pos
		truepos = False if self.trueposEdit.currentIndex() == 0 else True
		# xcentric
		xcentric = self.xcentricEdit.currentIndex()
		if xcentric == 0:
			xcentric = 'geo'
		elif xcentric == 1:
			xcentric = 'topo'
		elif xcentric == 2:
			xcentric = 'helio'
		else:
			xcentric = 'bary'
		# planets filter
		planets = all_planets_filters_names()[self.planetsEdit.currentIndex()]
		# aspects filter
		aspects = all_aspects_filters_names()[self.aspectsEdit.currentIndex()]
		# orbs filter
		orbs = all_orbs_filters_names()[self.orbsEdit.currentIndex()]
		# aspects restrictions
		asprestr = all_aspects_restrictions_names()[self.asprestrEdit.currentIndex()]
		# orbs restrictions
		orbrestr = all_orbs_restrictions_names()[self.orbrestrEdit.currentIndex()]
		# midpoints settings
		calc_midp = self.calc_midpEdit.isChecked()
		draw_midp = self.draw_midpEdit.isChecked()
		# midpoints filter
		midpoints = all_midpoints_filters_names()[self.midpointsEdit.currentIndex()]
		# comment
		cmt = unicode(self.commentEdit.toPlainText())
		# ### set filter ###
		self._filt.set(name=name, bg_color=bg, ephe_type=ephetype,
			ephe_path=ephepath, hsys=hsys, sid_mode=sidm, sid_t0=sidt0,
			sid_ayan_t0=sidayant0, true_pos=truepos, xcentric=xcentric,
			calc_midp=calc_midp, draw_midp=draw_midp,
			planets=planets, aspects=aspects, orbs=orbs, asprestr=asprestr,
			orbrestr=orbrestr, midpoints=midpoints, comment=cmt)
		# save
		try:
			self._filt.save()
		except ValueError: # duplicate filter
			QMessageBox.critical(self, tr('Error'),
				unicode(tr('Duplicate filter name \xab %(filter)s \xbb.')) % {
					'filter': self._filt._name})
			self.nameEdit.setFocus()
			return
		# reload cfg in case filter is default,
		# and opened charts if using this filter
		if __name__ != '__main__':
			app.filterUpdatedEvent(self._filt._idx_)
		# done
		self.done(QDialog.Accepted)



## oroboros.ui.filterdialog.main
def main():
	app = QApplication(sys.argv)
	main = FilterDialog()
	main.show()

	sys.exit(app.exec_())