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)))
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)))
Example #3
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'])
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
Example #5
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'])
Example #6
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 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