Exemple #1
0
 def __init__(self, view):
     super(_RefreshBtnStateController, self).__init__()
     self.__view = weakref.proxy(view)
     self.__cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
     self.__isEnabled = False
     self.__tooltip = None
     self.__isInCooldown = False
     return
Exemple #2
0
 def __init__(self, *args):
     super(ClanInvitesWindow, self).__init__()
     self.__actualRequestsCount = '0'
     self.__processedInvitesCount = '0'
     self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
     self.__clanDbID = self.clanProfile.getClanDbID()
     self.__clanDossier = weakref.proxy(self.clansCtrl.getClanDossier(self.__clanDbID))
     self.__pagiatorsController = _PaginatorsController(self.__clanDbID)
Exemple #3
0
 def __init__(self):
     super(CyberSportUnitsListView, self).__init__()
     self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
     self._cooldown = CooldownHelper(self.getCoolDownRequests(),
                                     self._onCooldownHandle,
                                     events.CoolDownEvent.PREBATTLE)
     self.__currentEmblem = None
     return
 def __init__(self, ctx):
     super(ClanSearchWindow, self).__init__()
     self.__clanFinder = ClanFinder(self.clansCtrl, None, _SEARCH_LIMIT)
     self.__clanFinder.init()
     self._cooldown = CooldownHelper(self.__coolDownRequests,
                                     self._onCooldownHandle,
                                     CoolDownEvent.CLAN)
     self.__isFirstPageRequested = False
     self.__invitesLimitReached = False
     return
 def __init__(self):
     super(CyberSportUnitsListView, self).__init__()
     self._isBackButtonClicked = False
     self._section = 'selectedListVehicles'
     self._selectedVehicles = self.unitFunctional.getSelectedVehicles(
         self._section)
     self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
     self._cooldown = CooldownHelper(self.getCoolDownRequests(),
                                     self._onCooldownHandle,
                                     events.CoolDownEvent.PREBATTLE)
Exemple #6
0
 def __init__(self):
     super(ClanRequestsView, self).__init__()
     self._cooldown = CooldownHelper([CLAN_REQUESTED_DATA_TYPE.CREATE_APPLICATIONS,
      CLAN_REQUESTED_DATA_TYPE.CREATE_INVITES,
      CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
      CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES,
      CLAN_REQUESTED_DATA_TYPE.CLAN_INVITES,
      CLAN_REQUESTED_DATA_TYPE.CLAN_MEMBERS_RATING], self._onCooldownHandle, CoolDownEvent.CLAN)
 def __init__(self):
     super(ClanPersonalInvitesView, self).__init__()
     self._paginator = ClanPersonalInvitesPaginator(self.webCtrl, getPlayerDatabaseID(), [CLAN_INVITE_STATES.ACTIVE])
     self._cooldown = CooldownHelper([WebRequestDataType.ACCEPT_APPLICATION,
      WebRequestDataType.ACCEPT_INVITE,
      WebRequestDataType.DECLINE_APPLICATION,
      WebRequestDataType.DECLINE_INVITE,
      WebRequestDataType.DECLINE_INVITES,
      WebRequestDataType.CLANS_INFO,
      WebRequestDataType.CLAN_RATINGS,
      WebRequestDataType.ACCOUNT_INVITES], self._onCooldownHandle, CoolDownEvent.WGCG)
class _RefreshBtnStateController(object):
    __coolDownRequests = [
        CLAN_REQUESTED_DATA_TYPE.CREATE_APPLICATIONS,
        CLAN_REQUESTED_DATA_TYPE.CREATE_INVITES,
        CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
        CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
        CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
        CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
        CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES
    ]

    def __init__(self, view):
        super(_RefreshBtnStateController, self).__init__()
        self.__view = weakref.proxy(view)
        self.__cooldown = CooldownHelper(self.__coolDownRequests,
                                         self._onCooldownHandle,
                                         CoolDownEvent.CLAN)
        self.__isEnabled = False
        self.__tooltip = None
        self.__isInCooldown = False
        return

    def start(self):
        self.__cooldown.start()

    def stop(self):
        self.__cooldown.stop()
        self.__cooldown = None
        return

    def setEnabled(self, enable, toolTip=None):
        self.__isEnabled = enable
        self.__tooltip = toolTip
        if not self.__isInCooldown:
            self._updateState()

    def _onCooldownHandle(self, isInCooldown):
        self.__isInCooldown = isInCooldown
        self._updateState()

    def _updateState(self):
        if self.__isEnabled:
            self.__view.as_updateButtonRefreshStateS(
                not self.__cooldown.isInCooldown(),
                makeTooltip(body=_ms(
                    self.__tooltip or
                    CLANS.CLANINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_ENABLED)))
        else:
            self.__view.as_updateButtonRefreshStateS(
                False,
                makeTooltip(body=_ms(
                    self.__tooltip or
                    CLANS.CLANINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_DISABLED)))
Exemple #9
0
 def __init__(self):
     super(ClanRequestsView, self).__init__()
     self._cooldown = CooldownHelper([
         WebRequestDataType.CREATE_APPLICATIONS,
         WebRequestDataType.CREATE_INVITES,
         WebRequestDataType.ACCEPT_APPLICATION,
         WebRequestDataType.ACCEPT_INVITE,
         WebRequestDataType.DECLINE_APPLICATION,
         WebRequestDataType.DECLINE_INVITE,
         WebRequestDataType.DECLINE_INVITES,
         WebRequestDataType.CLAN_INVITES,
         WebRequestDataType.CLAN_MEMBERS_RATING
     ], self._onCooldownHandle, CoolDownEvent.WGCG)
Exemple #10
0
 def __init__(self):
     super(ClanPersonalInvitesView, self).__init__()
     self._paginator = ClanPersonalInvitesPaginator(
         self.clansCtrl, getPlayerDatabaseID(), [CLAN_INVITE_STATES.ACTIVE])
     self._cooldown = CooldownHelper([
         CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
         CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
         CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
         CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
         CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES,
         CLAN_REQUESTED_DATA_TYPE.CLANS_INFO,
         CLAN_REQUESTED_DATA_TYPE.CLAN_RATINGS,
         CLAN_REQUESTED_DATA_TYPE.ACCOUNT_INVITES
     ], self._onCooldownHandle, CoolDownEvent.CLAN)
Exemple #11
0
 def __init__(self):
     super(BattleMessengerView, self).__init__()
     self.__controllers = {}
     self.__receivers = []
     self.__receiverIndex = 0
     self.__isEnabled = False
     self.__isFocused = False
     self._battleCtx = None
     self._arenaVisitor = None
     self._avatarSessionID = ''
     self._toxicPanelMsgID = ''
     self._addedMsgIDs = set()
     self._ignoreActionCooldown = CooldownHelper((CLIENT_ACTION_ID.ADD_IGNORED, CLIENT_ACTION_ID.REMOVE_IGNORED), self._onIgnoreActionCooldownHandle, CoolDownEvent.BATTLE_ACTION)
     return
 def __init__(self, *args):
     super(ClanInvitesWindow, self).__init__()
     self.__processedInvitesCount = '0'
     self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
     self.__clanDbID = self.clanProfile.getClanDbID()
     self.__clanDossier = weakref.proxy(self.clansCtrl.getClanDossier(self.__clanDbID))
     self.__pagiatorsController = _PaginatorsController(self.__clanDbID)
 def __init__(self, ctx):
     super(ClanSearchWindow, self).__init__()
     self.__clanFinder = ClanFinder(g_clanCtrl, None, _SEARCH_LIMIT)
     self.__clanFinder.init()
     self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
     self.__isFirstPageRequested = False
     return
 def __init__(self, view):
     super(_RefreshBtnStateController, self).__init__()
     self.__view = weakref.proxy(view)
     self.__cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
     self.__isEnabled = False
     self.__tooltip = None
     return
 def __init__(self):
     super(CyberSportUnitsListView, self).__init__()
     self._isBackButtonClicked = False
     self._section = 'selectedListVehicles'
     self._selectedVehicles = self.unitFunctional.getSelectedVehicles(self._section)
     self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
     self._cooldown = CooldownHelper(self.getCoolDownRequests(), self._onCooldownHandle, events.CoolDownEvent.PREBATTLE)
 def __init__(self):
     super(CyberSportUnitsListView, self).__init__()
     self._isBackButtonClicked = False
     self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
     self._cooldown = CooldownHelper(self.getCoolDownRequests(), self._onCooldownHandle, events.CoolDownEvent.PREBATTLE)
     self.__currentEmblem = None
     return
 def __init__(self):
     super(ClanPersonalInvitesView, self).__init__()
     self._paginator = ClanPersonalInvitesPaginator(g_clanCtrl, getPlayerDatabaseID(), [CLAN_INVITE_STATES.ACTIVE])
     self._cooldown = CooldownHelper([CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
      CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES,
      CLAN_REQUESTED_DATA_TYPE.CLANS_INFO,
      CLAN_REQUESTED_DATA_TYPE.CLAN_RATINGS,
      CLAN_REQUESTED_DATA_TYPE.ACCOUNT_INVITES], self._onCooldownHandle, CoolDownEvent.CLAN)
 def __init__(self):
     super(ClanRequestsView, self).__init__()
     self._cooldown = CooldownHelper([CLAN_REQUESTED_DATA_TYPE.CREATE_APPLICATIONS,
      CLAN_REQUESTED_DATA_TYPE.CREATE_INVITES,
      CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
      CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
      CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES,
      CLAN_REQUESTED_DATA_TYPE.CLAN_INVITES,
      CLAN_REQUESTED_DATA_TYPE.CLAN_MEMBERS_RATING], self._onCooldownHandle, CoolDownEvent.CLAN)
class _RefreshBtnStateController(object):
    __coolDownRequests = [CLAN_REQUESTED_DATA_TYPE.CREATE_APPLICATIONS,
     CLAN_REQUESTED_DATA_TYPE.CREATE_INVITES,
     CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
     CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
     CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
     CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
     CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES]

    def __init__(self, view):
        super(_RefreshBtnStateController, self).__init__()
        self.__view = weakref.proxy(view)
        self.__cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
        self.__isEnabled = False
        self.__tooltip = None
        self.__isInCooldown = False
        return

    def start(self):
        self.__cooldown.start()

    def stop(self):
        self.__cooldown.stop()
        self.__cooldown = None
        return

    def setEnabled(self, enable, toolTip = None):
        self.__isEnabled = enable
        self.__tooltip = toolTip
        if not self.__isInCooldown:
            self._updateState()

    def _onCooldownHandle(self, isInCooldown):
        self.__isInCooldown = isInCooldown
        self._updateState()

    def _updateState(self):
        if self.__isEnabled:
            self.__view.as_updateButtonRefreshStateS(not self.__cooldown.isInCooldown(), makeTooltip(body=_ms(self.__tooltip or CLANS.CLANINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_ENABLED)))
        else:
            self.__view.as_updateButtonRefreshStateS(False, makeTooltip(body=_ms(self.__tooltip or CLANS.CLANINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_DISABLED)))
 def __init__(self):
     super(BattleMessengerView, self).__init__()
     self.__controllers = {}
     self.__receivers = []
     self.__receiverIndex = 0
     self.__isEnabled = False
     self.__isFocused = False
     self._battleCtx = None
     self._arenaVisitor = None
     self._accDbID = 0
     self._toxicPanelMsgID = 0
     self._addedMsgIDs = set()
     self._ignoreActionCooldown = CooldownHelper((CLIENT_ACTION_ID.ADD_IGNORED, CLIENT_ACTION_ID.REMOVE_IGNORED), self._onIgnoreActionCooldownHandle, CoolDownEvent.XMPP)
     return
 def __init__(self):
     super(ClanRequestsView, self).__init__()
     self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
class ClanSearchWindow(ClanSearchWindowMeta, ClanListener):
    __coolDownRequests = [
        CLAN_REQUESTED_DATA_TYPE.CLAN_RATINGS,
        CLAN_REQUESTED_DATA_TYPE.SEARCH_CLANS,
        CLAN_REQUESTED_DATA_TYPE.GET_RECOMMENDED_CLANS
    ]
    MIN_CHARS_FOR_SEARCH = 2

    def __init__(self, ctx):
        super(ClanSearchWindow, self).__init__()
        self.__clanFinder = ClanFinder(self.clansCtrl, None, _SEARCH_LIMIT)
        self.__clanFinder.init()
        self._cooldown = CooldownHelper(self.__coolDownRequests,
                                        self._onCooldownHandle,
                                        CoolDownEvent.CLAN)
        self.__isFirstPageRequested = False
        self.__invitesLimitReached = False
        return

    def onWindowClose(self):
        self.destroy()

    def onClanStateChanged(self, oldStateID, newStateID):
        if not self.clansCtrl.isEnabled():
            self.onWindowClose()
        if not self.clansCtrl.isAvailable():
            pass

    def search(self, text):
        symbolsCount = len(text.decode('utf8'))
        if symbolsCount < self.MIN_CHARS_FOR_SEARCH:
            self._showDummy(True)
            self._setDummyData(
                CLANS.SEARCH_REQUESTTOOSHORT_HEADER,
                CLANS.SEARCH_REQUESTTOOSHORT_BODY, None,
                self.__clanFinder.hasSuccessRequest(),
                _ms(CLANS.SEARCH_REQUESTTOOSHORT_BUTTON),
                CLANS.SEARCH_REQUESTTOOSHORT_BUTTON_TOOLTIP_HEADER)
        else:
            self.__clanFinder.setRecommended(False)
            self.__doSearch(text)
        return

    def previousPage(self):
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self.__clanFinder.left()

    def nextPage(self):
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self.__clanFinder.right()

    def isInvitesLimitReached(self):
        return self.__invitesLimitReached

    def setInvitesLimitReached(self):
        return self.__invitesLimitReached

    def _populate(self):
        super(ClanSearchWindow, self)._populate()
        self._searchDP = _ClanSearchDataProvider()
        self._searchDP.setFlashObject(self.as_getDPS())
        self.startClanListening()
        self.__clanFinder.onListUpdated += self._onClansListUpdated
        self.__initControls()
        self._updateControlsState()
        self._cooldown.start()
        if not self.clansCtrl.getAccountProfile().isSynced():
            self.clansCtrl.getAccountProfile().resync()
        self.__clanFinder.setRecommended(True)
        self.__doSearch('')

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown = None
        self.stopClanListening()
        self.__clanFinder.onListUpdated -= self._onClansListUpdated
        self.clansCtrl.clearClanCommonDataCache()
        self._searchDP.fini()
        self._searchDP = None
        super(ClanSearchWindow, self)._dispose()
        return

    def getClanInfo(self, clanID):
        return self.__clanFinder.getItemByID(clanID)

    def _onRegisterFlashComponent(self, viewPy, alias):
        super(ClanSearchWindow, self)._onRegisterFlashComponent(viewPy, alias)
        if alias == CLANS_ALIASES.CLAN_SEARCH_INFO_PY:
            viewPy.bindDataProvider(self)

    def dummyButtonPress(self):
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self._searchDP.rebuildList(None)
        self.__clanFinder.requestLastSuccess()
        return

    def _onCooldownHandle(self, isInCooldown):
        self._updateControlsState()

    def _onClansListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown,
                            result):
        status, data = result
        self._processSearchResponse(status, data, self.__isFirstPageRequested)
        self.__isFirstPageRequested = False
        self.as_hideWaitingS()

    def _processSearchResponse(self, status, data, isInitial=False):
        if status:
            if len(data) > 0:
                self.__applyFoundData(data)
            elif isInitial:
                self._searchDP.rebuildList(None)
                self._showDummy(True)
                self._setDummyData(CLANS.SEARCH_EMPTYRESULT_HEADER,
                                   CLANS.SEARCH_EMPTYRESULT_BODY, None,
                                   self.__clanFinder.hasSuccessRequest(),
                                   _ms(CLANS.SEARCH_EMPTYRESULT_BUTTON),
                                   CLANS.SEARCH_EMPTYRESULT_BUTTON_TOOLTIP)
        else:
            self._showErrorDummy()
        self._updateControlsState()
        return

    def _updateControlsState(self):
        isNotInCooldown = not self._cooldown.isInCooldown()
        foundClans = clans_fmts.formatDataToString(
            self.__clanFinder.getTotalCount())
        self.as_setStateDataS({
            'foundClans':
            text_styles.highTitle(
                _ms(CLANS.SEARCH_CLANSLIST
                    if self.__clanFinder.isRecommended() else
                    CLANS.SEARCH_FOUNDCLANS,
                    value=foundClans)),
            'nextBtnEnabled':
            self.__clanFinder.canMoveRight() and isNotInCooldown,
            'previousBtnEnabled':
            self.__clanFinder.canMoveLeft() and isNotInCooldown,
            'searchBtnEnabled':
            isNotInCooldown,
            'searchInputEnabled':
            isNotInCooldown
        })

    def _showErrorDummy(self):
        self._searchDP.rebuildList(None)
        self._showDummy(True)
        self._setDummyData(CLANS.SEARCH_SERVERUNAVAILABLE_HEADER,
                           CLANS.SEARCH_SERVERUNAVAILABLE_BODY,
                           RES_ICONS.MAPS_ICONS_LIBRARY_ALERTBIGICON)
        return

    def _showDummy(self, isVisible):
        self.as_setDummyVisibleS(isVisible)

    def _setDummyData(self,
                      header,
                      body,
                      icon=None,
                      btnVisible=False,
                      btnLabel='',
                      btnTooltip=''):
        self.as_setDummyS({
            'iconSource':
            icon,
            'htmlText':
            str().join(
                (text_styles.middleTitle(header),
                 clans_fmts.getHtmlLineDivider(3), text_styles.main(body))),
            'alignCenter':
            False,
            'btnVisible':
            btnVisible,
            'btnLabel':
            btnLabel,
            'btnTooltip':
            btnTooltip
        })

    def __initControls(self):
        headers = [
            _packHeaderColumnData('clan',
                                  CLANS.SEARCH_TABLE_CLAN,
                                  244,
                                  CLANS.SEARCH_TABLE_CLAN_TOOLTIP,
                                  textAlign='left'),
            _packHeaderColumnData('players', CLANS.SEARCH_TABLE_PLAYERS, 107,
                                  CLANS.SEARCH_TABLE_PLAYERS_TOOLTIP),
            _packHeaderColumnData('creationDate',
                                  CLANS.SEARCH_TABLE_CREATIONDATE, 125,
                                  CLANS.SEARCH_TABLE_CREATIONDATE_TOOLTIP),
            _packHeaderColumnData('rating', CLANS.SEARCH_TABLE_RATING, 90,
                                  CLANS.SEARCH_TABLE_RATING_TOOLTIP, False,
                                  'right')
        ]
        self.as_setInitDataS({
            'windowTitle':
            CLANS.SEARCH_WINDOWTITLE,
            'title':
            text_styles.promoTitle(_ms(CLANS.SEARCH_TITLE)),
            'titleDescription':
            text_styles.main(_ms(CLANS.SEARCH_TITLEDESCRIPTION)),
            'searchBtnLabel':
            CLANS.SEARCH_SEARCHBTN,
            'searchBtnTooltip':
            CLANS.SEARCH_SEARCHBTN_TOOLTIP,
            'searchInputPrompt':
            CLANS.SEARCH_SEARCHINPUTPROMPT,
            'searchInputMaxChars':
            _SEARCH_MAX_CHARS,
            'nextBtnLabel':
            CLANS.SEARCH_NEXTBTN,
            'nextBtnTooltip':
            CLANS.SEARCH_NEXTBTN_TOOLTIP,
            'previousBtnLabel':
            CLANS.SEARCH_PREVIOUSBTN,
            'previousBtnTooltip':
            CLANS.SEARCH_PREVIOUSBTN_TOOLTIP,
            'tableHeaders':
            headers
        })
        self._showDummy(True)
        self._setDummyData(CLANS.SEARCH_PROMOTEXT_HEADER,
                           CLANS.SEARCH_PROMOTEXT_BODY, None)
        return

    def __applyFoundData(self, data):
        self._showDummy(False)
        self.clansCtrl.updateClanCommonDataCache(
            [ClanCommonData.fromClanSearchData(item) for item in data])
        self._searchDP.rebuildList(data)
        self.__lastSuccessfullyFoundClans = data

    def __doSearch(self, text):
        """
        :param text: - search criteria
        """
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self._searchDP.rebuildList(None)
        isValid, reason = self.clansCtrl.getLimits().canSearchClans(text)
        if self.__clanFinder.isRecommended() or isValid:
            self._showDummy(False)
            self.__isFirstPageRequested = True
            self.__clanFinder.setPattern(text)
            self.__clanFinder.reset()
        else:
            if reason == _CCR.SEARCH_PATTERN_INVALID:
                self._processSearchResponse(True, list(), True)
            else:
                self._processSearchResponse(False, list(), True)
            self.as_hideWaitingS()
        return
Exemple #23
0
class CyberSportUnitsListView(CyberSportUnitsListMeta, ClubListener, ClubEmblemsHelper):

    def __init__(self):
        super(CyberSportUnitsListView, self).__init__()
        self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
        self._cooldown = CooldownHelper(self.getCoolDownRequests(), self._onCooldownHandle, events.CoolDownEvent.PREBATTLE)
        self.__currentEmblem = None
        return

    def getPyDataProvider(self):
        return ManualSearchDataProvider()

    def getCoolDownRequests(self):
        return [REQUEST_TYPE.UNITS_LIST]

    def setTeamFilters(self, showOnlyStatic):
        self._unitTypeFlags = UNIT_BROWSER_TYPE.RATED_CLUBS if showOnlyStatic else UNIT_BROWSER_TYPE.ALL
        self.__recenterList()

    def loadPrevious(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_LEFT)

    def loadNext(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_RIGHT)

    def refreshTeams(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_REFRESH)

    def getRallyDetails(self, index):
        if index != self._searchDP.selectedRallyIndex:
            self.__currentEmblem = None
        cfdUnitID, vo = self._searchDP.getRally(index)
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.setSelectedID(cfdUnitID)
        self.__setDetailsData(cfdUnitID, vo)
        return

    def showRallyProfile(self, clubDBID):
        club_events.showClubProfile(clubDBID)

    def onPrbEntitySwitching(self):
        browser = self.prbEntity.getBrowser()
        if browser:
            browser.stop()

    def _populate(self):
        super(CyberSportUnitsListView, self)._populate()
        self._cooldown.start()
        self.prbEntity.getBrowser().start(self.__onUnitsListUpdated)
        self.as_setSearchResultTextS(_ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS), '', self.__getFiltersData())
        headerDescription = CYBERSPORT.WINDOW_UNITLISTVIEW_DESCRIPTION
        headerTitle = CYBERSPORT.WINDOW_UNITLISTVIEW_TITLE
        self.as_setHeaderS({'title': headerTitle,
         'description': headerDescription,
         'createBtnLabel': CYBERSPORT.WINDOW_UNITLISTVIEW_CREATE_BTN,
         'createBtnTooltip': None,
         'createBtnEnabled': True,
         'columnHeaders': self.__getColumnHeaders()})
        return

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown = None
        super(CyberSportUnitsListView, self)._dispose()
        return

    def _onUserActionReceived(self, _, user):
        self.__updateView(user)

    def _doEnableNavButtons(self, isEnabled):
        self.as_updateNavigationBlockS({'previousVisible': True,
         'previousEnabled': isEnabled,
         'nextVisible': True,
         'nextEnabled': isEnabled,
         'icon': RES_ICONS.MAPS_ICONS_STATISTIC_RATING24})

    def _onCooldownHandle(self, isInCooldown):
        self._doEnableNavButtons(not isInCooldown)

    def __getColumnHeaders(self):
        return [self.__createHedader('', 54, RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_LADDERICON),
         self.__createHedader('', 58, RES_ICONS.MAPS_ICONS_STATISTIC_RATING24),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_COMMANDER, 152),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_DESCRIPTION, 220),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_PLAYERS, 76)]

    def __createHedader(self, label, buttonWidth, iconSource = None):
        return {'label': label,
         'buttonWidth': buttonWidth,
         'iconSource': iconSource,
         'enabled': False}

    def __updateVehicleLabel(self):
        settings = self.prbEntity.getRosterSettings()
        self._updateVehiclesLabel(int2roman(settings.getMinLevel()), int2roman(settings.getMaxLevel()))

    def __getFiltersData(self):
        return {'isSelected': self._unitTypeFlags == UNIT_BROWSER_TYPE.RATED_CLUBS,
         'icon': RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_RANKEDICON,
         'label': _ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS_FILTERTEXT)}

    def __onUnitsListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown, units):
        if isFullUpdate:
            selectedIdx = self._searchDP.rebuildList(selectedID, units)
            self._doEnableNavButtons(not isReqInCoolDown)
        else:
            selectedIdx = self._searchDP.updateList(selectedID, units)
        if selectedIdx is not None:
            self.as_selectByIndexS(selectedIdx)
        return

    def __setDetailsData(self, unitID, vo):
        _, unit = self.prbEntity.getUnit(unitID)
        if unit is not None and unit.isClub():
            self.__setDetails(unitID, vo, unit.getExtra())
        else:
            self.__setDetails(unitID, vo)
        return

    def __setDetails(self, unitID, vo, clubExtraData = None):
        if clubExtraData is not None:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_STATIC_AS_LEGIONARY
            icon = None
            name = clubExtraData.clubName
            clubID = clubExtraData.clubDBID
            division = clubExtraData.divisionID
            description = vo['description']
            if self.__currentEmblem is None:
                self.requestClubEmblem64x64(clubID, clubExtraData.getEmblem64x64(), partial(self.__onClubEmblem64x64Received, unitID))
            else:
                icon = self.__currentEmblem
            buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_LEGIONARY
            buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_LEGIONARY
            buttonTooltip = TOOLTIPS.CYBERSPORT_UNITLIST_JOINTOSTATICASLEGIONARY
            if self.clubsState.getStateID() == CLIENT_CLUB_STATE.HAS_CLUB and self.clubsState.getClubDbID() == clubID:
                buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_MEMBER
                buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_MEMBER
                buttonTooltip = None
            vo.update({'joinBtnLabel': buttonLabel,
             'joinInfo': text_styles.standard(_ms(buttonInfo)),
             'joinBtnTooltip': buttonTooltip,
             'rallyInfo': {'icon': icon,
                           'name': text_styles.highTitle(name),
                           'profileBtnLabel': CYBERSPORT.RALLYINFO_PROFILEBTN_LABEL,
                           'profileBtnTooltip': TOOLTIPS.RALLYINFO_PROFILEBTN,
                           'description': text_styles.main(description),
                           'ladderIcon': getLadderChevron64x64(division),
                           'id': clubID,
                           'showLadder': True}})
            self.as_setDetailsS({'viewLinkage': linkage,
             'data': vo})
        else:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_NONSTATIC
            self.as_setDetailsS({'viewLinkage': linkage,
             'data': vo})
        self.__updateVehicleLabel()
        return

    def __refreshDetails(self, idx):
        cfdUnitID, vo = self._searchDP.getRally(idx)
        self.__setDetailsData(cfdUnitID, vo)

    def __updateView(self, user):
        self._searchDP.updateListItem(user.getID())
        self.__refreshDetails(self._searchDP.selectedRallyIndex)

    def __recenterList(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_RECENTER, unitTypeFlags=self._unitTypeFlags)

    def __onClubEmblem64x64Received(self, cfdUnitID, clubDbID, emblem):
        selectedCfdUnitID, _ = self._searchDP.getRally(self._searchDP.selectedRallyIndex)
        if emblem and cfdUnitID == selectedCfdUnitID:
            self.__currentEmblem = self.getMemoryTexturePath(emblem)
            self.as_updateRallyIconS(self.__currentEmblem)
class ClanRequestsView(ClanRequestsViewMeta):
    def __init__(self):
        super(ClanRequestsView, self).__init__()
        self._cooldown = CooldownHelper([
            CLAN_REQUESTED_DATA_TYPE.CREATE_APPLICATIONS,
            CLAN_REQUESTED_DATA_TYPE.CREATE_INVITES,
            CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
            CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
            CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
            CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
            CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES,
            CLAN_REQUESTED_DATA_TYPE.CLAN_INVITES,
            CLAN_REQUESTED_DATA_TYPE.CLAN_MEMBERS_RATING
        ], self._onCooldownHandle, CoolDownEvent.CLAN)

    @property
    def actualRequestsPaginator(self):
        return self._getPaginatorByFilterName(
            CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL)

    @property
    def expiredRequestsPaginator(self):
        return self._getPaginatorByFilterName(
            CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED)

    @property
    def processedRequestsPaginator(self):
        return self._getPaginatorByFilterName(
            CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED)

    def acceptRequest(self, applicationID):
        applicationID = int(applicationID)
        ctx = AcceptApplicationCtx(applicationID)
        self._getCurrentPaginator().accept(applicationID, ctx)

    def declineRequest(self, applicationID):
        applicationID = int(applicationID)
        ctx = DeclineApplicationCtx(applicationID)
        self._getCurrentPaginator().decline(applicationID, ctx)

    def sendInvite(self, dbId):
        dbId = int(dbId)
        paginator = self._getCurrentPaginator()
        requestWrapper = paginator.getInviteByDbID(dbId)
        ctx = CreateInviteCtx(requestWrapper.getClanDbID(),
                              [requestWrapper.getAccountDbID()])
        self._getCurrentPaginator().resend(dbId, ctx)
        self._enableRefreshBtn(True)

    def onClanAppsCountReceived(self, clanDbID, appsCount):
        super(ClanRequestsView,
              self).onClanAppsCountReceived(clanDbID, appsCount)
        if self.actualRequestsPaginator.isSynced():
            self._enableRefreshBtn(True)

    def _populate(self):
        super(ClanRequestsView, self)._populate()

    def _onAttachedToWindow(self):
        super(ClanRequestsView, self)._onAttachedToWindow()
        self._cooldown.start()
        self.filterBy(self.currentFilterName)

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown.stop()
        self._cooldown = None
        super(ClanRequestsView, self)._dispose()
        return

    def _onCooldownHandle(self, isInCooldown):
        self.dataProvider.allowActions(not isInCooldown)

    def _getViewAlias(self):
        return CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_ALIAS

    def _showDummyByFilterName(self, filterName):
        if filterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL:
            self._showDummy(
                CLANS.CLANINVITESWINDOW_DUMMY_NOACTUALREQUESTS_TITLE)
        elif filterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED:
            self._showDummy(
                CLANS.CLANINVITESWINDOW_DUMMY_NOEXPIREDREQUESTS_TITLE)
        elif filterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED:
            self._showDummy(
                CLANS.CLANINVITESWINDOW_DUMMY_NOPROCESSEDREQUESTS_TITLE)
        else:
            LOG_DEBUG('Unexpected behaviour: no dummy for filter', filterName)
            self._showDummy(
                CLANS.CLANINVITESWINDOW_DUMMY_NOACTUALREQUESTS_TITLE)

    def _getDefaultFilterName(self):
        return CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL

    def _getDefaultSortFields(self):
        return (('status', False), )

    def _getSecondSortFields(self):
        if self.currentFilterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED or self.currentFilterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED:
            return ('updatedAt', )
        else:
            return ('createdAt', )

    def _createSearchDP(self):
        return RequestDataProvider(self)

    @process
    def _onListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown,
                       result):
        yield lambda callback: callback(None)
        status, data = result
        accountsInfo = tuple()
        if status is True and data:
            ctx = AccountsInfoCtx(
                tuple((item.getAccountDbID() for item in data)))
            accountsResponse = yield self.clansCtrl.sendRequest(ctx)
            if accountsResponse.isSuccess():
                accountsInfo = ctx.getDataObj(accountsResponse.data)
        self.dataProvider.setAccountsInfo(accountsInfo)
        super(ClanRequestsView, self)._onListUpdated(selectedID, isFullUpdate,
                                                     isReqInCoolDown, result)

    def _makeFilters(self):
        return [{
            'alias':
            CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL,
            'text':
            _ms(CLANS.CLANINVITESWINDOW_FILTERS_ACTUAL,
                value=self.formatInvitesCount(self.actualRequestsPaginator))
        }, {
            'alias':
            CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED,
            'text':
            _ms(CLANS.CLANINVITESWINDOW_FILTERS_EXPIRED,
                value=self.formatInvitesCount(self.expiredRequestsPaginator))
        }, {
            'alias':
            CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED,
            'text':
            _ms(CLANS.CLANINVITESWINDOW_FILTERS_PROCESSED,
                value=self.formatInvitesCount(self.processedRequestsPaginator))
        }]

    def _makeHeaders(self):
        return [
            self._packHeaderColumnData(
                'userName',
                CLANS.CLANINVITESWINDOW_TABLE_USERNAME,
                225,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_USERNAME,
                textAlign='left',
                defaultSortDirection='ascending'),
            self._packHeaderColumnData(
                'message', '', 73,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_MESSAGE,
                RES_ICONS.
                MAPS_ICONS_CLANS_INVITESWINDOW_ICON_STATISTICS_CLAN_INVITE_098
            ),
            self._packHeaderColumnData(
                'personalRating', '', 98,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_PERSONALRATING,
                RES_ICONS.MAPS_ICONS_STATISTIC_RATING24),
            self._packHeaderColumnData(
                'battlesCount', '', 98,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_BATTLESCOUNT,
                RES_ICONS.MAPS_ICONS_STATISTIC_BATTLES24),
            self._packHeaderColumnData(
                'wins', '', 98,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_WINS,
                RES_ICONS.MAPS_ICONS_STATISTIC_WINS24),
            self._packHeaderColumnData(
                'awgExp', '', 98,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_AWGEXP,
                RES_ICONS.MAPS_ICONS_STATISTIC_AVGEXP24),
            self._packHeaderColumnData(
                'status', CLANS.CLANINVITESWINDOW_TABLE_STATUS, 160,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_STATUS),
            self._packHeaderColumnData(
                'actions',
                CLANS.CLANINVITESWINDOW_TABLE_ACTIONS,
                140,
                CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_ACTIONS,
                enabled=False)
        ]
class ClanInvitesWindow(ClanInvitesWindowMeta, ClanListener,
                        ClanEmblemsHelper):
    __coolDownRequests = [
        CLAN_REQUESTED_DATA_TYPE.CLAN_APPLICATIONS,
        CLAN_REQUESTED_DATA_TYPE.CLAN_INVITES
    ]

    def __init__(self, *args):
        super(ClanInvitesWindow, self).__init__()
        self.__actualRequestsCount = '0'
        self.__processedInvitesCount = '0'
        self._cooldown = CooldownHelper(self.__coolDownRequests,
                                        self._onCooldownHandle,
                                        CoolDownEvent.CLAN)
        self.__clanDbID = self.clanProfile.getClanDbID()
        self.__clanDossier = weakref.proxy(
            self.clansCtrl.getClanDossier(self.__clanDbID))
        self.__pagiatorsController = _PaginatorsController(self.__clanDbID)

    def onClanStateChanged(self, oldStateID, newStateID):
        if not self.clansCtrl.isEnabled():
            self.onWindowClose()
        if not self.clansCtrl.isAvailable():
            pass

    def onAccountClanProfileChanged(self, profile):
        if not profile.isInClan() or not profile.getMyClanPermissions(
        ).canHandleClanInvites():
            self.destroy()

    def onClanInfoReceived(self, clanDbID, clanInfo):
        if clanDbID == self.__clanDbID:
            self._updateClanInfo()
            self._updateHeaderState()

    def onInvitesButtonClick(self):
        showClanSendInviteWindow(self.clanProfile.getClanDbID())

    def onWindowClose(self):
        self.destroy()

    def onClanEmblem128x128Received(self, clanDbID, emblem):
        self.as_setClanEmblemS(self.getMemoryTexturePath(emblem))

    @property
    def clanProfile(self):
        return self.clansCtrl.getAccountProfile()

    @property
    def paginatorsController(self):
        return self.__pagiatorsController

    @property
    def clanInfo(self):
        return self.__clanDossier.getClanInfo()

    def resyncClanInfo(self, force=False):
        self.__clanDossier.resyncClanInfo(force=force)

    def showWaiting(self, show):
        if show:
            self.as_showWaitingS(WAITING.LOADINGDATA, {})
        elif not self.paginatorsController.isInProgress():
            self.as_hideWaitingS()

    def formatInvitesCount(self, paginator):
        return formatters.formatInvitesCount(paginator.getTotalCount())

    def _populate(self):
        self.showWaiting(True)
        super(ClanInvitesWindow, self)._populate()
        self.__updateTabsState()
        self._updateHeaderState()
        self._updateClanInfo()
        self._updateClanEmblem()
        self._cooldown.start()
        self.startClanListening()
        self.__pagiatorsController.setCallback(self._onPaginatorListChanged)
        self.resyncClanInfo()
        self.__pagiatorsController.getPanginator(
            CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_ALIAS,
            CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL).reset()
        self.__pagiatorsController.getPanginator(
            CLANS_ALIASES.CLAN_PROFILE_INVITES_VIEW_ALIAS,
            CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED).reset()

    def _dispose(self):
        if self.paginatorsController.isInProgress():
            self.as_hideWaitingS()
        self.stopClanListening()
        self.__pagiatorsController.removeCallbacks()
        self._cooldown.stop()
        self._cooldown = None
        super(ClanInvitesWindow, self)._dispose()
        return

    def _onRegisterFlashComponent(self, viewPy, alias):
        super(ClanInvitesWindow, self)._onRegisterFlashComponent(viewPy, alias)
        viewPy.setParentWindow(self)

    def _onCooldownHandle(self, isInCooldown):
        self.showWaiting(isInCooldown)

    def _onPaginatorListChanged(self, alias, filter, selectedID, isFullUpdate,
                                isReqInCoolDown, result):
        paginator = self.__pagiatorsController.getPanginator(alias, filter)
        if alias == CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_ALIAS:
            if filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL:
                self.__actualRequestsCount = self.formatInvitesCount(paginator)
                self.__updateTabsState()
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED:
                pass
            else:
                LOG_DEBUG(
                    'Unexpected behaviour: unknown filter {} for alias {}'.
                    format(filter, alias))
        elif alias == CLANS_ALIASES.CLAN_PROFILE_INVITES_VIEW_ALIAS:
            if filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_ALL:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED:
                self.__processedInvitesCount = self.formatInvitesCount(
                    paginator)
                self.__updateTabsState()
            else:
                LOG_DEBUG(
                    'Unexpected behaviour: unknown filter {} for alias {}'.
                    format(filter, alias))
        else:
            LOG_DEBUG('Unexpected behaviour: unknown view alias ', alias)
        self.showWaiting(False)

    def _updateClanEmblem(self):
        self.requestClanEmblem128x128(self.clanProfile.getClanDbID())

    def _updateClanInfo(self):
        self.as_setClanInfoS({
            'name':
            self.clanProfile.getClanFullName(),
            'bgIcon':
            RES_ICONS.MAPS_ICONS_CLANS_INVITESWINDOW_CC_HEADER_BACK,
            'creationDate':
            i18n.makeString(CLANS.CLAN_HEADER_CREATIONDATE,
                            creationDate=BigWorld.wg_getLongDateFormat(
                                self.clanProfile.getJoinedAt()))
        })

    def _updateHeaderState(self):
        freePlaces = self.clanInfo.getFreePlaces()
        freePlacesInClanText = text_styles.concatStylesToSingleLine(
            text_styles.standard(
                _ms(CLANS.CLANINVITESWINDOW_HEADER_FREEPLACESINCLAN,
                    count=text_styles.main(
                        formatField(getter=self.clanInfo.getFreePlaces)))))
        if freePlaces == 0:
            inviteButtonEnabled = False
            inviteButtonTooltip = _ms(
                CLANS.CLANINVITESWINDOW_HEADER_TOOLTIPS_NOPLACES)
            freePlacesInClanText = gui.makeHtmlString(
                'html_templates:lobby/research', 'warningMessage',
                {'text': freePlacesInClanText})
        else:
            inviteButtonEnabled = True
            inviteButtonTooltip = _ms(
                CLANS.CLANINVITESWINDOW_TOOLTIPS_HEADER_INVITEBUTTON)
        self.as_setHeaderStateS({
            'inviteButtonEnabled':
            inviteButtonEnabled,
            'inviteButtonText':
            CLANS.CLANINVITESWINDOW_HEADER_INVITEINCLAN,
            'inviteButtonTooltip':
            makeTooltip(body=inviteButtonTooltip),
            'freePlacesInClanText':
            freePlacesInClanText
        })

    def __updateTabsState(self):
        self.as_setDataS({
            'tabDataProvider': [{
                'label':
                i18n.makeString(CLANS.CLANINVITESWINDOW_TABREQUESTS,
                                value=self.__actualRequestsCount),
                'linkage':
                CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_LINKAGE
            }, {
                'label':
                i18n.makeString(CLANS.CLANINVITESWINDOW_TABINVITES,
                                value=self.__processedInvitesCount),
                'linkage':
                CLANS_ALIASES.CLAN_PROFILE_INVITES_VIEW_LINKAGE
            }]
        })
class CyberSportUnitsListView(CyberSportUnitsListMeta):
    itemsCache = dependency.descriptor(IItemsCache)

    def __init__(self):
        super(CyberSportUnitsListView, self).__init__()
        self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
        self._cooldown = CooldownHelper(self.getCoolDownRequests(), self._onCooldownHandle, events.CoolDownEvent.PREBATTLE)
        self.__currentEmblem = None
        return

    def getPyDataProvider(self):
        return ManualSearchDataProvider()

    def getCoolDownRequests(self):
        return [REQUEST_TYPE.UNITS_LIST]

    def loadPrevious(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_LEFT)

    def loadNext(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_RIGHT)

    def refreshTeams(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_REFRESH)

    def getRallyDetails(self, index):
        if index != self._searchDP.selectedRallyIndex:
            self.__currentEmblem = None
        cfdUnitID, vo = self._searchDP.getRally(index)
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.setSelectedID(cfdUnitID)
        self.__setDetails(vo)
        return

    def onPrbEntitySwitching(self):
        browser = self.prbEntity.getBrowser()
        if browser:
            browser.stop()

    def _populate(self):
        super(CyberSportUnitsListView, self)._populate()
        self._cooldown.start()
        self.prbEntity.getBrowser().start(self.__onUnitsListUpdated)
        self.as_setHeaderS({'title': text_styles.promoTitle(CYBERSPORT.WINDOW_UNITLISTVIEW_TITLE),
         'createBtnLabel': CYBERSPORT.WINDOW_UNITLISTVIEW_CREATE_BTN,
         'createBtnTooltip': None,
         'createBtnEnabled': True,
         'columnHeaders': self.__getColumnHeaders()})
        self.itemsCache.onSyncCompleted += self.__refreshData
        return

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown = None
        self.itemsCache.onSyncCompleted -= self.__refreshData
        super(CyberSportUnitsListView, self)._dispose()
        return

    def _onUserActionReceived(self, _, user, shadowMode):
        self.__updateView(user)

    def _doEnableNavButtons(self, isEnabled):
        self.as_updateNavigationBlockS({'previousVisible': True,
         'previousEnabled': isEnabled,
         'nextVisible': True,
         'nextEnabled': isEnabled})

    def _onCooldownHandle(self, isInCooldown):
        self._doEnableNavButtons(not isInCooldown)

    def __refreshData(self, reason, diff):
        if reason != CACHE_SYNC_REASON.CLIENT_UPDATE:
            return
        else:
            if diff is not None and GUI_ITEM_TYPE.VEHICLE in diff:
                vehDiff = diff[GUI_ITEM_TYPE.VEHICLE]
                for changedVehCD in vehDiff:
                    vehicle = self.itemsCache.items.getItemByCD(changedVehCD)
                    if not vehicle.activeInNationGroup:
                        self.__refreshDetails(self._searchDP.selectedRallyIndex)

            return

    def __getColumnHeaders(self):
        return [self.__createHedader('', 82, 'center', RES_ICONS.MAPS_ICONS_STATISTIC_RATING24),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_COMMANDER, 152),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_DESCRIPTION, 220),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_PLAYERS, 76)]

    def __createHedader(self, label, buttonWidth, position='left', iconSource=None):
        return {'label': label,
         'buttonWidth': buttonWidth,
         'iconSource': iconSource,
         'enabled': False,
         'textAlign': position}

    def __updateVehicleLabel(self):
        settings = self.prbEntity.getRosterSettings()
        self._updateVehiclesLabel(int2roman(settings.getMinLevel()), int2roman(settings.getMaxLevel()))

    def __onUnitsListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown, units):
        if isFullUpdate:
            selectedIdx = self._searchDP.rebuildList(selectedID, units)
            self._doEnableNavButtons(not isReqInCoolDown)
        else:
            selectedIdx = self._searchDP.updateList(selectedID, units)
            self.__refreshDetails(selectedIdx)
        if selectedIdx is not None:
            self.as_selectByIndexS(selectedIdx)
        if self._searchDP.collection:
            self.as_setDummyVisibleS(False)
        else:
            self.as_setDummyVisibleS(True)
            self.as_setDummyS({'htmlText': text_styles.main(CYBERSPORT.WINDOW_UNITLISTVIEW_NOITEMS),
             'alignCenter': True})
        return

    def __setDetails(self, vo):
        linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_NONSTATIC
        self.as_setDetailsS({'viewLinkage': linkage,
         'data': vo})
        self.__updateVehicleLabel()

    def __refreshDetails(self, idx):
        _, vo = self._searchDP.getRally(idx)
        self.__setDetails(vo)

    def __updateView(self, user):
        self._searchDP.updateListItem(user.getID())
        self.__refreshDetails(self._searchDP.selectedRallyIndex)

    def __recenterList(self):
        listReq = self.prbEntity.getBrowser()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_RECENTER, unitTypeFlags=self._unitTypeFlags)
class CyberSportUnitsListView(CyberSportUnitsListMeta, UnitListener, ClubListener, ClubEmblemsHelper):

    def __init__(self):
        super(CyberSportUnitsListView, self).__init__()
        self._isBackButtonClicked = False
        self._section = 'selectedListVehicles'
        self._selectedVehicles = self.unitFunctional.getSelectedVehicles(self._section)
        self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
        self._cooldown = CooldownHelper(self.getCoolDownRequests(), self._onCooldownHandle, events.CoolDownEvent.PREBATTLE)

    def onUnitFunctionalInited(self):
        self.unitFunctional.setEntityType(PREBATTLE_TYPE.UNIT)

    def getPyDataProvider(self):
        return ManualSearchDataProvider()

    def getCoolDownRequests(self):
        return [REQUEST_TYPE.UNITS_LIST]

    def canBeClosed(self, callback):
        self._isBackButtonClicked = True
        callback(True)

    def updateSelectedVehicles(self):
        maxLevel = self.unitFunctional.getRosterSettings().getMaxLevel()
        vehiclesCount = len(self._selectedVehicles)
        availableVehiclesCount = len([ k for k, v in g_itemsCache.items.getVehicles(REQ_CRITERIA.INVENTORY).items() if v.level <= maxLevel ])
        if vehiclesCount > 0 and vehiclesCount != availableVehiclesCount:
            infoText = makeHtmlString('html_templates:lobby/cyberSport/vehicle', 'selectedValid', {'count': vehiclesCount})
        else:
            infoText = CYBERSPORT.BUTTON_CHOOSEVEHICLES_SELECT
        self.as_setSelectedVehiclesInfoS(infoText, vehiclesCount)

    def setTeamFilters(self, showOnlyStatic):
        self._unitTypeFlags = UNIT_BROWSER_TYPE.RATED_CLUBS if showOnlyStatic else UNIT_BROWSER_TYPE.ALL
        self.__recenterList()

    def filterVehicles(self):
        levelsRange = self.unitFunctional.getRosterSettings().getLevelsRange()
        if self._selectedVehicles is not None and len(self._selectedVehicles) > 0:
            selectedVehicles = self._selectedVehicles
        else:
            selectedVehicles = [ k for k, v in g_itemsCache.items.getVehicles(REQ_CRITERIA.INVENTORY).items() if v.level in levelsRange ]
        self.fireEvent(events.LoadViewEvent(CYBER_SPORT_ALIASES.VEHICLE_SELECTOR_POPUP_PY, ctx={'isMultiSelect': True,
         'infoText': CYBERSPORT.WINDOW_VEHICLESELECTOR_INFO_SEARCH,
         'selectedVehicles': selectedVehicles,
         'section': 'cs_list_view_vehicle',
         'levelsRange': levelsRange}), scope=EVENT_BUS_SCOPE.LOBBY)
        return

    def loadPrevious(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_LEFT)

    def loadNext(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_RIGHT)

    def refreshTeams(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_REFRESH)

    def getRallyDetails(self, index):
        cfdUnitID, vo = self._searchDP.getRally(index)
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.setSelectedID(cfdUnitID)
        self.__setDetailsData(cfdUnitID, vo)

    def showRallyProfile(self, clubDBID):
        club_events.showClubProfile(clubDBID)

    def _populate(self):
        super(CyberSportUnitsListView, self)._populate()
        self._cooldown.start()
        self.addListener(CSVehicleSelectEvent.VEHICLE_SELECTED, self.__onVehiclesSelectedTeams)
        self.startUnitListening()
        if self.unitFunctional.getEntityType() != PREBATTLE_TYPE.NONE:
            self.unitFunctional.setEntityType(PREBATTLE_TYPE.UNIT)
        self.updateSelectedVehicles()
        unit_ext.initListReq(self._unitTypeFlags).start(self.__onUnitsListUpdated)
        g_clientUpdateManager.addCallbacks({'inventory.1': self.__onVehiclesChanged})
        self.as_setSearchResultTextS(_ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS), '', self.__getFiltersData())
        headerDescription = CYBERSPORT.WINDOW_UNITLISTVIEW_DESCRIPTION
        headerTitle = CYBERSPORT.WINDOW_UNITLISTVIEW_TITLE
        self.as_setHeaderS({'title': headerTitle,
         'description': headerDescription,
         'createBtnLabel': CYBERSPORT.WINDOW_UNITLISTVIEW_CREATE_BTN,
         'createBtnTooltip': None,
         'createBtnEnabled': True,
         'columnHeaders': self.__getColumnHeaders()})
        return

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown = None
        if self._isBackButtonClicked:
            unit_ext.destroyListReq()
            self._isBackButtonClicked = False
        else:
            listReq = unit_ext.getListReq()
            if listReq:
                listReq.stop()
        self.stopUnitListening()
        self.removeListener(CSVehicleSelectEvent.VEHICLE_SELECTED, self.__onVehiclesSelectedTeams)
        g_clientUpdateManager.removeObjectCallbacks(self)
        super(CyberSportUnitsListView, self)._dispose()
        return

    def _onUserActionReceived(self, _, user):
        self.__updateView(user)

    def _doEnableNavButtons(self, isEnabled):
        self.as_updateNavigationBlockS({'previousVisible': True,
         'previousEnabled': isEnabled,
         'nextVisible': True,
         'nextEnabled': isEnabled,
         'icon': RES_ICONS.MAPS_ICONS_STATISTIC_RATING24})

    def _onCooldownHandle(self, isInCooldown):
        self._doEnableNavButtons(not isInCooldown)

    def __getColumnHeaders(self):
        return [self.__createHedader('', 54, RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_LADDERICON),
         self.__createHedader('', 58, RES_ICONS.MAPS_ICONS_STATISTIC_RATING24),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_COMMANDER, 152),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_DESCRIPTION, 220),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_PLAYERS, 76)]

    def __createHedader(self, label, buttonWidth, iconSource = None):
        return {'label': label,
         'buttonWidth': buttonWidth,
         'iconSource': iconSource,
         'enabled': False}

    def __updateVehicleLabel(self):
        settings = self.unitFunctional.getRosterSettings()
        self._updateVehiclesLabel(int2roman(settings.getMinLevel()), int2roman(settings.getMaxLevel()))

    def __getFiltersData(self):
        return {'isSelected': self._unitTypeFlags == UNIT_BROWSER_TYPE.RATED_CLUBS,
         'icon': RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_RANKEDICON,
         'label': _ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS_FILTERTEXT)}

    def __onUnitsListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown, units):
        if isFullUpdate:
            selectedIdx = self._searchDP.rebuildList(selectedID, units)
            self._doEnableNavButtons(not isReqInCoolDown)
        else:
            selectedIdx = self._searchDP.updateList(selectedID, units)
        if selectedIdx is not None:
            self.as_selectByIndexS(selectedIdx)
        return

    def __onVehiclesSelectedTeams(self, event):
        self._selectedVehicles = event.ctx
        self.updateSelectedVehicles()
        self.unitFunctional.setSelectedVehicles(self._section, self._selectedVehicles)
        self.__recenterList()

    def __setDetailsData(self, unitID, vo):
        _, unit = self.unitFunctional.getUnit(unitID)
        if unit is not None and unit.isClub():
            self.__setDetails(unitID, vo, unit.getExtra())
        else:
            self.__setDetails(unitID, vo)
        return

    def __setDetails(self, unitID, vo, clubExtraData = None):
        if clubExtraData is not None:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_STATIC_AS_LEGIONARY
            icon = None
            name = clubExtraData.clubName
            clubID = clubExtraData.clubDBID
            division = clubExtraData.divisionID
            description = vo['description']
            self.requestClubEmblem64x64(clubID, clubExtraData.getEmblem64x64(), partial(self.__onClubEmblem64x64Received, unitID))
            buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_LEGIONARY
            buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_LEGIONARY
            buttonTooltip = TOOLTIPS.CYBERSPORT_UNITLIST_JOINTOSTATICASLEGIONARY
            if self.clubsState.getStateID() == CLIENT_CLUB_STATE.HAS_CLUB and self.clubsState.getClubDbID() == clubID:
                buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_MEMBER
                buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_MEMBER
                buttonTooltip = None
            vo.update({'joinBtnLabel': buttonLabel,
             'joinInfo': text_styles.standard(_ms(buttonInfo)),
             'joinBtnTooltip': buttonTooltip,
             'rallyInfo': {'icon': icon,
                           'name': text_styles.highTitle(name),
                           'profileBtnLabel': CYBERSPORT.RALLYINFO_PROFILEBTN_LABEL,
                           'profileBtnTooltip': TOOLTIPS.RALLYINFO_PROFILEBTN,
                           'description': text_styles.main(description),
                           'ladderIcon': getLadderChevron64x64(division),
                           'id': clubID,
                           'showLadder': True}})
            self.as_setDetailsS({'viewLinkage': linkage,
             'data': vo})
        else:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_NONSTATIC
            self.as_setDetailsS({'viewLinkage': linkage,
             'data': vo})
        self.__updateVehicleLabel()
        return

    def __refreshDetails(self, idx):
        cfdUnitID, vo = self._searchDP.getRally(idx)
        self.__setDetailsData(cfdUnitID, vo)

    def __updateView(self, user):
        self._searchDP.updateListItem(user.getID())
        self.__refreshDetails(self._searchDP.selectedRallyIndex)

    def __onVehiclesChanged(self, *args):
        self._selectedVehicles = self.unitFunctional.getSelectedVehicles(self._section)
        self.updateSelectedVehicles()
        self.unitFunctional.setSelectedVehicles(self._section, self._selectedVehicles)

    def __recenterList(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_RECENTER, unitTypeFlags=self._unitTypeFlags)

    def __onClubEmblem64x64Received(self, cfdUnitID, clubDbID, emblem):
        selectedCfdUnitID, _ = self._searchDP.getRally(self._searchDP.selectedRallyIndex)
        if emblem and cfdUnitID == selectedCfdUnitID:
            self.as_updateRallyIconS(self.getMemoryTexturePath(emblem))
class ClanInvitesWindow(ClanInvitesWindowMeta, ClanListener, ClanEmblemsHelper):
    __coolDownRequests = [CLAN_REQUESTED_DATA_TYPE.CLAN_APPLICATIONS, CLAN_REQUESTED_DATA_TYPE.CLAN_INVITES]

    def __init__(self, *args):
        super(ClanInvitesWindow, self).__init__()
        self.__actualRequestsCount = '0'
        self.__processedInvitesCount = '0'
        self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
        self.__clanDbID = self.clanProfile.getClanDbID()
        self.__clanDossier = weakref.proxy(self.clansCtrl.getClanDossier(self.__clanDbID))
        self.__pagiatorsController = _PaginatorsController(self.__clanDbID)

    def onClanStateChanged(self, oldStateID, newStateID):
        if not self.clansCtrl.isEnabled():
            self.onWindowClose()
        if not self.clansCtrl.isAvailable():
            pass

    def onAccountClanProfileChanged(self, profile):
        if not profile.isInClan() or not profile.getMyClanPermissions().canHandleClanInvites():
            self.destroy()

    def onClanInfoReceived(self, clanDbID, clanInfo):
        if clanDbID == self.__clanDbID:
            self._updateClanInfo()
            self._updateHeaderState()

    def onInvitesButtonClick(self):
        showClanSendInviteWindow(self.clanProfile.getClanDbID())

    def onWindowClose(self):
        self.destroy()

    def onClanEmblem128x128Received(self, clanDbID, emblem):
        self.as_setClanEmblemS(self.getMemoryTexturePath(emblem))

    @property
    def clanProfile(self):
        return self.clansCtrl.getAccountProfile()

    @property
    def paginatorsController(self):
        return self.__pagiatorsController

    @property
    def clanInfo(self):
        return self.__clanDossier.getClanInfo()

    def resyncClanInfo(self, force = False):
        self.__clanDossier.resyncClanInfo(force=force)

    def showWaiting(self, show):
        if show:
            self.as_showWaitingS(WAITING.LOADINGDATA, {})
        elif not self.paginatorsController.isInProgress():
            self.as_hideWaitingS()

    def formatInvitesCount(self, paginator):
        return formatters.formatInvitesCount(paginator.getTotalCount())

    def _populate(self):
        self.showWaiting(True)
        super(ClanInvitesWindow, self)._populate()
        self.__initControls()
        self._cooldown.start()
        self.startClanListening()
        self.__pagiatorsController.setCallback(self._onPaginatorListChanged)
        self.resyncClanInfo()
        self.__pagiatorsController.getPanginator(CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_ALIAS, CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL).reset()
        self.__pagiatorsController.getPanginator(CLANS_ALIASES.CLAN_PROFILE_INVITES_VIEW_ALIAS, CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED).reset()

    def _dispose(self):
        self.stopClanListening()
        self.__pagiatorsController.removeCallbacks()
        self._cooldown.stop()
        self._cooldown = None
        super(ClanInvitesWindow, self)._dispose()
        return

    def _onRegisterFlashComponent(self, viewPy, alias):
        super(ClanInvitesWindow, self)._onRegisterFlashComponent(viewPy, alias)
        viewPy.setParentWindow(self)

    def _onCooldownHandle(self, isInCooldown):
        self.showWaiting(isInCooldown)

    def _onPaginatorListChanged(self, alias, filter, selectedID, isFullUpdate, isReqInCoolDown, result):
        paginator = self.__pagiatorsController.getPanginator(alias, filter)
        if alias == CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_ALIAS:
            if filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL:
                self.__actualRequestsCount = self.formatInvitesCount(paginator)
                self._updateTabsState()
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED:
                pass
            else:
                LOG_DEBUG('Unexpected behaviour: unknown filter {} for alias {}'.format(filter, alias))
        elif alias == CLANS_ALIASES.CLAN_PROFILE_INVITES_VIEW_ALIAS:
            if filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_ALL:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED:
                pass
            elif filter == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED:
                self.__processedInvitesCount = self.formatInvitesCount(paginator)
                self._updateTabsState()
            else:
                LOG_DEBUG('Unexpected behaviour: unknown filter {} for alias {}'.format(filter, alias))
        else:
            LOG_DEBUG('Unexpected behaviour: unknown view alias ', alias)
        self.showWaiting(False)

    def _updateClanEmblem(self):
        self.requestClanEmblem128x128(self.clanProfile.getClanDbID())

    def _updateClanInfo(self):
        self.as_setClanInfoS({'name': self.clanProfile.getClanFullName(),
         'bgIcon': RES_ICONS.MAPS_ICONS_CLANS_INVITESWINDOW_CC_HEADER_BACK,
         'creationDate': i18n.makeString(CLANS.CLAN_HEADER_CREATIONDATE, creationDate=BigWorld.wg_getLongDateFormat(self.clanProfile.getJoinedAt()))})

    def _updateHeaderState(self):
        freePlaces = self.clanInfo.getFreePlaces()
        freePlacesInClanText = text_styles.concatStylesToSingleLine(text_styles.standard(_ms(CLANS.CLANINVITESWINDOW_HEADER_FREEPLACESINCLAN, count=text_styles.main(formatField(getter=self.clanInfo.getFreePlaces)))))
        if freePlaces == 0:
            inviteButtonEnabled = False
            inviteButtonTooltip = _ms(CLANS.CLANINVITESWINDOW_HEADER_TOOLTIPS_NOPLACES)
            freePlacesInClanText = gui.makeHtmlString('html_templates:lobby/research', 'warningMessage', {'text': freePlacesInClanText})
        else:
            inviteButtonEnabled = True
            inviteButtonTooltip = _ms(CLANS.CLANINVITESWINDOW_TOOLTIPS_HEADER_INVITEBUTTON)
        self.as_setHeaderStateS({'inviteButtonEnabled': inviteButtonEnabled,
         'inviteButtonText': CLANS.CLANINVITESWINDOW_HEADER_INVITEINCLAN,
         'inviteButtonTooltip': makeTooltip(body=inviteButtonTooltip),
         'freePlacesInClanText': freePlacesInClanText})

    def _updateTabsState(self):
        self.as_setDataS({'tabDataProvider': [{'label': i18n.makeString(CLANS.CLANINVITESWINDOW_TABREQUESTS, value=self.__actualRequestsCount),
                              'linkage': CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_LINKAGE}, {'label': i18n.makeString(CLANS.CLANINVITESWINDOW_TABINVITES, value=self.__processedInvitesCount),
                              'linkage': CLANS_ALIASES.CLAN_PROFILE_INVITES_VIEW_LINKAGE}]})

    def __initControls(self):
        self._updateTabsState()
        self._updateHeaderState()
        self._updateClanInfo()
        self._updateClanEmblem()
Exemple #29
0
class ClanPersonalInvitesView(ClanPersonalInvitesViewMeta, ClanListener):
    def __init__(self):
        super(ClanPersonalInvitesView, self).__init__()
        self._paginator = ClanPersonalInvitesPaginator(
            self.clansCtrl, getPlayerDatabaseID(), [CLAN_INVITE_STATES.ACTIVE])
        self._cooldown = CooldownHelper([
            CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
            CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
            CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
            CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
            CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES,
            CLAN_REQUESTED_DATA_TYPE.CLANS_INFO,
            CLAN_REQUESTED_DATA_TYPE.CLAN_RATINGS,
            CLAN_REQUESTED_DATA_TYPE.ACCOUNT_INVITES
        ], self._onCooldownHandle, CoolDownEvent.CLAN)

    def declineAllSelectedInvites(self):
        self._paginator.declineList(self.dataProvider.getCheckedIDs())

    def acceptInvite(self, dbID):
        self._paginator.accept(int(dbID))

    def declineInvite(self, dbID):
        self._paginator.decline(int(dbID))

    def showMore(self):
        if not self._paginator.isInProgress():
            self.showWaiting(True)
            self._paginator.right()

    def setSelectAllInvitesCheckBoxSelected(self, checked):
        self.dataProvider.setSelectAll(checked)
        self._updateDeclineSelectedGroup()

    def setInviteSelected(self, dbID, checked):
        self.dataProvider.setCheckedID(dbID, checked)
        self._updateDeclineSelectedGroup()

    def onSortChanged(self, dataProvider, sort):
        order = sort[0][1]
        secondSort = tuple(
            ((item, order) for item in self._getSecondSortFields()))
        if not self._paginator.isInProgress():
            self.showWaiting(True)
            self._paginator.sort(sort + secondSort)

    def onAccountInvitesReceived(self, invites):
        super(ClanPersonalInvitesView, self).onAccountInvitesReceived(invites)
        self._enableRefreshBtn(True)

    def showWaiting(self, show):
        if show:
            self._parentWnd.as_showWaitingS(
                CLANS.CLANPERSONALINVITESWINDOW_LOADING, {})
        elif not self._paginator.isInProgress():
            self._parentWnd.as_hideWaitingS()

    def refreshTable(self):
        self._enableRefreshBtn(False)
        self.showWaiting(True)
        self._paginator.refresh()

    def _createSearchDP(self):
        return PersonalInvitesDataProvider(self)

    def _onAttachedToWindow(self):
        super(ClanPersonalInvitesView, self)._onAttachedToWindow()
        self.showWaiting(True)
        self.setSelectAllInvitesCheckBoxSelected(False)
        self._updateDeclineSelectedText(0)
        self._cooldown.start()
        self._paginator.onListUpdated += self._onListUpdated
        self._paginator.onListItemsUpdated += self._onListItemsUpdated
        self._paginator.reset()

    def _populate(self):
        super(ClanPersonalInvitesView, self)._populate()
        self.startClanListening()

    def _dispose(self):
        self._paginator.onListUpdated -= self._onListUpdated
        self._paginator.onListItemsUpdated -= self._onListItemsUpdated
        self._cooldown.stop()
        self._cooldown = None
        self.stopClanListening()
        self.clansCtrl.clearClanCommonDataCache()
        super(ClanPersonalInvitesView, self)._dispose()
        return

    def _onCooldownHandle(self, isInCooldown):
        self.dataProvider.allowActions(not isInCooldown)

    def _onListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown,
                       result):
        self._updateSortField(self._paginator.getLastSort())
        status, data = result
        if status is True:
            self._enableRefreshBtn(False)
            if not data:
                self._showDummy(CLANS.CLANPERSONALINVITESWINDOW_NOINVITES)
                self.dataProvider.rebuildList(None, False)
            else:
                self.clansCtrl.updateClanCommonDataCache([
                    ClanCommonData.fromClanPersonalInviteWrapper(item)
                    for item in data
                ])
                self.dataProvider.rebuildList(data,
                                              self._paginator.canMoveRight())
                self.as_hideDummyS()
        else:
            self._enableRefreshBtn(
                True,
                toolTip=CLANS.
                CLANINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_ENABLEDTRYTOREFRESH)
            self._showDummy(CLANS.CLANINVITESWINDOW_DUMMY_SERVERERROR_TITLE,
                            CLANS.CLANINVITESWINDOW_DUMMY_SERVERERROR_TEXT,
                            RES_ICONS.MAPS_ICONS_LIBRARY_ALERTBIGICON,
                            alignCenter=False)
        self._updateDeclineSelectedGroup()
        self.showWaiting(False)
        return

    def _onListItemsUpdated(self, paginator, items):
        self.dataProvider.refreshItems(items)
        self._updateDeclineSelectedGroup()
        if not self._paginator.isInProgress():
            self.showWaiting(False)

    def _updateDeclineSelectedGroup(self):
        hasInvites = self.dataProvider.itemsCount() > 0
        self._updateDeclineSelectedText(self.dataProvider.selectedCount())
        self.as_setSelectAllCheckboxStateS(self.dataProvider.areAllSelected(),
                                           hasInvites)

    def _updateDeclineSelectedText(self, count):
        self.as_setDeclineAllSelectedInvitesStateS(
            _ms(CLANS.CLANPERSONALINVITESWINDOW_DECLINESELECTED, count=count),
            False if count == 0 or self._paginator.isInProgress() else True)

    def _getSecondSortFields(self):
        return ('createdAt', )

    def _makeHeaders(self):
        return [
            self._packHeaderColumnData(
                'clanName',
                CLANS.CLANPERSONALINVITESWINDOW_TABLE_CLANNAME,
                233,
                CLANS.
                CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_CLANNAME,
                textAlign='left',
                enabled=True,
                defaultSortDirection='ascending'),
            self._packHeaderColumnData(
                'message',
                '',
                73,
                CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_MESSAGE,
                RES_ICONS.
                MAPS_ICONS_CLANS_INVITESWINDOW_ICON_STATISTICS_CLAN_INVITE_098,
                enabled=True),
            self._packHeaderColumnData(
                'personalRating',
                '',
                98,
                CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_RATING,
                RES_ICONS.MAPS_ICONS_STATISTIC_RATING24,
                enabled=True),
            self._packHeaderColumnData(
                'battlesCount',
                '',
                98,
                CLANS.
                CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_BATTLESCOUNT,
                RES_ICONS.MAPS_ICONS_STATISTIC_BATTLES24,
                enabled=True),
            self._packHeaderColumnData(
                'wins',
                '',
                98,
                CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_WINS,
                RES_ICONS.MAPS_ICONS_STATISTIC_WINS24,
                enabled=True),
            self._packHeaderColumnData(
                'awgExp',
                '',
                98,
                CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_AWGEXP,
                RES_ICONS.MAPS_ICONS_STATISTIC_AVGEXP24,
                enabled=True),
            self._packHeaderColumnData(
                'status',
                CLANS.CLANPERSONALINVITESWINDOW_TABLE_STATUS,
                160,
                CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_STATUS,
                enabled=True),
            self._packHeaderColumnData(
                'actions',
                CLANS.CLANPERSONALINVITESWINDOW_TABLE_ACTIONS,
                132,
                CLANS.
                CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_ACTIONS,
                enabled=False)
        ]

    def _enableRefreshBtn(self, enable, toolTip=None):
        if enable:
            self.as_updateButtonRefreshStateS(
                True,
                makeTooltip(body=_ms(
                    toolTip or CLANS.
                    CLANPERSONALINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_ENABLED)))
        else:
            self.as_updateButtonRefreshStateS(
                False,
                makeTooltip(body=_ms(
                    toolTip or CLANS.
                    CLANPERSONALINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_DISABLED))
            )
Exemple #30
0
class BattleMessengerView(BattleMessengerMeta, IBattleChannelView,
                          IContactsAndPersonalInvitationsController):
    def __init__(self):
        super(BattleMessengerView, self).__init__()
        self.__controllers = {}
        self.__receivers = []
        self.__receiverIndex = 0
        self.__isEnabled = False
        self.__isFocused = False
        self._battleCtx = None
        self._arenaVisitor = None
        self._accDbID = 0
        self._toxicPanelMsgID = 0
        self._addedMsgIDs = set()
        self._ignoreActionCooldown = CooldownHelper(
            (CLIENT_ACTION_ID.ADD_IGNORED, CLIENT_ACTION_ID.REMOVE_IGNORED),
            self._onIgnoreActionCooldownHandle, CoolDownEvent.XMPP)
        return

    @storage_getter('users')
    def usersStorage(self):
        return None

    @proto_getter(PROTO_TYPE.MIGRATION)
    def protoMigration(self):
        return None

    @proto_getter(PROTO_TYPE.BW_CHAT2)
    def protoBwChat2(self):
        return None

    def getControllerID(self):
        return BATTLE_CTRL_ID.GUI

    def startControl(self, battleCtx, arenaVisitor):
        """Starts to controlling data of arena.
        
        :param battleCtx: proxy to battle context.
        :param arenaVisitor: proxy to arena visitor.
        """
        self._battleCtx = battleCtx
        self._arenaVisitor = arenaVisitor

    def stopControl(self):
        self._battleCtx = None
        self._arenaVisitor = None
        return

    def getToxicStatus(self, accountDbID):
        """
        Invoked by the view at runtime to get VO of buttons panel.
        
        :param accountDbID: Message ID that corresponds to player database ID.
        :return: dict
        """
        vo = None
        accountDbID = long(accountDbID)
        if 0 < accountDbID != self._accDbID:
            vo = self.__buildToxicStateVO(accountDbID)
        if vo is not None:
            self._toxicPanelMsgID = accountDbID
        return vo

    def updateToxicStatus(self, accountDbID):
        self.as_updateToxicPanelS(accountDbID,
                                  self.__buildToxicStateVO(accountDbID))

    def onToxicButtonClicked(self, accountDbID, actionID):
        """
        Callback on user's action. Note that the same callback is invoked for all 'toxic' buttons.
        To determine which button is pressed, action ID is used. Action ID corresponds to the
        following constants from BATTLE_MESSAGES_CONSTS enum.
        
        :param accountDbID: Message ID that corresponds to player database ID.
        :param actionID: Action ID.
        """
        accDbID = long(accountDbID)
        if accDbID > 0:
            needUpdateUI = True
            if actionID == BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST:
                if not self._ignoreActionCooldown.isInCooldown():
                    self.protoMigration.contacts.addTmpIgnored(
                        accDbID, self._battleCtx.getPlayerName(accID=accDbID))
            elif actionID == BATTLE_MESSAGES_CONSTS.REMOVE_FROM_BLACKLIST:
                if not self._ignoreActionCooldown.isInCooldown():
                    self.protoMigration.contacts.removeTmpIgnored(accDbID)
            else:
                needUpdateUI = False
            if needUpdateUI:
                self._invalidateToxicPanel(accDbID)

    def onToxicPanelClosed(self, messageID):
        """
        Callback on toxic panel close event.
        
        :param messageID: Message ID that corresponds to player database ID.
        """
        if 0 < self._toxicPanelMsgID == messageID:
            self._toxicPanelMsgID = 0

    def invalidateUsersTags(self):
        """
        New list of chat rosters has been received.
        """
        self._invalidateToxicPanel(self._toxicPanelMsgID)
        for msgID in self._addedMsgIDs:
            self._invalidatePlayerMessages(msgID)

    def invalidateUserTags(self, user):
        """
        Contact's chat roster has been changed.
        
        :param user: instance of UserEntity.
        """
        accDbID = user.getID()
        self._invalidatePlayerMessages(accDbID)
        self._invalidateToxicPanel(accDbID)

    def invalidateInvitationsStatuses(self, vos, arenaDP):
        """
        An invitation has been received.
        :param vos: invitations represented by list of VehicleArenaInfoVO objects.
        :param arenaDP: Reference to ArenaDataProvider
        """
        if self._toxicPanelMsgID > 0:
            for vInfo in vos:
                if vInfo.player.accountDBID == self._toxicPanelMsgID:
                    self._invalidateToxicPanel(self._toxicPanelMsgID)
                    break

    def handleEnterPressed(self):
        if not self.__isEnabled:
            return False
        if self.app.isModalViewShown() or self.app.hasGuiControlModeConsumers(
                *_CONSUMERS_LOCK_ENTER):
            return False
        if not self.__isFocused:
            self.__findReceiverIndexByModifiers()
        self.as_enterPressedS(self.__receiverIndex)
        return True

    def handleCTRLPressed(self, _, isDown):
        """
        Handler of Ctrl button press event.
        
        :param _: True if the event associated with the left Ctrl btn, False - if the right Ctrl.
        :param isDown: True if the Ctrl btn is down, False if it is up.
        """
        if self.app.isModalViewShown() or self.app.hasGuiControlModeConsumers(
                *_CONSUMERS_LOCK_ENTER):
            return False
        self.as_toggleCtrlPressFlagS(isDown)
        return True

    def setFocused(self, value):
        if self.__isFocused == value:
            return False
        self.__isFocused = value
        LOG_DEBUG('Sets focus to the battle chat', value)
        if self.__isFocused:
            self.as_setFocusS()
        else:
            self.as_unSetFocusS()
        return True

    def isFocused(self):
        return self.__isFocused

    def focusReceived(self):
        LOG_DEBUG('Battle chat is in focus')
        self.__setGuiMode(True)
        self.protoBwChat2.voipController.setMicrophoneMute(True)

    def focusLost(self):
        LOG_DEBUG('Battle chat is not in focus')
        self.__setGuiMode(False)

    def sendMessageToChannel(self, receiverIndex, rawMsgText):
        if receiverIndex < 0 or receiverIndex >= len(self.__receivers):
            LOG_ERROR('Index of receiver is not valid', receiverIndex)
            return False
        else:
            clientID = self.__receivers[receiverIndex][0]
            result = self.__canSendMessage(clientID)
            if result:
                controller = self.__getController(clientID)
                if not rawMsgText:
                    self.setFocused(False)
                if controller is not None:
                    controller.sendMessage(rawMsgText)
                else:
                    LOG_ERROR('Channel is not found to send message', clientID)
                return True
            return False
            return

    def enableToSendMessage(self):
        self.__isEnabled = True
        self.as_enableToSendMessageS()

    def setNextReceiver(self):
        if self.__isFocused and self.__findNextReceiverIndex():
            LOG_DEBUG('Sets receiver in the battle chat', self.__receiverIndex)
            g_settings.battle.lastReceiver = self.__receivers[
                self.__receiverIndex][1].name
            self.as_changeReceiverS(self.__receiverIndex)
            return True
        else:
            return False

    def invalidateReceivers(self):
        self.__receivers = []
        vos = []
        for clientID, ctrlRef in self.__controllers.iteritems():
            controller = ctrlRef()
            if controller is not None and controller.getChannel().isJoined():
                receiver, isReset = self.__addReceiver(clientID, controller)
                if receiver is not None:
                    if isReset:
                        vos = []
                    vos.append(_makeReceiverVO(*receiver))

        self.as_setReceiversS(vos)
        if self.__invalidateReceiverIndex():
            self.as_changeReceiverS(self.__receiverIndex)
        return

    def invalidateUserPreferences(self):
        self.as_setUserPreferencesS(_getToolTipText(self._arenaVisitor))
        self.invalidateReceivers()

    def addController(self, controller):
        channel = controller.getChannel()
        clientID = channel.getClientID()
        self.__controllers[clientID] = weakref.ref(controller)
        receiver, isReset = self.__addReceiver(clientID, controller)
        if receiver is not None:
            self.as_setReceiverS(_makeReceiverVO(*receiver), isReset)
        if self.__invalidateReceiverIndex():
            self.as_changeReceiverS(self.__receiverIndex)
        return

    def removeController(self, controller):
        self.__controllers.pop(controller.getChannel().getClientID(), None)
        return

    def addMessage(self, message, fillColor=FILL_COLORS.BLACK, accountDBID=0):
        if accountDBID == self._accDbID:
            accountDBID = 0
        if fillColor == FILL_COLORS.BLACK:
            self.as_showBlackMessageS(message, accountDBID)
        elif fillColor == FILL_COLORS.RED:
            self.as_showRedMessageS(message, accountDBID)
        elif fillColor == FILL_COLORS.BROWN:
            self.as_showSelfMessageS(message, accountDBID)
        elif fillColor == FILL_COLORS.GREEN:
            self.as_showGreenMessageS(message, accountDBID)
        else:
            LOG_UNEXPECTED('Unexpected fill color: ', fillColor)
        if accountDBID > 0:
            self._addedMsgIDs.add(accountDBID)

    def isToxicPanelAvailable(self):
        """
        Returns True if the toxic panel is available, otherwise returns false.
        """
        return not BattleReplay.g_replayCtrl.isPlaying and self._arenaVisitor is not None and not self._arenaVisitor.gui.isTrainingBattle(
        )

    def _populate(self):
        super(BattleMessengerView, self)._populate()
        self._accDbID = getAvatarDatabaseID()
        self.__receivers = []
        self.fireEvent(ChannelManagementEvent(
            0, ChannelManagementEvent.REGISTER_BATTLE, {'component': self}),
                       scope=EVENT_BUS_SCOPE.BATTLE)
        self.addListener(ChannelManagementEvent.MESSAGE_FADING_ENABLED,
                         self.__handleMessageFadingEnabled,
                         EVENT_BUS_SCOPE.GLOBAL)
        self.__restoreLastReceiverInBattle()
        g_sessionProvider.addArenaCtrl(self)
        self.as_setupListS(_makeSettingsVO(self._arenaVisitor))
        self._ignoreActionCooldown.start()
        if self.isToxicPanelAvailable():
            self.as_enableToxicPanelS()

    def _dispose(self):
        self.__receivers = []
        self._ignoreActionCooldown.stop()
        self._ignoreActionCooldown = None
        self.fireEvent(ChannelManagementEvent(
            0, ChannelManagementEvent.UNREGISTER_BATTLE),
                       scope=EVENT_BUS_SCOPE.BATTLE)
        self.removeListener(ChannelManagementEvent.MESSAGE_FADING_ENABLED,
                            self.__handleMessageFadingEnabled,
                            EVENT_BUS_SCOPE.GLOBAL)
        g_sessionProvider.removeArenaCtrl(self)
        super(BattleMessengerView, self)._dispose()
        return

    def _invalidateToxicPanel(self, msgID):
        """
        Updates toxic panel if it is visible for the given message.
        
        :param msgID: Message ID that corresponds to player database ID.
        """
        if 0 < self._toxicPanelMsgID == msgID:
            self.updateToxicStatus(msgID)

    def _invalidatePlayerMessages(self, accountDbID):
        if accountDbID > 0:
            contact = self.usersStorage.getUser(accountDbID)
            if contact is not None and contact.isIgnored():
                pInfo = self._battleCtx.getPlayerFullNameParts(
                    accID=accountDbID)
                template = i18n.makeString(
                    MESSENGER.CHAT_TOXICMESSAGES_BLOCKEDMESSAGE,
                    playerName=pInfo.playerName,
                    clanName=pInfo.clanAbbrev)
                self.as_updateMessagesS(accountDbID,
                                        text_styles.main(template))
            else:
                self.as_restoreMessagesS(accountDbID)
        return

    def _onIgnoreActionCooldownHandle(self, isInCooldown):
        self._invalidateToxicPanel(self._toxicPanelMsgID)

    def __buildToxicStateVO(self, accountDbID):
        """
        Builds vo related to the toxic panel.
        
        :param accountDbID: long representing account's database ID
        :return: dict
        """
        contact = self.usersStorage.getUser(accountDbID)
        return {
            'messageID': accountDbID,
            'vehicleID': self._battleCtx.getVehIDByAccDBID(accountDbID),
            'blackList': self.__buildBlackListVO(contact)
        }

    def __buildBlackListVO(self, contact):
        """
        Builds vo related to the Black List button.
        
        :param contact: an instance of UserEntity
        :return: dict
        """
        isEnabled = not self._ignoreActionCooldown.isInCooldown()
        if contact:
            if contact.isTemporaryIgnored():
                status = BATTLE_MESSAGES_CONSTS.REMOVE_FROM_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_REMOVE_FROM_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_REMOVE_FROM_BLACKLIST_BODY
            elif contact.isIgnored():
                status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_CANT_ADD_IN_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_CANT_ADD_IN_BLACKLIST_BODY
                isEnabled = False
            else:
                status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_BODY
        else:
            status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
            header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_HEADER
            body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_BODY
        return {
            'status': status,
            'tooltip': makeTooltip(header=header, body=body),
            'enabled': isEnabled
        }

    def __canSendMessage(self, clientID):
        result = True
        controller = self.__getController(clientID)
        if controller is None:
            return result
        else:
            result, errorMsg = controller.canSendMessage()
            if not result:
                message = g_settings.htmlTemplates.format(
                    'battleErrorMessage', ctx={'error': errorMsg})
                self.addMessage(message, fillColor=FILL_COLORS.BLACK)
            return result

    def __getController(self, clientID):
        controller = None
        if clientID in self.__controllers:
            ctrlRef = self.__controllers[clientID]
            if ctrlRef:
                controller = ctrlRef()
        return controller

    def __addReceiver(self, clientID, controller):
        isReset = False
        settings = controller.getSettings()
        isChatEnabled = controller.isEnabled()
        if isChatEnabled:
            if not isBattleChatEnabled(
            ) and settings.name == BATTLE_CHANNEL.SQUAD.name:
                self.__receivers = []
                self.__receiverIndex = 0
                isReset = True
        elif settings == BATTLE_CHANNEL.COMMON:
            return (None, isReset)
        receivers = g_settings.battle.receivers
        receiverName = settings.name
        if receiverName in receivers:
            guiSettings = receivers[receiverName]
        else:
            LOG_ERROR('Settings of receiver is not found', receiverName)
            guiSettings = None
        receiver = (clientID, guiSettings, isChatEnabled)
        self.__receivers.append(receiver)
        self.__receivers = sorted(self.__receivers,
                                  key=lambda item: item[1].order)
        return (receiver, isReset)

    def __setGuiMode(self, value):
        if value:
            self.__isFocused = True
            self.app.enterGuiControlMode('chat')
            self.__findReceiverIndexByModifiers()
            LOG_DEBUG('Sets receiver in the battle chat', self.__receiverIndex)
            self.as_changeReceiverS(self.__receiverIndex)
        else:
            self.__isFocused = False
            self.app.leaveGuiControlMode('chat')

    def __restoreLastReceiverInBattle(self):
        """ WOTD-71200 Restore last receiver in battle
        """
        if g_settings.userPrefs.storeReceiverInBattle:
            for idx, receiver in enumerate(self.__receivers):
                if g_settings.battle.lastReceiver == receiver[1].name:
                    if self.__isReceiverAvailable(idx):
                        self.__receiverIndex = idx
                    break

        self.__invalidateReceiverIndex()

    def __findReceiverIndexByModifiers(self):
        for idx, (clientID, settings, _) in enumerate(self.__receivers):
            modifiers = settings.bwModifiers
            for modifier in modifiers:
                if BigWorld.isKeyDown(modifier):
                    if self.__isReceiverAvailable(idx):
                        self.__receiverIndex = idx

        if not g_settings.userPrefs.storeReceiverInBattle:
            self.__receiverIndex = 0
        self.__invalidateReceiverIndex()

    def __invalidateReceiverIndex(self):
        if not self.__isReceiverAvailable(self.__receiverIndex):
            return self.__findNextReceiverIndex()
        return False

    def __findNextReceiverIndex(self):
        receiversCount = len(self.__receivers)
        if receiversCount > 0:
            leftReceiversCount = receiversCount - 1
        else:
            leftReceiversCount = 0
        index = self.__receiverIndex
        while leftReceiversCount:
            leftReceiversCount -= 1
            index += 1
            if index >= receiversCount:
                index = 0
            if self.__isReceiverAvailable(index):
                self.__receiverIndex = index
                return True

        return False

    def __isReceiverAvailable(self, index):
        if index < len(self.__receivers):
            _, _, isChatEnabled = self.__receivers[index]
            return isChatEnabled
        return False

    def __handleMessageFadingEnabled(self, event):
        self.as_setActiveS(not event.ctx['isEnabled'])
Exemple #31
0
class BattleMessengerView(BattleMessengerMeta, IBattleChannelView,
                          IContactsAndPersonalInvitationsController):
    sessionProvider = dependency.descriptor(IBattleSessionProvider)

    def __init__(self):
        super(BattleMessengerView, self).__init__()
        self.__controllers = {}
        self.__receivers = []
        self.__receiverIndex = 0
        self.__isEnabled = False
        self.__isFocused = False
        self._battleCtx = None
        self._arenaVisitor = None
        self._avatarSessionID = ''
        self._toxicPanelMsgID = ''
        self._addedMsgIDs = set()
        self._ignoreActionCooldown = CooldownHelper(
            (CLIENT_ACTION_ID.ADD_IGNORED, CLIENT_ACTION_ID.REMOVE_IGNORED),
            self._onIgnoreActionCooldownHandle, CoolDownEvent.BATTLE_ACTION)
        return

    @storage_getter('users')
    def usersStorage(self):
        return None

    @proto_getter(PROTO_TYPE.BW_CHAT2)
    def protoBwChat2(self):
        return None

    def getControllerID(self):
        return BATTLE_CTRL_ID.GUI

    def startControl(self, battleCtx, arenaVisitor):
        self._battleCtx = battleCtx
        self._arenaVisitor = arenaVisitor

    def stopControl(self):
        self._battleCtx = None
        self._arenaVisitor = None
        return

    def getToxicStatus(self, avatarSessionID):
        vo = None
        if avatarSessionID and avatarSessionID != self._avatarSessionID:
            vo = self.__buildToxicStateVO(avatarSessionID)
        if vo is not None:
            self._toxicPanelMsgID = avatarSessionID
        return vo

    def updateToxicStatus(self, avatarSessionID):
        self.as_updateToxicPanelS(avatarSessionID,
                                  self.__buildToxicStateVO(avatarSessionID))

    def onToxicButtonClicked(self, avatarSessionID, actionID):
        if avatarSessionID:
            needUpdateUI = True
            if actionID == BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST:
                if not self._ignoreActionCooldown.isInCooldown():
                    self.sessionProvider.shared.anonymizerFakesCtrl.addTmpIgnored(
                        avatarSessionID,
                        self._battleCtx.getPlayerName(
                            avatarSessionID=avatarSessionID))
            elif actionID == BATTLE_MESSAGES_CONSTS.REMOVE_FROM_BLACKLIST:
                if not self._ignoreActionCooldown.isInCooldown():
                    self.sessionProvider.shared.anonymizerFakesCtrl.removeTmpIgnored(
                        avatarSessionID)
            else:
                needUpdateUI = False
            if needUpdateUI:
                self._invalidateToxicPanel(avatarSessionID)

    def onToxicPanelClosed(self, messageID):
        if self._toxicPanelMsgID and self._toxicPanelMsgID == messageID:
            self._toxicPanelMsgID = ''

    def invalidateUsersTags(self):
        self._invalidateToxicPanel(self._toxicPanelMsgID)
        for messageID in self._addedMsgIDs:
            self._invalidatePlayerMessages(messageID)

    def invalidateUserTags(self, user):
        avatarSessionID = user.getID()
        self._invalidatePlayerMessages(avatarSessionID)
        self._invalidateToxicPanel(avatarSessionID)

    def invalidateInvitationsStatuses(self, vos, arenaDP):
        if self._toxicPanelMsgID:
            for vInfo in vos:
                if vInfo.player.avatarSessionID == self._toxicPanelMsgID:
                    self._invalidateToxicPanel(self._toxicPanelMsgID)
                    break

    def handleEnterPressed(self):
        if not self.__isEnabled:
            return False
        if self.app.isModalViewShown() or self.app.hasGuiControlModeConsumers(
                *_CONSUMERS_LOCK_ENTER):
            return False
        if not self.__isFocused:
            self.__findReceiverIndexByModifiers()
        self.as_enterPressedS(self.__receiverIndex)
        return True

    def handleCTRLPressed(self, _, isDown):
        if self.app.isModalViewShown() or self.app.hasGuiControlModeConsumers(
                *_CONSUMERS_LOCK_ENTER):
            return False
        self.as_toggleCtrlPressFlagS(isDown)
        return True

    def setFocused(self, value):
        if self.__isFocused == value:
            return False
        self.__isFocused = value
        LOG_DEBUG('Sets focus to the battle chat', value)
        if self.__isFocused:
            self.as_setFocusS()
        else:
            self.as_unSetFocusS()
        return True

    def isFocused(self):
        return self.__isFocused

    def focusReceived(self):
        LOG_DEBUG('Battle chat is in focus')
        self.__setGuiMode(True)
        self.protoBwChat2.voipController.setMicrophoneMute(True)

    def focusLost(self):
        LOG_DEBUG('Battle chat is not in focus')
        self.__setGuiMode(False)

    def sendMessageToChannel(self, receiverIndex, rawMsgText):
        if receiverIndex < 0 or receiverIndex >= len(self.__receivers):
            LOG_ERROR('Index of receiver is not valid', receiverIndex)
            return False
        else:
            clientID = self.__receivers[receiverIndex][0]
            result = self.__canSendMessage(clientID)
            if result:
                controller = self.__getController(clientID)
                if not rawMsgText:
                    self.setFocused(False)
                if controller is not None:
                    controller.sendMessage(rawMsgText)
                else:
                    LOG_ERROR('Channel is not found to send message', clientID)
                return True
            return False
            return

    def enableToSendMessage(self):
        self.__isEnabled = True
        self.as_enableToSendMessageS()

    def setNextReceiver(self):
        if self.__isFocused and self.__findNextReceiverIndex():
            LOG_DEBUG('Sets receiver in the battle chat', self.__receiverIndex)
            g_settings.battle.lastReceiver = self.__receivers[
                self.__receiverIndex][1].name
            self.as_changeReceiverS(self.__receiverIndex)
            return True
        return False

    def invalidateReceivers(self):
        self.__receivers = []
        vos = []
        for clientID, ctrlRef in self.__controllers.iteritems():
            controller = ctrlRef()
            if controller is not None and controller.getChannel().isJoined():
                receiver, isReset = self.__addReceiver(clientID, controller)
                if receiver is not None:
                    if isReset:
                        vos = []
                    vos.append(_makeReceiverVO(*receiver))

        self.as_setReceiversS(vos)
        if self.__invalidateReceiverIndex():
            self.as_changeReceiverS(self.__receiverIndex)
        return

    def invalidateUserPreferences(self):
        self.as_setUserPreferencesS(_getToolTipText(self._arenaVisitor))
        self.invalidateReceivers()

    def addController(self, controller):
        channel = controller.getChannel()
        clientID = channel.getClientID()
        self.__controllers[clientID] = weakref.ref(controller)
        receiver, isReset = self.__addReceiver(clientID, controller)
        if receiver is not None:
            self.as_setReceiverS(_makeReceiverVO(*receiver), isReset)
        self.__restoreLastReceiverInBattle()
        if self.__invalidateReceiverIndex():
            self.as_changeReceiverS(self.__receiverIndex)
        return

    def removeController(self, controller):
        self.__controllers.pop(controller.getChannel().getClientID(), None)
        return

    def addMessage(self,
                   message,
                   fillColor=FILL_COLORS.BLACK,
                   avatarSessionID=''):
        if self.__isInTimeWarp:
            return
        if avatarSessionID == self._avatarSessionID:
            avatarSessionID = ''
        if fillColor == FILL_COLORS.BLACK:
            self.as_showBlackMessageS(message, avatarSessionID)
        elif fillColor == FILL_COLORS.RED:
            self.as_showRedMessageS(message, avatarSessionID)
        elif fillColor == FILL_COLORS.BROWN:
            self.as_showSelfMessageS(message, avatarSessionID)
        elif fillColor == FILL_COLORS.GREEN:
            self.as_showGreenMessageS(message, avatarSessionID)
        else:
            LOG_UNEXPECTED('Unexpected fill color: ', fillColor)
        if avatarSessionID:
            self._addedMsgIDs.add(avatarSessionID)

    def isToxicPanelAvailable(self):
        return not BattleReplay.g_replayCtrl.isPlaying and self._arenaVisitor is not None and not self._arenaVisitor.gui.isTrainingBattle(
        )

    def _populate(self):
        super(BattleMessengerView, self)._populate()
        self._avatarSessionID = getAvatarSessionID()
        self.__isInTimeWarp = BattleReplay.g_replayCtrl.isTimeWarpInProgress
        self.__receivers = []
        self.fireEvent(ChannelManagementEvent(
            0, ChannelManagementEvent.REGISTER_BATTLE, {'component': self}),
                       scope=EVENT_BUS_SCOPE.BATTLE)
        self.addListener(ChannelManagementEvent.MESSAGE_FADING_ENABLED,
                         self.__handleMessageFadingEnabled,
                         EVENT_BUS_SCOPE.GLOBAL)
        self.__restoreLastReceiverInBattle()
        self.sessionProvider.addArenaCtrl(self)
        self.as_setupListS(_makeSettingsVO(self._arenaVisitor))
        self._ignoreActionCooldown.start()
        if self.isToxicPanelAvailable():
            self.as_enableToxicPanelS()
        if self.__invalidateReceiverIndex():
            self.as_changeReceiverS(self.__receiverIndex)
        if BattleReplay.g_replayCtrl.isPlaying:
            g_replayEvents.onTimeWarpStart += self.__onReplayTimeWarpStart
            g_replayEvents.onTimeWarpFinish += self.__onReplayTimeWarpFinished

    def __onReplayTimeWarpFinished(self):
        self.__isInTimeWarp = False

    def __onReplayTimeWarpStart(self):
        self.__isInTimeWarp = True

    def _dispose(self):
        self.__receivers = []
        self._ignoreActionCooldown.stop()
        self._ignoreActionCooldown = None
        self.fireEvent(ChannelManagementEvent(
            0, ChannelManagementEvent.UNREGISTER_BATTLE),
                       scope=EVENT_BUS_SCOPE.BATTLE)
        self.removeListener(ChannelManagementEvent.MESSAGE_FADING_ENABLED,
                            self.__handleMessageFadingEnabled,
                            EVENT_BUS_SCOPE.GLOBAL)
        self.sessionProvider.removeArenaCtrl(self)
        g_replayEvents.onTimeWarpStart -= self.__onReplayTimeWarpStart
        g_replayEvents.onTimeWarpFinish -= self.__onReplayTimeWarpFinished
        super(BattleMessengerView, self)._dispose()
        return

    def _invalidateToxicPanel(self, messageID):
        if self._toxicPanelMsgID and self._toxicPanelMsgID == messageID:
            self.updateToxicStatus(messageID)

    def _invalidatePlayerMessages(self, avatarSessionID):
        if avatarSessionID:
            contact = self.usersStorage.getUser(avatarSessionID,
                                                scope=UserEntityScope.BATTLE)
            if contact is not None and contact.isIgnored():
                pInfo = self._battleCtx.getPlayerFullNameParts(
                    avatarSessionID=avatarSessionID)
                template = i18n.makeString(
                    MESSENGER.CHAT_TOXICMESSAGES_BLOCKEDMESSAGE,
                    playerName=pInfo.playerName)
                self.as_updateMessagesS(avatarSessionID,
                                        text_styles.main(template))
            else:
                self.as_restoreMessagesS(avatarSessionID)
        return

    def _onIgnoreActionCooldownHandle(self, _):
        self._invalidateToxicPanel(self._toxicPanelMsgID)

    def __buildToxicStateVO(self, avatarSessionID):
        contact = self.usersStorage.getUser(avatarSessionID,
                                            scope=UserEntityScope.BATTLE)
        return {
            'messageID': avatarSessionID,
            'vehicleID': self._battleCtx.getVehIDBySessionID(avatarSessionID),
            'blackList': self.__buildBlackListVO(contact)
        }

    def __buildBlackListVO(self, contact):
        isEnabled = not self._ignoreActionCooldown.isInCooldown()
        if contact:
            if contact.isTemporaryIgnored():
                status = BATTLE_MESSAGES_CONSTS.REMOVE_FROM_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_REMOVE_FROM_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_REMOVE_FROM_BLACKLIST_BODY
            elif contact.isIgnored():
                status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_CANT_ADD_IN_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_CANT_ADD_IN_BLACKLIST_BODY
                isEnabled = False
            else:
                status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_BODY
        else:
            status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
            header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_HEADER
            body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_BODY
        return {
            'status': status,
            'tooltip': makeTooltip(header=header, body=body),
            'enabled': isEnabled
        }

    def __canSendMessage(self, clientID):
        result = True
        controller = self.__getController(clientID)
        if controller is None:
            return result
        else:
            result, errorMsg = controller.canSendMessage()
            if not result:
                message = g_settings.htmlTemplates.format(
                    'battleErrorMessage', ctx={'error': errorMsg})
                self.addMessage(message, fillColor=FILL_COLORS.BLACK)
            return result

    def __getController(self, clientID):
        controller = None
        if clientID in self.__controllers:
            ctrlRef = self.__controllers[clientID]
            if ctrlRef:
                controller = ctrlRef()
        return controller

    def __addReceiver(self, clientID, controller):
        isReset = False
        settings = controller.getSettings()
        isChatEnabled = controller.isEnabled()
        if isChatEnabled:
            if not isBattleChatEnabled(
            ) and settings.name == BATTLE_CHANNEL.SQUAD.name:
                self.__receivers = []
                self.__receiverIndex = 0
                isReset = True
        elif settings == BATTLE_CHANNEL.COMMON:
            return (None, isReset)
        receivers = g_settings.battle.receivers
        receiverName = settings.name
        if receiverName in receivers:
            guiSettings = receivers[receiverName]
        else:
            LOG_ERROR('Settings of receiver is not found', receiverName)
            guiSettings = None
        receiver = (clientID, guiSettings, isChatEnabled)
        self.__receivers.append(receiver)
        self.__receivers = sorted(self.__receivers,
                                  key=lambda item: item[1].order)
        return (receiver, isReset)

    def __setGuiMode(self, value):
        if value:
            self.__isFocused = True
            self.app.enterGuiControlMode('chat')
            self.__findReceiverIndexByModifiers()
            LOG_DEBUG('Sets receiver in the battle chat', self.__receiverIndex)
            self.as_changeReceiverS(self.__receiverIndex)
        else:
            self.__isFocused = False
            self.app.leaveGuiControlMode('chat')

    def __restoreLastReceiverInBattle(self):
        if g_settings.userPrefs.storeReceiverInBattle:
            for idx, receiver in enumerate(self.__receivers):
                if g_settings.battle.lastReceiver == receiver[1].name:
                    if self.__isReceiverAvailable(idx):
                        self.__receiverIndex = idx
                    break

    def __findReceiverIndexByModifiers(self):
        for idx, (_, settings, _) in enumerate(self.__receivers):
            modifiers = settings.bwModifiers
            for modifier in modifiers:
                if BigWorld.isKeyDown(modifier):
                    if self.__isReceiverAvailable(idx):
                        self.__receiverIndex = idx

        if not g_settings.userPrefs.storeReceiverInBattle:
            self.__receiverIndex = 0
        self.__invalidateReceiverIndex()

    def __invalidateReceiverIndex(self):
        return self.__findNextReceiverIndex(
        ) if not self.__isReceiverAvailable(self.__receiverIndex) else False

    def __findNextReceiverIndex(self):
        receiversCount = len(self.__receivers)
        if receiversCount > 0:
            leftReceiversCount = receiversCount - 1
        else:
            leftReceiversCount = 0
        index = self.__receiverIndex
        while leftReceiversCount:
            leftReceiversCount -= 1
            index += 1
            if index >= receiversCount:
                index = 0
            if self.__isReceiverAvailable(index):
                self.__receiverIndex = index
                return True

        return False

    def __isReceiverAvailable(self, index):
        if index < len(self.__receivers):
            _, _, isChatEnabled = self.__receivers[index]
            return isChatEnabled
        return False

    def __handleMessageFadingEnabled(self, event):
        self.as_setActiveS(not event.ctx['isEnabled'])
class CyberSportUnitsListView(CyberSportUnitsListMeta, UnitListener, ClubListener, ClubEmblemsHelper):

    def __init__(self):
        super(CyberSportUnitsListView, self).__init__()
        self._isBackButtonClicked = False
        self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
        self._cooldown = CooldownHelper(self.getCoolDownRequests(), self._onCooldownHandle, events.CoolDownEvent.PREBATTLE)
        self.__currentEmblem = None
        return

    def onUnitFunctionalInited(self):
        self.unitFunctional.setEntityType(PREBATTLE_TYPE.UNIT)

    def getPyDataProvider(self):
        return ManualSearchDataProvider()

    def getCoolDownRequests(self):
        return [REQUEST_TYPE.UNITS_LIST]

    def canBeClosed(self, callback):
        self._isBackButtonClicked = True
        callback(True)

    def setTeamFilters(self, showOnlyStatic):
        self._unitTypeFlags = UNIT_BROWSER_TYPE.RATED_CLUBS if showOnlyStatic else UNIT_BROWSER_TYPE.ALL
        self.__recenterList()

    def loadPrevious(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_LEFT)

    def loadNext(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_RIGHT)

    def refreshTeams(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_REFRESH)

    def getRallyDetails(self, index):
        if index != self._searchDP.selectedRallyIndex:
            self.__currentEmblem = None
        cfdUnitID, vo = self._searchDP.getRally(index)
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.setSelectedID(cfdUnitID)
        self.__setDetailsData(cfdUnitID, vo)
        return

    def showRallyProfile(self, clubDBID):
        club_events.showClubProfile(clubDBID)

    def _populate(self):
        super(CyberSportUnitsListView, self)._populate()
        self._cooldown.start()
        self.startUnitListening()
        if self.unitFunctional.getEntityType() != PREBATTLE_TYPE.NONE:
            self.unitFunctional.setEntityType(PREBATTLE_TYPE.UNIT)
        unit_ext.initListReq(self._unitTypeFlags).start(self.__onUnitsListUpdated)
        self.as_setSearchResultTextS(_ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS), '', self.__getFiltersData())
        headerDescription = CYBERSPORT.WINDOW_UNITLISTVIEW_DESCRIPTION
        headerTitle = CYBERSPORT.WINDOW_UNITLISTVIEW_TITLE
        self.as_setHeaderS({'title': headerTitle,
         'description': headerDescription,
         'createBtnLabel': CYBERSPORT.WINDOW_UNITLISTVIEW_CREATE_BTN,
         'createBtnTooltip': None,
         'createBtnEnabled': True,
         'columnHeaders': self.__getColumnHeaders()})
        return

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown = None
        if self._isBackButtonClicked:
            unit_ext.destroyListReq()
            self._isBackButtonClicked = False
        else:
            listReq = unit_ext.getListReq()
            if listReq:
                listReq.stop()
        self.stopUnitListening()
        super(CyberSportUnitsListView, self)._dispose()
        return

    def _onUserActionReceived(self, _, user):
        self.__updateView(user)

    def _doEnableNavButtons(self, isEnabled):
        self.as_updateNavigationBlockS({'previousVisible': True,
         'previousEnabled': isEnabled,
         'nextVisible': True,
         'nextEnabled': isEnabled,
         'icon': RES_ICONS.MAPS_ICONS_STATISTIC_RATING24})

    def _onCooldownHandle(self, isInCooldown):
        self._doEnableNavButtons(not isInCooldown)

    def __getColumnHeaders(self):
        return [self.__createHedader('', 54, RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_LADDERICON),
         self.__createHedader('', 58, RES_ICONS.MAPS_ICONS_STATISTIC_RATING24),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_COMMANDER, 152),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_DESCRIPTION, 220),
         self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_PLAYERS, 76)]

    def __createHedader(self, label, buttonWidth, iconSource = None):
        return {'label': label,
         'buttonWidth': buttonWidth,
         'iconSource': iconSource,
         'enabled': False}

    def __updateVehicleLabel(self):
        settings = self.unitFunctional.getRosterSettings()
        self._updateVehiclesLabel(int2roman(settings.getMinLevel()), int2roman(settings.getMaxLevel()))

    def __getFiltersData(self):
        return {'isSelected': self._unitTypeFlags == UNIT_BROWSER_TYPE.RATED_CLUBS,
         'icon': RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_RANKEDICON,
         'label': _ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS_FILTERTEXT)}

    def __onUnitsListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown, units):
        if isFullUpdate:
            selectedIdx = self._searchDP.rebuildList(selectedID, units)
            self._doEnableNavButtons(not isReqInCoolDown)
        else:
            selectedIdx = self._searchDP.updateList(selectedID, units)
        if selectedIdx is not None:
            self.as_selectByIndexS(selectedIdx)
        return

    def __setDetailsData(self, unitID, vo):
        _, unit = self.unitFunctional.getUnit(unitID)
        if unit is not None and unit.isClub():
            self.__setDetails(unitID, vo, unit.getExtra())
        else:
            self.__setDetails(unitID, vo)
        return

    def __setDetails(self, unitID, vo, clubExtraData = None):
        if clubExtraData is not None:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_STATIC_AS_LEGIONARY
            icon = None
            name = clubExtraData.clubName
            clubID = clubExtraData.clubDBID
            division = clubExtraData.divisionID
            description = vo['description']
            if self.__currentEmblem is None:
                self.requestClubEmblem64x64(clubID, clubExtraData.getEmblem64x64(), partial(self.__onClubEmblem64x64Received, unitID))
            else:
                icon = self.__currentEmblem
            buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_LEGIONARY
            buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_LEGIONARY
            buttonTooltip = TOOLTIPS.CYBERSPORT_UNITLIST_JOINTOSTATICASLEGIONARY
            if self.clubsState.getStateID() == CLIENT_CLUB_STATE.HAS_CLUB and self.clubsState.getClubDbID() == clubID:
                buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_MEMBER
                buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_MEMBER
                buttonTooltip = None
            vo.update({'joinBtnLabel': buttonLabel,
             'joinInfo': text_styles.standard(_ms(buttonInfo)),
             'joinBtnTooltip': buttonTooltip,
             'rallyInfo': {'icon': icon,
                           'name': text_styles.highTitle(name),
                           'profileBtnLabel': CYBERSPORT.RALLYINFO_PROFILEBTN_LABEL,
                           'profileBtnTooltip': TOOLTIPS.RALLYINFO_PROFILEBTN,
                           'description': text_styles.main(description),
                           'ladderIcon': getLadderChevron64x64(division),
                           'id': clubID,
                           'showLadder': True}})
            self.as_setDetailsS({'viewLinkage': linkage,
             'data': vo})
        else:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_NONSTATIC
            self.as_setDetailsS({'viewLinkage': linkage,
             'data': vo})
        self.__updateVehicleLabel()
        return

    def __refreshDetails(self, idx):
        cfdUnitID, vo = self._searchDP.getRally(idx)
        self.__setDetailsData(cfdUnitID, vo)

    def __updateView(self, user):
        self._searchDP.updateListItem(user.getID())
        self.__refreshDetails(self._searchDP.selectedRallyIndex)

    def __recenterList(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_RECENTER, unitTypeFlags=self._unitTypeFlags)

    def __onClubEmblem64x64Received(self, cfdUnitID, clubDbID, emblem):
        selectedCfdUnitID, _ = self._searchDP.getRally(self._searchDP.selectedRallyIndex)
        if emblem and cfdUnitID == selectedCfdUnitID:
            self.__currentEmblem = self.getMemoryTexturePath(emblem)
            self.as_updateRallyIconS(self.__currentEmblem)
class ClanSearchWindow(ClanSearchWindowMeta, ClanListener):
    __coolDownRequests = [CLAN_REQUESTED_DATA_TYPE.CLAN_RATINGS, CLAN_REQUESTED_DATA_TYPE.SEARCH_CLANS, CLAN_REQUESTED_DATA_TYPE.GET_RECOMMENDED_CLANS]
    MIN_CHARS_FOR_SEARCH = 2

    def __init__(self, ctx):
        super(ClanSearchWindow, self).__init__()
        self.__clanFinder = ClanFinder(g_clanCtrl, None, _SEARCH_LIMIT)
        self.__clanFinder.init()
        self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
        self.__isFirstPageRequested = False
        self.__invitesLimitReached = False
        return

    def onWindowClose(self):
        self.destroy()

    def onClanStateChanged(self, oldStateID, newStateID):
        if not self.clansCtrl.isEnabled():
            self.onWindowClose()
        if not self.clansCtrl.isAvailable():
            pass

    def search(self, text):
        if len(text) < self.MIN_CHARS_FOR_SEARCH:
            self._showDummy(True)
            self._setDummyData(CLANS.SEARCH_REQUESTTOOSHORT_HEADER, CLANS.SEARCH_REQUESTTOOSHORT_BODY, None, self.__clanFinder.hasSuccessRequest(), _ms(CLANS.SEARCH_REQUESTTOOSHORT_BUTTON), CLANS.SEARCH_REQUESTTOOSHORT_BUTTON_TOOLTIP_HEADER)
        else:
            self.__clanFinder.setRecommended(False)
            self.__doSearch(text)
        return

    def previousPage(self):
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self.__clanFinder.left()

    def nextPage(self):
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self.__clanFinder.right()

    def isInvitesLimitReached(self):
        return self.__invitesLimitReached

    def setInvitesLimitReached(self):
        return self.__invitesLimitReached

    def _populate(self):
        super(ClanSearchWindow, self)._populate()
        self._searchDP = _ClanSearchDataProvider()
        self._searchDP.setFlashObject(self.as_getDPS())
        self.startClanListening()
        self.__clanFinder.onListUpdated += self._onClansListUpdated
        self.__initControls()
        self._updateControlsState()
        self._cooldown.start()
        if not g_clanCtrl.getAccountProfile().isSynced():
            g_clanCtrl.getAccountProfile().resync()
        self.__clanFinder.setRecommended(True)
        self.__doSearch('')

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown = None
        self.stopClanListening()
        self.__clanFinder.onListUpdated -= self._onClansListUpdated
        g_clanCtrl.clearClanCommonDataCache()
        self._searchDP.fini()
        self._searchDP = None
        super(ClanSearchWindow, self)._dispose()
        return

    def getClanInfo(self, clanID):
        return self.__clanFinder.getItemByID(clanID)

    def _onRegisterFlashComponent(self, viewPy, alias):
        super(ClanSearchWindow, self)._onRegisterFlashComponent(viewPy, alias)
        if alias == CLANS_ALIASES.CLAN_SEARCH_INFO_PY:
            viewPy.bindDataProvider(self)

    def dummyButtonPress(self):
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self._searchDP.rebuildList(None)
        self.__clanFinder.requestLastSuccess()
        return

    def _onCooldownHandle(self, isInCooldown):
        self._updateControlsState()

    def _onClansListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown, result):
        status, data = result
        self._processSearchResponse(status, data, self.__isFirstPageRequested)
        self.__isFirstPageRequested = False
        self.as_hideWaitingS()

    def _processSearchResponse(self, status, data, isInitial = False):
        if status:
            if len(data) > 0:
                self.__applyFoundData(data)
            elif isInitial:
                self._searchDP.rebuildList(None)
                self._showDummy(True)
                self._setDummyData(CLANS.SEARCH_EMPTYRESULT_HEADER, CLANS.SEARCH_EMPTYRESULT_BODY, None, self.__clanFinder.hasSuccessRequest(), _ms(CLANS.SEARCH_EMPTYRESULT_BUTTON), CLANS.SEARCH_EMPTYRESULT_BUTTON_TOOLTIP)
        else:
            self._showErrorDummy()
        self._updateControlsState()
        return

    def _updateControlsState(self):
        isNotInCooldown = not self._cooldown.isInCooldown()
        foundClans = clans_fmts.formatDataToString(self.__clanFinder.getTotalCount())
        self.as_setStateDataS({'foundClans': text_styles.highTitle(_ms(CLANS.SEARCH_CLANSLIST if self.__clanFinder.isRecommended() else CLANS.SEARCH_FOUNDCLANS, value=foundClans)),
         'nextBtnEnabled': self.__clanFinder.canMoveRight() and isNotInCooldown,
         'previousBtnEnabled': self.__clanFinder.canMoveLeft() and isNotInCooldown,
         'searchBtnEnabled': isNotInCooldown,
         'searchInputEnabled': isNotInCooldown})

    def _showErrorDummy(self):
        self._searchDP.rebuildList(None)
        self._showDummy(True)
        self._setDummyData(CLANS.SEARCH_SERVERUNAVAILABLE_HEADER, CLANS.SEARCH_SERVERUNAVAILABLE_BODY, RES_ICONS.MAPS_ICONS_LIBRARY_ALERTBIGICON)
        return

    def _showDummy(self, isVisible):
        self.as_setDummyVisibleS(isVisible)

    def _setDummyData(self, header, body, icon = None, btnVisible = False, btnLabel = '', btnTooltip = ''):
        self.as_setDummyS({'iconSource': icon,
         'htmlText': str().join((text_styles.middleTitle(header), clans_fmts.getHtmlLineDivider(3), text_styles.main(body))),
         'alignCenter': False,
         'btnVisible': btnVisible,
         'btnLabel': btnLabel,
         'btnTooltip': btnTooltip})

    def __initControls(self):
        headers = [_packHeaderColumnData('clan', CLANS.SEARCH_TABLE_CLAN, 244, CLANS.SEARCH_TABLE_CLAN_TOOLTIP, textAlign='left'),
         _packHeaderColumnData('players', CLANS.SEARCH_TABLE_PLAYERS, 107, CLANS.SEARCH_TABLE_PLAYERS_TOOLTIP),
         _packHeaderColumnData('creationDate', CLANS.SEARCH_TABLE_CREATIONDATE, 125, CLANS.SEARCH_TABLE_CREATIONDATE_TOOLTIP),
         _packHeaderColumnData('rating', CLANS.SEARCH_TABLE_RATING, 90, CLANS.SEARCH_TABLE_RATING_TOOLTIP, False, 'right')]
        self.as_setInitDataS({'windowTitle': CLANS.SEARCH_WINDOWTITLE,
         'title': text_styles.promoTitle(_ms(CLANS.SEARCH_TITLE)),
         'titleDescription': text_styles.main(_ms(CLANS.SEARCH_TITLEDESCRIPTION)),
         'searchBtnLabel': CLANS.SEARCH_SEARCHBTN,
         'searchBtnTooltip': CLANS.SEARCH_SEARCHBTN_TOOLTIP,
         'searchInputPrompt': CLANS.SEARCH_SEARCHINPUTPROMPT,
         'searchInputMaxChars': _SEARCH_MAX_CHARS,
         'nextBtnLabel': CLANS.SEARCH_NEXTBTN,
         'nextBtnTooltip': CLANS.SEARCH_NEXTBTN_TOOLTIP,
         'previousBtnLabel': CLANS.SEARCH_PREVIOUSBTN,
         'previousBtnTooltip': CLANS.SEARCH_PREVIOUSBTN_TOOLTIP,
         'tableHeaders': headers})
        self._showDummy(True)
        self._setDummyData(CLANS.SEARCH_PROMOTEXT_HEADER, CLANS.SEARCH_PROMOTEXT_BODY, None)
        return

    def __applyFoundData(self, data):
        self._showDummy(False)
        g_clanCtrl.updateClanCommonDataCache([ ClanCommonData.fromClanSearchData(item) for item in data ])
        self._searchDP.rebuildList(data)
        self.__lastSuccessfullyFoundClans = data

    def __doSearch(self, text):
        """
        :param text: - search criteria
        :param getRecommended: - flag determines is need to get recommended clans
        :type text: str
        :type getRecommended: bool
        """
        self.as_showWaitingS(WAITING.PREBATTLE_AUTO_SEARCH, {})
        self._searchDP.rebuildList(None)
        isValid, reason = g_clanCtrl.getLimits().canSearchClans(text)
        if self.__clanFinder.isRecommended() or isValid:
            self._showDummy(False)
            self.__isFirstPageRequested = True
            self.__clanFinder.setPattern(text)
            self.__clanFinder.reset()
        else:
            if reason == _CCR.SEARCH_PATTERN_INVALID:
                self._processSearchResponse(True, list(), True)
            else:
                self._processSearchResponse(False, list(), True)
            self.as_hideWaitingS()
        return
class BattleMessengerView(BattleMessengerMeta, IBattleChannelView, IContactsAndPersonalInvitationsController):

    def __init__(self):
        super(BattleMessengerView, self).__init__()
        self.__controllers = {}
        self.__receivers = []
        self.__receiverIndex = 0
        self.__isEnabled = False
        self.__isFocused = False
        self._battleCtx = None
        self._arenaVisitor = None
        self._accDbID = 0
        self._toxicPanelMsgID = 0
        self._addedMsgIDs = set()
        self._ignoreActionCooldown = CooldownHelper((CLIENT_ACTION_ID.ADD_IGNORED, CLIENT_ACTION_ID.REMOVE_IGNORED), self._onIgnoreActionCooldownHandle, CoolDownEvent.XMPP)
        return

    @storage_getter('users')
    def usersStorage(self):
        return None

    @proto_getter(PROTO_TYPE.MIGRATION)
    def protoMigration(self):
        return None

    @proto_getter(PROTO_TYPE.BW_CHAT2)
    def protoBwChat2(self):
        return None

    def getControllerID(self):
        return BATTLE_CTRL_ID.GUI

    def startControl(self, battleCtx, arenaVisitor):
        """Starts to controlling data of arena.
        
        :param battleCtx: proxy to battle context.
        :param arenaVisitor: proxy to arena visitor.
        """
        self._battleCtx = battleCtx
        self._arenaVisitor = arenaVisitor

    def stopControl(self):
        self._battleCtx = None
        self._arenaVisitor = None
        return

    def getToxicStatus(self, accountDbID):
        """
        Invoked by the view at runtime to get VO of buttons panel.
        
        :param accountDbID: Message ID that corresponds to player database ID.
        :return: dict
        """
        vo = None
        accountDbID = long(accountDbID)
        if 0 < accountDbID != self._accDbID:
            vo = self.__buildToxicStateVO(accountDbID)
        if vo is not None:
            self._toxicPanelMsgID = accountDbID
        return vo

    def updateToxicStatus(self, accountDbID):
        self.as_updateToxicPanelS(accountDbID, self.__buildToxicStateVO(accountDbID))

    def onToxicButtonClicked(self, accountDbID, actionID):
        """
        Callback on user's action. Note that the same callback is invoked for all 'toxic' buttons.
        To determine which button is pressed, action ID is used. Action ID corresponds to the
        following constants from BATTLE_MESSAGES_CONSTS enum.
        
        :param accountDbID: Message ID that corresponds to player database ID.
        :param actionID: Action ID.
        """
        accDbID = long(accountDbID)
        if accDbID > 0:
            needUpdateUI = True
            if actionID == BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST:
                if not self._ignoreActionCooldown.isInCooldown():
                    self.protoMigration.contacts.addTmpIgnored(accDbID, self._battleCtx.getPlayerName(accID=accDbID))
            elif actionID == BATTLE_MESSAGES_CONSTS.REMOVE_FROM_BLACKLIST:
                if not self._ignoreActionCooldown.isInCooldown():
                    self.protoMigration.contacts.removeTmpIgnored(accDbID)
            else:
                needUpdateUI = False
            if needUpdateUI:
                self._invalidateToxicPanel(accDbID)

    def onToxicPanelClosed(self, messageID):
        """
        Callback on toxic panel close event.
        
        :param messageID: Message ID that corresponds to player database ID.
        """
        if 0 < self._toxicPanelMsgID == messageID:
            self._toxicPanelMsgID = 0

    def invalidateUsersTags(self):
        """
        New list of chat rosters has been received.
        """
        self._invalidateToxicPanel(self._toxicPanelMsgID)
        for msgID in self._addedMsgIDs:
            self._invalidatePlayerMessages(msgID)

    def invalidateUserTags(self, user):
        """
        Contact's chat roster has been changed.
        
        :param user: instance of UserEntity.
        """
        accDbID = user.getID()
        self._invalidatePlayerMessages(accDbID)
        self._invalidateToxicPanel(accDbID)

    def invalidateInvitationsStatuses(self, vos, arenaDP):
        """
        An invitation has been received.
        :param vos: invitations represented by list of VehicleArenaInfoVO objects.
        :param arenaDP: Reference to ArenaDataProvider
        """
        if self._toxicPanelMsgID > 0:
            for vInfo in vos:
                if vInfo.player.accountDBID == self._toxicPanelMsgID:
                    self._invalidateToxicPanel(self._toxicPanelMsgID)
                    break

    def handleEnterPressed(self):
        if not self.__isEnabled:
            return False
        if self.app.isModalViewShown() or self.app.hasGuiControlModeConsumers(*_CONSUMERS_LOCK_ENTER):
            return False
        if not self.__isFocused:
            self.__findReceiverIndexByModifiers()
        self.as_enterPressedS(self.__receiverIndex)
        return True

    def handleCTRLPressed(self, _, isDown):
        """
        Handler of Ctrl button press event.
        
        :param _: True if the event associated with the left Ctrl btn, False - if the right Ctrl.
        :param isDown: True if the Ctrl btn is down, False if it is up.
        """
        if self.app.isModalViewShown() or self.app.hasGuiControlModeConsumers(*_CONSUMERS_LOCK_ENTER):
            return False
        self.as_toggleCtrlPressFlagS(isDown)
        return True

    def setFocused(self, value):
        if self.__isFocused == value:
            return False
        self.__isFocused = value
        LOG_DEBUG('Sets focus to the battle chat', value)
        if self.__isFocused:
            self.as_setFocusS()
        else:
            self.as_unSetFocusS()
        return True

    def isFocused(self):
        return self.__isFocused

    def focusReceived(self):
        LOG_DEBUG('Battle chat is in focus')
        self.__setGuiMode(True)
        self.protoBwChat2.voipController.setMicrophoneMute(True)

    def focusLost(self):
        LOG_DEBUG('Battle chat is not in focus')
        self.__setGuiMode(False)

    def sendMessageToChannel(self, receiverIndex, rawMsgText):
        if receiverIndex < 0 or receiverIndex >= len(self.__receivers):
            LOG_ERROR('Index of receiver is not valid', receiverIndex)
            return False
        else:
            clientID = self.__receivers[receiverIndex][0]
            result = self.__canSendMessage(clientID)
            if result:
                controller = self.__getController(clientID)
                if not rawMsgText:
                    self.setFocused(False)
                if controller is not None:
                    controller.sendMessage(rawMsgText)
                else:
                    LOG_ERROR('Channel is not found to send message', clientID)
                return True
            return False
            return

    def enableToSendMessage(self):
        self.__isEnabled = True
        self.as_enableToSendMessageS()

    def setNextReceiver(self):
        if self.__isFocused and self.__findNextReceiverIndex():
            LOG_DEBUG('Sets receiver in the battle chat', self.__receiverIndex)
            g_settings.battle.lastReceiver = self.__receivers[self.__receiverIndex][1].name
            self.as_changeReceiverS(self.__receiverIndex)
            return True
        else:
            return False

    def invalidateReceivers(self):
        self.__receivers = []
        vos = []
        for clientID, ctrlRef in self.__controllers.iteritems():
            controller = ctrlRef()
            if controller is not None and controller.getChannel().isJoined():
                receiver, isReset = self.__addReceiver(clientID, controller)
                if receiver is not None:
                    if isReset:
                        vos = []
                    vos.append(_makeReceiverVO(*receiver))

        self.as_setReceiversS(vos)
        if self.__invalidateReceiverIndex():
            self.as_changeReceiverS(self.__receiverIndex)
        return

    def invalidateUserPreferences(self):
        self.as_setUserPreferencesS(_getToolTipText(self._arenaVisitor))
        self.invalidateReceivers()

    def addController(self, controller):
        channel = controller.getChannel()
        clientID = channel.getClientID()
        self.__controllers[clientID] = weakref.ref(controller)
        receiver, isReset = self.__addReceiver(clientID, controller)
        if receiver is not None:
            self.as_setReceiverS(_makeReceiverVO(*receiver), isReset)
        if self.__invalidateReceiverIndex():
            self.as_changeReceiverS(self.__receiverIndex)
        return

    def removeController(self, controller):
        self.__controllers.pop(controller.getChannel().getClientID(), None)
        return

    def addMessage(self, message, fillColor = FILL_COLORS.BLACK, accountDBID = 0):
        if accountDBID == self._accDbID:
            accountDBID = 0
        if fillColor == FILL_COLORS.BLACK:
            self.as_showBlackMessageS(message, accountDBID)
        elif fillColor == FILL_COLORS.RED:
            self.as_showRedMessageS(message, accountDBID)
        elif fillColor == FILL_COLORS.BROWN:
            self.as_showSelfMessageS(message, accountDBID)
        elif fillColor == FILL_COLORS.GREEN:
            self.as_showGreenMessageS(message, accountDBID)
        else:
            LOG_UNEXPECTED('Unexpected fill color: ', fillColor)
        if accountDBID > 0:
            self._addedMsgIDs.add(accountDBID)

    def isToxicPanelAvailable(self):
        """
        Returns True if the toxic panel is available, otherwise returns false.
        """
        return not BattleReplay.g_replayCtrl.isPlaying and self._arenaVisitor is not None and not self._arenaVisitor.gui.isTrainingBattle()

    def _populate(self):
        super(BattleMessengerView, self)._populate()
        self._accDbID = getAvatarDatabaseID()
        self.__receivers = []
        self.fireEvent(ChannelManagementEvent(0, ChannelManagementEvent.REGISTER_BATTLE, {'component': self}), scope=EVENT_BUS_SCOPE.BATTLE)
        self.addListener(ChannelManagementEvent.MESSAGE_FADING_ENABLED, self.__handleMessageFadingEnabled, EVENT_BUS_SCOPE.GLOBAL)
        self.__restoreLastReceiverInBattle()
        g_sessionProvider.addArenaCtrl(self)
        self.as_setupListS(_makeSettingsVO(self._arenaVisitor))
        self._ignoreActionCooldown.start()
        if self.isToxicPanelAvailable():
            self.as_enableToxicPanelS()

    def _dispose(self):
        self.__receivers = []
        self._ignoreActionCooldown.stop()
        self._ignoreActionCooldown = None
        self.fireEvent(ChannelManagementEvent(0, ChannelManagementEvent.UNREGISTER_BATTLE), scope=EVENT_BUS_SCOPE.BATTLE)
        self.removeListener(ChannelManagementEvent.MESSAGE_FADING_ENABLED, self.__handleMessageFadingEnabled, EVENT_BUS_SCOPE.GLOBAL)
        g_sessionProvider.removeArenaCtrl(self)
        super(BattleMessengerView, self)._dispose()
        return

    def _invalidateToxicPanel(self, msgID):
        """
        Updates toxic panel if it is visible for the given message.
        
        :param msgID: Message ID that corresponds to player database ID.
        """
        if 0 < self._toxicPanelMsgID == msgID:
            self.updateToxicStatus(msgID)

    def _invalidatePlayerMessages(self, accountDbID):
        if accountDbID > 0:
            contact = self.usersStorage.getUser(accountDbID)
            if contact is not None and contact.isIgnored():
                pInfo = self._battleCtx.getPlayerFullNameParts(accID=accountDbID)
                template = i18n.makeString(MESSENGER.CHAT_TOXICMESSAGES_BLOCKEDMESSAGE, playerName=pInfo.playerName, clanName=pInfo.clanAbbrev)
                self.as_updateMessagesS(accountDbID, text_styles.main(template))
            else:
                self.as_restoreMessagesS(accountDbID)
        return

    def _onIgnoreActionCooldownHandle(self, isInCooldown):
        self._invalidateToxicPanel(self._toxicPanelMsgID)

    def __buildToxicStateVO(self, accountDbID):
        """
        Builds vo related to the toxic panel.
        
        :param accountDbID: long representing account's database ID
        :return: dict
        """
        contact = self.usersStorage.getUser(accountDbID)
        return {'messageID': accountDbID,
         'vehicleID': self._battleCtx.getVehIDByAccDBID(accountDbID),
         'blackList': self.__buildBlackListVO(contact)}

    def __buildBlackListVO(self, contact):
        """
        Builds vo related to the Black List button.
        
        :param contact: an instance of UserEntity
        :return: dict
        """
        isEnabled = not self._ignoreActionCooldown.isInCooldown()
        if contact:
            if contact.isTemporaryIgnored():
                status = BATTLE_MESSAGES_CONSTS.REMOVE_FROM_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_REMOVE_FROM_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_REMOVE_FROM_BLACKLIST_BODY
            elif contact.isIgnored():
                status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_CANT_ADD_IN_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_CANT_ADD_IN_BLACKLIST_BODY
                isEnabled = False
            else:
                status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
                header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_HEADER
                body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_BODY
        else:
            status = BATTLE_MESSAGES_CONSTS.ADD_IN_BLACKLIST
            header = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_HEADER
            body = INGAME_GUI.BATTLEMESSENGER_TOXIC_BLACKLIST_ADD_IN_BLACKLIST_BODY
        return {'status': status,
         'tooltip': makeTooltip(header=header, body=body),
         'enabled': isEnabled}

    def __canSendMessage(self, clientID):
        result = True
        controller = self.__getController(clientID)
        if controller is None:
            return result
        else:
            result, errorMsg = controller.canSendMessage()
            if not result:
                message = g_settings.htmlTemplates.format('battleErrorMessage', ctx={'error': errorMsg})
                self.addMessage(message, fillColor=FILL_COLORS.BLACK)
            return result

    def __getController(self, clientID):
        controller = None
        if clientID in self.__controllers:
            ctrlRef = self.__controllers[clientID]
            if ctrlRef:
                controller = ctrlRef()
        return controller

    def __addReceiver(self, clientID, controller):
        isReset = False
        settings = controller.getSettings()
        isChatEnabled = controller.isEnabled()
        if isChatEnabled:
            if not isBattleChatEnabled() and settings.name == BATTLE_CHANNEL.SQUAD.name:
                self.__receivers = []
                self.__receiverIndex = 0
                isReset = True
        elif settings == BATTLE_CHANNEL.COMMON:
            return (None, isReset)
        receivers = g_settings.battle.receivers
        receiverName = settings.name
        if receiverName in receivers:
            guiSettings = receivers[receiverName]
        else:
            LOG_ERROR('Settings of receiver is not found', receiverName)
            guiSettings = None
        receiver = (clientID, guiSettings, isChatEnabled)
        self.__receivers.append(receiver)
        self.__receivers = sorted(self.__receivers, key=lambda item: item[1].order)
        return (receiver, isReset)

    def __setGuiMode(self, value):
        if value:
            self.__isFocused = True
            self.app.enterGuiControlMode('chat')
            self.__findReceiverIndexByModifiers()
            LOG_DEBUG('Sets receiver in the battle chat', self.__receiverIndex)
            self.as_changeReceiverS(self.__receiverIndex)
        else:
            self.__isFocused = False
            self.app.leaveGuiControlMode('chat')

    def __restoreLastReceiverInBattle(self):
        """ WOTD-71200 Restore last receiver in battle
        """
        if g_settings.userPrefs.storeReceiverInBattle:
            for idx, receiver in enumerate(self.__receivers):
                if g_settings.battle.lastReceiver == receiver[1].name:
                    if self.__isReceiverAvailable(idx):
                        self.__receiverIndex = idx
                    break

        self.__invalidateReceiverIndex()

    def __findReceiverIndexByModifiers(self):
        for idx, (clientID, settings, _) in enumerate(self.__receivers):
            modifiers = settings.bwModifiers
            for modifier in modifiers:
                if BigWorld.isKeyDown(modifier):
                    if self.__isReceiverAvailable(idx):
                        self.__receiverIndex = idx

        if not g_settings.userPrefs.storeReceiverInBattle:
            self.__receiverIndex = 0
        self.__invalidateReceiverIndex()

    def __invalidateReceiverIndex(self):
        if not self.__isReceiverAvailable(self.__receiverIndex):
            return self.__findNextReceiverIndex()
        return False

    def __findNextReceiverIndex(self):
        receiversCount = len(self.__receivers)
        if receiversCount > 0:
            leftReceiversCount = receiversCount - 1
        else:
            leftReceiversCount = 0
        index = self.__receiverIndex
        while leftReceiversCount:
            leftReceiversCount -= 1
            index += 1
            if index >= receiversCount:
                index = 0
            if self.__isReceiverAvailable(index):
                self.__receiverIndex = index
                return True

        return False

    def __isReceiverAvailable(self, index):
        if index < len(self.__receivers):
            _, _, isChatEnabled = self.__receivers[index]
            return isChatEnabled
        return False

    def __handleMessageFadingEnabled(self, event):
        self.as_setActiveS(not event.ctx['isEnabled'])
class ClanPersonalInvitesView(ClanPersonalInvitesViewMeta, ClanListener):
    __coolDownRequests = [CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
     CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
     CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
     CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
     CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES]

    def __init__(self):
        super(ClanPersonalInvitesView, self).__init__()
        self._paginator = ClanPersonalInvitesPaginator(g_clanCtrl, getPlayerDatabaseID(), [CLAN_INVITE_STATES.ACTIVE])
        self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)

    def declineAllSelectedInvites(self):
        self._paginator.declineList(self.dataProvider.getCheckedIDs())

    def acceptInvite(self, dbID):
        self._paginator.accept(int(dbID))

    def declineInvite(self, dbID):
        self._paginator.decline(int(dbID))

    def showMore(self):
        if not self._paginator.isInProgress():
            self.showWaiting(True)
            self._paginator.right()

    def setSelectAllInvitesCheckBoxSelected(self, checked):
        self.dataProvider.setSelectAll(checked)
        self._updateDeclineSelectedGroup()

    def setInviteSelected(self, dbID, checked):
        self.dataProvider.setCheckedID(dbID, checked)
        self._updateDeclineSelectedGroup()

    def onSortChanged(self, dataProvider, sort):
        order = sort[0][1]
        secondSort = tuple(((item, order) for item in self._getSecondSortFields()))
        if not self._paginator.isInProgress():
            self.showWaiting(True)
            self._paginator.sort(sort + secondSort)

    def onAccountInvitesReceived(self, invites):
        super(ClanPersonalInvitesView, self).onAccountInvitesReceived(invites)
        self._enableRefreshBtn(True)

    def showWaiting(self, show):
        if show:
            self._parentWnd.as_showWaitingS(CLANS.CLANPERSONALINVITESWINDOW_LOADING, {})
        elif not self._paginator.isInProgress():
            self._parentWnd.as_hideWaitingS()

    def refreshTable(self):
        self._enableRefreshBtn(False)
        self.showWaiting(True)
        self._paginator.refresh()

    def _createSearchDP(self):
        return PersonalInvitesDataProvider(self)

    def _onAttachedToWindow(self):
        super(ClanPersonalInvitesView, self)._onAttachedToWindow()
        self.showWaiting(True)
        self.setSelectAllInvitesCheckBoxSelected(False)
        self._updateDeclineSelectedText(0)
        self._cooldown.start()
        self._paginator.onListUpdated += self._onListUpdated
        self._paginator.onListItemsUpdated += self._onListItemsUpdated
        self._paginator.reset()

    def _populate(self):
        super(ClanPersonalInvitesView, self)._populate()
        self.startClanListening()

    def _dispose(self):
        self._paginator.onListUpdated -= self._onListUpdated
        self._paginator.onListItemsUpdated -= self._onListItemsUpdated
        self._cooldown.stop()
        self._cooldown = None
        self.stopClanListening()
        g_clanCtrl.clearClanCommonDataCache()
        super(ClanPersonalInvitesView, self)._dispose()
        return

    def _onCooldownHandle(self, isInCooldown):
        self.showWaiting(isInCooldown)

    def _onListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown, result):
        self._updateSortField(self._paginator.getLastSort())
        status, data = result
        if status is True:
            self._enableRefreshBtn(False)
            if len(data) == 0:
                self.as_showDummyS(CLANS_ALIASES.INVITE_WINDOW_DUMMY_NO_PERSONAL_INVITES)
                self.dataProvider.rebuildList(None, False)
            else:
                g_clanCtrl.updateClanCommonDataCache([ ClanCommonData.fromClanPersonalInviteWrapper(item) for item in data ])
                self.dataProvider.rebuildList(data, self._paginator.canMoveRight())
                self.as_hideDummyS()
        else:
            self._enableRefreshBtn(True, toolTip=CLANS.CLANINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_ENABLEDTRYTOREFRESH)
            self.as_showDummyS(CLANS_ALIASES.INVITE_WINDOW_DUMMY_SERVER_ERROR)
        self._updateDeclineSelectedGroup()
        self.showWaiting(False)
        return

    def _onListItemsUpdated(self, paginator, items):
        self.dataProvider.refreshItems(items)
        self._updateDeclineSelectedGroup()
        if not self._paginator.isInProgress():
            self.showWaiting(False)

    def _updateDeclineSelectedGroup(self):
        hasInvites = self.dataProvider.itemsCount() > 0
        self._updateDeclineSelectedText(self.dataProvider.selectedCount())
        self.as_setSelectAllCheckboxStateS(self.dataProvider.areAllSelected(), hasInvites)

    def _updateDeclineSelectedText(self, count):
        self.as_setDeclineAllSelectedInvitesStateS(_ms(CLANS.CLANPERSONALINVITESWINDOW_DECLINESELECTED, count=count), False if count == 0 or self._paginator.isInProgress() else True)

    def _getSecondSortFields(self):
        return ('createdAt',)

    def _makeHeaders(self):
        return [self._packHeaderColumnData('clanName', CLANS.CLANPERSONALINVITESWINDOW_TABLE_CLANNAME, 233, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_CLANNAME, textAlign='left', enabled=True),
         self._packHeaderColumnData('message', '', 73, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_MESSAGE, RES_ICONS.MAPS_ICONS_CLANS_INVITESWINDOW_ICON_STATISTICS_CLAN_INVITE_098, enabled=True),
         self._packHeaderColumnData('personalRating', '', 98, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_RATING, RES_ICONS.MAPS_ICONS_STATISTIC_RATING24, enabled=True),
         self._packHeaderColumnData('battlesCount', '', 98, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_BATTLESCOUNT, RES_ICONS.MAPS_ICONS_STATISTIC_BATTLES24, enabled=True),
         self._packHeaderColumnData('wins', '', 98, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_WINS, RES_ICONS.MAPS_ICONS_STATISTIC_WINS24, enabled=True),
         self._packHeaderColumnData('awgExp', '', 98, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_AWGEXP, RES_ICONS.MAPS_ICONS_STATISTIC_AVGEXP24, enabled=True),
         self._packHeaderColumnData('status', CLANS.CLANPERSONALINVITESWINDOW_TABLE_STATUS, 160, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_INVITES_STATUS, enabled=True),
         self._packHeaderColumnData('actions', CLANS.CLANPERSONALINVITESWINDOW_TABLE_ACTIONS, 132, CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_ACTIONS, enabled=False)]

    def _makeTexts(self):
        texts = super(ClanPersonalInvitesView, self)._makeTexts()
        texts.append({'alias': CLANS_ALIASES.INVITE_WINDOW_DUMMY_NO_PERSONAL_INVITES,
         'title': CLANS.CLANPERSONALINVITESWINDOW_NOINVITES})
        return texts

    def _enableRefreshBtn(self, enable, toolTip = None):
        if enable:
            self.as_updateButtonRefreshStateS(True, makeTooltip(body=_ms(toolTip or CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_ENABLED)))
        else:
            self.as_updateButtonRefreshStateS(False, makeTooltip(body=_ms(toolTip or CLANS.CLANPERSONALINVITESWINDOW_TOOLTIPS_REFRESHBUTTON_DISABLED)))
 def __init__(self):
     super(ClanPersonalInvitesView, self).__init__()
     self._paginator = ClanPersonalInvitesPaginator(g_clanCtrl, getPlayerDatabaseID(), [CLAN_INVITE_STATES.ACTIVE])
     self._cooldown = CooldownHelper(self.__coolDownRequests, self._onCooldownHandle, CoolDownEvent.CLAN)
class CyberSportUnitsListView(CyberSportUnitsListMeta, UnitListener,
                              ClubListener, ClubEmblemsHelper):
    def __init__(self):
        super(CyberSportUnitsListView, self).__init__()
        self._isBackButtonClicked = False
        self._section = 'selectedListVehicles'
        self._selectedVehicles = self.unitFunctional.getSelectedVehicles(
            self._section)
        self._unitTypeFlags = UNIT_BROWSER_TYPE.ALL
        self._cooldown = CooldownHelper(self.getCoolDownRequests(),
                                        self._onCooldownHandle,
                                        events.CoolDownEvent.PREBATTLE)

    def onUnitFunctionalInited(self):
        self.unitFunctional.setPrbType(PREBATTLE_TYPE.UNIT)

    def getPyDataProvider(self):
        return ManualSearchDataProvider()

    def getCoolDownRequests(self):
        return [REQUEST_TYPE.UNITS_LIST]

    def canBeClosed(self, callback):
        self._isBackButtonClicked = True
        callback(True)

    def updateSelectedVehicles(self):
        maxLevel = self.unitFunctional.getRosterSettings().getMaxLevel()
        vehiclesCount = len(self._selectedVehicles)
        availableVehiclesCount = len([
            k for k, v in g_itemsCache.items.getVehicles(
                REQ_CRITERIA.INVENTORY).items() if v.level <= maxLevel
        ])
        if vehiclesCount > 0 and vehiclesCount != availableVehiclesCount:
            infoText = makeHtmlString(
                'html_templates:lobby/cyberSport/vehicle', 'selectedValid',
                {'count': vehiclesCount})
        else:
            infoText = CYBERSPORT.BUTTON_CHOOSEVEHICLES_SELECT
        self.as_setSelectedVehiclesInfoS(infoText, vehiclesCount)

    def setTeamFilters(self, showOnlyStatic):
        self._unitTypeFlags = UNIT_BROWSER_TYPE.RATED_CLUBS if showOnlyStatic else UNIT_BROWSER_TYPE.ALL
        self.__recenterList()

    def filterVehicles(self):
        levelsRange = self.unitFunctional.getRosterSettings().getLevelsRange()
        if self._selectedVehicles is not None and len(
                self._selectedVehicles) > 0:
            selectedVehicles = self._selectedVehicles
        else:
            selectedVehicles = [
                k for k, v in g_itemsCache.items.getVehicles(
                    REQ_CRITERIA.INVENTORY).items() if v.level in levelsRange
            ]
        self.fireEvent(events.LoadViewEvent(
            CYBER_SPORT_ALIASES.VEHICLE_SELECTOR_POPUP_PY,
            ctx={
                'isMultiSelect': True,
                'infoText': CYBERSPORT.WINDOW_VEHICLESELECTOR_INFO_SEARCH,
                'selectedVehicles': selectedVehicles,
                'section': 'cs_list_view_vehicle',
                'levelsRange': levelsRange
            }),
                       scope=EVENT_BUS_SCOPE.LOBBY)

    def loadPrevious(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_LEFT)

    def loadNext(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_NAV_RIGHT)

    def refreshTeams(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_REFRESH)

    def getRallyDetails(self, index):
        cfdUnitID, vo = self._searchDP.getRally(index)
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.setSelectedID(cfdUnitID)
        self.__setDetailsData(cfdUnitID, vo)

    def showRallyProfile(self, clubDBID):
        club_events.showClubProfile(clubDBID)

    def _populate(self):
        super(CyberSportUnitsListView, self)._populate()
        self._cooldown.start()
        self.addListener(CSVehicleSelectEvent.VEHICLE_SELECTED,
                         self.__onVehiclesSelectedTeams)
        self.startUnitListening()
        if self.unitFunctional.getPrbType() != PREBATTLE_TYPE.NONE:
            self.unitFunctional.setPrbType(PREBATTLE_TYPE.UNIT)
        self.updateSelectedVehicles()
        unit_ext.initListReq(self._unitTypeFlags).start(
            self.__onUnitsListUpdated)
        g_clientUpdateManager.addCallbacks(
            {'inventory.1': self.__onVehiclesChanged})
        self.as_setSearchResultTextS(
            _ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS), '',
            self.__getFiltersData())
        headerDescription = CYBERSPORT.WINDOW_UNITLISTVIEW_DESCRIPTION
        headerTitle = CYBERSPORT.WINDOW_UNITLISTVIEW_TITLE
        self.as_setHeaderS({
            'title': headerTitle,
            'description': headerDescription,
            'createBtnLabel': CYBERSPORT.WINDOW_UNITLISTVIEW_CREATE_BTN,
            'createBtnTooltip': None,
            'createBtnEnabled': True,
            'columnHeaders': self.__getColumnHeaders()
        })

    def _dispose(self):
        self._cooldown.stop()
        self._cooldown = None
        if self._isBackButtonClicked:
            unit_ext.destroyListReq()
            self._isBackButtonClicked = False
        else:
            listReq = unit_ext.getListReq()
            if listReq:
                listReq.stop()
        self.stopUnitListening()
        self.removeListener(CSVehicleSelectEvent.VEHICLE_SELECTED,
                            self.__onVehiclesSelectedTeams)
        g_clientUpdateManager.removeObjectCallbacks(self)
        super(CyberSportUnitsListView, self)._dispose()

    def _onUserActionReceived(self, _, user):
        self.__updateView(user)

    def _doEnableNavButtons(self, isEnabled):
        self.as_updateNavigationBlockS({
            'previousVisible':
            True,
            'previousEnabled':
            isEnabled,
            'nextVisible':
            True,
            'nextEnabled':
            isEnabled,
            'icon':
            RES_ICONS.MAPS_ICONS_STATISTIC_RATING24
        })

    def _onCooldownHandle(self, isInCooldown):
        self._doEnableNavButtons(not isInCooldown)

    def __getColumnHeaders(self):
        return [
            self.__createHedader(
                '', 54, RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_LADDERICON),
            self.__createHedader('', 58,
                                 RES_ICONS.MAPS_ICONS_STATISTIC_RATING24),
            self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_COMMANDER,
                                 152),
            self.__createHedader(
                CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_DESCRIPTION, 220),
            self.__createHedader(CYBERSPORT.WINDOW_UNIT_UNITLISTVIEW_PLAYERS,
                                 76)
        ]

    def __createHedader(self, label, buttonWidth, iconSource=None):
        return {
            'label': label,
            'buttonWidth': buttonWidth,
            'iconSource': iconSource,
            'enabled': False
        }

    def __updateVehicleLabel(self):
        settings = self.unitFunctional.getRosterSettings()
        self._updateVehiclesLabel(int2roman(settings.getMinLevel()),
                                  int2roman(settings.getMaxLevel()))

    def __getFiltersData(self):
        return {
            'isSelected': self._unitTypeFlags == UNIT_BROWSER_TYPE.RATED_CLUBS,
            'icon': RES_ICONS.MAPS_ICONS_LIBRARY_CYBERSPORT_RANKEDICON,
            'label': _ms(CYBERSPORT.WINDOW_UNITLISTVIEW_FOUNDTEAMS_FILTERTEXT)
        }

    def __onUnitsListUpdated(self, selectedID, isFullUpdate, isReqInCoolDown,
                             units):
        if isFullUpdate:
            selectedIdx = self._searchDP.rebuildList(selectedID, units)
            self._doEnableNavButtons(not isReqInCoolDown)
        else:
            selectedIdx = self._searchDP.updateList(selectedID, units)
        if selectedIdx is not None:
            self.as_selectByIndexS(selectedIdx)

    def __onVehiclesSelectedTeams(self, event):
        self._selectedVehicles = event.ctx
        self.updateSelectedVehicles()
        self.unitFunctional.setSelectedVehicles(self._section,
                                                self._selectedVehicles)
        self.__recenterList()

    def __setDetailsData(self, unitID, vo):
        _, unit = self.unitFunctional.getUnit(unitID)
        if unit is not None and unit.isClub():
            self.__setDetails(unitID, vo, unit.getExtra())
        else:
            self.__setDetails(unitID, vo)

    def __setDetails(self, unitID, vo, clubExtraData=None):
        if clubExtraData is not None:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_STATIC_AS_LEGIONARY
            icon = None
            name = clubExtraData.clubName
            clubID = clubExtraData.clubDBID
            division = clubExtraData.divisionID
            description = vo['description']
            self.requestClubEmblem64x64(
                clubID, clubExtraData.getEmblem64x64(),
                partial(self.__onClubEmblem64x64Received, unitID))
            buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_LEGIONARY
            buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_LEGIONARY
            buttonTooltip = TOOLTIPS.CYBERSPORT_UNITLIST_JOINTOSTATICASLEGIONARY
            if self.clubsState.getStateID(
            ) == CLIENT_CLUB_STATE.HAS_CLUB and self.clubsState.getClubDbID(
            ) == clubID:
                buttonLabel = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERBTN_MEMBER
                buttonInfo = CYBERSPORT.WINDOW_UNITLISTVIEW_ENTERTEXT_MEMBER
                buttonTooltip = None
            vo.update({
                'joinBtnLabel': buttonLabel,
                'joinInfo': text_styles.standard(_ms(buttonInfo)),
                'joinBtnTooltip': buttonTooltip,
                'rallyInfo': {
                    'icon': icon,
                    'name': text_styles.highTitle(name),
                    'profileBtnLabel': CYBERSPORT.RALLYINFO_PROFILEBTN_LABEL,
                    'profileBtnTooltip': TOOLTIPS.RALLYINFO_PROFILEBTN,
                    'description': text_styles.main(description),
                    'ladderIcon': getLadderChevron64x64(division),
                    'id': clubID,
                    'showLadder': True
                }
            })
            self.as_setDetailsS({'viewLinkage': linkage, 'data': vo})
        else:
            linkage = CYBER_SPORT_ALIASES.COMMNAD_DETAILS_LINKAGE_JOIN_TO_NONSTATIC
            self.as_setDetailsS({'viewLinkage': linkage, 'data': vo})
        self.__updateVehicleLabel()

    def __refreshDetails(self, idx):
        cfdUnitID, vo = self._searchDP.getRally(idx)
        self.__setDetailsData(cfdUnitID, vo)

    def __updateView(self, user):
        self._searchDP.updateListItem(user.getID())
        self.__refreshDetails(self._searchDP.selectedRallyIndex)

    def __onVehiclesChanged(self, *args):
        self._selectedVehicles = self.unitFunctional.getSelectedVehicles(
            self._section)
        self.updateSelectedVehicles()
        self.unitFunctional.setSelectedVehicles(self._section,
                                                self._selectedVehicles)

    def __recenterList(self):
        listReq = unit_ext.getListReq()
        if listReq:
            listReq.request(req=REQUEST_TYPE.UNITS_RECENTER,
                            unitTypeFlags=self._unitTypeFlags)

    def __onClubEmblem64x64Received(self, cfdUnitID, clubDbID, emblem):
        selectedCfdUnitID, _ = self._searchDP.getRally(
            self._searchDP.selectedRallyIndex)
        if emblem and cfdUnitID == selectedCfdUnitID:
            self.as_updateRallyIconS(self.getMemoryTexturePath(emblem))
class ClanRequestsView(ClanRequestsViewMeta):

    def __init__(self):
        super(ClanRequestsView, self).__init__()
        self._cooldown = CooldownHelper([CLAN_REQUESTED_DATA_TYPE.CREATE_APPLICATIONS,
         CLAN_REQUESTED_DATA_TYPE.CREATE_INVITES,
         CLAN_REQUESTED_DATA_TYPE.ACCEPT_APPLICATION,
         CLAN_REQUESTED_DATA_TYPE.ACCEPT_INVITE,
         CLAN_REQUESTED_DATA_TYPE.DECLINE_APPLICATION,
         CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITE,
         CLAN_REQUESTED_DATA_TYPE.DECLINE_INVITES,
         CLAN_REQUESTED_DATA_TYPE.CLAN_INVITES,
         CLAN_REQUESTED_DATA_TYPE.CLAN_MEMBERS_RATING], self._onCooldownHandle, CoolDownEvent.CLAN)

    @property
    def actualRequestsPaginator(self):
        return self._getPaginatorByFilterName(CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL)

    @property
    def expiredRequestsPaginator(self):
        return self._getPaginatorByFilterName(CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED)

    @property
    def processedRequestsPaginator(self):
        return self._getPaginatorByFilterName(CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED)

    def acceptRequest(self, applicationID):
        applicationID = int(applicationID)
        ctx = AcceptApplicationCtx(applicationID)
        self._getCurrentPaginator().accept(applicationID, ctx)

    def declineRequest(self, applicationID):
        applicationID = int(applicationID)
        ctx = DeclineApplicationCtx(applicationID)
        self._getCurrentPaginator().decline(applicationID, ctx)

    def sendInvite(self, dbId):
        dbId = int(dbId)
        paginator = self._getCurrentPaginator()
        requestWrapper = paginator.getInviteByDbID(dbId)
        ctx = CreateInviteCtx(requestWrapper.getClanDbID(), [requestWrapper.getAccountDbID()])
        self._getCurrentPaginator().resend(dbId, ctx)
        self._enableRefreshBtn(True)

    def onClanAppsCountReceived(self, clanDbID, appsCount):
        super(ClanRequestsView, self).onClanAppsCountReceived(clanDbID, appsCount)
        if self.actualRequestsPaginator.isSynced():
            self._enableRefreshBtn(True)

    def _populate(self):
        super(ClanRequestsView, self)._populate()

    def _onAttachedToWindow(self):
        super(ClanRequestsView, self)._onAttachedToWindow()
        self._cooldown.start()
        self.actualRequestsPaginator.onListUpdated += self._onListUpdated
        self.actualRequestsPaginator.onListItemsUpdated += self._onListItemsUpdated
        self.expiredRequestsPaginator.onListUpdated += self._onListUpdated
        self.expiredRequestsPaginator.onListItemsUpdated += self._onListItemsUpdated
        self.processedRequestsPaginator.onListUpdated += self._onListUpdated
        self.processedRequestsPaginator.onListItemsUpdated += self._onListItemsUpdated
        self.filterBy(self.currentFilterName)

    def _dispose(self):
        self.actualRequestsPaginator.onListUpdated -= self._onListUpdated
        self.actualRequestsPaginator.onListItemsUpdated -= self._onListItemsUpdated
        self.expiredRequestsPaginator.onListUpdated -= self._onListUpdated
        self.expiredRequestsPaginator.onListItemsUpdated -= self._onListItemsUpdated
        self.processedRequestsPaginator.onListUpdated -= self._onListUpdated
        self.processedRequestsPaginator.onListItemsUpdated -= self._onListItemsUpdated
        self._cooldown.stop()
        self._cooldown = None
        super(ClanRequestsView, self)._dispose()
        return

    def _onCooldownHandle(self, isInCooldown):
        self.dataProvider.allowActions(not isInCooldown)

    def _getViewAlias(self):
        return CLANS_ALIASES.CLAN_PROFILE_REQUESTS_VIEW_ALIAS

    def _showDummyByFilterName(self, filterName):
        if filterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL:
            self._showDummy(CLANS.CLANINVITESWINDOW_DUMMY_NOACTUALREQUESTS_TITLE)
        elif filterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED:
            self._showDummy(CLANS.CLANINVITESWINDOW_DUMMY_NOEXPIREDREQUESTS_TITLE)
        elif filterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED:
            self._showDummy(CLANS.CLANINVITESWINDOW_DUMMY_NOPROCESSEDREQUESTS_TITLE)
        else:
            LOG_DEBUG('Unexpected behaviour: no dummy for filter', filterName)
            self._showDummy(CLANS.CLANINVITESWINDOW_DUMMY_NOACTUALREQUESTS_TITLE)

    def _getDefaultFilterName(self):
        return CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL

    def _getDefaultSortFields(self):
        return (('status', False),)

    def _getSecondSortFields(self):
        if self.currentFilterName == CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED:
            return ('updatedAt',)
        else:
            return ('createdAt',)

    def _createSearchDP(self):
        return RequestDataProvider(self)

    def _makeFilters(self):
        return [{'alias': CLANS_ALIASES.INVITE_WINDOW_FILTER_ACTUAL,
          'text': _ms(CLANS.CLANINVITESWINDOW_FILTERS_ACTUAL, value=self.formatInvitesCount(self.actualRequestsPaginator))}, {'alias': CLANS_ALIASES.INVITE_WINDOW_FILTER_EXPIRED,
          'text': _ms(CLANS.CLANINVITESWINDOW_FILTERS_EXPIRED, value=self.formatInvitesCount(self.expiredRequestsPaginator))}, {'alias': CLANS_ALIASES.INVITE_WINDOW_FILTER_PROCESSED,
          'text': _ms(CLANS.CLANINVITESWINDOW_FILTERS_PROCESSED, value=self.formatInvitesCount(self.processedRequestsPaginator))}]

    def _makeHeaders(self):
        return [self._packHeaderColumnData('userName', CLANS.CLANINVITESWINDOW_TABLE_USERNAME, 225, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_USERNAME, textAlign='left', defaultSortDirection='ascending'),
         self._packHeaderColumnData('message', '', 73, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_MESSAGE, RES_ICONS.MAPS_ICONS_CLANS_INVITESWINDOW_ICON_STATISTICS_CLAN_INVITE_098),
         self._packHeaderColumnData('personalRating', '', 98, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_PERSONALRATING, RES_ICONS.MAPS_ICONS_STATISTIC_RATING24),
         self._packHeaderColumnData('battlesCount', '', 98, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_BATTLESCOUNT, RES_ICONS.MAPS_ICONS_STATISTIC_BATTLES24),
         self._packHeaderColumnData('wins', '', 98, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_WINS, RES_ICONS.MAPS_ICONS_STATISTIC_WINS24),
         self._packHeaderColumnData('awgExp', '', 98, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_AWGEXP, RES_ICONS.MAPS_ICONS_STATISTIC_AVGEXP24),
         self._packHeaderColumnData('status', CLANS.CLANINVITESWINDOW_TABLE_STATUS, 160, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_STATUS),
         self._packHeaderColumnData('actions', CLANS.CLANINVITESWINDOW_TABLE_ACTIONS, 140, CLANS.CLANINVITESWINDOW_TOOLTIPS_TABLE_REQUESTS_ACTIONS, enabled=False)]