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)))
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
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 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