class ExternalLinksHandler(IExternalLinksController):
    def __init__(self):
        super(ExternalLinksHandler, self).__init__()
        self.__urlMacros = None
        return

    def init(self):
        self.__urlMacros = URLMacros()
        addListener = g_eventBus.addListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if not handler:
                LOG_ERROR('Handler is not found', eventType, handlerName)
                continue
            if not callable(handler):
                LOG_ERROR('Handler is invalid', eventType, handlerName,
                          handler)
                continue
            addListener(eventType, handler)

        return

    def fini(self):
        if self.__urlMacros is not None:
            self.__urlMacros.clear()
            self.__urlMacros = None
        removeListener = g_eventBus.removeListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if handler:
                removeListener(eventType, handler)

        super(ExternalLinksHandler, self).fini()
        return

    def open(self, url):
        if not url:
            LOG_ERROR('URL is empty', url)
            return
        try:
            BigWorld.wg_openWebBrowser(url)
        except Exception:
            LOG_ERROR('There is error while opening web browser at page:', url)
            LOG_CURRENT_EXCEPTION()

    @async
    @process
    def getURL(self, name, params=None, callback=lambda *args: None):
        urlSettings = GUI_SETTINGS.lookup(name)
        if urlSettings:
            url = yield self.__urlMacros.parse(str(urlSettings), params)
        else:
            url = yield lambda callback: callback('')
        callback(url)

    def _handleSpecifiedURL(self, event):
        self.open(event.url)

    @process
    def __openParsedUrl(self, urlName, params=None):
        parsedUrl = yield self.getURL(urlName, params)
        self.open(parsedUrl)

    def _handleParsedURL(self, event):
        self.__openParsedUrl(event.url)

    def _handleOpenRegistrationURL(self, _):
        self.__openParsedUrl('registrationURL')

    def _handleOpenRecoveryPasswordURL(self, _):
        self.__openParsedUrl('recoveryPswdURL')

    def _handleOpenPaymentURL(self, _):
        self.__openParsedUrl('paymentURL')

    def _handleSecuritySettingsURL(self, _):
        self.__openParsedUrl('securitySettingsURL')

    def _handleSupportURL(self, _):
        self.__openParsedUrl('supportURL')

    def _handleMigrationURL(self):
        self.__openParsedUrl('migrationURL')

    def _handleFortDescription(self, _):
        self.__openParsedUrl('fortDescription')

    def _handleClanSearch(self, _):
        self.__openParsedUrl('clanSearch')

    def _handleClanCreate(self, _):
        self.__openParsedUrl('clanCreate')

    def _handleInvitesManagementURL(self, _):
        self.__openParsedUrl('invitesManagementURL')

    def _handleGmSummaryURL(self, _):
        self.__openParsedUrl('globalMapSummary')

    def _handleGmPromoSummaryURL(self, _):
        self.__openParsedUrl('globalMapPromoSummary')

    def _handleGmCapURL(self, _):
        self.__openParsedUrl('globalMapCap')

    def _handleGmPromoURL(self, _):
        self.__openParsedUrl('globalMapPromo')

    def _handleOpenPremShopURL(self, _):
        self.__openParsedUrl('premShopURL')

    def _handleFrontlineChangesURL(self, _):
        self.__openParsedUrl('frontlineChangesURL')

    def _handleTokenShopURL(self, event):
        self.__openParsedUrl('tokenShopURL', event.params)

    def _handleTechTreeNewsURL(self, event):
        self.__openParsedUrl('techTreeUpdateNewsURL', event.params)
class ExternalLinksHandler(IExternalLinksController):
    __loginManager = dependency.descriptor(ILoginManager)

    def __init__(self):
        super(ExternalLinksHandler, self).__init__()
        self.__urlMacros = None
        self.__linksHandlers = None
        return

    def init(self):
        self.__urlMacros = URLMacros()
        addListener = g_eventBus.addListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if not handler:
                _logger.error('Handler is not found %s %s', eventType,
                              handlerName)
                continue
            if not callable(handler):
                _logger.error('Handler is invalid %s %s %r', eventType,
                              handlerName, handler)
                continue
            addListener(eventType, handler)

        return

    def fini(self):
        if self.__urlMacros is not None:
            self.__urlMacros.clear()
            self.__urlMacros = None
        removeListener = g_eventBus.removeListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if handler:
                removeListener(eventType, handler)

        super(ExternalLinksHandler, self).fini()
        return

    def open(self, url):
        if not url:
            _logger.error('URL is empty %r', url)
            return
        handled = False
        for handler in self._getHandlers():
            handled = handler.handle(url)
            if handled:
                break

        if not handled:
            _logger.error('Cant handle external link: %s', url)

    @async
    @process
    def getURL(self, name, params=None, callback=lambda *args: None):
        urlSettings = GUI_SETTINGS.lookup(name)
        if urlSettings:
            url = yield self.__urlMacros.parse(str(urlSettings), params)
        else:
            url = yield lambda callback: callback('')
        callback(url)

    def externalAllowed(self, url):
        for handler in self._getHandlers():
            result = handler.checkHandle(url)
            if result.handled:
                return result.externalAllowed

        return False

    def _handleSpecifiedURL(self, event):
        self.open(event.url)

    @process
    def __openParsedUrl(self, urlName, params=None):
        parsedUrl = yield self.getURL(urlName, params)
        self.open(parsedUrl)

    def _handleParsedURL(self, event):
        self.__openParsedUrl(event.url)

    def _handleOpenRegistrationURL(self, _):
        self.__openParsedUrl('registrationURL')

    def _handleOpenRecoveryPasswordURL(self, _):
        self.__openParsedUrl('recoveryPswdURL')

    def _handleOpenPaymentURL(self, _):
        self.__openParsedUrl('paymentURL')

    def _handleSecuritySettingsURL(self, _):
        self.__openParsedUrl('securitySettingsURL')

    def _handleClanRulesURL(self, _):
        self.__openParsedUrl('clanRulesURL')

    def _handleSupportURL(self, _):
        self.__openParsedUrl('supportURL')

    def _handleMigrationURL(self):
        self.__openParsedUrl('migrationURL')

    def _handleFortDescription(self, _):
        self.__openParsedUrl('fortDescription')

    def _handleClanSearch(self, _):
        self.__openParsedUrl('clanSearch')

    def _handleClanCreate(self, _):
        self.__openParsedUrl('clanCreate')

    def _handleInvitesManagementURL(self, _):
        self.__openParsedUrl('invitesManagementURL')

    def _handleGmSummaryURL(self, _):
        self.__openParsedUrl('globalMapSummary')

    def _handleGmPromoSummaryURL(self, _):
        self.__openParsedUrl('globalMapPromoSummary')

    def _handleGmCapURL(self, _):
        self.__openParsedUrl('globalMapCap')

    def _handleGmPromoURL(self, _):
        self.__openParsedUrl('globalMapPromo')

    def _handleOpenPremShopURL(self, _):
        self.__openParsedUrl('premShopURL')

    def _handleFrontlineChangesURL(self, _):
        self.__openParsedUrl('frontlineChangesURL')

    def _handleTokenShopURL(self, event):
        self.__openParsedUrl('tokenShopURL', event.params)

    def _getHandlers(self):
        if not self.__linksHandlers:
            self.__linksHandlers = []
            if self.__loginManager.isWgcSteam:
                self.__linksHandlers.append(external.PremShopLinksHandler())
                self.__linksHandlers.append(
                    external.AddPlatformTagLinksHandler())
                self.__linksHandlers.append(
                    external.PremShopLinksForArgsUrlHandler())
                self.__linksHandlers.append(
                    external.AddPlatformTagLinksToArgsUrlHandler())
            self.__linksHandlers.append(external.OpenBrowserHandler())
        return self.__linksHandlers
class PromoController(IPromoController):
    __browserCtrl = dependency.descriptor(IBrowserController)
    __notificationsCtrl = dependency.descriptor(IEventsNotificationsController)
    __webController = dependency.descriptor(IWebController)
    __settingsCore = dependency.descriptor(ISettingsCore)
    __lobbyContext = dependency.descriptor(ILobbyContext)
    __logger = dependency.descriptor(IPromoLogger)
    __bootcamp = dependency.descriptor(IBootcampController)

    def __init__(self):
        super(PromoController, self).__init__()
        self.__urlMacros = URLMacros()
        self.__externalCloseCallback = None
        self.__isLobbyInited = False
        self.__pendingPromo = None
        self.__promoCount = 0
        self.__lastUpdateTimeMark = 0
        self.__promoData = None
        self.__waitingForWebBridgeData = False
        self.__battlesFromLastTeaser = 0
        self.__wasInBattle = False
        self.__hasPendingTeaser = False
        self.__isPromoOpen = False
        self.__browserCreationCallbacks = {}
        self.__browserWatchers = {}
        self.__isInHangar = False
        self.__isTeaserOpen = False
        self.__checkIntervalInBattles = GUI_SETTINGS.checkPromoFrequencyInBattles
        self.__em = EventManager()
        self.onNewTeaserReceived = Event(self.__em)
        self.onPromoCountChanged = Event(self.__em)
        self.onTeaserShown = Event(self.__em)
        self.onTeaserClosed = Event(self.__em)
        return

    @sf_lobby
    def app(self):
        pass

    def fini(self):
        self.__stop()
        self.__pendingPromo = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__externalCloseCallback = None
        self.__em.clear()
        g_eventBus.removeListener(BrowserEvent.BROWSER_CREATED,
                                  self.__handleBrowserCreated)
        self.__browserCreationCallbacks = {}
        self.__browserWatchers = {}
        super(PromoController, self).fini()
        return

    def onLobbyInited(self, event):
        if not isPlayerAccount():
            return
        g_eventBus.addListener(BrowserEvent.BROWSER_CREATED,
                               self.__handleBrowserCreated)
        self.__isLobbyInited = True
        if self.__needToGetTeasersInfo():
            self.__updateWebBrgData()
        elif self.__hasPendingTeaser:
            self.__tryToShowTeaser()
        self.__notificationsCtrl.onEventNotificationsChanged += self.__onEventNotification
        if not isPopupsWindowsOpenDisabled():
            self.__processPromo(
                self.__notificationsCtrl.getEventsNotifications())
        self.app.loaderManager.onViewLoaded += self.__onViewLoaded

    @property
    def checkIntervalInBattles(self):
        return self.__checkIntervalInBattles

    def setNewTeaserData(self, teaserData):
        timestamp = teaserData['timestamp']
        if self.__lastUpdateTimeMark < timestamp and not self.__isPromoOpen and not self.__isTeaserOpen:
            self.__updateTeaserData(teaserData)

    def showFieldPost(self):
        url = GUI_SETTINGS.promoscreens
        loadingCallback = self.__logger.getLoggingFuture(
            action=PromoLogActions.OPEN_FROM_MENU,
            type=PromoLogSubjectType.INDEX,
            url=url)
        self.__showBrowserView(url, loadingCallback, soundSpaceID='field_post')

    @process
    def showLastTeaserPromo(self):
        rowUrl = self.__promoData.get('url', '')
        loadingCallback = self.__logger.getLoggingFuture(
            self.__promoData,
            action=PromoLogActions.OPEN_FROM_TEASER,
            type=PromoLogSubjectType.PROMO_SCREEN,
            url=rowUrl)
        url = yield self.__addAuthParams(rowUrl)
        self.__showBrowserView(url, loadingCallback)

    def setUnreadPromoCount(self, count):
        self.__updatePromoCount(count)

    def isTeaserOpen(self):
        return self.__isTeaserOpen

    def onAvatarBecomePlayer(self):
        if self.__isLobbyInited:
            self.__battlesFromLastTeaser += 1
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    def isActive(self):
        return self.__lobbyContext.getServerSettings().isFieldPostEnabled(
        ) and not self.__bootcamp.isInBootcamp()

    def getPromoCount(self):
        return self.__promoCount

    def showPromo(self, url, closeCallback=None, source=None):
        if self.__isLobbyInited:
            if not self.__isPromoOpen and not self.__waitingForWebBridgeData:
                self.__registerAndShowPromoBrowser(
                    url, closeCallback,
                    self.__logger.getLoggingFuture(
                        action=PromoLogActions.OPEN_IN_OLD,
                        type=PromoLogSubjectType.PROMO_SCREEN,
                        source=source,
                        url=url))
        else:
            self.__pendingPromo = _PromoData(url, closeCallback, source)

    def __needToGetTeasersInfo(self):
        return True if self.__battlesFromLastTeaser == 0 else self.__checkIntervalInBattles > 0 and self.__battlesFromLastTeaser % self.__checkIntervalInBattles == 0

    def __onTeaserClosed(self, byUser=False):
        self.__isTeaserOpen = False
        self.onTeaserClosed()
        if byUser:
            self.__showBubbleTooltip()

    def __showBubbleTooltip(self):
        storageData = self.__settingsCore.serverSettings.getUIStorage()
        if not storageData.get(UI_STORAGE_KEYS.FIELD_POST_HINT_IS_SHOWN):
            showBubbleTooltip(i18n.makeString(TOOLTIPS.HEADER_VERSIONINFOHINT))
            self.__settingsCore.serverSettings.saveInUIStorage(
                {UI_STORAGE_KEYS.FIELD_POST_HINT_IS_SHOWN: True})

    @process
    def __updateWebBrgData(self):
        ctx = PromoGetTeaserRequestCtx()
        if self.__battlesFromLastTeaser == 0:
            sourceType = PromoLogSourceType.FIRST_LOGIN
        else:
            sourceType = PromoLogSourceType.AFTER_BATTLE
        answerCallback = self.__logger.getLoggingFuture(
            action=PromoLogActions.GET_MOST_IMPORTANT, source=sourceType)
        self.__waitingForWebBridgeData = True
        response = yield self.__webController.sendRequest(ctx=ctx)
        self.__waitingForWebBridgeData = False
        if response.isSuccess():
            self.__updateTeaserData(ctx.getDataObj(response.getData()))
        elif self.__hasPendingTeaser:
            self.__tryToShowTeaser()
        if answerCallback:
            answerCallback(success=response.extraCode)

    def __onPromoClosed(self, **kwargs):
        self.__isPromoOpen = False
        self.__showBubbleTooltip()
        if self.__externalCloseCallback:
            self.__externalCloseCallback()
        self.__requestPromoCount()
        actionType = PromoLogActions.CLOSED_BY_USER if kwargs.get(
            'byUser') else PromoLogActions.KILLED_BY_SYSTEM
        self.__logger.logAction(action=actionType,
                                type=PromoLogSubjectType.PROMO_SCREEN_OR_INDEX,
                                url=kwargs.get('url'))

    @process
    def __requestPromoCount(self):
        if not self.isActive():
            _logger.warning(
                'Trying to request unread promos count when promo functionality is disabled'
            )
            return
        ctx = PromoGetUnreadCountRequestCtx()
        response = yield self.__webController.sendRequest(ctx=ctx)
        if response.isSuccess():
            self.__updatePromoCount(ctx.getCount(response))

    def __updatePromoCount(self, count):
        countChanged = count != self.__promoCount
        self.__promoCount = count
        if countChanged:
            self.onPromoCountChanged()

    def __updateTeaserData(self, teaserData):
        self.__lastUpdateTimeMark = teaserData['timestamp']
        self.__promoData = teaserData['lastPromo']
        self.__updatePromoCount(teaserData['count'])
        if self.__promoData.get('url'):
            self.__tryToShowTeaser()

    def __showTeaser(self):
        if self.isActive():
            self.__battlesFromLastTeaser = 0
            self.__hasPendingTeaser = False
            self.onNewTeaserReceived(self.__promoData, self.__onTeaserShown,
                                     self.__onTeaserClosed)
        else:
            _logger.warning(
                'Impossible to show teaser, functionality is disabled')

    @process
    def __onTeaserShown(self, promoID):
        self.__isTeaserOpen = True
        self.onTeaserShown()
        yield self.__webController.sendRequest(
            PromoSendTeaserShownRequestCtx(promoID))

    def __tryToShowTeaser(self):
        if self.__isLobbyInited and self.__isInHangar and not self.__waitingForWebBridgeData:
            self.__showTeaser()
        else:
            self.__hasPendingTeaser = True

    def __stop(self):
        if self.app and self.app.loaderManager:
            self.app.loaderManager.onViewLoaded -= self.__onViewLoaded
        self.__isLobbyInited = False
        self.__isInHangar = False
        self.__isPromoOpen = False
        self.__externalCloseCallback = None
        self.__isTeaserOpen = False
        self.__notificationsCtrl.onEventNotificationsChanged -= self.__onEventNotification
        g_eventBus.removeListener(BrowserEvent.BROWSER_CREATED,
                                  self.__handleBrowserCreated)
        self.__browserCreationCallbacks = {}
        watcherKeys = self.__browserWatchers.keys()
        for browserID in watcherKeys:
            self.__clearWatcher(browserID)

        return

    def __processPromo(self, promos):
        if not self.__isPromoOpen and not self.__waitingForWebBridgeData:
            logData = {
                'action': PromoLogActions.OPEN_IN_OLD,
                'type': PromoLogSubjectType.PROMO_SCREEN
            }
            if self.__pendingPromo is not None:
                promoData = self.__pendingPromo
                logData.update({
                    'source': promoData.source,
                    'url': promoData.url
                })
                loadingCallback = self.__logger.getLoggingFuture(**logData)
                self.__registerAndShowPromoBrowser(promoData.url,
                                                   promoData.closeCallback,
                                                   loadingCallback)
                self.__pendingPromo = None
                return
            promo = findFirst(
                lambda item: item.eventType.startswith(
                    gc_constants.PROMO.TEMPLATE.ACTION), promos)
            if promo:
                logData.update({
                    'source': PromoLogSourceType.SSE,
                    'url': promo.data
                })
                self.__showBrowserView(
                    promo.data, self.__logger.getLoggingFuture(**logData))
        return

    def __onEventNotification(self, added, _):
        self.__processPromo(added)

    def __registerAndShowPromoBrowser(self, url, closeCallback,
                                      loadingCallback):
        self.__externalCloseCallback = closeCallback
        self.__showBrowserView(url, loadingCallback)

    @process
    def __showBrowserView(self, url, loadingCallback=None, soundSpaceID=None):
        promoUrl = yield self.__urlMacros.parse(url)
        self.__registerLoadingCallback(promoUrl, loadingCallback)
        _showBrowserView(promoUrl,
                         self.__onPromoClosed,
                         soundSpaceID=soundSpaceID)
        self.__isPromoOpen = True

    def __registerLoadingCallback(self, url, callback):
        if callback is not None:
            self.__browserCreationCallbacks[url] = callback
        return

    def __handleBrowserCreated(self, event):
        url = event.ctx.get('url')
        if url in self.__browserCreationCallbacks:
            callback = self.__browserCreationCallbacks.pop(url)
            browserID = event.ctx.get('browserID')
            browser = self.__browserCtrl.getBrowser(browserID)
            if browser is None:
                return

            def callbackWrapper(clbUrl, _, statusCode):
                if clbUrl == url:
                    callback(url=url, success=statusCode)
                    self.__clearWatcher(browserID)

            browser.onLoadEnd += callbackWrapper
            self.__browserWatchers[browserID] = callbackWrapper
        return

    def __clearWatcher(self, browserID):
        if browserID in self.__browserWatchers:
            watcher = self.__browserWatchers.pop(browserID)
            browser = self.__browserCtrl.getBrowser(browserID)
            if browser is not None:
                browser.onLoadEnd -= watcher
        return

    @async
    @process
    def __addAuthParams(self, url, callback):
        if not url or not self.__webController:
            callback(url)
        accessTokenData = yield self.__webController.getAccessTokenData(
            force=True)
        params = {
            'access_token': str(accessTokenData.accessToken),
            'spa_id': BigWorld.player().databaseID
        }
        callback(url_formatters.addParamsToUrlQuery(url, params))

    def __onViewLoaded(self, pyView, _):
        if self.__isLobbyInited:
            if pyView.alias == VIEW_ALIAS.LOBBY_HANGAR:
                self.__isInHangar = True
                if self.__hasPendingTeaser:
                    self.__tryToShowTeaser()
            elif pyView.viewType == ViewTypes.LOBBY_SUB:
                self.__isInHangar = False
class GameWindowController(IGameWindowController):
    eventsCache = dependency.descriptor(IEventsCache)
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        self.__urlMacros = URLMacros()
        self.__isLobbyInited = False
        super(GameWindowController, self).__init__()

    def fini(self):
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.hideWindow()
        super(GameWindowController, self).fini()
        return

    def onLobbyInited(self, event):
        self.__isLobbyInited = True
        self._addListeners()

    def onAvatarBecomePlayer(self):
        self._removeListeners()
        if self.__isLobbyInited:
            self.hideWindow()
        self.__isLobbyInited = False
        super(GameWindowController, self).onAvatarBecomePlayer()

    def onDisconnected(self):
        self.__isLobbyInited = False
        self._removeListeners()
        self.hideWindow()
        super(GameWindowController, self).onDisconnected()

    def hideWindow(self):
        raise NotImplementedError

    def showWindow(self, url=None, invokedFrom=None):
        self.hideWindow()
        self._showWindow(url, invokedFrom)

    @async
    @process
    def getUrl(self, callback=lambda *args: None):
        url = yield self.__urlMacros.parse(self._getUrl())
        callback(url)

    def _addListeners(self):
        self.eventsCache.onSyncCompleted += self._onSyncCompleted

    def _removeListeners(self):
        self.eventsCache.onSyncCompleted -= self._onSyncCompleted

    def _onSyncCompleted(self, *_):
        pass

    @process
    def _showWindow(self, url, invokedFrom=None):
        if url is None:
            url = yield self.getUrl()
            if not url:
                return
        self._openWindow(url, invokedFrom)
        return

    def _openWindow(self, url, invokedFrom=None):
        raise NotImplementedError
Пример #5
0
class BrowserController(IBrowserController):
    def __init__(self):
        super(BrowserController, self).__init__()
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserCreationCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMacros()
        self.__pendingBrowsers = {}
        self.__creatingBrowserID = None
        self.__filters = _getGlobalFilters()
        return

    def fini(self):
        self.__filters = None
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browsersCallbacks.clear()
        self.__browsersCallbacks = None
        self.__browsers.clear()
        self.__browsers = None
        self.__pendingBrowsers.clear()
        self.__pendingBrowsers = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()
        BigWorld.destroyBrowser()

    def onDisconnected(self):
        self.__stop()
        BigWorld.destroyBrowser()

    def onLobbyStarted(self, ctx):
        BigWorld.createBrowser()

    def addFilterHandler(self, handler):
        self.__filters.add(handler)

    def removeFilterHandler(self, handler):
        self.__filters.discard(handler)

    @async
    @process
    def load(self,
             url=None,
             title=None,
             showActionBtn=True,
             showWaiting=True,
             browserID=None,
             isAsync=False,
             browserSize=None,
             isDefault=True,
             callback=None,
             showCloseBtn=False,
             useBrowserWindow=True,
             isModal=False,
             showCreateWaiting=False,
             handlers=None,
             showBrowserCallback=None,
             isSolidBorder=False):
        if showCreateWaiting:
            Waiting.show('browser/init')
        url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url)
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        webBrowserID = browserID
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
            webBrowserID = browserID
        elif not isinstance(browserID, int):
            webBrowserID = self.__browserIDGenerator.next()
        ctx = {
            'url': url,
            'title': title,
            'showActionBtn': showActionBtn,
            'showWaiting': showWaiting,
            'browserID': browserID,
            'size': size,
            'isAsync': isAsync,
            'showCloseBtn': showCloseBtn,
            'showWindow': useBrowserWindow,
            'alias': VIEW_ALIAS.BROWSER_WINDOW_MODAL
            if isModal else VIEW_ALIAS.BROWSER_WINDOW,
            'showCreateWaiting': showCreateWaiting,
            'handlers': handlers,
            'showBrowserCallback': showBrowserCallback,
            'isSolidBorder': isSolidBorder
        }
        if browserID not in self.__browsers and browserID not in self.__pendingBrowsers:
            appLoader = dependency.instance(IAppLoader)
            app = appLoader.getApp()
            if app is None:
                raise SoftException('Application can not be None')
            browser = WebBrowser(webBrowserID,
                                 app,
                                 size,
                                 url,
                                 handlers=self.__filters)
            self.__browsers[browserID] = browser
            if self.__isCreatingBrowser():
                _logger.info('CTRL: Queueing a browser creation: %r - %s',
                             browserID, url)
                self.__pendingBrowsers[browserID] = ctx
            else:
                self.__createBrowser(ctx)
        elif browserID in self.__pendingBrowsers:
            _logger.info(
                'CTRL: Re-queuing a browser creation, overriding: %r - %s',
                browserID, url)
            self.__pendingBrowsers[browserID] = ctx
        elif browserID in self.__browsers:
            _logger.info('CTRL: Re-navigating an existing browser: %r - %s',
                         browserID, url)
            browser = self.__browsers[browserID]
            browser.navigate(url)
            browser.changeTitle(title)
        callback(browserID)
        return

    def getAllBrowsers(self):
        return self.__browsers

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            _logger.info('CTRL: Deleting a browser: %s', browserID)
            browser = self.__browsers.pop(browserID)
            self.__clearCallbacks(browserID, browser, True)
            browser.destroy()
            if self.__creatingBrowserID == browserID:
                self.__creatingBrowserID = None
                self.__tryCreateNextPendingBrowser()
            if browserID in self.__pendingBrowsers:
                del self.__pendingBrowsers[browserID]
        self.onBrowserDeleted(browserID)
        return

    def __isCreatingBrowser(self):
        return self.__creatingBrowserID is not None

    def __createDone(self, ctx):
        _logger.info('CTRL: Finished creating a browser: %r',
                     self.__creatingBrowserID)
        if ctx['showCreateWaiting']:
            Waiting.hide('browser/init')

    def __tryCreateNextPendingBrowser(self):
        self.__creatingBrowserID = None
        if self.__pendingBrowsers:
            nextCtx = self.__pendingBrowsers.popitem()[1]
            self.__createBrowser(nextCtx)
        return

    def __createBrowser(self, ctx):
        browserID = ctx['browserID']
        _logger.info('CTRL: Creating a browser: %r - %s', browserID,
                     ctx['url'])
        self.__creatingBrowserID = browserID
        browser = self.__browsers[browserID]
        if not browser.create():
            _logger.info('CTRL: Failed the create step: %r', browserID)
            self.delBrowser(browserID)
            self.__tryCreateNextPendingBrowser()
            return
        else:
            self.onBrowserAdded(browserID)

            def createNextBrowser():
                _logger.info(
                    'CTRL: Triggering create of next browser from: %r',
                    browserID)
                creation = self.__browserCreationCallbacks.pop(browserID, None)
                if creation is not None:
                    self.__browsers[
                        browserID].onCanCreateNewBrowser -= creation
                self.__tryCreateNextPendingBrowser()
                return

            def failedCreationCallback(url):
                _logger.info('CTRL: Failed a creation: %r - %s', browserID,
                             url)
                self.__clearCallbacks(browserID, self.__browsers[browserID],
                                      False)
                self.delBrowser(browserID)

            def successfulCreationCallback(url, isLoaded, httpStatusCode=None):
                _logger.info('CTRL: Ready to show: %r isLoaded: %r %s',
                             browserID, isLoaded, url)
                self.__clearCallbacks(browserID, self.__browsers[browserID],
                                      False)
                if isLoaded:
                    self.__showBrowser(browserID, ctx)
                else:
                    _logger.warning('Browser request url %s was not loaded!',
                                    url)
                g_eventBus.handleEvent(
                    BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx))
                self.__createDone(ctx)

            def titleUpdateCallback(title):
                ctx['title'] = title

            browser.onCanCreateNewBrowser += createNextBrowser
            self.__browserCreationCallbacks[browserID] = createNextBrowser
            browser.onFailedCreation += failedCreationCallback
            browser.onTitleChange += titleUpdateCallback
            if ctx['isAsync']:
                self.__browsersCallbacks[browserID] = (
                    None, successfulCreationCallback, failedCreationCallback,
                    titleUpdateCallback)
                browser.onLoadEnd += successfulCreationCallback
            else:
                self.__browsersCallbacks[browserID] = (
                    successfulCreationCallback, None, failedCreationCallback,
                    titleUpdateCallback)
                browser.onReady += successfulCreationCallback
            return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            self.__clearCallbacks(browserID, browser, True)
            browser.destroy()

    def __clearCallbacks(self, browserID, browser, incDelayedCreation):
        ready, loadEnd, failed, title = self.__browsersCallbacks.pop(
            browserID, (None, None, None, None))
        if browser is not None:
            if failed is not None:
                browser.onFailedCreation -= failed
            if ready is not None:
                browser.onReady -= ready
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            if title is not None:
                browser.onTitleChange -= title
        if incDelayedCreation:
            creation = self.__browserCreationCallbacks.pop(browserID, None)
            if browser is not None and creation is not None:
                browser.onCanCreateNewBrowser -= creation
        return

    def __showBrowser(self, browserID, ctx):
        _logger.info('CTRL: Showing a browser: %r - %s', browserID, ctx['url'])
        if ctx.get('showWindow'):
            alias = ctx['alias']
            g_eventBus.handleEvent(
                LoadViewEvent(SFViewLoadParams(alias,
                                               getViewName(alias, browserID)),
                              ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
        showBrowserCallback = ctx.get('showBrowserCallback')
        if showBrowserCallback:
            showBrowserCallback()
class RssNewsFeed(RssNewsFeedMeta):
    UPDATE_INTERVAL = 60
    DESCRIPTION_MAX_LENGTH = 250
    DESCRIPTION_TAIL = '...'
    DESCRIPTION_CUT_LENGTH = DESCRIPTION_MAX_LENGTH - len(DESCRIPTION_TAIL)
    SHOW_NEWS_COUNT = 3
    externalBrowser = dependency.descriptor(IExternalLinksController)
    internalBrowser = dependency.descriptor(IBrowserController)

    def __init__(self):
        super(RssNewsFeed, self).__init__()
        self.__requestCbID = None
        self.__feed = []
        self.__urlMacros = URLMacros()
        return

    def getFeed(self):
        return self.__feed

    def openBrowser(self, linkToOpen):
        if linkToOpen:
            openBrowser = self.externalBrowser.open
            if GUI_SETTINGS.loginRssFeed.internalBrowser:
                browser = self.internalBrowser
                if browser is not None:
                    openBrowser = browser.load
                else:
                    _logger.error(
                        'Attempting to open internal browser, but browseris not exist. External browser will be opened: %r',
                        linkToOpen)
            _logger.debug('Open browser: %r', linkToOpen)
            openBrowser(linkToOpen)
        return

    def _populate(self):
        super(RssNewsFeed, self)._populate()
        self.__updateCallback()

    def _dispose(self):
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__feed = []
        self.__clearCallback()
        super(RssNewsFeed, self)._dispose()
        return

    @process
    def __requestFeed(self):
        yield lambda callback: callback(True)
        if GUI_SETTINGS.loginRssFeed.show:
            requestUrl = yield self.__getRssUrl()
            from helpers.RSSDownloader import g_downloader as g_rss
            if g_rss is not None:
                g_rss.download(self.__onRssFeedReceived, url=requestUrl)
            _logger.debug('Requesting login RSS news: %s', requestUrl)
        return

    def __onRssFeedReceived(self, data):
        if self.isDisposed():
            return
        else:
            self.__feed = []
            for entry in reversed(data.get('entries', [])):
                data = self.__prepareData(entry)
                if data is not None:
                    self.__feed.append(data)

            _logger.debug('RSS feed received, entries count %d',
                          len(self.__feed))
            self.as_updateFeedS(self.__feed[:self.SHOW_NEWS_COUNT])
            return

    def __clearCallback(self):
        if self.__requestCbID is not None:
            BigWorld.cancelCallback(self.__requestCbID)
            self.__requestCbID = None
        return

    def __updateCallback(self):
        self.__requestFeed()
        self.__clearCallback()
        self.__requestCbID = BigWorld.callback(self.UPDATE_INTERVAL,
                                               self.__updateCallback)

    @async
    @process
    def __getRssUrl(self, callback):
        url = yield self.__urlMacros.parse(str(GUI_SETTINGS.loginRssFeed.url))
        callback(url)

    def __prepareData(self, entryData):
        description = entryData.get('description')
        if description is not None:
            try:
                section = ResMgr.DataSection()
                section.createSectionFromString(encodeUtf8(description))
                _, section = findFirst(lambda (name, _): name == 'div',
                                       section.items())
                description, _ = unicode_from_utf8(section.asString)
                if len(description) > self.DESCRIPTION_MAX_LENGTH:
                    description = description[:self.
                                              DESCRIPTION_CUT_LENGTH] + self.DESCRIPTION_TAIL
            except Exception:
                _logger.exception('Invalid RSS entry description: %r, %r',
                                  entryData, description)
                return

        return {
            'id': entryData.get('id', str(uuid.uuid4())),
            'link': entryData.get('link'),
            'description': encodeUtf8(description)
        }
Пример #7
0
class VehiclePreviewBuyingPanel(VehiclePreviewBuyingPanelMeta):
    appLoader = dependency.descriptor(IAppLoader)
    _itemsCache = dependency.descriptor(IItemsCache)
    _goodiesCache = dependency.descriptor(IGoodiesCache)
    _comparisonBasket = dependency.descriptor(IVehicleComparisonBasket)
    _tradeIn = dependency.descriptor(ITradeInController)
    _restores = dependency.descriptor(IRestoreController)
    _heroTanks = dependency.descriptor(IHeroTankController)
    _lobbyContext = dependency.descriptor(ILobbyContext)
    _marathonsCtrl = dependency.descriptor(IMarathonEventsController)
    __calendarController = dependency.descriptor(ICalendarController)
    __linksCtrl = dependency.descriptor(IExternalLinksController)

    def __init__(self, skipConfirm=False):
        super(VehiclePreviewBuyingPanel, self).__init__()
        heroTankCD = self._heroTanks.getCurrentTankCD()
        self._vehicleCD = g_currentPreviewVehicle.item.intCD
        self._vehicleLevel = g_currentPreviewVehicle.item.level
        self._actionType = None
        self._skipConfirm = skipConfirm
        self._disableBuyButton = False
        self._marathonEvent = None
        self.__previewDP = DefaultVehPreviewDataProvider()
        self.__isHeroTank = heroTankCD and heroTankCD == self._vehicleCD
        self.__price = None
        self.__title = None
        self.__description = None
        self.__items = None
        self.__offers = None
        self.__currentOffer = None
        self.__styleByGroup = {}
        self.__vehicleByGroup = {}
        self.__endTime = None
        self.__oldPrice = MONEY_UNDEFINED
        self.__buyParams = None
        self.__backAlias = None
        self.__backCallback = None
        self.__timeCallbackID = None
        self.__timeLeftIcon = icons.makeImageTag(
            RES_ICONS.MAPS_ICONS_LIBRARY_TIME_ICON, 16, 16)
        self.__cachedVehiclesVOs = None
        self.__cachedItemsVOs = None
        self.__cachedCollapsedItemsVOs = None
        self.__couponInfo = None
        self.__hasSSEDiscount = False
        self.__urlMacros = URLMacros()
        g_techTreeDP.load()
        return

    def onBuyOrResearchClick(self):
        vehicle = g_currentPreviewVehicle.item
        shopPackage = self.__items is not None and self.__couponInfo is None
        frontlineCouponPackage = self.__couponInfo is not None and self.__couponInfo.selected
        if self._marathonEvent:
            self.__purchaseMarathonPackage()
        elif shopPackage or frontlineCouponPackage:
            self.__purchasePackage()
        elif self.__offers is not None:
            self.__purchaseOffer()
        elif self.__isHeroTank:
            self.__purchaseHeroTank()
        elif canBuyGoldForVehicleThroughWeb(vehicle):
            self.__purchaseSingleVehicle(vehicle)
        else:
            self.__research()
        return

    def onCouponSelected(self, isActive):
        if self.__couponInfo:
            self.__couponInfo.selected = isActive
            if isActive:
                self.__title = backport.text(
                    R.strings.vehicle_preview.buyingPanel.frontlinePack.
                    titleLabel.active())
            elif self.__hasSSEDiscount:
                self.__title = backport.text(
                    R.strings.vehicle_preview.buyingPanel.frontlinePack.
                    titleLabel.inactive_add_discount())
            else:
                self.__title = backport.text(
                    R.strings.vehicle_preview.buyingPanel.frontlinePack.
                    titleLabel.inactive())
            self.__update()

    def setMarathonEvent(self, prefix):
        self._marathonEvent = self._marathonsCtrl.getMarathon(prefix)

    def setTimerData(self, endTime):
        if self.__couponInfo is not None:
            return
        else:
            if endTime is not None:
                self.__endTime = endTime
                self.__onLeftTimeUpdated()
            self.__updateBtnState()
            return

    def setInfoTooltip(self):
        tooltip = self._marathonEvent.getVehiclePreviewTitleTooltip()
        self.as_setSetTitleTooltipS(tooltip)

    def setBuyParams(self, buyParams):
        self.__buyParams = buyParams

    def setBackAlias(self, backAlias):
        self.__backAlias = backAlias

    def setBackCallback(self, backCallback):
        self.__backCallback = backCallback

    def setIsHeroTank(self, isHero):
        self.__isHeroTank = isHero

    def setPackItems(self, packItems, price, oldPrice, title):
        self.__title = title if title is not None else ''
        self.__price = price
        self.__hasSSEDiscount = oldPrice != MONEY_UNDEFINED
        self.__oldPrice = oldPrice
        self.__items = packItems
        self.__styleByGroup.clear()
        self.__vehicleByGroup.clear()
        vehiclesItems, items = self.__previewDP.separateItemsPack(self.__items)
        for item in items:
            if item.type in ItemPackTypeGroup.STYLE and item.groupID not in self.__styleByGroup:
                self.__styleByGroup[item.groupID] = item.id
            if item.type in ItemPackTypeGroup.DISCOUNT:
                self.__title = backport.text(
                    R.strings.vehicle_preview.buyingPanel.frontlinePack.
                    titleLabel.active())
                self.__couponInfo = _CouponData(item=item, selected=True)
                self.as_setCouponS(
                    self.__previewDP.packCouponData(
                        self.__items, self.__price.get(Currency.GOLD)))
                if not self.__oldPrice:
                    self.__oldPrice = self.__price

        for vehicleItem in vehiclesItems:
            self.__vehicleByGroup[vehicleItem.id] = vehicleItem.groupID

        vehiclesVOs, itemsVOs, collapseItemsVOs = self.__previewDP.getItemsPackData(
            g_currentPreviewVehicle.item, items, vehiclesItems)
        self.__cachedVehiclesVOs = vehiclesVOs
        self.__cachedItemsVOs = itemsVOs
        self.__cachedCollapsedItemsVOs = collapseItemsVOs
        self.__update()
        return

    def onCarouselVehicleSelected(self, intCD):
        self._vehicleCD = intCD
        g_currentPreviewVehicle.selectVehicle(intCD)

    def setOffers(self, offers, title, description):
        self.__offers = offers
        self.__title = title
        self.__description = description
        selectedID = getActiveOffer(self.__offers).id
        offersData = self.__previewDP.getOffersData(
            self.__offers, selectedID) if len(self.__offers) > 1 else []
        self.as_setOffersDataS(offersData)
        self.onOfferSelected(selectedID)

    def onOfferSelected(self, offerID):
        self.__currentOffer = findFirst(lambda o: o.id == offerID,
                                        self.__offers)
        if self.__currentOffer:
            vehicle = g_currentPreviewVehicle.item
            crew = self.__currentOffer.crew
            g_eventBus.handleEvent(
                HasCtxEvent(ctx={
                    'vehicleItems':
                    [ItemPackEntry(id=vehicle.intCD, groupID=crew.groupID)],
                    'crewItems': [crew],
                    'offer':
                    self.__currentOffer
                },
                            eventType=OFFER_CHANGED_EVENT))
            self.__buyParams = self.__currentOffer.buyParams
            self.__price = self.__currentOffer.buyPrice
            self.as_setBuyDataS(
                self.__previewDP.getOffersBuyingPanelData(self.__getBtnData()))
            description = self.__description or self.__getCurrentOfferDescription(
            ) or {}
            self.as_setSetTitleTooltipS(makeTooltip(**description))

    def showTooltip(self, intCD, itemType):
        toolTipMgr = self.appLoader.getApp().getToolTipMgr()
        if itemType == BOX_TYPE:
            toolTipMgr.onCreateComplexTooltip(
                makeTooltip(TOOLTIPS.VEHICLEPREVIEW_BOXTOOLTIP_HEADER,
                            TOOLTIPS.VEHICLEPREVIEW_BOXTOOLTIP_BODY), 'INFO')
            return
        try:
            try:
                itemId = int(intCD)
            except ValueError:
                itemId = intCD

            rawItem = [
                item for item in self.__items
                if item.id == itemId and item.type == itemType
            ][0]
            item = lookupItem(rawItem, self._itemsCache, self._goodiesCache)
            showItemTooltip(toolTipMgr, rawItem, item)
        except IndexError:
            return

    def updateData(self, useCompactData):
        self.__update(collapseItems=False)

    def _populate(self):
        super(VehiclePreviewBuyingPanel, self)._populate()
        g_clientUpdateManager.addMoneyCallback(self.__updateBtnState)
        g_clientUpdateManager.addCallbacks({
            'stats.freeXP':
            self.__updateBtnState,
            'inventory':
            self.__updateBtnState,
            'serverSettings.blueprints_config':
            self.__onBlueprintsModeChanged
        })
        g_currentPreviewVehicle.onVehicleUnlocked += self.__updateBtnState
        g_currentPreviewVehicle.onChanged += self.__onVehicleChanged
        self._heroTanks.onUpdated += self.__updateBtnState
        self._restores.onRestoreChangeNotify += self.__onRestoreChanged
        self._lobbyContext.getServerSettings(
        ).onServerSettingsChange += self.__onServerSettingsChanged
        self.addListener(CameraRelatedEvents.VEHICLE_LOADING,
                         self.__onVehicleLoading)

    def _dispose(self):
        g_clientUpdateManager.removeObjectCallbacks(self)
        g_currentPreviewVehicle.onVehicleUnlocked -= self.__updateBtnState
        g_currentPreviewVehicle.onChanged -= self.__onVehicleChanged
        self._heroTanks.onUpdated -= self.__updateBtnState
        self._restores.onRestoreChangeNotify -= self.__onRestoreChanged
        self._lobbyContext.getServerSettings(
        ).onServerSettingsChange -= self.__onServerSettingsChanged
        self.removeListener(CameraRelatedEvents.VEHICLE_LOADING,
                            self.__onVehicleLoading)
        self.__stopTimer()
        self.__styleByGroup.clear()
        self.__vehicleByGroup.clear()
        self.__urlMacros.clear()
        self.__urlMacros = None
        super(VehiclePreviewBuyingPanel, self)._dispose()
        return

    def __update(self, collapseItems=False):
        if self.__cachedVehiclesVOs:
            g_currentPreviewVehicle.selectVehicle(
                self.__cachedVehiclesVOs[0]['intCD'])
            self.as_setSetVehiclesDataS({'vehicles': self.__cachedVehiclesVOs})
        if self.__couponInfo:
            self.__updateEnabledState(self.__cachedCollapsedItemsVOs,
                                      self.__couponInfo.selected)
            self.__updateEnabledState(self.__cachedItemsVOs,
                                      self.__couponInfo.selected)
        if collapseItems and self.__cachedCollapsedItemsVOs:
            self.as_setSetItemsDataS({'items': self.__cachedCollapsedItemsVOs})
        elif self.__cachedItemsVOs:
            self.as_setSetItemsDataS({'items': self.__cachedItemsVOs})
        self.__updateBtnState()

    def __getOfferByID(self, offerID):
        return findFirst(lambda o: o.buy_params['transactionID'] == offerID,
                         self.__offers)

    def __isReferralWindow(self):
        return self.__backAlias == VIEW_ALIAS.REFERRAL_PROGRAM_WINDOW

    def __getConfirmationDialogKey(self):
        key = 'buyConfirmation'
        if self.__isReferralWindow():
            key = 'referralReward'
        return key

    def __buyRequestConfirmation(self, key='buyConfirmation'):
        product = self.__title if self.__couponInfo is None else g_currentPreviewVehicle.item.shortUserName
        return DialogsInterface.showDialog(meta=I18nConfirmDialogMeta(
            key=key,
            messageCtx={
                'product':
                product,
                'price':
                formatPrice(self.__getPackPrice(), reverse=True, useIcon=True)
            },
            focusedID=DIALOG_BUTTON_ID.SUBMIT))

    def __onVehicleLoading(self, ctxEvent):
        vehicle = g_currentPreviewVehicle.item
        if vehicle is None:
            return
        else:
            groupID = self.__vehicleByGroup.get(vehicle.intCD)
            if not ctxEvent.ctx.get(
                    'started') and groupID in self.__styleByGroup:
                customizationStyle = self.__styleByGroup[groupID]
                style = self._itemsCache.items.getItemByCD(customizationStyle)
                if style is not None and not style.isRentable:
                    g_currentPreviewVehicle.previewStyle(style)
            return

    @process
    def __updateBtnState(self, *_):
        item = g_currentPreviewVehicle.item
        if item is None:
            return
        else:
            btnData = self.__getBtnData()
            self._actionType = self.__previewDP.getBuyType(item)
            if self.__items:
                buyingPanelData = self.__previewDP.getItemPackBuyingPanelData(
                    btnData, self.__items,
                    self.__couponInfo.selected if self.__couponInfo else False,
                    self.__price.get(Currency.GOLD))
            elif self.__offers:
                buyingPanelData = self.__previewDP.getOffersBuyingPanelData(
                    btnData)
            else:
                buyingPanelData = self.__previewDP.getBuyingPanelData(
                    item, btnData, self.__isHeroTank)
            buyingPanelData.update(
                {'isReferralEnabled': self.__isReferralWindow()})
            hasExternalLink = yield self.__hasExternalLink()
            if hasExternalLink:
                btnIcon = backport.image(
                    R.images.gui.maps.icons.library.buyInWeb())
                buyingPanelData.update({
                    'buyButtonIcon': btnIcon,
                    'buyButtonIconAlign': 'right'
                })
            self.as_setBuyDataS(buyingPanelData)
            return

    def __onVehicleChanged(self, *_):
        if g_currentPreviewVehicle.isPresent():
            self._vehicleCD = g_currentPreviewVehicle.item.intCD
            if not self.__price:
                self.__updateBtnState()

    def __onRestoreChanged(self, vehicles):
        if g_currentPreviewVehicle.isPresent():
            if self._vehicleCD in vehicles:
                self.__updateBtnState()

    def __onServerSettingsChanged(self, diff):
        if self._lobbyContext.getServerSettings().isShopDataChangedInDiff(
                diff,
                'isEnabled') or CollectorVehicleConsts.CONFIG_NAME in diff:
            self.__updateBtnState()

    def __onBlueprintsModeChanged(self, _):
        self.__updateBtnState()

    def __getBtnData(self):
        if self.__price is not None:
            return self.__getBtnDataPack()
        else:
            vehicle = g_currentPreviewVehicle.item
            if vehicle.isCollectible:
                return self.__getBtnDataCollectibleVehicle(vehicle)
            return self.__getBtnDataUnlockedVehicle(
                vehicle
            ) if vehicle.isUnlocked else self.__getBtnDataLockedVehicle(
                vehicle)

    def __getBtnDataPack(self):
        buyButtonTooltip = ''
        actionTooltip = None
        customOffer = None
        price = self.__getPackPrice()
        currency = price.getCurrency()
        walletAvailable = self.__walletAvailableForCurrency(currency)
        enabled = False
        if not walletAvailable:
            buyButtonTooltip = _buildBuyButtonTooltip('walletUnavailable')
        elif self._disableBuyButton:
            buyButtonTooltip = _buildBuyButtonTooltip('endTime')
        elif self.__price.isSet(currency):
            enabled = currency == Currency.GOLD or mayObtainForMoney(
                price) or mayObtainWithMoneyExchange(price)
        else:
            enabled = True
        if self.__currentOffer and self.__currentOffer.bestOffer and self.__currentOffer.eventType:
            actionTooltip = self.__getBestOfferTooltipData(
                self.__currentOffer.eventType)
        buttonIcon = None
        buttonIconAlign = None
        itemPrices = ItemPrice(price=price, defPrice=self.__oldPrice)
        specialData = getHeroTankPreviewParams() if self.__isHeroTank else None
        if specialData is not None and specialData.buyButtonLabel:
            buttonLabel = backport.text(specialData.buyButtonLabel)
        elif self.__isReferralWindow():
            buttonLabel = backport.text(
                R.strings.vehicle_preview.buyingPanel.buyBtn.label.obtain())
        elif self._marathonEvent is not None:
            itemPrices = ITEM_PRICE_EMPTY
            buttonData = self._marathonEvent.getPreviewBuyBtnData()
            buttonLabel = buttonData['label']
            enabled = buttonData['enabled']
            buttonIcon = buttonData['btnIcon']
            buttonIconAlign = buttonData['btnIconAlign']
            buyButtonTooltip = buttonData['btnTooltip']
            customOffer = buttonData['customOffer']
        elif self.__items and self.__couponInfo is None:
            buttonLabel = backport.text(R.strings.vehicle_preview.buyingPanel.
                                        buyBtn.label.buyItemPack())
        elif self.__offers and self.__currentOffer:
            buttonLabel = backport.text(
                R.strings.vehicle_preview.buyingPanel.buyBtn.label.rent())
            self.__title = self.__getCurrentOfferTitle()
        else:
            buttonLabel = backport.text(
                R.strings.vehicle_preview.buyingPanel.buyBtn.label.buy())
        isAction = self.__oldPrice.isDefined(
        ) and self.__oldPrice != self.__price or actionTooltip is not None or self.__couponInfo and self.__couponInfo.selected
        return _ButtonState(enabled=enabled,
                            itemPrice=getItemPricesVO(itemPrices),
                            label=buttonLabel,
                            icon=buttonIcon,
                            iconAlign=buttonIconAlign,
                            isAction=isAction,
                            actionTooltip=actionTooltip,
                            tooltip=buyButtonTooltip,
                            title=self.__title,
                            isMoneyEnough=True,
                            isUnlock=False,
                            isPrevItemsUnlock=True,
                            customOffer=customOffer,
                            isShowSpecial=False)

    def __getPackPrice(self):
        if self.__couponInfo and self.__couponInfo.selected:
            discount = self.__couponInfo.discount
            currency = self.__price.getCurrency()
            if currency == Currency.GOLD:
                discountPrice = self.__price - discount
                return discountPrice.toNonNegative()
        return self.__price

    def __getBtnDataUnlockedVehicle(self, vehicle):
        money = self._itemsCache.items.stats.money
        money = self._tradeIn.addTradeInPriceIfNeeded(vehicle, money)
        buyButtonTooltip = ''
        actionTooltip = getActionPriceData(vehicle)
        exchangeRate = self._itemsCache.items.shop.exchangeRate
        priceType, price = getPriceTypeAndValue(vehicle, money, exchangeRate)
        itemPrice = chooseItemPriceVO(priceType, price)
        currency = price.getCurrency(byWeight=True)
        walletAvailable = self.__walletAvailableForCurrency(currency)
        buttonLabel = self.__getUnlockedVehicleBtnLabel(priceType)
        buttonIcon = None
        buttonIconAlign = None
        isAction = False
        minRentPricePackage = vehicle.getRentPackage()
        if minRentPricePackage:
            isAction = minRentPricePackage['rentPrice'] != minRentPricePackage[
                'defaultRentPrice']
        elif not vehicle.isRestoreAvailable():
            isAction = vehicle.buyPrices.getSum().isActionPrice()
        mayObtain = self.__isHeroTank or walletAvailable and vehicle.mayObtainWithMoneyExchange(
            money, exchangeRate)
        isBuyingAvailable = not vehicle.isHidden or vehicle.isRentable or vehicle.isRestorePossible(
        )
        isMoneyEnough = True
        if not walletAvailable:
            buyButtonTooltip = _buildBuyButtonTooltip('walletUnavailable')
        elif not mayObtain and isBuyingAvailable:
            if currency == Currency.GOLD:
                mayObtain = True
            else:
                buyButtonTooltip = _buildBuyButtonTooltip('notEnoughCredits')
                isMoneyEnough = False
        if self._disableBuyButton or self.__isHeroTank and self._vehicleCD != self._heroTanks.getCurrentTankCD(
        ):
            mayObtain = False
            isMoneyEnough = False
        return _ButtonState(enabled=mayObtain,
                            itemPrice=itemPrice,
                            label=buttonLabel,
                            icon=buttonIcon,
                            iconAlign=buttonIconAlign,
                            isAction=isAction,
                            actionTooltip=actionTooltip,
                            tooltip=buyButtonTooltip,
                            title=self.__title,
                            isMoneyEnough=isMoneyEnough,
                            isUnlock=False,
                            isPrevItemsUnlock=True,
                            customOffer=None,
                            isShowSpecial=False)

    def __getBtnDataCollectibleVehicle(self, vehicle):
        isVehicleCollectorEnabled = self._lobbyContext.getServerSettings(
        ).isCollectorVehicleEnabled()
        isNationUnlocked = vehicle_collector_helper.isAvailableForPurchase(
            vehicle)
        resultVO = self.__getBtnDataUnlockedVehicle(vehicle)
        if isVehicleCollectorEnabled and isNationUnlocked:
            return resultVO
        if not isVehicleCollectorEnabled:
            tooltip = TOOLTIPS_CONSTANTS.VEHICLE_COLLECTOR_DISABLED
            isSpecialTooltip = True
        else:
            key = 'notUnlockedNation'
            tooltip = makeTooltip(
                header=TOOLTIPS.vehiclepreview_buybutton_all(key, 'header'),
                body=_getCollectibleWarningStr(
                    TOOLTIPS.vehiclepreview_buybutton_all(key, 'body'),
                    vehicle)) if resultVO.isMoneyEnough else resultVO.tooltip
            isSpecialTooltip = False
        resultVO = resultVO._replace(enabled=False,
                                     tooltip=tooltip,
                                     isShowSpecial=isSpecialTooltip)
        return resultVO

    def __getBtnDataLockedVehicle(self, vehicle):
        stats = self._itemsCache.items.stats
        tooltip = ''
        buttonIcon = None
        buttonIconAlign = None
        nodeCD = vehicle.intCD
        _, isXpEnough = g_techTreeDP.isVehicleAvailableToUnlock(
            nodeCD, self._vehicleLevel)
        unlocks = self._itemsCache.items.stats.unlocks
        isNext2Unlock, unlockProps = g_techTreeDP.isNext2Unlock(
            nodeCD,
            unlocked=set(unlocks),
            xps=stats.vehiclesXPs,
            freeXP=stats.freeXP,
            level=self._vehicleLevel)
        isAvailableToUnlock = isXpEnough and isNext2Unlock
        if not isAvailableToUnlock:
            if not isXpEnough:
                tooltip = _buildBuyButtonTooltip('notEnoughXp')
            elif any((bool(cd in unlocks)
                      for cd in g_techTreeDP.getTopLevel(nodeCD))):
                tooltip = _buildBuyButtonTooltip('parentModuleIsLocked')
            else:
                tooltip = _buildBuyButtonTooltip('parentVehicleIsLocked')
        specialData = getHeroTankPreviewParams() if self.__isHeroTank else None
        if specialData is not None and specialData.buyButtonLabel:
            buyLabel = backport.text(specialData.buyButtonLabel)
        else:
            buyLabel = backport.text(
                R.strings.vehicle_preview.buyingPanel.buyBtn.label.research())
        return _ButtonState(enabled=isAvailableToUnlock,
                            itemPrice=getItemUnlockPricesVO(unlockProps),
                            label=buyLabel,
                            icon=buttonIcon,
                            iconAlign=buttonIconAlign,
                            isAction=unlockProps.discount > 0,
                            actionTooltip=None,
                            tooltip=tooltip,
                            title=self.__title,
                            isMoneyEnough=isXpEnough,
                            isUnlock=True,
                            isPrevItemsUnlock=isNext2Unlock,
                            customOffer=None,
                            isShowSpecial=False)

    @staticmethod
    def __getBestOfferTooltipData(eventType=None):
        return VEHICLE_PREVIEW.BUYINGPANEL_OFFER_RENT_FRONTLINE_TOOLTIP_BEST_OFFER if eventType == 'frontline' else None

    def __getCurrentOfferTitle(self):
        if self.__offers and self.__currentOffer:
            if self.__currentOffer.eventType == 'frontline':
                firstRent = first(self.__currentOffer.rent)
                if len(self.__offers) > 1 or firstRent and firstRent.get(
                        'season') is not None:
                    return _ms(
                        backport.text(R.strings.vehicle_preview.buyingPanel.
                                      offer.rent.title.frontline.ordinal()))
                return _ms(
                    backport.text(R.strings.vehicle_preview.buyingPanel.offer.
                                  rent.title.frontline.single_cycle()),
                    cycles=self.__currentOffer.name)
        return self.__title

    def __getCurrentOfferDescription(self):
        return {
            'header':
            backport.text(R.strings.vehicle_preview.buyingPanel.offer.rent.
                          frontline.description.header()),
            'body':
            backport.text(R.strings.vehicle_preview.buyingPanel.offer.rent.
                          frontline.description.body.credits())
        } if self.__currentOffer and self.__currentOffer.eventType == 'frontline' else None

    def __startTimer(self, interval):
        self.__stopTimer()
        self.__timeCallbackID = BigWorld.callback(interval,
                                                  self.__onLeftTimeUpdated)

    def __stopTimer(self):
        if self.__timeCallbackID is not None:
            BigWorld.cancelCallback(self.__timeCallbackID)
            self.__timeCallbackID = None
        return

    def __setUsageLeftTime(self, leftTime):
        self.as_updateLeftTimeS(formattedTime='{} {}'.format(
            self.__timeLeftIcon,
            text_styles.tutorial(
                time_utils.getTillTimeString(leftTime,
                                             MENU.VEHICLEPREVIEW_TIMELEFT))),
                                hasHoursAndMinutes=True)

    def __setShortLeftTime(self, leftTime):
        self.as_updateLeftTimeS(formattedTime='{} {}'.format(
            self.__timeLeftIcon,
            text_styles.tutorial(
                time_utils.getTillTimeString(
                    leftTime, MENU.VEHICLEPREVIEW_TIMELEFTSHORT))),
                                hasHoursAndMinutes=True)

    def __setDateLeftTime(self):
        tm = time_utils.getTimeStructInLocal(self.__endTime)
        monthName = backport.text(
            R.strings.menu.dateTime.months.num(tm.tm_mon)())
        fmtValues = backport.text(R.strings.menu.dateTime.order(),
                                  day=tm.tm_mday,
                                  month=monthName,
                                  year=tm.tm_year)
        tooltip = makeTooltip(
            header=backport.text(R.strings.tooltips.vehiclePreview.shopPack.
                                 dateTimeTooltip.header()),
            body=backport.text(R.strings.tooltips.vehiclePreview.shopPack.
                               dateTimeTooltip.body(),
                               namePack=text_styles.neutral(self.__title),
                               date=fmtValues))
        self.as_setSetTitleTooltipS(tooltip)
        self.as_updateLeftTimeS(formattedTime='')

    def __timeOver(self):
        self.__endTime = None
        self._disableBuyButton = True
        formattedTime = '{} {}'.format(
            icons.makeImageTag(RES_ICONS.MAPS_ICONS_LIBRARY_ALERTICON2,
                               vSpace=-2),
            text_styles.alert(MENU.VEHICLEPREVIEW_ENDTIME))
        self.as_updateLeftTimeS(formattedTime=formattedTime)
        self.__updateBtnState()
        return

    def __onLeftTimeUpdated(self):
        leftTime = self.__endTime - time_utils.getServerUTCTime()
        self.__timeCallbackID = None
        if leftTime < 0:
            self.__timeOver()
        elif leftTime > time_utils.ONE_DAY:
            self.__setDateLeftTime()
            self.__startTimer(leftTime - time_utils.ONE_DAY)
        else:
            gmTime = time.gmtime(leftTime)
            if gmTime.tm_min == 0:
                self.__setShortLeftTime(leftTime)
            else:
                self.__setUsageLeftTime(leftTime)
            self.__startTimer(gmTime.tm_sec + 1)
        return

    @process
    def __purchasePackage(self):
        if self.__items is not None:
            product = self.__title if self.__couponInfo is None else g_currentPreviewVehicle.item.shortUserName
            price = self.__getPackPrice()
            if not mayObtainForMoney(price) and mayObtainWithMoneyExchange(
                    price):
                isOk, _ = yield DialogsInterface.showDialog(
                    ExchangeCreditsWebProductMeta(name=product,
                                                  count=1,
                                                  price=price.get(
                                                      Currency.CREDITS)))
                if isOk:
                    self.__purchasePackage()
                    return
                return
            requestConfirmed = yield self.__buyRequestConfirmation(
                self.__getConfirmationDialogKey())
            if requestConfirmed:
                if self.__isReferralWindow():
                    inventoryVehicle = self._itemsCache.items.getItemByCD(
                        g_currentPreviewVehicle.item.intCD)
                    showGetVehiclePage(inventoryVehicle, self.__buyParams)
                    return
                if mayObtainForMoney(price):
                    showBuyVehicleOverlay(self.__buyParams)
                elif price.get(Currency.GOLD,
                               0) > self._itemsCache.items.stats.gold:
                    showBuyGoldForBundle(price.get(Currency.GOLD, 0),
                                         self.__buyParams)
        return

    def __purchaseOffer(self):
        rent = self.__currentOffer.rent
        cycles = [r['cycle'] for r in rent if r.get('cycle')]
        seasons = [r['season'] for r in rent if r.get('season')]
        showVehicleRentDialog(
            g_currentPreviewVehicle.item.intCD,
            RentType.SEASON_CYCLE_RENT if cycles else RentType.SEASON_RENT,
            cycles if cycles else seasons, GameSeasonType.EPIC
            if self.__currentOffer.eventType == 'frontline' else None,
            self.__currentOffer.buyPrice, self.__currentOffer.buyParams)
        return

    def __purchaseSingleVehicle(self, vehicle):
        event_dispatcher.showVehicleBuyDialog(
            vehicle,
            returnAlias=self.__backAlias,
            returnCallback=self.__backCallback)

    @process
    def __purchaseHeroTank(self):
        if self._heroTanks.isAdventHero():
            self.__calendarController.showWindow(
                invokedFrom=CalendarInvokeOrigin.HANGAR)
            return
        shopUrl = self._heroTanks.getCurrentShopUrl()
        if shopUrl:
            event_dispatcher.showShop(shopUrl)
        else:
            url = yield self.__urlMacros.parse(
                self._heroTanks.getCurrentRelatedURL())
            self.fireEvent(
                events.OpenLinkEvent(events.OpenLinkEvent.SPECIFIED, url=url))

    @async
    @process
    def __hasExternalLink(self, callback=None):
        url = ''
        if self._marathonEvent:
            url = yield self._marathonEvent.getMarathonVehicleUrl()
        elif self.__isHeroTank:
            if not self._heroTanks.isAdventHero(
            ) and not self._heroTanks.getCurrentShopUrl():
                url = self._heroTanks.getCurrentRelatedURL()
        callback(self.__linksCtrl.externalAllowed(url) if url else False)

    @process
    def __purchaseMarathonPackage(self):
        if self._marathonEvent.hasIgbLink():
            url = yield self._marathonEvent.getMarathonVehicleUrlIgb()
            event_dispatcher.showShop(url)
        else:
            url = yield self._marathonEvent.getMarathonVehicleUrl()
            self.fireEvent(
                events.OpenLinkEvent(events.OpenLinkEvent.SPECIFIED, url=url))

    def __research(self):
        if self._actionType == factory.UNLOCK_ITEM:
            unlockProps = g_techTreeDP.getUnlockProps(self._vehicleCD,
                                                      self._vehicleLevel)
            factory.doAction(factory.UNLOCK_ITEM,
                             self._vehicleCD,
                             unlockProps,
                             skipConfirm=self._skipConfirm)
        else:
            factory.doAction(factory.BUY_VEHICLE,
                             self._vehicleCD,
                             False,
                             None,
                             VIEW_ALIAS.VEHICLE_PREVIEW,
                             self.__backAlias,
                             self.__backCallback,
                             skipConfirm=self._skipConfirm)
        return

    def __walletAvailableForCurrency(self, currency):
        return self._itemsCache.items.stats.currencyStatuses.get(
            currency) == WalletController.STATUS.AVAILABLE

    def __getUnlockedVehicleBtnLabel(self, priceType):
        specialData = getHeroTankPreviewParams() if self.__isHeroTank else None
        if specialData is not None and specialData.buyButtonLabel:
            buttonLabel = backport.text(specialData.buyButtonLabel)
        elif priceType == ActualPrice.RESTORE_PRICE:
            buttonLabel = backport.text(
                R.strings.vehicle_preview.buyingPanel.buyBtn.label.restore())
        elif priceType == ActualPrice.RENT_PRICE:
            buttonLabel = backport.text(
                R.strings.vehicle_preview.buyingPanel.buyBtn.label.rent())
        elif self.__isHeroTank and self._heroTanks.isAdventHero():
            buttonLabel = backport.text(R.strings.vehicle_preview.buyingPanel.
                                        buyBtn.label.showAdventCalendar())
        else:
            buttonLabel = backport.text(
                R.strings.vehicle_preview.buyingPanel.buyBtn.label.buy())
        return buttonLabel

    @staticmethod
    def __updateEnabledState(collection, enabled):
        if collection is None:
            return
        else:
            for item in collection:
                if 'isEnabled' in item:
                    item['isEnabled'] = enabled

            return
Пример #8
0
class InternalLinksHandler(IInternalLinksController):
    browserCtrl = dependency.descriptor(IBrowserController)

    def __init__(self):
        super(InternalLinksHandler, self).__init__()
        self.__urlMacros = None
        self._browserID = None
        return

    def init(self):
        self.__urlMacros = URLMacros()
        addListener = g_eventBus.addListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if not handler:
                LOG_ERROR('Handler is not found', eventType, handlerName)
                continue
            if not callable(handler):
                LOG_ERROR('Handler is invalid', eventType, handlerName,
                          handler)
                continue
            addListener(eventType, handler)

        return

    def fini(self):
        if self.__urlMacros is not None:
            self.__urlMacros.clear()
            self.__urlMacros = None
        self._browserID = None
        removeListener = g_eventBus.removeListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if handler:
                removeListener(eventType, handler)

        super(InternalLinksHandler, self).fini()
        return

    @async
    @process
    def getURL(self, name, callback):
        urlSettings = GUI_SETTINGS.lookup(name)
        if urlSettings:
            url = yield self.__urlMacros.parse(str(urlSettings))
        else:
            url = yield lambda callback: callback('')
        callback(url)

    @process
    def __openInternalBrowse(self,
                             urlName,
                             title='',
                             browserSize=None,
                             showActionBtn=True,
                             showCloseBtn=False):
        parsedUrl = yield self.getURL(urlName)
        if parsedUrl:
            self._browserID = yield self.browserCtrl.load(
                parsedUrl,
                browserID=self._browserID,
                title=title,
                browserSize=browserSize,
                showActionBtn=showActionBtn,
                showCloseBtn=showCloseBtn)