NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

uilog.py (46132B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\uilog.py
      2 import os
      3 import sys
      4 import blue
      5 import eveicon
      6 import evetypes
      7 import signals
      8 import uthread
      9 from actionLog.client.formatters import FormatBountyMessage, FormatModifiedBountyMessage, FormatMiningMessage, FormatMiningRewardsMessage, FormatOreDepositedMessage, FormatPirateKilledMessage, FormatMiningCritMessage, FormatMiningWasteMessage
     10 from carbon.common.script.sys.service import Service
     11 from carbon.common.script.sys.serviceConst import ROLE_SERVICE
     12 from carbon.common.script.util.commonutils import StripTags
     13 from carbon.common.script.util.format import FmtDate
     14 from carbonui import uiconst
     15 from carbonui.control.contextMenu.menuData import MenuData
     16 from carbonui.control.contextMenu.menuEntryData import MenuEntryDataCheckbox, MenuEntryDataRadioButton
     17 from carbonui.control.window import Window
     18 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     19 from clientsettings.setting import UserSettingBool, UserSettingEnum
     20 from carbonui.uicore import uicore
     21 from eve.client.script.ui import eveColor
     22 from eve.client.script.ui.control.entries.generic import Generic
     23 from eve.client.script.ui.control.entries.util import GetFromClass
     24 from carbonui.button.menu import MenuButtonIcon
     25 from eve.client.script.ui.menuUtil import DESTRUCTIVEGROUP
     26 from eve.client.script.ui.util import uix
     27 from eve.common.lib import appConst as const
     28 from carbon.common.script.util import timerstuff
     29 from carbon.common.script.util.logUtil import LogError, LogException, LogInfo, LogWarn
     30 from eve.client.script.ui.control import eveScroll
     31 import localization
     32 import telemetry
     33 import trinity
     34 import itertoolsext
     35 import log
     36 from eve.client.script.ui.control.message import CombatMessage
     37 from eve.common.script.sys import idCheckers
     38 from eveprefs import prefs
     39 from localization import GetByLabel
     40 from menu import MenuLabel
     41 from mining.client.mining_const import MiningQuantityColor
     42 MAX_MSGS = 256
     43 
     44 class MessageType():
     45     INFO = 'info'
     46     WARNING = 'warning'
     47     ERROR = 'error'
     48     COMBAT = 'combat'
     49     NOTIFY = 'notify'
     50     QUESTION = 'question'
     51     HINT = 'hint'
     52     SLASH = 'slash'
     53     MINING = 'mining'
     54     BOUNTY = 'bounty'
     55 
     56 
     57 COLORS_BY_TYPE = {MessageType.ERROR: '0xffeb3700',
     58  MessageType.WARNING: '0xffffd800',
     59  MessageType.SLASH: '0xffff5500',
     60  MessageType.COMBAT: '0xffff0000',
     61  MessageType.BOUNTY: '0xff00aa00',
     62  MessageType.MINING: MiningQuantityColor.YIELD.hex_argb}
     63 ENERGY_WARFARE_MESSAGES = ['OnEnergyNeutDefender',
     64  'OnEnergyNeutAttacker',
     65  'OnEnergyNosDefender',
     66  'OnEnergyNosAttacker']
     67 INCOMING_REMOTE_ASSISTANCE_MESSAGES = ['OnRemoteShieldBoostTarget',
     68  'OnRemoteArmorRepairTarget',
     69  'OnRemoteHullRepairTarget',
     70  'OnRemoteCapacitorTransmitterTarget']
     71 OUTGOING_REMOTE_ASSISTANCE_MESSAGES = ['OnRemoteShieldBoostSource',
     72  'OnRemoteArmorRepairSource',
     73  'OnRemoteHullRepairSource',
     74  'OnRemoteCapacitorTransmitterSource']
     75 REMOTE_ASSISTANCE_MESSAGES = INCOMING_REMOTE_ASSISTANCE_MESSAGES + OUTGOING_REMOTE_ASSISTANCE_MESSAGES
     76 DAMAGE_TYPE_ICONS = {const.attributeKineticDamage: 'res:/UI/Texture/classes/DamageTypes/Kinetic.png',
     77  const.attributeThermalDamage: 'res:/UI/Texture/classes/DamageTypes/Thermal.png',
     78  const.attributeExplosiveDamage: 'res:/UI/Texture/classes/DamageTypes/Explosive.png',
     79  const.attributeEmDamage: 'res:/UI/Texture/classes/DamageTypes/Electromagnetic.png'}
     80 
     81 class Logger(Service):
     82     __exportedcalls__ = {'AddMessage': [],
     83      'AddCombatMessage': [],
     84      'AddText': [],
     85      'AddBountyMessage': [],
     86      'AddMiningMessage': [],
     87      'GetLog': [ROLE_SERVICE]}
     88     __guid__ = 'svc.logger'
     89     __notifyevents__ = ['ProcessSessionChange']
     90     __servicename__ = 'logger'
     91     __displayname__ = 'Logger Client Service'
     92     __dependencies__ = []
     93     __update_on_reload__ = 0
     94 
     95     def Run(self, memStream = None):
     96         self.LogInfo('Starting Logger')
     97         self.broken = 0
     98         self.Reset()
     99         self.newfileAttempts = 0
    100         self.addmsg = []
    101         self.persistInterval = 1000
    102         self.combatMessagePeriod = 10000 * prefs.GetValue('combatMessagePeriod', 200)
    103         self.lastCombatMessage = 0
    104         self.inMovingMode = False
    105         self.frameCounterAndWindow = (None, None)
    106         self.cachedHitQualityText = {}
    107         self.notificationFontSize = inflight_message_font_size_setting.get()
    108         uthread.new(self._PersistWorker)
    109 
    110     def Stop(self, memStream = None):
    111         self.DumpToLog()
    112         self.messages = []
    113         self.msglog = []
    114         self.addmsg = []
    115 
    116     def ProcessSessionChange(self, isremote, session, change):
    117         if 'charid' in change:
    118             self.Reset()
    119         if not session.charid:
    120             self.Stop()
    121 
    122     def GetTimePartsForLog(self, timestamp = None):
    123         if timestamp is None:
    124             timestamp = blue.os.GetWallclockTime()
    125         timestamp += localization.GetTimeDeltaSeconds() * const.SEC
    126         return blue.os.GetTimeParts(timestamp)
    127 
    128     def GetLog(self, maxsize = const.petitionMaxCombatLogSize, *args):
    129         LogInfo('Getting logfiles')
    130         self.DumpToLog()
    131         year, month, weekday, day, hour, minute, second, msec = self.GetTimePartsForLog()
    132         now = '%d%.2d%.2d' % (year, month, day)
    133         year, month, weekday, day, hour, minute, second, msec = self.GetTimePartsForLog(blue.os.GetWallclockTime() - const.DAY)
    134         yesterday = '%d%.2d%.2d' % (year, month, day)
    135         root = blue.sysinfo.GetUserDocumentsDirectory() + '/EVE/logs/Gamelogs'
    136         logs = []
    137         for each in os.listdir(root):
    138             filename = os.path.join(root, each)
    139             fooname = filename[:-11]
    140             if fooname.endswith(now) or fooname.endswith(yesterday):
    141                 logs.append((each, filename))
    142 
    143         logs.sort(reverse=True)
    144         ret = []
    145         bytesread = 0
    146         for k, filename in logs:
    147             f = None
    148             try:
    149                 f = file(filename)
    150                 tmp = f.read()
    151                 f.close()
    152                 line = '\n\n%s:\n%s' % (filename.encode('utf8', 'replace'), tmp)
    153                 bytesread += len(line)
    154                 ret.append(line)
    155                 if bytesread > maxsize:
    156                     break
    157             except:
    158                 LogException()
    159                 sys.exc_clear()
    160                 if f and not f.closed:
    161                     f.close()
    162 
    163         LogInfo('Getting logfiles done')
    164         ret.reverse()
    165         return ''.join(ret)[-maxsize:]
    166 
    167     def Reset(self):
    168         self.resettime = blue.os.GetWallclockTime()
    169         self.messages = []
    170         self.msglog = ['-' * 60 + '\n', '  %s\n' % GetByLabel('UI/Accessories/Log/GameLog').encode('utf8', 'replace')]
    171         if session.charid:
    172             self.msglog.append(('  %s: %s\n' % (GetByLabel('UI/Accessories/Log/Listener'), cfg.eveowners.Get(session.charid).name)).encode('utf8', 'replace'))
    173         self.msglog += [('  %s: %s\n' % (GetByLabel('UI/Accessories/Log/SessionStarted'), FmtDate(self.resettime))).encode('utf8', 'replace'),
    174          '',
    175          '-' * 60 + '\n',
    176          '']
    177         self.DumpToLog()
    178 
    179     @telemetry.ZONE_METHOD
    180     def GetWnd(self):
    181         return LoggerWindow.GetIfOpen()
    182 
    183     @telemetry.ZONE_METHOD
    184     def GetWndWithFrameCounter(self, *args):
    185         frameCounter = trinity.GetCurrentFrameCounter()
    186         if frameCounter == self.frameCounterAndWindow[0]:
    187             return self.frameCounterAndWindow[1]
    188         wnd = self.GetWnd()
    189         self.frameCounterAndWindow = (frameCounter, wnd)
    190         return wnd
    191 
    192     def GetMessages(self):
    193         self.addmsg = []
    194         return self.messages
    195 
    196     def ClearAllMessages(self):
    197         self.Reset()
    198 
    199     def GetPendingMessages(self):
    200         retval = self.addmsg
    201         self.addmsg = []
    202         return retval
    203 
    204     def AddMessage(self, msg, msgtype = None):
    205         if msg.type == MessageType.ERROR and not settings.user.ui.Get('logerrors', 0):
    206             return
    207         self.AddText(msg.text, msgtype or msg.type or MessageType.NOTIFY, msg)
    208 
    209     def GetHitQualityMessage(self, hitQuality):
    210         try:
    211             hitQuality = int(hitQuality)
    212             label = {1: 'UI/Inflight/HitQuality1',
    213              2: 'UI/Inflight/HitQuality2',
    214              3: 'UI/Inflight/HitQuality3',
    215              4: 'UI/Inflight/HitQuality4',
    216              5: 'UI/Inflight/HitQuality5',
    217              6: 'UI/Inflight/HitQuality6'}[hitQuality]
    218         except (KeyError, ValueError):
    219             return 'No hit quality message for level %s' % hitQuality
    220 
    221         return GetByLabel(label)
    222 
    223     def AddMiningMessage(self, oreTypeID, quantity_mined, has_rewards, quantity_wasted, quantity_crit_bonus):
    224         if not show_inflight_mining_messages_setting.is_enabled():
    225             return
    226         if quantity_mined > 0:
    227             if has_rewards:
    228                 msg = FormatMiningRewardsMessage(normalFontSize=self.notificationFontSize, oreTypeID=oreTypeID, amount=quantity_mined)
    229             else:
    230                 msg = FormatMiningMessage(normalFontSize=self.notificationFontSize, oreTypeID=oreTypeID, amount=quantity_mined)
    231             self.SayMessage(msg, MessageType.MINING)
    232         if quantity_wasted:
    233             msg = FormatMiningWasteMessage(normalFontSize=self.notificationFontSize, oreTypeID=oreTypeID, amountWasted=quantity_wasted)
    234             self.SayMessage(msg, MessageType.MINING)
    235         if quantity_crit_bonus:
    236             msg = FormatMiningCritMessage(normalFontSize=self.notificationFontSize, oreTypeID=oreTypeID, amount=quantity_crit_bonus)
    237             self.SayMessage(msg, MessageType.MINING, icons=[eveicon.crit_success], icon_color=MiningQuantityColor.CRIT_BONUS)
    238 
    239     def AddOreDepositedMessage(self, oreTypeID, amount, charID):
    240         if amount > 0:
    241             if show_inflight_mining_messages_setting.get():
    242                 msg = FormatOreDepositedMessage(charID=charID, normalFontSize=self.notificationFontSize, oreTypeID=oreTypeID, amount=amount)
    243                 self.SayMessage(msg, MessageType.MINING)
    244 
    245     def AddRwPirateKilledByCharacterMessage(self, killerID, killedShipItem):
    246         if show_inflight_damage_messages_setting.get():
    247             killerName = cfg.eveowners.Get(killerID).name
    248             killedName = sm.GetService('bracket').GetDisplayNameForBracket(killedShipItem)
    249             msg = FormatPirateKilledMessage(killerName=killerName, normalFontSize=self.notificationFontSize, killedName=killedName)
    250             self.SayMessage(msg, MessageType.COMBAT)
    251 
    252     def AddRwPirateKilledByNpcMessage(self, killerShipItem, killedShipItem):
    253         if show_inflight_damage_messages_setting.get():
    254             killerName = sm.GetService('bracket').GetDisplayNameForBracket(killerShipItem)
    255             killedName = sm.GetService('bracket').GetDisplayNameForBracket(killedShipItem)
    256             msg = FormatPirateKilledMessage(killerName=killerName, normalFontSize=self.notificationFontSize, killedName=killedName)
    257             self.SayMessage(msg, MessageType.COMBAT)
    258 
    259     def AddBountyMessage(self, bountyPayout, payoutTime, enemyTypeID, isModified):
    260         if bountyPayout > 0:
    261             if show_inflight_bounty_messages_setting.get():
    262                 blue.synchro.Sleep(1000)
    263                 if not isModified:
    264                     msg = FormatBountyMessage(normalFontSize=self.notificationFontSize, bounty=bountyPayout)
    265                     self.SayMessage(msg, MessageType.BOUNTY)
    266                 else:
    267                     msg = FormatModifiedBountyMessage(normalFontSize=self.notificationFontSize, bounty=bountyPayout)
    268                     self.SayMessage(msg, MessageType.BOUNTY)
    269 
    270     def _ReadIconsFromMessageDict(self, damageMessagesArgs):
    271         icons = []
    272         if damageMessagesArgs.get('hitQuality', 0) == 0:
    273             return []
    274         damageAttributes = damageMessagesArgs.get('damageAttributes', {})
    275         for attr in damageAttributes:
    276             if attr in DAMAGE_TYPE_ICONS and damageAttributes[attr] > 0:
    277                 icons.append(DAMAGE_TYPE_ICONS[attr])
    278 
    279         return icons
    280 
    281     @telemetry.ZONE_METHOD
    282     def AddCombatMessageFromDict(self, damageMessagesArgs):
    283         hitQuality = damageMessagesArgs['hitQuality']
    284         isBanked = damageMessagesArgs['isBanked']
    285         if hitQuality == 0:
    286             msgKey = 'AttackMiss'
    287         elif hitQuality > 0 and hitQuality <= 6:
    288             msgKey = 'AttackHits'
    289             try:
    290                 hitQualityText = self.cachedHitQualityText[hitQuality]
    291             except KeyError:
    292                 hitQualityText = self.GetHitQualityMessage(hitQuality)
    293                 self.cachedHitQualityText[hitQuality] = hitQualityText
    294 
    295             damageMessagesArgs['hitQualityText'] = hitQualityText
    296         else:
    297             msgKey = 'AttackHits'
    298             hitQualityText = ''
    299             damageMessagesArgs['hitQualityText'] = hitQualityText
    300         attackType = damageMessagesArgs.get('attackType', 'me')
    301         if attackType == 'otherPlayer':
    302             msgKey += 'RD'
    303         elif attackType == 'otherPlayerWeapons':
    304             msgKey += 'R'
    305         elif attackType == 'me':
    306             if isBanked:
    307                 msgKey += 'Banked'
    308         else:
    309             LogError('attackType not valid! attackType = ' + attackType)
    310             return
    311         for argName in ('source', 'target', 'owner'):
    312             if argName not in damageMessagesArgs:
    313                 continue
    314             if argName == 'owner':
    315                 ownerTypeID, ownerID = damageMessagesArgs[argName]
    316                 if ownerTypeID != const.UE_OWNERID:
    317                     continue
    318                 objectID = damageMessagesArgs.get('attackerID', None)
    319                 if objectID is None:
    320                     continue
    321             else:
    322                 objectID = damageMessagesArgs[argName]
    323             bracket = sm.GetService('bracket').GetBracket(objectID)
    324             if bracket:
    325                 slimItem = bracket.slimItem
    326             else:
    327                 ballpark = sm.GetService('michelle').GetBallpark()
    328                 if ballpark is None:
    329                     self.LogWarn('OnDamageMessage: No ballpark, not showing damage message.')
    330                     return
    331                 slimItem = ballpark.GetInvItem(objectID)
    332             if slimItem:
    333                 if slimItem.corpID and not idCheckers.IsNPC(slimItem.corpID):
    334                     damageMessagesArgs['typeName'] = evetypes.GetName(slimItem.typeID)
    335                     tickerText = cfg.corptickernames.Get(slimItem.corpID).tickerName
    336                     damageMessagesArgs['tickerText'] = tickerText
    337             objectName = self._GetObjectName(slimItem, argName, damageMessagesArgs)
    338             if objectName is None:
    339                 if argName == 'owner':
    340                     continue
    341                 else:
    342                     return
    343             damageMessagesArgs[argName] = objectName
    344             damageMessagesArgs['%s_ID' % argName] = objectID
    345 
    346         self.AddCombatMessage(msgKey, damageMessagesArgs)
    347 
    348     def _GetObjectName(self, slimItem, argName, damageMessagesArgs):
    349         if slimItem:
    350             return uix.GetSlimItemName(slimItem) or 'Some object'
    351         if argName == 'owner':
    352             return
    353         if argName == 'source' and 'sourceCharID' in damageMessagesArgs:
    354             charID = damageMessagesArgs['sourceCharID']
    355             return cfg.eveowners.Get(charID).name
    356         if argName == 'target' and 'targetOwnerID' in damageMessagesArgs:
    357             targetOwnerID = damageMessagesArgs['targetOwnerID']
    358             return cfg.eveowners.Get(targetOwnerID).name
    359         self.LogError('Failed to display message', damageMessagesArgs)
    360 
    361     @telemetry.ZONE_METHOD
    362     def AddCombatMessage(self, msgKey, msgTextArgs):
    363         if msgKey in ENERGY_WARFARE_MESSAGES and not show_inflight_energy_warfare_messages_setting.get():
    364             return
    365         if msgKey in REMOTE_ASSISTANCE_MESSAGES:
    366             if not show_inflight_remote_assistance_messages_setting.get():
    367                 return
    368             if msgKey in INCOMING_REMOTE_ASSISTANCE_MESSAGES and not show_inflight_remote_assistance_incoming_messages_setting.get():
    369                 return
    370             if msgKey in OUTGOING_REMOTE_ASSISTANCE_MESSAGES and not show_inflight_remote_assistance_outgoing_messages_setting.get():
    371                 return
    372         icons = self._ReadIconsFromMessageDict(msgTextArgs)
    373         smallFontsize = max(10, self.notificationFontSize - 2)
    374         msgTextArgs.update({'strongColor': '<color=0xff00ffff>',
    375          'faintColor': '<color=0x77ffffff>',
    376          'fontMarkUpStart': '<font size=%s>' % smallFontsize,
    377          'fontMarkUpEnd': '</font>'})
    378         showTicker = show_inflight_message_ticker_setting.get()
    379         showShip = show_inflight_message_ship_setting.get()
    380         showWeapon = show_inflight_message_weapon_setting.get()
    381         showQuality = show_inflight_message_quality_setting.get()
    382         doShowInspaceNotifications = show_inflight_messages_setting.get()
    383         notificationsExtraNameText = ''
    384         logExtraNameText = ''
    385         if msgTextArgs.get('tickerText', ''):
    386             extra = '[%s]' % msgTextArgs.get('tickerText', '')
    387             logExtraNameText += extra
    388             if showTicker:
    389                 notificationsExtraNameText += extra
    390         if msgTextArgs.get('typeName', ''):
    391             extra = '(%s)' % msgTextArgs.get('typeName', '')
    392             logExtraNameText += extra
    393             if showShip:
    394                 notificationsExtraNameText += extra
    395         deflectedDmg = msgTextArgs.get('deflectedDmg', None)
    396         if deflectedDmg:
    397             damage = msgTextArgs.get('damage', 0)
    398             msgTextArgs['damage'] = damage + deflectedDmg
    399         msgTextArgs['extraNameText'] = logExtraNameText
    400         msgFullText = cfg.GetMessageTypeAndText(msgKey, msgTextArgs)
    401         if msgFullText.type == MessageType.ERROR and not settings.user.ui.Get('logerrors', 0):
    402             return
    403         if doShowInspaceNotifications:
    404             if logExtraNameText == notificationsExtraNameText:
    405                 msgLimited = msgFullText
    406             else:
    407                 msgTextArgs['extraNameText'] = notificationsExtraNameText
    408                 msgLimited = cfg.GetMessageTypeAndText(msgKey, msgTextArgs)
    409         logPostText = ''
    410         notificationsPostText = ''
    411         if 'weapon' in msgTextArgs:
    412             extra = ' - %s' % evetypes.GetName(msgTextArgs['weapon'])
    413             logPostText += extra
    414             if showWeapon:
    415                 notificationsPostText += extra
    416         if msgTextArgs.get('hitQualityText', ''):
    417             extra = ' - %s' % msgTextArgs['hitQualityText']
    418             logPostText += extra
    419             if showQuality:
    420                 notificationsPostText += extra
    421         if deflectedDmg:
    422             notificationsPostText += ' (%s)' % GetByLabel('UI/Accessories/Log/DeflectedDamage', damageDeflected=deflectedDmg)
    423             logPostText += notificationsPostText
    424         damage = msgTextArgs.get('damage', None)
    425         hitQuality = msgTextArgs.get('hitQuality', None)
    426         damageHtml = None
    427         if damage is not None and hitQuality > 0:
    428             rounded_damage = int(round(damage))
    429             red = '0xffcc0000'
    430             blue = '0xff00ffff'
    431             color = red if msgTextArgs.get('attackType', 'me') != 'me' else blue
    432             damageHtml = '<color={color}><b>{damage}</b>'.format(color=color, damage=rounded_damage)
    433         fullText = msgFullText.text + logPostText
    434         if damageHtml is not None:
    435             fullText = ' '.join((damageHtml, fullText))
    436         self.AddText(fullText, MessageType.COMBAT)
    437         if doShowInspaceNotifications:
    438             limitedText = msgLimited.text + notificationsPostText
    439             hitQuality = msgTextArgs.get('hitQuality', None)
    440             attackerID = msgTextArgs.get('attackerID', None)
    441             self.Say(limitedText, hitQuality, attackerID, icons, damageHtml)
    442 
    443     @telemetry.ZONE_METHOD
    444     def AddText(self, msgtext, msgtype = None, msg = None):
    445         timestamp = blue.os.GetWallclockTime()
    446         if not self.broken:
    447             formattedTime = self.GetFormattedTime(timestamp)
    448             formattedMessage = '[%20s ] (%s) %s\n' % (formattedTime, msgtype, msgtext)
    449             encodedMessage = formattedMessage.encode('utf8', 'replace')
    450             self.msglog.append(encodedMessage)
    451         if not self.ShowMessage(msgtype):
    452             return
    453         msgData = (msgtext, msgtype, timestamp)
    454         self.messages.append(msgData)
    455         maxlog = log_message_count_setting.get()
    456         if len(self.messages) > maxlog * 2:
    457             self.messages = self.messages[-maxlog:]
    458         wnd = self.GetWndWithFrameCounter()
    459         if wnd and not wnd.destroyed:
    460             self.addmsg.append(msgData)
    461 
    462     @telemetry.ZONE_METHOD
    463     def GetFormattedTime(self, timestamp, *args):
    464         year, month, wd, day, hour, min, sec, ms = self.GetTimePartsForLog(timestamp)
    465         return '%d.%.2d.%.2d %.2d:%.2d:%.2d' % (year,
    466          month,
    467          day,
    468          hour,
    469          min,
    470          sec)
    471 
    472     def SayMessage(self, text, msgType, icons = None, icon_color = None):
    473         message = self._MakeOrGetMessageUI()
    474         message.AddActionMessage(text, icons=icons, icon_color=icon_color)
    475         self.AddText(text, msgType)
    476 
    477     def Say(self, msgtext, hitQuality, attackerID, *args):
    478         message = self._MakeOrGetMessageUI()
    479         message.AddMessage(msgtext, hitQuality, attackerID, *args)
    480 
    481     def CloseMessageUI(self):
    482         message = getattr(uicore.layer.target, 'message', None)
    483         if message and not message.destroyed:
    484             message.Close()
    485 
    486     def _MakeOrGetMessageUI(self):
    487         message = getattr(uicore.layer.target, 'message', None)
    488         if not message or message.destroyed:
    489             message = CombatMessage(parent=uicore.layer.target, name='combatMessage', state=uiconst.UI_PICKCHILDREN)
    490             uicore.layer.target.message = message
    491         return message
    492 
    493     def ShowMessage(self, msgtype):
    494         setting = MESSAGE_FILTER_SETTING_BY_MESSAGE_TYPE.get(msgtype, None)
    495         if setting is not None:
    496             return setting.get()
    497         else:
    498             return True
    499 
    500     def DumpToLog(self):
    501         uthread.new(self.DumpToLogThread)
    502 
    503     @telemetry.ZONE_METHOD
    504     def DumpToLogThread(self):
    505         if self.broken or not self.msglog:
    506             return
    507         logfile = None
    508         try:
    509             filename = self.GetLogfileName()
    510             try:
    511                 logfile = file(filename, 'a')
    512             except:
    513                 if self.newfileAttempts < 3:
    514                     LogWarn('Failed to open the logfile %s, creating new logfile...' % filename)
    515                     filename = self.GetLogfileName(reset=True)
    516                     LogWarn('new logfile name is: ', filename)
    517                     self.newfileAttempts += 1
    518                     logfile = file(filename, 'a')
    519                 else:
    520                     self.broken = 1
    521                     LogException(toAlertSvc=0)
    522                 sys.exc_clear()
    523 
    524             if logfile:
    525                 try:
    526                     logfile.writelines(self.msglog)
    527                     logfile.close()
    528                 except IOError:
    529                     log.LogTraceback()
    530                     sys.exc_clear()
    531 
    532                 self.msglog = []
    533         except:
    534             LogException(toAlertSvc=0)
    535             sys.exc_clear()
    536 
    537         if logfile and not logfile.closed:
    538             logfile.close()
    539 
    540     def CopyLog(self):
    541         self.DumpToLog()
    542         logfile = None
    543         try:
    544             filename = self.GetLogfileName()
    545             logfile = file(filename)
    546             ret = logfile.read()
    547             logfile.close()
    548             blue.pyos.SetClipboardData(ret)
    549         except:
    550             LogException()
    551             sys.exc_clear()
    552 
    553         if logfile and not logfile.closed:
    554             logfile.close()
    555 
    556     def GetLogfileName(self, reset = False):
    557         if reset:
    558             self.Reset()
    559         year, month, weekday, day, hour, minute, second, msec = self.GetTimePartsForLog(self.resettime)
    560         postFix = '_%s' % session.charid if session.charid else ''
    561         filename = '%d%.2d%.2d_%.2d%.2d%.2d%s' % (year,
    562          month,
    563          day,
    564          hour,
    565          minute,
    566          second,
    567          postFix)
    568         filename = blue.sysinfo.GetUserDocumentsDirectory() + '/EVE/logs/Gamelogs/%s.txt' % filename
    569         return filename
    570 
    571     def _PersistWorker(self):
    572         while self.IsRunning():
    573             blue.pyos.synchro.SleepWallclock(self.persistInterval)
    574             self.DumpToLog()
    575 
    576     def MoveNotifications(self, enterMode, *args):
    577         self.SetDragModeState(state=enterMode)
    578         message = getattr(uicore.layer.target, 'message', None)
    579         if not message or message.destroyed:
    580             message = CombatMessage(parent=uicore.layer.target, name='combatMessage', state=uiconst.UI_PICKCHILDREN, width=400, height=60)
    581             uicore.layer.target.message = message
    582             message.SetSizeAndPosition()
    583         msg = None
    584         for each in uicore.layer.abovemain.children[:]:
    585             if each.name == 'message':
    586                 msg = each
    587                 break
    588 
    589         if msg is None:
    590             from carbonui.control.message import QuickMessage
    591             msg = QuickMessage(parent=uicore.layer.abovemain, name='message', height=40, width=300, state=uiconst.UI_HIDDEN)
    592         if enterMode:
    593             msg.EnterDragMode()
    594             message.EnterDragMode()
    595         else:
    596             msg.ExitDragMode()
    597             message.ExitDragMode()
    598 
    599     def IsInDragMode(self, *args):
    600         return self.inMovingMode
    601 
    602     def SetDragModeState(self, state, *args):
    603         self.inMovingMode = state
    604 
    605 
    606 log_message_count_setting = UserSettingEnum(settings_key='logmessageamount', default_value=100, options=[100, 1000])
    607 show_info_messages_setting = UserSettingBool(settings_key='showinfologmessages', default_value=True)
    608 show_warning_messages_setting = UserSettingBool(settings_key='showwarninglogmessages', default_value=True)
    609 show_error_messages_setting = UserSettingBool(settings_key='showerrorlogmessages', default_value=True)
    610 show_combat_messages_setting = UserSettingBool(settings_key='showcombatlogmessages', default_value=True)
    611 show_notify_messages_setting = UserSettingBool(settings_key='shownotifylogmessages', default_value=True)
    612 show_question_messages_setting = UserSettingBool(settings_key='showquestionlogmessages', default_value=True)
    613 show_mining_messages_setting = UserSettingBool(settings_key='showmininglogmessages', default_value=True)
    614 show_bounty_messages_setting = UserSettingBool(settings_key='showbountylogmessages', default_value=True)
    615 MESSAGE_FILTER_SETTING_BY_MESSAGE_TYPE = {MessageType.INFO: show_info_messages_setting,
    616  MessageType.WARNING: show_warning_messages_setting,
    617  MessageType.ERROR: show_error_messages_setting,
    618  MessageType.COMBAT: show_combat_messages_setting,
    619  MessageType.NOTIFY: show_notify_messages_setting,
    620  MessageType.QUESTION: show_question_messages_setting,
    621  MessageType.MINING: show_mining_messages_setting,
    622  MessageType.BOUNTY: show_bounty_messages_setting}
    623 LABEL_BY_MESSAGE_TYPE = {MessageType.ERROR: 'UI/Accessories/Log/LogError',
    624  MessageType.WARNING: 'UI/Accessories/Log/LogWarn',
    625  MessageType.SLASH: 'UI/Accessories/Log/LogSlash',
    626  MessageType.COMBAT: 'UI/Accessories/Log/LogCombat',
    627  MessageType.NOTIFY: 'UI/Accessories/Log/LogNotify',
    628  MessageType.QUESTION: 'UI/Accessories/Log/LogQuestion',
    629  MessageType.INFO: 'UI/Accessories/Log/LogInfo',
    630  MessageType.HINT: 'UI/Accessories/Log/LogHint',
    631  MessageType.MINING: 'UI/Accessories/Log/LogMining',
    632  MessageType.BOUNTY: 'UI/Accessories/Log/LogBounty'}
    633 LABEL_BY_MESSAGE_FILTER_SETTING = {show_info_messages_setting: 'UI/Accessories/Log/ShowInfo',
    634  show_warning_messages_setting: 'UI/Accessories/Log/ShowWarn',
    635  show_error_messages_setting: 'UI/Accessories/Log/ShowError',
    636  show_combat_messages_setting: 'UI/Accessories/Log/ShowCombat',
    637  show_notify_messages_setting: 'UI/Accessories/Log/ShowNotify',
    638  show_question_messages_setting: 'UI/Accessories/Log/ShowQuestion',
    639  show_mining_messages_setting: 'UI/Accessories/Log/ShowMining',
    640  show_bounty_messages_setting: 'UI/Accessories/Log/ShowBounty'}
    641 
    642 class ShowDamageMessageSetting(UserSettingBool):
    643     _on_available_changed = None
    644 
    645     def __init__(self, settings_key, default_value, caption_label, hint_label = None, depends_on = None):
    646         self._caption = caption_label
    647         self._hint = hint_label
    648         self._dependency = depends_on
    649         super(ShowDamageMessageSetting, self).__init__(settings_key=settings_key, default_value=default_value)
    650         if self._dependency:
    651             self._dependency.on_change.connect(self._on_dependency_changed)
    652 
    653     @property
    654     def available(self):
    655         if self._dependency is not None:
    656             return self._dependency.get()
    657         return True
    658 
    659     @property
    660     def on_available_changed(self):
    661         if self._on_available_changed is None:
    662             self._on_available_changed = signals.Signal('{}.on_available_changed'.format(self.__class__.__name__))
    663         return self._on_available_changed
    664 
    665     @property
    666     def caption(self):
    667         return GetByLabel(self._caption)
    668 
    669     @property
    670     def hint(self):
    671         return GetByLabel(self._hint)
    672 
    673     def _on_dependency_changed(self, value):
    674         if self._on_available_changed is not None:
    675             self._on_available_changed(self)
    676 
    677 
    678 show_inflight_notify_messages_setting = ShowDamageMessageSetting(settings_key='notifyMessagesEnabled', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowTacticalNotifications', hint_label='UI/SystemMenu/GeneralSettings/Inflight/ShowTacticalNotificationTooltip')
    679 show_inflight_damage_messages_setting = ShowDamageMessageSetting(settings_key='damageMessages', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/DamageNotifications')
    680 show_inflight_energy_warfare_messages_setting = ShowDamageMessageSetting(settings_key='energyWarfareMessages', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowEnergyWarfareNotifications')
    681 show_inflight_remote_assistance_messages_setting = ShowDamageMessageSetting(settings_key='remoteAssistanceMessages', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowRemoteAssistanceNotifications')
    682 show_inflight_bounty_messages_setting = ShowDamageMessageSetting(settings_key='actionMessagesBounty', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowBountyNotifications')
    683 show_inflight_mining_messages_setting = ShowDamageMessageSetting(settings_key='actionMessagesMining', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowMiningNotification')
    684 show_inflight_damage_miss_messages_setting = ShowDamageMessageSetting(settings_key='damageMessagesNoDamage', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/MissedHitNotifications', depends_on=show_inflight_damage_messages_setting)
    685 show_inflight_damage_incoming_messages_setting = ShowDamageMessageSetting(settings_key='damageMessagesMine', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowInflictedDamageNotifications', depends_on=show_inflight_damage_messages_setting)
    686 show_inflight_damage_outgoing_messages_setting = ShowDamageMessageSetting(settings_key='damageMessagesEnemy', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowIncurredDamageNotification', depends_on=show_inflight_damage_messages_setting)
    687 show_inflight_remote_assistance_incoming_messages_setting = ShowDamageMessageSetting(settings_key='remoteAssistanceMessagesMine', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowIncomingRemoteAssistanceNotifications', depends_on=show_inflight_remote_assistance_messages_setting)
    688 show_inflight_remote_assistance_outgoing_messages_setting = ShowDamageMessageSetting(settings_key='remoteAssistanceMessagesOthers', default_value=True, caption_label='UI/SystemMenu/GeneralSettings/Inflight/ShowOutgoingRemoteAssistanceNotifications', depends_on=show_inflight_remote_assistance_messages_setting)
    689 SHOW_INFLIGHT_MESSAGE_SETTINGS = (show_inflight_notify_messages_setting,
    690  show_inflight_damage_messages_setting,
    691  show_inflight_energy_warfare_messages_setting,
    692  show_inflight_remote_assistance_messages_setting,
    693  show_inflight_bounty_messages_setting,
    694  show_inflight_mining_messages_setting,
    695  show_inflight_damage_miss_messages_setting,
    696  show_inflight_damage_incoming_messages_setting,
    697  show_inflight_damage_outgoing_messages_setting,
    698  show_inflight_remote_assistance_incoming_messages_setting,
    699  show_inflight_remote_assistance_outgoing_messages_setting)
    700 
    701 class ShowInflightMessageCheckboxMenuEntryData(MenuEntryDataCheckbox):
    702 
    703     def __init__(self, setting):
    704         super(ShowInflightMessageCheckboxMenuEntryData, self).__init__(text=setting.caption, setting=setting, isEnabled=setting.available)
    705         setting.on_available_changed.connect(self._on_available_changed)
    706 
    707     def _on_available_changed(self, setting):
    708         self.isEnabled = setting.available
    709 
    710 
    711 class DependentCheckboxMenuEntryData(MenuEntryDataCheckbox):
    712 
    713     def __init__(self, text, setting, dependencies):
    714         self._dependencies = dependencies
    715         super(DependentCheckboxMenuEntryData, self).__init__(text=text, setting=setting, isEnabled=self._are_all_dependencies_enabled())
    716         for dependency in self._dependencies:
    717             dependency.on_change.connect(self._on_dependency_changed)
    718 
    719     def _on_dependency_changed(self, value):
    720         self.isEnabled = self._are_all_dependencies_enabled()
    721 
    722     def _are_all_dependencies_enabled(self):
    723         return all((dependency.get() for dependency in self._dependencies))
    724 
    725 
    726 show_inflight_messages_setting = UserSettingBool(settings_key='damageMessageShowInspaceNotifications', default_value=True)
    727 show_inflight_message_ship_setting = UserSettingBool(settings_key='damageMessagesShowShip', default_value=False)
    728 show_inflight_message_ticker_setting = UserSettingBool(settings_key='damageMessagesShowTicker', default_value=False)
    729 show_inflight_message_weapon_setting = UserSettingBool(settings_key='damageMessagesShowWeapon', default_value=False)
    730 show_inflight_message_quality_setting = UserSettingBool(settings_key='damageMessagesShowQuality', default_value=True)
    731 inflight_message_font_size_setting = UserSettingEnum(settings_key='dmgnotifictions_fontsize', options=[10, 12, 14], default_value=12)
    732 inflight_messages_alignment_setting = UserSettingEnum(settings_key='dmgnotifictions_alignment', options=['auto',
    733  'left',
    734  'right',
    735  'center'], default_value='auto')
    736 CAPTION_LABEL_BY_INFLIGHT_MESSAGE_ALIGNMENT = {'auto': 'UI/Accessories/Log/AlignmentAuto',
    737  'left': 'UI/Accessories/Log/AlignmentLeft',
    738  'right': 'UI/Accessories/Log/AlignmentRight',
    739  'center': 'UI/Accessories/Log/AlignmentCenter'}
    740 
    741 class LoggerWindow(Window):
    742     default_isLightBackground = True
    743     default_windowID = 'logger'
    744     default_captionLabelPath = 'UI/Accessories/Log/Log'
    745     default_iconNum = 'res:/ui/Texture/WindowIcons/log.png'
    746     default_minSize = (256, 136)
    747     default_width = 400
    748     default_height = 200
    749     default_isCompactable = True
    750     _actions = None
    751     _toolbar = None
    752 
    753     def __init__(self, **kwargs):
    754         super(LoggerWindow, self).__init__(**kwargs)
    755         self._toolbar = ContainerAutoSize(parent=self.content, align=uiconst.TOTOP, padLeft=-4)
    756         self._actions = ContainerAutoSize(parent=self._get_actions_parent(), align=self._get_actions_alignment(), height=24, alignMode=uiconst.TOLEFT)
    757         self.scroll = eveScroll.Scroll(parent=self.content, align=uiconst.TOALL, padLeft=-8)
    758         self.scroll.Load(contentList=[], headers=[GetByLabel('UI/Common/DateWords/Time'), GetByLabel('UI/Accessories/Log/Type'), GetByLabel('UI/Accessories/Log/Message')])
    759         self.scroll.sr.id = 'logScroll'
    760         MenuButtonIcon(parent=ContainerAutoSize(parent=self._actions, align=uiconst.TOLEFT), align=uiconst.TOPLEFT, width=24, height=24, iconSize=16, texturePath=eveicon.filter, get_menu_func=self._get_log_filter_menu, hint=GetByLabel('UI/Generic/Filters'))
    761         MenuButtonIcon(parent=ContainerAutoSize(parent=self._actions, align=uiconst.TOLEFT), align=uiconst.TOPLEFT, width=24, height=24, iconSize=16, texturePath=eveicon.settings, get_menu_func=self._get_combat_message_menu, hint=GetByLabel('UI/Accessories/Log/CombatSettings'))
    762         self.LoadAllMessages()
    763         self.timer = timerstuff.AutoTimer(1000, self.CheckMessages)
    764         log_message_count_setting.on_change.connect(self._on_log_message_count_setting_changed)
    765         show_inflight_messages_setting.on_change.connect(self._on_show_inflight_messages_setting_changed)
    766         inflight_message_font_size_setting.on_change.connect(self._on_inflight_message_font_size_setting_changed)
    767         inflight_messages_alignment_setting.on_change.connect(self._on_inflight_messages_alignment_setting_changed)
    768         for setting in MESSAGE_FILTER_SETTING_BY_MESSAGE_TYPE.values():
    769             setting.on_change.connect(self._on_message_filter_setting_changed)
    770 
    771         self.on_compact_mode_changed.connect(self._on_window_compact_mode_changed)
    772         self.on_stacked_changed.connect(self._on_window_stacked_changed)
    773 
    774     def _get_actions_parent(self):
    775         if self.compact and not self.stacked:
    776             return self.header.extra_content
    777         else:
    778             return self._toolbar
    779 
    780     def _get_actions_alignment(self):
    781         if self.compact and not self.stacked:
    782             return uiconst.CENTERRIGHT
    783         else:
    784             return uiconst.TOPLEFT
    785 
    786     def _update_actions(self):
    787         self._actions.SetParent(None)
    788         self._actions.align = self._get_actions_alignment()
    789         self._actions.SetParent(self._get_actions_parent())
    790 
    791     def _on_window_compact_mode_changed(self, window):
    792         self._update_actions()
    793 
    794     def _on_window_stacked_changed(self, window):
    795         self._update_actions()
    796 
    797     def _PrepareListEntries(self, messages):
    798         showmsgs = []
    799         dateSortKey = 'sort_%s' % GetByLabel('UI/Common/DateWords/Time')
    800         openMsgTitle = GetByLabel('UI/Accessories/Log/LogMessage')
    801         for msg in messages:
    802             msgtext, msgtype, timestamp = msg
    803             if not self.ShowMessage(msgtype):
    804                 continue
    805             color = COLORS_BY_TYPE.get(msgtype, eveColor.WHITE_HEX)
    806             color = u'<color={}>'.format(color)
    807             if msgtype:
    808                 if msgtype in LABEL_BY_MESSAGE_TYPE:
    809                     label = GetByLabel(LABEL_BY_MESSAGE_TYPE[msgtype])
    810                 else:
    811                     label = msgtype
    812             else:
    813                 label = GetByLabel('UI/Accessories/Log/Generic')
    814             text = GetByLabel('UI/Accessories/Log/MessageOutput', logtime=timestamp, color=color, label=label, message=StripTags(msgtext, stripOnly=['t']))
    815             entry = GetFromClass(Generic, {'label': text,
    816              'canOpen': openMsgTitle,
    817              dateSortKey: timestamp,
    818              'line': 1})
    819             showmsgs.append(entry)
    820 
    821         return showmsgs
    822 
    823     @telemetry.ZONE_METHOD
    824     def LoadAllMessages(self):
    825         maxlog = log_message_count_setting.get()
    826         messages = sm.GetService('logger').GetMessages()
    827         if len(messages) > maxlog:
    828             messages = messages[-maxlog:]
    829         showmsgs = self._PrepareListEntries(messages)
    830         self.scroll.Load(contentList=showmsgs, headers=[GetByLabel('UI/Common/DateWords/Time'), GetByLabel('UI/Accessories/Log/Type'), GetByLabel('UI/Accessories/Log/Message')])
    831 
    832     @telemetry.ZONE_METHOD
    833     def CheckMessages(self):
    834         if self.scroll.IsVisible():
    835             messages = sm.GetService('logger').GetPendingMessages()
    836             if messages:
    837                 entryList = self._PrepareListEntries(messages)
    838                 maxlog = log_message_count_setting.get()
    839                 self.scroll.AddEntries(0, entryList)
    840                 revSorting = self.scroll.GetSortDirection() or self.scroll.GetSortBy() is None
    841                 if revSorting:
    842                     self.scroll.RemoveEntries(self.scroll.GetNodes()[maxlog:])
    843                 else:
    844                     self.scroll.RemoveEntries(self.scroll.GetNodes()[:-maxlog])
    845 
    846     def GetMenu(self, *args):
    847         m = super(LoggerWindow, self).GetMenu(*args)
    848         return m
    849 
    850     def GetMenuMoreOptions(self):
    851         menu = super(LoggerWindow, self).GetMenuMoreOptions()
    852         menu.AddEntry(text=MenuLabel('UI/Accessories/Log/CaptureLog'), func=sm.GetService('logger').DumpToLog)
    853         menu.AddEntry(text=MenuLabel('UI/Accessories/Log/CopyLog'), func=sm.GetService('logger').CopyLog, texturePath=eveicon.copy)
    854         menu.AddSeparator()
    855         menu.AddEntry(GetByLabel('UI/Accessories/Log/ClearLog'), self.ClearAllMessages, texturePath=eveicon.trashcan)
    856         return menu
    857 
    858     def _get_log_filter_menu(self):
    859         menu = MenuData()
    860         menu.AddCaption(GetByLabel('UI/Accessories/Log/MessageTypesToLog'))
    861         for setting, label in LABEL_BY_MESSAGE_FILTER_SETTING.items():
    862             menu.AddCheckbox(text=GetByLabel(label), setting=setting)
    863 
    864         menu.AddCaption(GetByLabel('UI/Accessories/Log/NumMessagesInLogView'))
    865         for message_count in log_message_count_setting.options:
    866             menu.AddRadioButton(text=unicode(message_count), setting=log_message_count_setting, value=message_count)
    867 
    868         return menu
    869 
    870     def ResetDmgNotificationAlignment(self, *args):
    871         settings.char.ui.Delete('damageMessages_config')
    872         inflight_messages_alignment_setting.reset()
    873         message = getattr(uicore.layer.target, 'message', None)
    874         if message:
    875             message.ResetAlignment()
    876         message = itertoolsext.first_or_default(uicore.layer.abovemain.children, predicate=lambda each: each.name == 'message')
    877         if message:
    878             message.ResetAlignment()
    879 
    880     def _get_combat_message_menu(self):
    881         menu = MenuData()
    882         menu.AddEntry(text=GetByLabel('UI/Accessories/Log/CombatMessagesToDisplay'), subMenuData=[ ShowInflightMessageCheckboxMenuEntryData(setting) for setting in SHOW_INFLIGHT_MESSAGE_SETTINGS ])
    883         inflight_message_sub_menu = MenuData()
    884         inflight_message_sub_menu.AppendMenuEntryData(DependentCheckboxMenuEntryData(text=GetByLabel('UI/Accessories/Log/ShowInspaceNotifications'), setting=show_inflight_messages_setting, dependencies=[show_inflight_damage_messages_setting]))
    885         inflight_message_sub_menu.AddSeparator()
    886         inflight_message_sub_menu.AppendMenuEntryData(DependentCheckboxMenuEntryData(text=GetByLabel('UI/Accessories/Log/DmgNotificationsShowShip'), setting=show_inflight_message_ship_setting, dependencies=[show_inflight_messages_setting, show_inflight_damage_messages_setting]))
    887         inflight_message_sub_menu.AppendMenuEntryData(DependentCheckboxMenuEntryData(text=GetByLabel('UI/Accessories/Log/DmgNotificationsShowTicker'), setting=show_inflight_message_ticker_setting, dependencies=[show_inflight_messages_setting, show_inflight_damage_messages_setting]))
    888         inflight_message_sub_menu.AppendMenuEntryData(DependentCheckboxMenuEntryData(text=GetByLabel('UI/Accessories/Log/DmgNotificationsShowWeapon'), setting=show_inflight_message_weapon_setting, dependencies=[show_inflight_messages_setting, show_inflight_damage_messages_setting]))
    889         inflight_message_sub_menu.AppendMenuEntryData(DependentCheckboxMenuEntryData(text=GetByLabel('UI/Accessories/Log/DmgNotificationsShowQuality'), setting=show_inflight_message_quality_setting, dependencies=[show_inflight_messages_setting, show_inflight_damage_messages_setting]))
    890         inflight_message_sub_menu.AddSeparator()
    891         drag_mode_active = sm.GetService('logger').IsInDragMode()
    892         inflight_message_sub_menu.AddEntry(text=GetByLabel('UI/Accessories/Log/ExitMessageMovingMode') if drag_mode_active else GetByLabel('UI/Accessories/Log/EnterMessageMovingMode'), func=lambda : sm.GetService('logger').MoveNotifications(not drag_mode_active), texturePath=eveicon.caret_up_down_left_right)
    893         menu.AddEntry(text=GetByLabel('UI/Accessories/Log/ExtraInfoHeader'), subMenuData=inflight_message_sub_menu)
    894         menu.AddEntry(text=GetByLabel('UI/Accessories/Log/FontSize'), subMenuData=[ MenuEntryDataRadioButton(text=unicode(font_size), setting=inflight_message_font_size_setting, value=font_size) for font_size in inflight_message_font_size_setting.options ])
    895         alignment_sub_menu = MenuData(entryList=[ MenuEntryDataRadioButton(text=GetByLabel(CAPTION_LABEL_BY_INFLIGHT_MESSAGE_ALIGNMENT.get(alignment)), setting=inflight_messages_alignment_setting, value=alignment) for alignment in inflight_messages_alignment_setting.options ])
    896         alignment_sub_menu.AddSeparator()
    897         alignment_sub_menu.AddEntry(text=GetByLabel('UI/Accessories/Log/ResetAlignment'), func=self.ResetDmgNotificationAlignment, menuGroupID=DESTRUCTIVEGROUP)
    898         menu.AddEntry(text=GetByLabel('UI/Accessories/Log/InspaceNotificationFontAlignment'), subMenuData=alignment_sub_menu)
    899         return menu
    900 
    901     def ClearAllMessages(self):
    902         sm.GetService('logger').ClearAllMessages()
    903         self.LoadAllMessages()
    904 
    905     def OnEndMaximize(self, *args):
    906         self.LoadAllMessages()
    907 
    908     def _OnClose(self, *args):
    909         self.timer = None
    910 
    911     def ShowMessage(self, msgtype):
    912         return sm.GetService('logger').ShowMessage(msgtype)
    913 
    914     def _on_log_message_count_setting_changed(self, value):
    915         self.LoadAllMessages()
    916 
    917     def _on_message_filter_setting_changed(self, value):
    918         self.LoadAllMessages()
    919 
    920     @staticmethod
    921     def _on_show_inflight_messages_setting_changed(value):
    922         message_box = getattr(uicore.layer.target, 'message', None)
    923         if message_box and not message_box.destroyed:
    924             message_box.Close()
    925 
    926     @staticmethod
    927     def _on_inflight_message_font_size_setting_changed(value):
    928         sm.GetService('logger').notificationFontSize = value
    929         message = getattr(uicore.layer.target, 'message', None)
    930         if message:
    931             message.ChangeFontSize()
    932 
    933     @staticmethod
    934     def _on_inflight_messages_alignment_setting_changed(value):
    935         message = getattr(uicore.layer.target, 'message', None)
    936         if message:
    937             message.ChangeAlignment()