예제 #1
0
 def __generic_init(self):
     # Attributes which store objects hidden behind properties
     self.__source = None
     self.__ship = None
     self.__character_proxy = None
     self.__character_core = None
     # Eos fit will be primary point of using Eos calculation engine for
     # fit-specific data
     self._eos_fit = EosFit()
     # Manages fit-specific data needed for undo/redo
     self._cmd_mgr = CommandManager(100)
     # There's little sense in changing proxy character, thus we assign
     # it here and it stays with fit forever
     self.__set_character_proxy(CharacterProxy())
예제 #2
0
class Fit(PyfaBase):
    """
    Full pyfa model of fit:
    .fit
      .character_core (read-write fit-agnostic)
        .RestrictedSet(skills)
      .character_proxy (read-only fit-specific)
        .RestrictedSet(skills)
      .ship
        .stance
        .{subsystems}
        .modules.[high]/[med]/[low]
    """

    __tablename__ = 'fits'

    id = Column('fit_id', Integer, primary_key=True)
    name = Column('fit_name', String, nullable=False)
    _db_ship_type_id = Column('ship_type_id', Integer)
    _db_stance_type_id = Column('stance_type_id', Integer)

    _db_character_id = Column('character_id', Integer, ForeignKey('characters.character_id'))
    _db_character = relationship('Character')

    def __init__(self, name='', source=None, ship=None):
        self.__generic_init()
        # Use default source, unless specified otherwise
        if source is None:
            source = SourceManager.default
        self._set_source(source)
        self._set_ship(ship)
        self.name = name

    @reconstructor
    def _dbinit(self):
        self.__generic_init()
        # Use default source for all reconstructed fits
        self._set_source(SourceManager.default)
        # Restore entities which are stored on fit in DB
        if self._db_ship_type_id is not None:
            self._set_ship(Ship(self._db_ship_type_id))
            if self._db_stance_type_id is not None:
                self.ship._set_stance(Stance(self._db_stance_type_id))
            # TODO: find appropriate way to reconstruct modules
            for module in self._db_modules:
                pass
            for subsystem in self._db_subsystems:
                self.ship.subsystems._add_to_set(subsystem)
        self.character_core = self._db_character

    def __generic_init(self):
        # Attributes which store objects hidden behind properties
        self.__source = None
        self.__ship = None
        self.__character_proxy = None
        self.__character_core = None
        # Eos fit will be primary point of using Eos calculation engine for
        # fit-specific data
        self._eos_fit = EosFit()
        # Manages fit-specific data needed for undo/redo
        self._cmd_mgr = CommandManager(100)
        # There's little sense in changing proxy character, thus we assign
        # it here and it stays with fit forever
        self.__set_character_proxy(CharacterProxy())

    # Define list of source-dependent child objects, it's necessary
    # to update fit source
    @property
    def _src_children(self):
        return get_src_children(chain(
            (self.ship,),
            # Just proxy, character core is completely separate entity with
            # its own source management
            (self.character_proxy,),
        ))

    # Read-only info
    @property
    def stats(self):
        return self._eos_fit.stats

    # Children getters/setters
    @property
    def character_core(self):
        return self.__character_core

    @character_core.setter
    def character_core(self, new_char_core):
        old_char_core = self.__character_core
        if new_char_core is old_char_core:
            return
        # Update child reference
        self.__character_core = new_char_core
        # Update DB
        self._db_character = new_char_core
        # Handle all interactions between new character core and
        # character proxy (which is attached to this fit) on proxy
        # side
        self.character_proxy._parent_char_core = new_char_core

    @property
    def character_proxy(self):
        """
        For character proxy we're not providing setter because it's
        supposed to stay with fit all the time.
        """
        return self.__character_proxy

    def __set_character_proxy(self, new_char_proxy):
        old_char_proxy = self.__character_proxy
        if new_char_proxy is old_char_proxy:
            return
        if old_char_proxy is not None:
            if old_char_proxy._parent_fit is not self:
                raise ItemRemovalConsistencyError(old_char_proxy)
            # Handle all character proxy children removal on proxy itself
            old_char_proxy._parent_fit = None
        # Update child reference
        self.__character_proxy = new_char_proxy
        if new_char_proxy is not None:
            if new_char_proxy._parent_fit is not None:
                raise ItemAlreadyUsedError(new_char_proxy)
            # Handle all character proxy children addition on proxy itself
            new_char_proxy._parent_fit = self

    @property
    def ship(self):
        return self.__ship

    @ship.setter
    def ship(self, new_ship):
        command = ShipChangeCommand(self, new_ship)
        self._cmd_mgr.do(command)

    def _set_ship(self, new_ship):
        old_ship = self.__ship
        if new_ship is old_ship:
            return
        if old_ship is not None:
            if old_ship._parent_fit is not self:
                raise ItemRemovalConsistencyError(old_ship)
            old_ship._parent_fit = None
        self.__ship = new_ship
        if new_ship is not None:
            if new_ship._parent_fit is not None:
                raise ItemAlreadyUsedError(new_ship)
            new_ship._parent_fit = self

    # Undo/redo proxies
    @property
    def has_undo(self):
        return self._cmd_mgr.has_undo

    @property
    def has_redo(self):
        return self._cmd_mgr.has_redo

    def undo(self):
        self._cmd_mgr.undo()

    def redo(self):
        self._cmd_mgr.redo()

    def purge_commands(self):
        """
        Purge all undos/redos fit currently has. Useful when you want to
        do some initial setup on the fit, and then purge commands to present
        fit without undo queue.
        """
        self._cmd_mgr.purge()

    # Miscellanea public stuff
    @property
    def source(self):
        return self.__source

    @source.setter
    def source(self, new_source):
        command = SourceChangeCommand(self, new_source)
        self._cmd_mgr.do(command)

    def _set_source(self, new_source):
        """
        Set fit's source. Source represents EVE data to be used.

        Required arguments:
        new_source -- source to use, can be None
        """
        # Attempt to fetch source from source manager if passed object
        # is not instance of source class
        if not isinstance(new_source, Source) and new_source is not None:
            new_source = SourceManager.get(new_source)
        old_source = self.source
        # Do not update anything if sources are the same
        if new_source is old_source:
            return
        self.__source = new_source
        # Update eos model with new data
        self._eos_fit.source = getattr(new_source, 'eos', None)
        # Update pyfa model with new data
        for src_child in self._src_children:
            src_child._update_source()

    persist = pyfa_persist
    abandon = pyfa_abandon

    def validate(self):
        self._eos_fit.validate()

    # Auxiliary methods
    def __repr__(self):
        spec = ['id']
        return make_repr_str(self, spec)