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

evemail.py (126420B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\evemail.py
      2 import math
      3 import sys
      4 import blue
      5 import carbonui.const as uiconst
      6 import characterSettingsStorage.characterSettingsConsts as cSettings
      7 import copy
      8 import eveicon
      9 import localization
     10 import log
     11 import types
     12 import uthread
     13 import utillib
     14 from bannedwords.client import bannedwords
     15 from brennivin.itertoolsext import Bundle
     16 from carbon.client.script.environment.AudioUtil import PlaySound
     17 from carbon.common.script.sys.serviceConst import ROLE_GML
     18 from carbon.common.script.util import timerstuff
     19 from carbon.common.script.util.commonutils import GetAttrs, StripTags
     20 from carbon.common.script.util.format import FmtDate
     21 from carbonui.button.const import HEIGHT_NORMAL
     22 from carbonui.button.group import ButtonGroup
     23 from carbonui.control.button import Button
     24 from carbonui.control.buttonIcon import ButtonIcon
     25 from carbonui.control.checkbox import Checkbox
     26 from carbonui.control.dragResizeCont import DragResizeCont
     27 from carbonui.control.radioButton import RadioButton
     28 from carbonui.control.singlelineedits.baseSingleLineEdit import BaseSingleLineEdit
     29 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     30 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText
     31 from carbonui.control.window import Window
     32 from carbonui.primitives.container import Container
     33 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     34 from carbonui.primitives.fill import Fill
     35 from carbonui.primitives.line import Line
     36 from carbonui.primitives.sprite import Sprite
     37 from carbonui.uicore import uicore
     38 from carbonui.util.various_unsorted import SortListOfTuples
     39 from carbonui.window.header.tab_navigation import TabNavigationWindowHeader
     40 from carbonui.window.underlay import WindowUnderlay
     41 from eve.client.script.ui.control import eveIcon, eveLabel, eveScroll
     42 from eve.client.script.ui.control.allUserEntries import AllUserEntries
     43 from eve.client.script.ui.control.colorpicker import ColorSwatch
     44 from eve.client.script.ui.control.divider import Divider
     45 from eve.client.script.ui.control.entries.checkbox import CheckboxEntry
     46 from eve.client.script.ui.control.entries.generic import Generic
     47 from eve.client.script.ui.control.entries.mail import CorpAllianceEntry
     48 from eve.client.script.ui.control.entries.space import Space
     49 from eve.client.script.ui.control.entries.util import GetFromClass
     50 from eve.client.script.ui.control.eveEditPlainText import EditPlainText
     51 from eve.client.script.ui.control.listgroup import ListGroup as Group, ListGroup
     52 from eve.client.script.ui.shared.neocom.ownerSearch import OwnerSearchWindow
     53 from eve.client.script.ui.util import searchOld, searchUtil
     54 from eve.client.script.ui.util import uix
     55 from eve.client.script.ui.util.linkUtil import GetCharIDFromTextLink
     56 from eve.common.lib import appConst as const
     57 from eve.common.script.search.const import MatchBy
     58 from eve.common.script.sys import idCheckers
     59 from eve.common.script.util.notificationconst import groupNamePaths as notificationGroupNamePaths
     60 from eveexceptions import UserError
     61 from eveservices.menu import GetMenuService
     62 from localization import GetByLabel
     63 from menu import MenuLabel
     64 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     65 GROUP_CHAR = 1
     66 GROUP_LIST = 2
     67 GROUP_CORP = 3
     68 MAILLABELTRASH = -1
     69 CORPTEXT = 'corp'
     70 ALLIANCTEXT = 'alliance'
     71 DEFAULTNUMMAILS = 30
     72 MAXNUMMAILS = 100
     73 MINNUMMAILS = 20
     74 SAVE_INTERVAL = 120 * 1000
     75 DELETE_INTERVAL = 0.3 * const.SEC
     76 WHITE = (1.0, 1.0, 1.0)
     77 
     78 class MailWindow(Window):
     79     __guid__ = 'form.MailWindow'
     80     __notifyevents__ = ['OnNewMailReceived', 'OnMailStartStopBlinkingTab']
     81     default_width = 800
     82     default_height = 600
     83     default_minSize = (500, 350)
     84     default_windowID = 'mail'
     85     default_captionLabelPath = 'Tooltips/Neocom/Mail'
     86     default_descriptionLabelPath = 'Tooltips/Neocom/Mail_description'
     87     default_iconNum = 'res:/ui/Texture/WindowIcons/evemail.png'
     88 
     89     def ApplyAttributes(self, attributes):
     90         Window.ApplyAttributes(self, attributes)
     91         if sm.GetService('mailSvc').IsFileCacheCorrupted():
     92             self.Close()
     93             raise UserError('MailCacheFileError')
     94         sm.GetService('mailSvc').SetBlinkNeocomState(False)
     95         self.mailInited = 0
     96         self.sr.mail = MailForm(name='mailform', parent=self.content)
     97         from eve.client.script.ui.shared.neocom.notifications import NotificationForm
     98         self.sr.notifications = NotificationForm(name='notificationform', parent=self.content)
     99         self.ConstructTabGroup()
    100         shouldBlink = sm.GetService('mailSvc').ShouldTabBlink()
    101         if shouldBlink:
    102             uthread.new(self.OnNewMailReceived)
    103 
    104     def ConstructTabGroup(self):
    105         self.tabGroup = self.header.tab_group
    106         self.tabGroup.AddTab(label=localization.GetByLabel('Tooltips/Neocom/Mail'), panel=self.sr.mail, code=self, tabID='mail')
    107         self.tabGroup.AddTab(localization.GetByLabel('UI/Mail/Notifications/Notifications'), self.sr.notifications, self, 'notifications')
    108         self.tabGroup.AutoSelect()
    109 
    110     def Prepare_Header_(self):
    111         self.header = TabNavigationWindowHeader()
    112 
    113     def SelectMailTab(self):
    114         self.tabGroup.SelectByIdx(0)
    115 
    116     def SelectNotificationTab(self):
    117         self.tabGroup.SelectByIdx(1)
    118 
    119     def Load(self, key):
    120         if key == 'mail':
    121             self.LoadMail()
    122         elif key == 'notifications':
    123             self.LoadNotifications()
    124 
    125     def LoadMail(self):
    126         if getattr(self, 'mailIniting', 0):
    127             return
    128         if not getattr(self, 'mailInited', 0):
    129             self.mailIniting = 1
    130             self.sr.mail.Setup()
    131             if not self or self.destroyed:
    132                 return
    133             self.mailInited = 1
    134             self.mailIniting = 0
    135         sm.GetService('mailSvc').SetBlinkTabState(False)
    136         self.sr.mail.LoadMailForm()
    137 
    138     def LoadNotifications(self):
    139         if not getattr(self, 'notificationsInited', 0):
    140             self.sr.notifications.Setup()
    141             self.notificationsInited = 1
    142         self.sr.notifications.LoadNotificationForm()
    143 
    144     def _OnClose(self, *args):
    145         if getattr(self, 'mailInited', 0):
    146             self.sr.mail._OnClose()
    147         Window._OnClose(self, *args)
    148 
    149     def OnNewMailReceived(self, *args):
    150         self.OnMailStartStopBlinkingTab('mail', blink=1)
    151 
    152     def OnMailStartStopBlinkingTab(self, configname, blink = 1):
    153         if self.tabGroup.destroyed:
    154             return
    155         mailSettings = sm.GetService('mailSvc').GetMailSettings()
    156         if configname == 'mail':
    157             doBlinkTab = mailSettings.GetSingleValue(cSettings.MAIL_BLINK_TAB, True)
    158             if blink == 0 or doBlinkTab:
    159                 self.tabGroup.BlinkPanelByName(localization.GetByLabel('UI/Mail/EveMail'), blink)
    160 
    161     def GetArrowMenu(self, *args):
    162         m = [(MenuLabel('UI/Common/Settings'), self.OpenMailSettings, ())]
    163         return m
    164 
    165     def GetMenuMoreOptions(self):
    166         menuData = super(MailWindow, self).GetMenuMoreOptions()
    167         menuData.AddEntry(text=GetByLabel('UI/Mail/CommunicationSettings'), func=self.OpenMailSettings, texturePath=eveicon.settings)
    168         return menuData
    169 
    170     def OpenMailSettings(self, *args):
    171         if getattr(self, 'mailIniting', 0):
    172             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/SystemLoading')})
    173         MailSettings.Open()
    174 
    175 
    176 class MailForm(Container):
    177     __guid__ = 'form.MailForm'
    178     __notifyevents__ = ['OnMyMaillistChanged',
    179      'OnMyLabelsChanged',
    180      'OnNewMailReceived',
    181      'OnMailTrashedDeleted',
    182      'OnMailSettingsChanged',
    183      'OnMailStatusUpdate',
    184      'OnMailCountersUpdate']
    185 
    186     def Setup(self):
    187         sm.RegisterNotify(self)
    188         self.viewing = None
    189         self.readTimer = 0
    190         self.startPos = 0
    191         self.scrollHeight = 0
    192         self.readingPaneVisible = settings.user.ui.Get('mail_readingPaneVisible', True)
    193         self.lastDeleted = 0
    194         self.inited = 0
    195         sortBy = settings.user.ui.Get('evemail_sortBy', localization.GetByLabel('UI/Mail/Received'))
    196         if sortBy in [localization.GetByLabel('UI/Mail/Status'),
    197          localization.GetByLabel('UI/Mail/Sender'),
    198          localization.GetByLabel('UI/Mail/Subject'),
    199          localization.GetByLabel('UI/Mail/Received')]:
    200             self.sortBy = sortBy
    201         else:
    202             self.sortBy = localization.GetByLabel('UI/Mail/Received')
    203         self.sortOrder = settings.user.ui.Get('evemail_sortOrder', True)
    204         self.content = self
    205         self.DrawStuff()
    206         sm.GetService('mailSvc').TrySyncMail()
    207         if self and not self.destroyed:
    208             self.worker = uthread.new(self.SaveChangesWorker)
    209             self.inited = 1
    210 
    211     def CheckInited(self):
    212         if not self.inited:
    213             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/SystemLoading')})
    214 
    215     def DrawStuff(self, *args):
    216         self.toolbarCont = Container(name='toolbarCont', parent=self.content, align=uiconst.TOTOP, height=Button.default_height, padding=(0, 0, 0, 16))
    217         leftContWidth = settings.user.ui.Get('evemail_leftContWidth', 200)
    218         self.sr.leftCont = Container(name='leftCont', parent=self.content, align=uiconst.TOLEFT, width=leftContWidth)
    219         self.sr.btns = ButtonGroup(btns=[(localization.GetByLabel('UI/Mail/AddMailingList'),
    220           self.GetMailingListWnd,
    221           'self',
    222           None)], parent=self.sr.leftCont)
    223         self.sr.leftScroll = eveScroll.Scroll(name='leftScroll', parent=self.sr.leftCont)
    224         self.sr.leftScroll.multiSelect = 0
    225         self.sr.leftScroll.allowBrowsing = 0
    226         divider = Divider(name='divider', parent=self.content, state=uiconst.UI_NORMAL, align=uiconst.TOLEFT, width=const.defaultPadding)
    227         divider.Startup(self.sr.leftCont, 'width', 'x', 180, 275)
    228         self.sr.bottomCont = Container(name='bottomCont', parent=self.content, align=uiconst.TOBOTTOM, pos=(0, 0, 0, 22))
    229         self.sr.expanderCont = Container(name='expanderCont', parent=self.sr.bottomCont, align=uiconst.CENTER, pos=(0, 0, 16, 16))
    230         expander = Sprite(parent=self.sr.expanderCont, pos=(5, 2, 11, 11), name='expandericon', state=uiconst.UI_NORMAL, texturePath='res:/UI/Texture/Shared/expanderDown.png', align=uiconst.TOPRIGHT)
    231         expander.OnClick = self.ChangeReadingPaneVisiblity
    232         self.sr.expander = expander
    233         self.sr.readingPaneCont = DragResizeCont(name='rightCont', parent=self.content, align=uiconst.TOBOTTOM_PROP, settingsID='evemail_readingContProporations2', minSize=0.1, defaultSize=0.4, maxSize=0.65, show_line=True)
    234         self.sr.readingPane = EditPlainText(setvalue='', parent=self.sr.readingPaneCont, align=uiconst.TOALL, readonly=1)
    235         self.sr.msgScroll = eveScroll.Scroll(name='msgScroll', parent=self.content)
    236         self.sr.msgScroll.sr.id = 'mail_msgs'
    237         self.sr.msgScroll.sr.fixedColumns = {localization.GetByLabel('UI/Mail/Status'): 52}
    238         self.sr.msgScroll.sr.maxDefaultColumns = {localization.GetByLabel('UI/Mail/Subject'): 250}
    239         self.sr.msgScroll.Sort = self.SortMail
    240         self.sr.msgScroll.OnDelete = self.DeleteFromKeyboard
    241         self.sr.msgScroll.OnSelectionChange = self.MsgScrollSelectionChange
    242         self.sr.msgScroll.DrawHeaders = self.RefreshMsgScrollHeaders
    243         self.sr.msgScroll.Load(contentList=[], noContentHint=localization.GetByLabel('UI/Mail/FetchingMails'), ignoreSort=1)
    244         self.inited = True
    245         self.DrawToolbar()
    246         self.viewingLabel = 1
    247         self.viewingList = None
    248 
    249     def DrawToolbar(self, *args):
    250         actions = utillib.KeyVal()
    251         actions.composeClicked = self.ComposeClicked
    252         actions.replyClicked = self.ReplyClicked
    253         actions.replyAllClicked = self.ReplyAllClicked
    254         actions.forwardClicked = self.ForwardClicked
    255         actions.trashClicked = self.TrashClicked
    256         actions.deleteClicked = self.DeleteClicked
    257         self.mailActions = MailActionPanel(name='mailActionCont', parent=self.toolbarCont, align=uiconst.TOPLEFT, pos=(0,
    258          0,
    259          250,
    260          Button.default_height))
    261         self.mailActions.Startup(actions)
    262         labelBtn = Button(align=uiconst.TOPLEFT, texturePath='res:/ui/Texture/WindowIcons/evemailtag.png', hint=localization.GetByLabel('UI/Mail/ManageLabels'), func=self.ManageLabels)
    263         self.mailActions.AddExtraButton(labelBtn, withSpace=1, size=32, hint=localization.GetByLabel('UI/Mail/ManageLabels'))
    264         self.ConstructPaginationControls()
    265         self.SetReadingPaneVisibility(self.readingPaneVisible)
    266 
    267     def ConstructPaginationControls(self):
    268         self.browserCont = ContainerAutoSize(name='browseCont', parent=self.toolbarCont, align=uiconst.TORIGHT, alignMode=uiconst.TOLEFT)
    269         labelCont = ContainerAutoSize(name='labelCont', parent=self.browserCont, align=uiconst.TOLEFT, padRight=4)
    270         self.pageCountLabel = eveLabel.EveLabelMedium(parent=labelCont, state=uiconst.UI_DISABLED, align=uiconst.CENTERRIGHT)
    271         self.backBtn = Button(parent=self.browserCont, align=uiconst.TOLEFT, state=uiconst.UI_HIDDEN, texturePath='res:/UI/Texture/Icons/23_64_1.png', iconSize=24, hint=localization.GetByLabel('UI/Common/Previous'), func=lambda : self.BrowseMail(-1), args=(), padRight=2)
    272         self.fwdBtn = Button(parent=self.browserCont, align=uiconst.TOLEFT, state=uiconst.UI_HIDDEN, texturePath='res:/UI/Texture/Icons/23_64_2.png', iconSize=24, hint=localization.GetByLabel('UI/Common/Next'), func=lambda : self.BrowseMail(1), args=())
    273 
    274     def _OnClose(self, *args):
    275         if self.sr.leftCont:
    276             settings.user.ui.Set('evemail_leftContWidth', self.sr.leftCont.width)
    277         sm.UnregisterNotify(self)
    278         sm.GetService('mailSvc').SaveChangesToDisk()
    279 
    280     def SaveChangesWorker(self):
    281         while self and not self.destroyed:
    282             blue.pyos.synchro.SleepWallclock(SAVE_INTERVAL)
    283             try:
    284                 sm.GetService('mailSvc').SaveChangesToDisk()
    285             except Exception:
    286                 log.LogTraceback('SaveChangesWorker', 'Error while saving to disk...', severity=log.LGERR)
    287                 sys.exc_clear()
    288 
    289     def LoadMailForm(self):
    290         self.ReloadAll()
    291         self.MsgScrollSelectionChange()
    292 
    293     def LoadLeftSide(self, *args):
    294         scrolllist = []
    295         groups = self.GetStaticLabelsGroups()
    296         scrolllist += groups
    297         scrolllist.insert(1, GetFromClass(Space, {'height': 16}))
    298         scrolllist.append(GetFromClass(Space, {'height': 16}))
    299         scrolllist.append(GetFromClass(ListGroup, {'GetSubContent': self.GetLabelsSubContent,
    300          'MenuFunction': self.LabelGroupMenu,
    301          'label': localization.GetByLabel('UI/Mail/Labels'),
    302          'cleanLabel': localization.GetByLabel('UI/Mail/Labels'),
    303          'id': ('evemail', 'Labels', localization.GetByLabel('UI/Mail/Labels')),
    304          'state': 'locked',
    305          'BlockOpenWindow': 1,
    306          'showicon': 'ui_73_16_9',
    307          'showlen': 0,
    308          'groupName': 'labels',
    309          'groupItems': [],
    310          'updateOnToggle': 0}))
    311         scrolllist.append(GetFromClass(Space, {'height': 16}))
    312         scrolllist.append(GetFromClass(ListGroup, {'GetSubContent': self.GetMaillistSubContent,
    313          'label': localization.GetByLabel('UI/Mail/MailingLists'),
    314          'cleanLabel': localization.GetByLabel('UI/Mail/MailingLists'),
    315          'id': ('evemail', 'maillists', localization.GetByLabel('UI/Mail/MailingLists')),
    316          'state': 'locked',
    317          'BlockOpenWindow': 1,
    318          'showicon': 'ui_38_16_190',
    319          'showlen': 0,
    320          'groupName': 'mailinglists',
    321          'groupItems': [],
    322          'updateOnToggle': 0}))
    323         self.sr.leftScroll.Load(contentList=scrolllist)
    324         self.UpdateCounters()
    325 
    326     def UpdateCounters(self):
    327         newMailsInGroups = {'labels': False,
    328          'mailinglists': False}
    329         static = [None,
    330          const.mailLabelInbox,
    331          const.mailLabelSent,
    332          const.mailLabelCorporation,
    333          const.mailLabelAlliance,
    334          MAILLABELTRASH]
    335         unreadCountsForLabels = sm.GetService('mailSvc').GetUnreadCounts().labels
    336         for key in unreadCountsForLabels.iterkeys():
    337             if unreadCountsForLabels.get(key, 0) > 0 and key not in static:
    338                 newMailsInGroups['labels'] = True
    339                 break
    340 
    341         myLists = sm.GetService('mailinglists').GetMyMailingLists()
    342         unreadCountsForLists = sm.GetService('mailSvc').GetUnreadCounts().lists
    343         for key in unreadCountsForLists.iterkeys():
    344             if unreadCountsForLists.get(key, 0) > 0 and key in myLists:
    345                 newMailsInGroups['mailinglists'] = True
    346                 break
    347 
    348         for each in self.sr.leftScroll.GetNodes():
    349             if each.get('currentView', -1) not in [-1, const.mailLabelSent]:
    350                 count = unreadCountsForLabels.get(each.currentView, 0)
    351                 self.TryChangePanelLabel(each, count)
    352             elif each.listID is not None:
    353                 count = unreadCountsForLists.get(each.listID, 0)
    354                 self.TryChangePanelLabel(each, count)
    355             elif each.groupName is not None:
    356                 new = newMailsInGroups.get(each.groupName, False)
    357                 self.TryChangePanelLabel(each, None, forceBold=new)
    358 
    359     def GetStaticLabelsGroups(self):
    360         myLabels = sm.GetService('mailSvc').GetAllLabels()
    361         swatchColors = sm.GetService('mailSvc').GetSwatchColors()
    362         if self.viewingList is not None:
    363             viewingLabel = -100
    364         else:
    365             viewingLabel = self.viewingLabel
    366         scrolllist = []
    367         for label, id, icon in [(localization.GetByLabel('UI/Mail/LabelAllMails'), None, 'ui_73_16_5'),
    368          (localization.GetByLabel('UI/Mail/LabelInbox'), const.mailLabelInbox, 'ui_73_16_6'),
    369          (localization.GetByLabel('UI/Mail/LabelSent'), const.mailLabelSent, 'ui_73_16_7'),
    370          (localization.GetByLabel('UI/Common/Corp'), const.mailLabelCorporation, 'ui_73_16_32'),
    371          (localization.GetByLabel('UI/Common/Groups/Alliance'), const.mailLabelAlliance, 'ui_73_16_31'),
    372          (localization.GetByLabel('UI/Mail/LabelTrash'), MAILLABELTRASH, 'ui_73_16_11')]:
    373             labelInfo = myLabels.get(id, None)
    374             colorID = None
    375             color = 'ffffff'
    376             if labelInfo:
    377                 colorID = labelInfo.get('color', None)
    378                 color = swatchColors.get(colorID, (None, None))
    379                 color = color[0]
    380             if id == MAILLABELTRASH:
    381                 onClickFunction = self.LoadTrashGroup
    382             else:
    383                 onClickFunction = self.LoadLabelGroup
    384             scrolllist.append(GetFromClass(MailGroup, {'GetSubContent': self.GetLeftGroups,
    385              'label': label,
    386              'cleanLabel': label,
    387              'id': ('evemail', id, label),
    388              'state': 'locked',
    389              'BlockOpenWindow': 1,
    390              'disableToggle': 1,
    391              'expandable': 0,
    392              'showicon': icon,
    393              'colorID': colorID,
    394              'color': color,
    395              'showlen': 0,
    396              'groupItems': [],
    397              'hideNoItem': 1,
    398              'hideExpander': 1,
    399              'hideExpanderLine': 1,
    400              'selectGroup': 1,
    401              'OnClick': onClickFunction,
    402              'MenuFunction': self.StaticMenu,
    403              'isSelected': viewingLabel == id,
    404              'currentView': id,
    405              'DropData': self.OnGroupDropData}))
    406 
    407         return scrolllist
    408 
    409     def GetLeftGroups(self, items, *args):
    410         return []
    411 
    412     def GetLabelsSubContent(self, items):
    413         scrolllist = []
    414         myLabels = sm.GetService('mailSvc').GetAllLabels().values()
    415         unreadCounts = sm.GetService('mailSvc').GetUnreadCounts().labels
    416         swatchColors = sm.GetService('mailSvc').GetSwatchColors()
    417         if self.viewingList is not None:
    418             viewingLabel = -100
    419         else:
    420             viewingLabel = self.viewingLabel
    421         for each in myLabels:
    422             if getattr(each, 'static', 0):
    423                 continue
    424             count = unreadCounts.get(each.labelID, 0)
    425             colorID = each.color or 0
    426             scrolllist.append((each.name.lower(), GetFromClass(MailLabelEntry, {'cleanLabel': each.name,
    427               'label': self.GetPanelLabel(each.name, count),
    428               'sublevel': 1,
    429               'currentView': each.labelID,
    430               'OnClick': self.LoadLabelGroup,
    431               'GetMenu': self.GetLabelMenu,
    432               'isSelected': viewingLabel == each.labelID,
    433               'OnDropData': self.OnGroupDropData,
    434               'color': swatchColors.get(colorID, (None, None))[0],
    435               'colorID': colorID})))
    436 
    437         scrolllist = SortListOfTuples(scrolllist)
    438         return scrolllist
    439 
    440     def GetMaillistSubContent(self, *args):
    441         scrolllist = []
    442         myLists = sm.GetService('mailinglists').GetMyMailingLists()
    443         unreadCounts = sm.GetService('mailSvc').GetUnreadCounts().lists
    444         for key, value in myLists.iteritems():
    445             scrolllist.append((value.displayName.lower(), GetFromClass(Generic, {'cleanLabel': value.displayName,
    446               'label': self.GetPanelLabel(value.displayName, unreadCounts.get(key, 0)),
    447               'sublevel': 1,
    448               'GetMenu': self.MaillistMenu,
    449               'isSelected': key == self.viewingList,
    450               'listID': key,
    451               'OnClick': self.LoadMailinglistMails,
    452               'listData': value})))
    453 
    454         scrolllist = SortListOfTuples(scrolllist)
    455         return scrolllist
    456 
    457     def GetMailingListWnd(self, *args):
    458         MailinglistWnd.Open()
    459 
    460     def LeaveMaillist(self, listID, *args):
    461         sm.GetService('mailinglists').LeaveMaillist(listID)
    462 
    463     def DeleteMaillist(self, listID, *args):
    464         mailinglistName = sm.GetService('mailinglists').GetDisplayName(listID)
    465         if prompt_player_fsd_dialog('DeleteMailingList', {'mailinglistName': mailinglistName}, uiconst.YESNO) == uiconst.ID_YES:
    466             sm.GetService('mailinglists').DeleteMaillist(listID)
    467 
    468     def OpenMaillistSetup(self, listID, *args):
    469         windowID = 'MaillistSetupWindow_%s' % listID
    470         from eve.client.script.ui.shared.neocom.evemailingListConfig import MaillistSetupWindow
    471         MaillistSetupWindow.Open(windowID=windowID, mailingListID=listID)
    472 
    473     def SendMailToList(self, listID, *args):
    474         sm.GetService('mailSvc').SendMsgDlg(toListID=listID)
    475 
    476     def SendMailToCorp(self, corpID, *args):
    477         sm.GetService('mailSvc').SendMsgDlg(toCorpOrAllianceID=[corpID])
    478 
    479     def SendMailToAlliance(self, allianceID, *args):
    480         sm.GetService('mailSvc').SendMsgDlg(toCorpOrAllianceID=[allianceID])
    481 
    482     def LoadMailinglistMails(self, entry, *args):
    483         self.startPos = 0
    484         self.viewingList = entry.sr.node.listID
    485         self.viewingLabel = None
    486         self.LoadFromLabelIDOrLabelID(listID=entry.sr.node.listID)
    487 
    488     def MaillistMenu(self, entry):
    489         m = []
    490         listID = entry.sr.node.listID
    491         data = entry.sr.node.listData
    492         if not data.isMuted:
    493             m.append((MenuLabel('UI/Mail/SendMailToList'), self.SendMailToList, (listID,)))
    494         if data.isOperator or data.isOwner:
    495             m.append((MenuLabel('UI/Mail/OpenMailingListMgmt'), self.OpenMaillistSetup, (listID,)))
    496         m.append(None)
    497         name = entry.sr.node.cleanLabel
    498         text = MenuLabel('UI/Mail/MarkAllAsReadWithFolderName', {'folderName': name})
    499         m.append((text, self.MarkAsReadByList, (listID, name)))
    500         text = MenuLabel('UI/Mail/TrashAllWithFolderName', {'folderName': name})
    501         m.append((text, self.MoveToTrashByList, (listID, name)))
    502         m.append(None)
    503         if data.isOwner:
    504             m.append((MenuLabel('UI/Mail/DeleteMailingList'), self.DeleteMaillist, (listID,)))
    505         else:
    506             m.append((MenuLabel('UI/Mail/LeaveMailingList'), self.LeaveMaillist, (listID,)))
    507         return m
    508 
    509     def GetLabelMenu(self, entry):
    510         labelID = entry.sr.node.currentView
    511         m = []
    512         m.append((MenuLabel('UI/Mail/AssignColor'), self.GetAssignColorWnd, (labelID,)))
    513         m.append((MenuLabel('UI/Mail/LabelRename'), sm.GetService('mailSvc').RenameLabelFromUI, (labelID,)))
    514         m.append(None)
    515         text = MenuLabel('UI/Mail/MarkAllAsReadWithFolderName', {'folderName': entry.sr.node.cleanLabel})
    516         m.append((text, self.MarkAsReadByLabel, (labelID, entry.sr.node.cleanLabel)))
    517         text = MenuLabel('UI/Mail/TrashAllWithFolderName', {'folderName': entry.sr.node.cleanLabel})
    518         m.append((text, self.MoveToTrashByLabel, (labelID, entry.sr.node.cleanLabel)))
    519         m.append(None)
    520         m.append((MenuLabel('UI/Common/Delete'), sm.GetService('mailSvc').DeleteLabelFromUI, (labelID, entry.sr.node.label)))
    521         return m
    522 
    523     def GetAssignColorWnd(self, labelID):
    524         blue.pyos.synchro.Yield()
    525         doneCallBack = sm.StartService('mailSvc').ChangeLabelColorFromUI
    526         doneArgs = (labelID,)
    527         sm.GetService('mailSvc').GetAssignColorWnd(labelID, doneCallBack=doneCallBack, doneArgs=doneArgs)
    528 
    529     def CheckLabelName(self, dict, *args):
    530         name = dict.get('name', '').strip()
    531         myLabelNames = [ label.name for label in sm.GetService('mailSvc').GetAllLabels(assignable=0).values() ]
    532         if name in myLabelNames:
    533             return localization.GetByLabel('UI/Mail/LabelNameTaken')
    534 
    535     def LoadLabelGroup(self, entry):
    536         self.startPos = 0
    537         self.viewingLabel = entry.sr.node.currentView
    538         self.viewingList = None
    539         entry.label = entry.sr.node.label
    540         self.LoadFromLabelIDOrLabelID(labelID=entry.sr.node.currentView)
    541 
    542     def LoadTrashGroup(self, entry):
    543         self.startPos = 0
    544         self.viewingLabel = entry.sr.node.currentView
    545         self.viewingList = None
    546         self.LoadFromLabelIDOrLabelID(labelID=MAILLABELTRASH)
    547 
    548     def ReloadAll(self, *args):
    549         self.LoadLeftSide()
    550         self.ReloadMails()
    551 
    552     def ReloadMails(self, refreshing = 0):
    553         labelID = self.viewingLabel
    554         listID = self.viewingList
    555         self.LoadFromLabelIDOrLabelID(labelID=labelID, listID=listID, refreshing=refreshing)
    556 
    557     def LoadFromLabelIDOrLabelID(self, labelID = None, listID = None, refreshing = 0):
    558         mailInfo = self.GetMailInfo(labelID, listID)
    559         self.LoadMails(mails=mailInfo.sorted, labelID=labelID, refreshing=refreshing, totalNum=mailInfo.totalNum)
    560         self.UpdateCounters()
    561 
    562     def GetMailInfo(self, labelID = None, listID = None):
    563         mailSettings = sm.GetService('mailSvc').GetMailSettings()
    564         numMails = max(1, mailSettings.GetSingleValue(cSettings.MAILS_PER_PAGE, DEFAULTNUMMAILS))
    565         if labelID == MAILLABELTRASH:
    566             mailInfo = sm.GetService('mailSvc').GetTrashedMails(orderBy=self.sortBy, ascending=self.sortOrder, pos=self.startPos, count=numMails)
    567         elif listID is not None:
    568             mailInfo = sm.GetService('mailSvc').GetMailsByLabelOrListID(listID=listID, orderBy=self.sortBy, ascending=self.sortOrder, pos=self.startPos, count=numMails)
    569         else:
    570             mailInfo = sm.GetService('mailSvc').GetMailsByLabelOrListID(labelID=labelID, orderBy=self.sortBy, ascending=self.sortOrder, pos=self.startPos, count=numMails)
    571         return mailInfo
    572 
    573     def LoadMails(self, mails = [], labelID = None, refreshing = 0, totalNum = None):
    574         sel = self.sr.msgScroll.GetSelected()
    575         selIDs = [ msg.messageID for msg in sel ]
    576         pos = self.sr.msgScroll.GetScrollProportion()
    577         scrolllist = []
    578         myLabels = sm.GetService('mailSvc').GetAllLabels(assignable=0)
    579         for info in mails:
    580             entry = self.GetMsgEntry(info, labelID, selIDs, myLabels, refreshing)
    581             scrolllist.append(entry)
    582 
    583         self.sr.msgScroll.labelID = labelID
    584         scrollHeaders = [localization.GetByLabel('UI/Mail/Status'),
    585          localization.GetByLabel('UI/Mail/Sender'),
    586          localization.GetByLabel('UI/Mail/Subject'),
    587          localization.GetByLabel('UI/Mail/Received'),
    588          localization.GetByLabel('UI/Mail/Labels')]
    589         self.sr.msgScroll.Load(contentList=scrolllist, headers=scrollHeaders, noContentHint=localization.GetByLabel('UI/Mail/NoMailsFound'), ignoreSort=1, reversesort=self.sortOrder, sortby=self.sortBy)
    590         if not refreshing:
    591             self.ClearReadingPane()
    592         else:
    593             self.sr.msgScroll.ScrollToProportion(pos)
    594         if totalNum is not None:
    595             self.ShowHideBrowse(totalNum)
    596         self.ShowHideToolbarButtons()
    597 
    598     def RefreshMsgScrollHeaders(self, headers, tabs = []):
    599         eveScroll.Scroll.DrawHeaders(self.sr.msgScroll, headers, tabs)
    600         labelID = getattr(self.sr.msgScroll, 'labelID', None)
    601         senderColumn = self.sr.msgScroll.FindChild(localization.GetByLabel('UI/Mail/Sender'))
    602         if senderColumn is not None:
    603             if labelID == const.mailLabelSent:
    604                 text = localization.GetByLabel('UI/Mail/Recipient')
    605             else:
    606                 text = localization.GetByLabel('UI/Mail/Sender')
    607             senderColumn.set_label(text)
    608         dateColumn = self.sr.msgScroll.FindChild(localization.GetByLabel('UI/Mail/Received'))
    609         if dateColumn is not None:
    610             if labelID == const.mailLabelSent:
    611                 text = localization.GetByLabel('UI/Mail/DateSent')
    612             else:
    613                 text = localization.GetByLabel('UI/Mail/Received')
    614             dateColumn.set_label(text)
    615 
    616     def GetMsgEntry(self, info, labelID, selIDs, myLabels, refreshing = 0):
    617         labels = self.GetLabelText(info.labels, myLabels)
    618         date = FmtDate(info.sentDate, 'ls')
    619         if labelID == const.mailLabelSent:
    620             name = sm.GetService('mailSvc').GetRecipient(info, getName=1)
    621         else:
    622             name = info.senderName
    623         label = '<t>'.join(('',
    624          name,
    625          info.subject,
    626          date,
    627          labels))
    628         entry = GetFromClass(MailEntry, {'messageID': info.messageID,
    629          'data': info.copy(),
    630          'currentView': labelID,
    631          'OnClick': self.LoadReadingPaneFromEntry,
    632          'OnDblClick': self.DblMailClickEntry,
    633          'GetMenu': self.GetMsgMenu,
    634          'ignoreRightClick': 1,
    635          'isSelected': refreshing and info.messageID in selIDs,
    636          'id': info.messageID,
    637          'name': name,
    638          'label': label,
    639          'cleanLabel': label})
    640         return entry
    641 
    642     def GetLabelText(self, labels, myLabels):
    643         labelText = ''
    644         labelNames = []
    645         swatchColors = sm.GetService('mailSvc').GetSwatchColors()
    646         for labelID in labels:
    647             label = myLabels.get(labelID, None)
    648             if label is not None:
    649                 labelNames.append((label.name, label.color))
    650 
    651         labelNames.sort()
    652         for each, colorID in labelNames:
    653             if colorID is None or colorID not in swatchColors:
    654                 colorID = 0
    655             color = swatchColors.get(colorID)[0]
    656             labelText += '<color=0xBF%s>%s</color>, ' % (color, each)
    657 
    658         labelText = labelText[:-2]
    659         return labelText
    660 
    661     def ShowHideBrowse(self, totalNum):
    662         btnDisplayed = 0
    663         if self.startPos == 0:
    664             self.backBtn.state = uiconst.UI_HIDDEN
    665         else:
    666             self.backBtn.state = uiconst.UI_NORMAL
    667             btnDisplayed = 1
    668         mailSettings = sm.GetService('mailSvc').GetMailSettings()
    669         numMails = max(1, mailSettings.GetSingleValue(cSettings.MAILS_PER_PAGE, DEFAULTNUMMAILS))
    670         if self.startPos + numMails >= totalNum:
    671             self.fwdBtn.state = uiconst.UI_HIDDEN
    672         else:
    673             self.fwdBtn.state = uiconst.UI_NORMAL
    674             btnDisplayed = 1
    675         if btnDisplayed:
    676             numPages = int(math.ceil(totalNum / float(numMails)))
    677             currentPage = self.startPos / numMails + 1
    678             self.pageCountLabel.text = '%s/%s' % (currentPage, numPages)
    679         else:
    680             self.pageCountLabel.text = ''
    681 
    682     def ClearReadingPane(self):
    683         self.sr.readingPane.SetText('')
    684         self.viewing = None
    685 
    686     def ChangeReadingPaneVisiblity(self, *args):
    687         if self.readingPaneVisible is True:
    688             self.SetReadingPaneVisibility(on=False)
    689         else:
    690             self.SetReadingPaneVisibility(on=True)
    691         settings.user.ui.Set('mail_readingPaneVisible', self.readingPaneVisible)
    692 
    693     def SetReadingPaneVisibility(self, on = True):
    694         if on:
    695             self.readingPaneVisible = True
    696             self.sr.expander.hint = localization.GetByLabel('UI/Mail/HideReadingPane')
    697             self.sr.expander.texturePath = 'res:/UI/Texture/Shared/expanderDown.png'
    698             sel = self.sr.msgScroll.GetSelected()
    699             if len(sel) > 0:
    700                 self.viewing = sel[0]
    701             self.ShowHideReadingPane(show=1)
    702             if self.viewing is not None:
    703                 self.LoadReadingPane(self.viewing)
    704         else:
    705             self.readingPaneVisible = False
    706             self.sr.expander.hint = localization.GetByLabel('UI/Mail/ShowReadingPane')
    707             self.sr.expander.texturePath = 'res:/UI/Texture/Shared/expanderUp.png'
    708             self.ShowHideReadingPane(show=0)
    709 
    710     def ShowHideReadingPane(self, show):
    711         if show:
    712             self.sr.readingPaneCont.state = uiconst.UI_PICKCHILDREN
    713             self.sr.readingPane._OnResize()
    714         else:
    715             self.sr.readingPaneCont.state = uiconst.UI_HIDDEN
    716 
    717     def OpenMailSettings(self, *args):
    718         MailSettings.Open()
    719 
    720     def DblMailClickEntry(self, entry):
    721         if not entry or entry.destroyed:
    722             return
    723         node = entry.sr.node
    724         sm.GetService('mailSvc').OnOpenPopupMail(node.data)
    725         mail = sm.GetService('mailSvc').GetMailByID(node.messageID)
    726         if self and not self.destroyed:
    727             self.TryReloadNode(node, mail)
    728 
    729     def LoadReadingPaneFromEntry(self, entry):
    730         self.ShowHideReadingPane(show=self.readingPaneVisible)
    731         uthread.new(self.LoadReadingPaneFromNode, entry.sr.node)
    732 
    733     def LoadReadingPaneFromNode(self, node):
    734         shift = uicore.uilib.Key(uiconst.VK_SHIFT)
    735         if not shift:
    736             self.LoadReadingPane(node)
    737 
    738     def LoadReadingPane(self, node):
    739         self.readTimer = 0
    740         if node not in self.sr.msgScroll.GetNodes():
    741             return
    742         if self.sr.readingPaneCont.state != uiconst.UI_HIDDEN:
    743             txt = sm.GetService('mailSvc').GetMailText(node.data)
    744             self.sr.readingPane.SetText(txt)
    745             self.viewing = node.messageID
    746             if not node.data.read:
    747                 mail = sm.GetService('mailSvc').GetMailByID(node.messageID)
    748                 if self and not self.destroyed:
    749                     self.TryReloadNode(node, mail)
    750 
    751     def OnMailStatusUpdate(self, replyTo, forwardedFrom, forcedIDs = []):
    752         if not self.inited:
    753             return
    754         mailList = forcedIDs[:]
    755         if replyTo:
    756             mailList.append(replyTo)
    757         if forwardedFrom:
    758             mailList.append(forwardedFrom)
    759         self.RefreshEntriesFromIDs(mailList)
    760 
    761     def RefreshEntriesFromIDs(self, mailIDs):
    762         nodes = []
    763         for node in self.sr.msgScroll.GetNodes():
    764             if node.messageID in mailIDs:
    765                 nodes.append(node)
    766 
    767         self.RefreshEntries(mailIDs, nodes)
    768 
    769     def RefreshEntries(self, mailIDs, nodes):
    770         mails = sm.GetService('mailSvc').GetMailsByIDs(mailIDs)
    771         for node in nodes:
    772             mailData = mails.get(node.messageID, None)
    773             if mailData is not None:
    774                 self.TryReloadNode(node, mailData)
    775 
    776     def TryReloadNode(self, node, data):
    777         node.data = data.copy()
    778         panel = node.Get('panel', None)
    779         if panel is None:
    780             return
    781         panel.LoadMailEntry(node)
    782 
    783     def RefreshLabels(self, nodes, mailIDs):
    784         myLabels = sm.GetService('mailSvc').GetAllLabels(assignable=0)
    785         mails = sm.GetService('mailSvc').GetMailsByIDs(mailIDs)
    786         nodesToRemove = {}
    787         for node in nodes:
    788             mailData = mails.get(node.messageID, None)
    789             if mailData is not None:
    790                 shouldRemove = self.RefreshLabel(node, mailData, myLabels)
    791                 if shouldRemove:
    792                     nodesToRemove[node.messageID] = node
    793 
    794         if len(nodesToRemove) > 0:
    795             self.GoRemoveEntries(nodesToRemove.values(), nodesToRemove.keys())
    796 
    797     def RefreshLabel(self, node, data, myLabels):
    798         if node.currentView is not None and node.currentView not in data.labels + [MAILLABELTRASH]:
    799             return True
    800         node.data = data.copy()
    801         labelText = self.GetLabelText(data.labels, myLabels)
    802         date = FmtDate(node.data.sentDate, 'ls')
    803         node.cleanLabel = '<t>'.join(('',
    804          node.name,
    805          node.data.subject,
    806          date,
    807          labelText))
    808         panel = node.Get('panel', None)
    809         if panel is None:
    810             return
    811         panel.UpdateLabel(data)
    812         return False
    813 
    814     def MsgScrollSelectionChange(self, sel = [], *args):
    815         self.ShowHideToolbarButtons(sel=sel)
    816         if len(sel) == 0:
    817             return
    818         node = sel[0]
    819         if self.viewing != node.messageID:
    820             self.readTimer = timerstuff.AutoTimer(1000, self.LoadReadingPane, node)
    821 
    822     def ShowHideToolbarButtons(self, sel = []):
    823         if len(sel) < 1:
    824             sel = self.sr.msgScroll.GetSelected()
    825         numSelected = len(sel)
    826         showDelete = self.viewingLabel == MAILLABELTRASH
    827         if numSelected == 0:
    828             self.mailActions.SetDeleteVisibility(disabled=1, showDelete=showDelete)
    829         else:
    830             self.mailActions.SetDeleteVisibility(disabled=0, showDelete=showDelete)
    831         if numSelected == 1:
    832             if sel[0].data.statusMask & const.mailStatusMaskAutomated == const.mailStatusMaskAutomated:
    833                 self.mailActions.SingleMsgBtnStateAllowFwd()
    834             else:
    835                 self.mailActions.SingleMsgBtnsState(disabled=0)
    836         else:
    837             self.mailActions.SingleMsgBtnsState(disabled=1)
    838 
    839     def SortMail(self, by = None, reversesort = 0, forceHilite = 0):
    840         scroll = self.sr.msgScroll
    841         if by == localization.GetByLabel('UI/Mail/Labels'):
    842             return
    843         self.sortBy = by
    844         self.sortOrder = reversesort
    845         settings.user.ui.Set('evemail_sortBy', by)
    846         settings.user.ui.Set('evemail_sortOrder', reversesort)
    847         self.startPos = 0
    848         self.ReloadMails()
    849         if scroll.sr.sortBy != by or forceHilite:
    850             scroll.HiliteSorted(by, reversesort)
    851             scroll.sr.sortBy = by
    852 
    853     def GetMsgMenu(self, entry, *args):
    854         trashed = entry.sr.node.data.trashed
    855         sel = self.sr.msgScroll.GetSelected()
    856         selIDs = [ x.id for x in sel ]
    857         msgID = entry.sr.node.messageID
    858         if msgID not in selIDs:
    859             selIDs = [msgID]
    860             sel = [entry.sr.node]
    861         m = []
    862         readMails = {}
    863         unreadMails = {}
    864         for mail in sel:
    865             if mail.data.read:
    866                 readMails[mail.id] = mail
    867             else:
    868                 unreadMails[mail.id] = mail
    869 
    870         if len(readMails) > 0:
    871             m.append((MenuLabel('UI/Mail/MarkAsUnread'), self.MarkAsUnread, (readMails.keys(), readMails.values())))
    872         if len(unreadMails) > 0:
    873             m.append((MenuLabel('UI/Mail/MarkAsRead'), self.MarkAsRead, (unreadMails.keys(), unreadMails.values())))
    874         if trashed:
    875             m.append(None)
    876             m.append((MenuLabel('UI/Mail/Restore'), self.RestoreMail, (sel, selIDs)))
    877             m.append(None)
    878             if len(sel) == 1:
    879                 m += self.GetSenderMenu(sel[0])
    880             m.append((MenuLabel('UI/Mail/Delete'), self.DeleteMail, (sel, selIDs)))
    881         else:
    882             assignLabelMenu = self.GetAssignLabelMenu(sel, selIDs)
    883             if len(assignLabelMenu) > 0:
    884                 m.append((MenuLabel('UI/Mail/AssignLabel'), assignLabelMenu))
    885             removeLabelMenu = self.GetRemoveLabelMenu(sel, selIDs)
    886             if len(removeLabelMenu) > 0:
    887                 m.append((MenuLabel('UI/Mail/LabelRemove'), removeLabelMenu))
    888             m.append(None)
    889             if len(sel) == 1:
    890                 m += self.GetSenderMenu(sel[0])
    891             m.append((MenuLabel('UI/Mail/Trash'), self.TrashMail, (sel, selIDs)))
    892         if session.role & ROLE_GML:
    893             m.append(('GM: MessageID=%s' % msgID, blue.pyos.SetClipboardData, (msgID,)))
    894         return m
    895 
    896     def GetSenderMenu(self, node):
    897         charMenu = []
    898         m = []
    899         itemID = None
    900         typeID = None
    901         text = localization.GetByLabel('UI/Common/Character')
    902         if node.data.statusMask & const.mailStatusMaskAutomated == const.mailStatusMaskAutomated:
    903             return m
    904         if node.currentView == const.mailLabelSent:
    905             recipient = sm.GetService('mailSvc').GetRecipient(node.data, getName=0)
    906             if recipient > 0:
    907                 itemID = recipient
    908                 if idCheckers.IsCharacter(itemID):
    909                     typeID = const.typeCharacter
    910                 elif idCheckers.IsCorporation(itemID):
    911                     typeID = const.typeCorporation
    912                     text = localization.GetByLabel('UI/Common/Corporation')
    913                 elif idCheckers.IsAlliance(itemID):
    914                     typeID = const.typeAlliance
    915                     text = localization.GetByLabel('UI/Common/Alliance')
    916         else:
    917             itemID = node.data.senderID
    918             typeID = const.typeCharacter
    919         if itemID:
    920             charMenu = GetMenuService().GetMenuFromItemIDTypeID(itemID, typeID)
    921         if len(charMenu):
    922             m.append((text, charMenu))
    923             m.append(None)
    924         return m
    925 
    926     def GetAssignLabelMenu(self, sel, selIDs, *args):
    927         m = []
    928         myLabels = sm.GetService('mailSvc').GetAllLabels(assignable=1).values()
    929         labelMask = const.maxInt
    930         for node in sel:
    931             labelMask = labelMask & node.data.labelMask
    932 
    933         for each in myLabels:
    934             labelID = each.labelID
    935             if labelMask & labelID == labelID:
    936                 continue
    937             label = each.name
    938             static = getattr(each, 'static', 0)
    939             if static:
    940                 label = '  %s' % each.labelID
    941             m.append((label.lower(), (each.name, self.AssignLabelFromMenu, (sel,
    942                selIDs,
    943                each.labelID,
    944                each.name))))
    945 
    946         m = SortListOfTuples(m)
    947         return m
    948 
    949     def GetRemoveLabelMenu(self, sel, selIDs, *args):
    950         m = []
    951         myLabels = sm.GetService('mailSvc').GetAllLabels(assignable=1).values()
    952         labelMask = 0
    953         for node in sel:
    954             labelMask = labelMask | node.data.labelMask
    955 
    956         for each in myLabels:
    957             labelID = each.labelID
    958             if labelMask & labelID != labelID:
    959                 continue
    960             label = each.name
    961             static = getattr(each, 'static', 0)
    962             if static:
    963                 label = '  %s' % labelID
    964             m.append((label.lower(), (each.name, self.RemoveLabelFromMenu, (sel,
    965                selIDs,
    966                each.labelID,
    967                each.name))))
    968 
    969         m = SortListOfTuples(m)
    970         return m
    971 
    972     def AssignLabelFromMenu(self, sel, selIDs, labelID, labelName):
    973         self.AssignLabelFromMailWnd(sel, selIDs, labelID)
    974         text = localization.GetByLabel('UI/Mail/LabelAssigned', labelName=labelName, numMails=len(selIDs))
    975         prompt_player_fsd_dialog('CustomNotify', {'notify': text})
    976 
    977     def AssignLabelFromMailWnd(self, sel, selIDs, labelID):
    978         sm.StartService('mailSvc').AssignLabels(selIDs, labelID)
    979         self.RefreshLabels(sel, selIDs)
    980 
    981     def RemoveLabelFromMenu(self, sel, selIDs, labelID, labelName):
    982         sm.StartService('mailSvc').RemoveLabels(selIDs, labelID)
    983         text = localization.GetByLabel('UI/Mail/LabelRemoved', labelName=labelName, numMails=len(selIDs))
    984         prompt_player_fsd_dialog('CustomNotify', {'notify': text})
    985         self.RefreshLabels(sel, selIDs)
    986 
    987     def TrashMail(self, mails, mailIDs):
    988         sm.GetService('mailSvc').MoveMessagesToTrash(mailIDs)
    989         self.GoRemoveEntries(mails, mailIDs)
    990         sm.ScatterEvent('OnMessageChanged', const.mailTypeMail, mailIDs, 'trashed')
    991         self.UpdateCounters()
    992 
    993     def DeleteMail(self, mails, mailIDs):
    994         sm.GetService('mailSvc').DeleteMails(mailIDs)
    995         self.GoRemoveEntries(mails, mailIDs)
    996         sm.ScatterEvent('OnMessageChanged', const.mailTypeMail, mailIDs, 'deleted')
    997 
    998     def RestoreMail(self, mails, mailIDs):
    999         sm.GetService('mailSvc').MoveMessagesFromTrash(mailIDs)
   1000         self.GoRemoveEntries(mails, mailIDs)
   1001 
   1002     def MarkAsUnread(self, mailIDs, mails):
   1003         sm.GetService('mailSvc').MarkMessagesAsUnread(mailIDs)
   1004         self.RefreshEntries(mailIDs, mails)
   1005 
   1006     def MarkAsRead(self, mailIDs, mails, *args):
   1007         sm.GetService('mailSvc').MarkMessagesAsRead(mailIDs)
   1008         self.RefreshEntries(mailIDs, mails)
   1009 
   1010     def LabelGroupMenu(self, entry, *args):
   1011         m = []
   1012         m.append((MenuLabel('UI/Mail/ManageLabels'), self.ManageLabels))
   1013         return m
   1014 
   1015     def StaticMenu(self, entry, *args):
   1016         currentView = entry.currentView
   1017         m = []
   1018         if currentView == const.mailLabelCorporation and not idCheckers.IsNPC(session.corpid):
   1019             m.append((MenuLabel('UI/Mail/SendMailToCorp'), self.SendMailToCorp, (session.corpid,)))
   1020         elif currentView == const.mailLabelAlliance and session.allianceid is not None and session.corprole & const.corpRoleChatManager == const.corpRoleChatManager:
   1021             m.append((MenuLabel('UI/Mail/SendMailToAlliance'), self.SendMailToAlliance, (session.allianceid,)))
   1022         if currentView is None:
   1023             text = MenuLabel('UI/Mail/MarkAllAsReadWithFolderName', {'folderName': localization.GetByLabel('UI/Common/All')})
   1024             m.append((text, self.MarkAllAsRead, ()))
   1025             text = MenuLabel('UI/Mail/TrashAllWithFolderName', {'folderName': localization.GetByLabel('UI/Common/All')})
   1026             m.append((text, self.MoveAllToTrash, ()))
   1027         elif currentView == MAILLABELTRASH:
   1028             m.append((MenuLabel('UI/Mail/RestoreAll'), self.MoveAllFromTrash, ()))
   1029             m.append((MenuLabel('UI/Mail/EmptyTrash'), self.EmptyTrash, ()))
   1030         else:
   1031             m.append((MenuLabel('UI/Mail/AssignColor'), self.GetAssignColorWnd, (entry.currentView,)))
   1032             m.append(None)
   1033             text = MenuLabel('UI/Mail/MarkAllAsReadWithFolderName', {'folderName': entry.cleanLabel})
   1034             m.append((text, self.MarkAsReadByLabel, (entry.currentView, entry.cleanLabel)))
   1035             text = MenuLabel('UI/Mail/TrashAllWithFolderName', {'folderName': entry.cleanLabel})
   1036             m.append((text, self.MoveToTrashByLabel, (entry.currentView, entry.cleanLabel)))
   1037         return m
   1038 
   1039     def MarkAllAsRead(self, *args):
   1040         if prompt_player_fsd_dialog('EvemailMailMarkAllRead', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1041             sm.GetService('mailSvc').MarkAllAsRead()
   1042             self.ReloadAll()
   1043 
   1044     def MoveAllToTrash(self, *args):
   1045         if prompt_player_fsd_dialog('EvemailMailTrashAll', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1046             sm.GetService('mailSvc').MoveAllToTrash()
   1047             self.ReloadAll()
   1048 
   1049     def MoveAllFromTrash(self, *args):
   1050         if prompt_player_fsd_dialog('EvemailMailRestoreAll', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1051             sm.GetService('mailSvc').MoveAllFromTrash()
   1052             self.ReloadAll()
   1053 
   1054     def EmptyTrash(self, *args):
   1055         if prompt_player_fsd_dialog('EvemailMaillDeleteAll', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1056             sm.GetService('mailSvc').EmptyTrash()
   1057             self.ReloadAll()
   1058 
   1059     def MarkAsReadByLabel(self, labelID, name, *args):
   1060         if prompt_player_fsd_dialog('EvemailMailReadLabelGroup', {'labelName': name}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1061             sm.GetService('mailSvc').MarkAsReadByLabel(labelID)
   1062             self.ReloadAll()
   1063 
   1064     def MarkAsReadByList(self, listID, name, *args):
   1065         if prompt_player_fsd_dialog('EvemailMailReadMailinglistGroup', {'listName': name}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1066             sm.GetService('mailSvc').MarkAsReadByList(listID)
   1067             self.ReloadAll()
   1068 
   1069     def MoveToTrashByLabel(self, labelID, name, *args):
   1070         if prompt_player_fsd_dialog('EvemailMailTrashLabelGroup', {'labelName': name}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1071             sm.GetService('mailSvc').MoveToTrashByLabel(labelID)
   1072             self.ReloadAll()
   1073 
   1074     def MoveToTrashByList(self, listID, name, *args):
   1075         if prompt_player_fsd_dialog('EvemailMailTrashMailinglistGroup', {'listName': name}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
   1076             sm.GetService('mailSvc').MoveToTrashByList(listID)
   1077             self.ReloadAll()
   1078 
   1079     def GoRemoveEntries(self, nodes, mailIDs):
   1080         if getattr(self, 'removingEntries', 0):
   1081             return
   1082         self.removingEntries = 1
   1083         pos = self.sr.msgScroll.GetScrollProportion()
   1084         self.sr.msgScroll.RemoveEntries(nodes)
   1085         if self.viewing in mailIDs:
   1086             self.ClearReadingPane()
   1087         mailInfo = self.GetMailInfo(labelID=self.viewingLabel, listID=self.viewingList)
   1088         mails = mailInfo.sorted
   1089         mailsInScroll = [ msg.id for msg in self.sr.msgScroll.GetNodes() ]
   1090         mailsToAdd = []
   1091         for info in mails:
   1092             if info.messageID not in mailsInScroll:
   1093                 mailsToAdd.append(info)
   1094 
   1095         if len(mailsToAdd) < 1:
   1096             self.removingEntries = 0
   1097             if len(self.sr.msgScroll.GetNodes()) < 1:
   1098                 self.BrowseMail(-1)
   1099             return
   1100         myLabels = sm.GetService('mailSvc').GetAllLabels(assignable=0)
   1101         entriesToAdd = []
   1102         for each in mailsToAdd:
   1103             entry = self.GetMsgEntry(each, self.viewingLabel, [], myLabels, 0)
   1104             entriesToAdd.append(entry)
   1105 
   1106         self.sr.msgScroll.AddEntries(-1, entriesToAdd, ignoreSort=1)
   1107         self.sr.msgScroll.ScrollToProportion(pos)
   1108         self.ShowHideBrowse(mailInfo.totalNum)
   1109         self.removingEntries = 0
   1110 
   1111     def ComposeClicked(self, *args):
   1112         PlaySound(uiconst.SOUND_BUTTON_CLICK)
   1113         bannedwords.check_chat_character_allowed(session.charid)
   1114         self.CheckInited()
   1115         sm.GetService('mailSvc').SendMsgDlg()
   1116 
   1117     def ReplyClicked(self, *args):
   1118         PlaySound(uiconst.SOUND_BUTTON_CLICK)
   1119         bannedwords.check_chat_character_allowed(session.charid)
   1120         self.CheckInited()
   1121         self.Reply(all=0)
   1122 
   1123     def ForwardClicked(self, *args):
   1124         PlaySound(uiconst.SOUND_BUTTON_CLICK)
   1125         bannedwords.check_chat_character_allowed(session.charid)
   1126         self.CheckInited()
   1127         sel = self.sr.msgScroll.GetSelected()
   1128         if len(sel) < 1:
   1129             return
   1130         msg = sel[0]
   1131         sm.GetService('mailSvc').GetForwardWnd(msg.data)
   1132 
   1133     def ReplyAllClicked(self, *args):
   1134         PlaySound(uiconst.SOUND_BUTTON_CLICK)
   1135         bannedwords.check_chat_character_allowed(session.charid)
   1136         self.CheckInited()
   1137         self.Reply(all=1)
   1138 
   1139     def DeleteFromKeyboard(self, *args):
   1140         self.CheckInited()
   1141         delete = self.viewingLabel == MAILLABELTRASH
   1142         if blue.os.GetWallclockTime() - self.lastDeleted < DELETE_INTERVAL:
   1143             prompt_player_fsd_dialog('uiwarning03')
   1144             return
   1145         if delete:
   1146             self.DeleteClicked()
   1147         else:
   1148             self.TrashClicked()
   1149         self.UpdateCounters()
   1150         self.lastDeleted = blue.os.GetWallclockTime()
   1151 
   1152     def TrashClicked(self, *args):
   1153         PlaySound(uiconst.SOUND_BUTTON_CLICK)
   1154         self.CheckInited()
   1155         self.TrashDeleteFunctionality('trashed')
   1156 
   1157     def DeleteClicked(self, *args):
   1158         PlaySound(uiconst.SOUND_BUTTON_CLICK)
   1159         self.CheckInited()
   1160         self.TrashDeleteFunctionality('deleted')
   1161 
   1162     def TrashDeleteFunctionality(self, what):
   1163         selected = self.sr.msgScroll.GetSelected()
   1164         if len(selected) < 1:
   1165             return
   1166         idx = selected[0].idx
   1167         messageIDs = [ mail.messageID for mail in selected ]
   1168         if what == 'trashed':
   1169             self.TrashMail(selected, messageIDs)
   1170         elif what == 'deleted':
   1171             self.DeleteMail(selected, messageIDs)
   1172         numChildren = len(self.sr.msgScroll.GetNodes())
   1173         newIdx = min(idx, numChildren - 1)
   1174         newSelectedNode = self.sr.msgScroll.GetNode(newIdx)
   1175         if newSelectedNode is not None:
   1176             self.sr.msgScroll.SelectNode(newSelectedNode)
   1177 
   1178     def ManageLabels(self, *args):
   1179         PlaySound(uiconst.SOUND_BUTTON_CLICK)
   1180         self.CheckInited()
   1181         ManageLabelsExistingMails.Open()
   1182 
   1183     def BrowseMail(self, backforth, *args):
   1184         mailSettings = sm.GetService('mailSvc').GetMailSettings()
   1185         numMails = max(1, mailSettings.GetSingleValue(cSettings.MAILS_PER_PAGE, DEFAULTNUMMAILS))
   1186         pos = max(0, self.startPos + numMails * backforth)
   1187         self.startPos = pos
   1188         self.ReloadMails()
   1189 
   1190     def Reply(self, all = 0):
   1191         sel = self.sr.msgScroll.GetSelected()
   1192         if len(sel) < 1:
   1193             return
   1194         msg = sel[0]
   1195         if msg is None:
   1196             return
   1197         sm.GetService('mailSvc').GetReplyWnd(msg.data, all)
   1198 
   1199     def OnMyMaillistChanged(self, *args):
   1200         if not self.inited:
   1201             return
   1202         self.LoadLeftSide()
   1203 
   1204     def OnMyLabelsChanged(self, labelType, created = None, *args):
   1205         if labelType == 'mail_labels':
   1206             if not self.inited:
   1207                 return
   1208             self.ReloadAll()
   1209 
   1210     def OnMailSettingsChanged(self, *args):
   1211         if not self.inited:
   1212             return
   1213         self.startPos = 0
   1214         self.ReloadMails()
   1215 
   1216     def OnNewMailReceived(self, *args):
   1217         if not self.inited:
   1218             return
   1219         self.UpdateCounters()
   1220 
   1221     def OnMailCountersUpdate(self, *args):
   1222         if not self.inited:
   1223             return
   1224         self.UpdateCounters()
   1225 
   1226     def OnMailTrashedDeleted(self, mail, force = 0):
   1227         if not self.inited:
   1228             return
   1229         reload = force
   1230         if not force:
   1231             if self.viewingLabel == MAILLABELTRASH:
   1232                 reload = 1
   1233             elif not mail.trashed:
   1234                 if self.viewingList is not None:
   1235                     if self.viewingList == mail.toListID:
   1236                         reload = 1
   1237                 elif self.viewingLabel is None:
   1238                     reload = 1
   1239                 elif self.viewingLabel in mail.labels:
   1240                     reload = 1
   1241         if reload:
   1242             self.ReloadMails(refreshing=1)
   1243         self.UpdateCounters()
   1244 
   1245     def TryChangePanelLabel(self, node, count, forceBold = False):
   1246         panel = node.Get('panel', None)
   1247         label = self.GetPanelLabel(node.cleanLabel, count, forceBold)
   1248         node.label = label
   1249         if panel is None:
   1250             return
   1251         panelLabel = label
   1252         panel.sr.label.text = panelLabel
   1253         if hasattr(panel, 'UpdateHint'):
   1254             panel.UpdateHint()
   1255 
   1256     def GetPanelLabel(self, label, count, forceBold = False):
   1257         if count > 0:
   1258             return '<b>' + localization.GetByLabel('UI/Mail/FolderLabelWithCount', folderName=label, unreadCount=count) + '</b>'
   1259         elif forceBold:
   1260             return '<b>' + label + '</b>'
   1261         else:
   1262             return label
   1263 
   1264     def OnGroupDropData(self, groupID, nodes, *args):
   1265         what, labelID, labelName = groupID
   1266         shift = uicore.uilib.Key(uiconst.VK_SHIFT)
   1267         if len(nodes) < 1 or nodes[0].__guid__ != 'listentry.MailEntry':
   1268             return
   1269         if labelID is None or labelID == const.mailLabelSent:
   1270             prompt_player_fsd_dialog('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/CannotAssignLabel')})
   1271             return
   1272         currentView = nodes[0].currentView
   1273         allLabels = sm.GetService('mailSvc').GetAllLabels(assignable=0)
   1274         currentName = allLabels.get(currentView, None)
   1275         if currentName is not None:
   1276             currentName = currentName.name
   1277         messageIDs = [ node.messageID for node in nodes ]
   1278         removeText = ''
   1279         if labelID == MAILLABELTRASH:
   1280             if currentView == labelID:
   1281                 return
   1282             self.TrashMail(nodes, messageIDs)
   1283         else:
   1284             if currentView == MAILLABELTRASH:
   1285                 self.RestoreMail(nodes, messageIDs)
   1286             if not shift and currentView:
   1287                 if currentView == labelID:
   1288                     return
   1289                 if currentView not in [MAILLABELTRASH, const.mailLabelSent]:
   1290                     sm.StartService('mailSvc').RemoveLabels(messageIDs, currentView)
   1291                     removeText = localization.GetByLabel('UI/Mail/LabelRemoved', labelName=currentName, numMails=len(messageIDs))
   1292             self.AssignLabelFromMailWnd(nodes, messageIDs, labelID)
   1293             text = localization.GetByLabel('UI/Mail/LabelAssigned', labelName=labelName, numMails=len(messageIDs))
   1294             if removeText:
   1295                 text += '<br>%s' % removeText
   1296             prompt_player_fsd_dialog('CustomNotify', {'notify': text})
   1297 
   1298 
   1299 class MailGroup(Group):
   1300     __guid__ = 'listentry.MailGroup'
   1301 
   1302     def Startup(self, *args):
   1303         Group.Startup(self, args)
   1304         self.sr.colorTag = Container(name='colorTag', parent=self, align=uiconst.CENTERRIGHT, pos=(4, 0, 8, 8), idx=0)
   1305 
   1306     def Load(self, node):
   1307         Group.Load(self, node)
   1308         if node.Get('colorID', None) is not None and node.Get('color', None) is not None:
   1309             import colorsys
   1310             rgb = colorsys.hex_to_rgb(node.color)
   1311             if rgb == WHITE:
   1312                 return
   1313             Fill(parent=self.sr.colorTag, color=rgb, opacity=0.75)
   1314 
   1315 
   1316 class MailEntry(Generic):
   1317     __guid__ = 'listentry.MailEntry'
   1318     isDragObject = True
   1319 
   1320     def Startup(self, *args):
   1321         Generic.Startup(self, args)
   1322         self.sr.statusIcon = Container(name='statusIcon', parent=self, align=uiconst.TOLEFT, pos=(0, 0, 52, 0))
   1323 
   1324     def Load(self, node):
   1325         self.sr.node = node
   1326         Generic.Load(self, node)
   1327         self.LoadMailEntry(node)
   1328 
   1329     def LoadMailEntry(self, node):
   1330         self.sr.statusIcon.Flush()
   1331         iconPath = 'ui_73_16_15'
   1332         hint = localization.GetByLabel('UI/Mail/Read')
   1333         data = node.data
   1334         self.UpdateLabel(data)
   1335         if not data.read:
   1336             iconPath = 'ui_73_16_14'
   1337             hint = localization.GetByLabel('UI/Mail/Unread')
   1338         elif node.Get('showAllStatus', 1):
   1339             if data.Get('replied', 0):
   1340                 iconPath = 'ui_73_16_12'
   1341                 hint = localization.GetByLabel('UI/Mail/Replied')
   1342             elif data.Get('forwarded', 0):
   1343                 iconPath = 'ui_73_16_13'
   1344                 hint = localization.GetByLabel('UI/Mail/Forwarded')
   1345         icon = eveIcon.Icon(icon=iconPath, parent=self.sr.statusIcon, align=uiconst.CENTER, pos=(0, 0, 16, 16), state=uiconst.UI_PICKCHILDREN)
   1346         icon.hint = hint
   1347 
   1348     def GetDragData(self, *args):
   1349         node = self.sr.node
   1350         if node.isNotification:
   1351             return []
   1352         return node.scroll.GetSelectedNodes(node)
   1353 
   1354     def OnDropData(self, dragObj, nodes):
   1355         pass
   1356 
   1357     def UpdateLabel(self, data):
   1358         label = self.sr.node.cleanLabel
   1359         if not data.read:
   1360             label = '<b>' + label + '</b>'
   1361         self.sr.label.text = label
   1362         self.sr.node.label = label
   1363         self.sr.label.Update()
   1364 
   1365 
   1366 class MailLabelEntry(Generic):
   1367     __guid__ = 'listentry.MailLabelEntry'
   1368 
   1369     def Startup(self, *args):
   1370         Generic.Startup(self, args)
   1371         self.sr.colorTag = Container(name='colorTag', parent=self, align=uiconst.CENTERRIGHT, pos=(4, 0, 8, 8), idx=0)
   1372 
   1373     def Load(self, node):
   1374         Generic.Load(self, node)
   1375         self.labelID = self.sr.node.currentView
   1376         self.sr.colorTag.Flush()
   1377         self.sr.label.autoFadeSides = 25
   1378         if node.Get('color', None) is not None:
   1379             import colorsys
   1380             rgb = colorsys.hex_to_rgb(node.color)
   1381             if rgb == WHITE:
   1382                 return
   1383             Fill(parent=self.sr.colorTag, color=rgb, opacity=0.75)
   1384 
   1385     def OnDropData(self, dragObj, nodes):
   1386         data = self.sr.node
   1387         currentView = data.currentView
   1388         if data.OnDropData:
   1389             data.OnDropData(('MailLabelEntry', currentView, data.cleanLabel), nodes)
   1390 
   1391 
   1392 class ManageLabelsBase(Window):
   1393     __guid__ = 'form.ManageLabelsBase'
   1394     __notifyevents__ = ['OnMyLabelsChanged']
   1395     default_iconNum = 'res:/ui/Texture/WindowIcons/evemailtag.png'
   1396     default_minSize = (320, 320)
   1397 
   1398     def ApplyAttributes(self, attributes):
   1399         Window.ApplyAttributes(self, attributes)
   1400         labelType = self.labelType = attributes.labelType
   1401         self.loadingShowcontent = 0
   1402         caption = localization.GetByLabel('UI/Mail/ManageLabels')
   1403         if labelType == 'contact':
   1404             caption = localization.GetByLabel('UI/Mail/ManageLabelsWithType', labelType=localization.GetByLabel('UI/Mail/Contacts'))
   1405         elif labelType == 'corpcontact':
   1406             caption = localization.GetByLabel('UI/Mail/ManageLabelsWithType', labelType=localization.GetByLabel('UI/Mail/CorpContacts'))
   1407         elif labelType == 'alliancecontact':
   1408             caption = localization.GetByLabel('UI/Mail/ManageLabelsWithType', labelType=localization.GetByLabel('UI/Mail/AllianceContacts'))
   1409         self.SetCaption(caption)
   1410         topParent = Container(name='topParent', parent=self.GetMainArea(), align=uiconst.TOTOP, height=60, clipChildren=True)
   1411         self.sr.bottom = Container(name='bottom', parent=self.content, align=uiconst.TOBOTTOM, height=HEIGHT_NORMAL)
   1412         self.sr.inpt = inpt = SingleLineEditText(name='input', parent=topParent, maxLength=const.mailMaxLabelSize, pos=(0, 20, 86, 0), label=localization.GetByLabel('UI/Mail/LabelName'))
   1413         Button(parent=topParent, label=localization.GetByLabel('UI/Mail/Create'), pos=(inpt.left + inpt.width + 4,
   1414          inpt.top,
   1415          0,
   1416          0), func=self.CreateLabel, btn_default=1)
   1417         self.sr.textCont = ContainerAutoSize(name='textCont', parent=self.content, align=uiconst.TOTOP, state=uiconst.UI_HIDDEN, padBottom=2)
   1418         self.sr.textCont2 = ContainerAutoSize(name='textCont', parent=self.content, align=uiconst.TOBOTTOM, state=uiconst.UI_HIDDEN, padBottom=2)
   1419         self.sr.selectedText = eveLabel.EveLabelMedium(text='', parent=self.sr.textCont2, left=0, top=0, state=uiconst.UI_DISABLED, align=uiconst.CENTERTOP)
   1420         self.sr.labelScroll = eveScroll.Scroll(name='labelScroll', parent=self.content, padding=(const.defaultPadding,
   1421          0,
   1422          const.defaultPadding,
   1423          const.defaultPadding))
   1424         self.sr.labelScroll.sr.id = labelType
   1425 
   1426     def FindLabelsChecked(self, *args):
   1427         labelsChecked = []
   1428         for each in self.sr.labelScroll.GetNodes():
   1429             if each.checked == 1:
   1430                 labelsChecked.append(each.retval)
   1431 
   1432         return labelsChecked
   1433 
   1434     def CreateLabel(self, *args):
   1435         labelName = self.sr.inpt.GetValue()
   1436         labelName = labelName.strip()
   1437         existingLabels = []
   1438         for each in self.sr.labelScroll.GetNodes():
   1439             existingLabels.append(each.label.lower())
   1440 
   1441         if labelName.lower() in existingLabels:
   1442             raise UserError('MailLabelNameExists')
   1443         if len(labelName) < 1:
   1444             prompt_player_fsd_dialog('LookupStringMinimum', {'minimum': 1})
   1445             return
   1446         if len(labelName) > const.mailMaxLabelSize:
   1447             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/LabelTooLong')})
   1448         if self.labelType == 'mail_labels':
   1449             wasCreated = sm.GetService('mailSvc').CreateLabel(labelName)
   1450         else:
   1451             sm.GetService('addressbook').CreateContactLabel(labelName)
   1452 
   1453     def LoadScroll(self, *args):
   1454         if self.labelType == 'mail_labels':
   1455             labels = sm.GetService('mailSvc').GetAllLabels(assignable=1).values()
   1456         else:
   1457             labels = sm.GetService('addressbook').GetContactLabels(self.labelType).values()
   1458         scrolllist = []
   1459         for each in labels:
   1460             label = each.name
   1461             static = getattr(each, 'static', 0)
   1462             if static:
   1463                 label = '  %s' % each.labelID
   1464             scrolllist.append((label.lower(), GetFromClass(CheckboxEntry, {'label': each.name,
   1465               'cfgname': each.name,
   1466               'retval': each.labelID,
   1467               'checked': each.labelID in self.storedSelection,
   1468               'OnChange': self.ShowTextHint,
   1469               'GetMenu': self.GetLabelMenu,
   1470               'ignoreRightClick': 1})))
   1471 
   1472         scrolllist = SortListOfTuples(scrolllist)
   1473         self.sr.labelScroll.Load(contentList=scrolllist)
   1474         self.ShowTextHint()
   1475 
   1476     def OnMyLabelsChanged(self, labelType, created = None, *args):
   1477         if labelType == self.labelType:
   1478             self.UpdateLabelsList(created)
   1479 
   1480     def UpdateLabelsList(self, created = None, *args):
   1481         self.storedSelection = self.FindLabelsChecked()
   1482         if created is not None:
   1483             self.storedSelection.append(created)
   1484         self.LoadScroll()
   1485         self.storedSelection = []
   1486 
   1487     def ShowTextHint(self, *args):
   1488         labelsChecked = self.FindLabelsChecked()
   1489         numLabels = len(labelsChecked)
   1490         if numLabels > 0:
   1491             self.sr.selectedText.text = localization.GetByLabel('UI/Mail/LabelsSelected', numSelected=numLabels)
   1492             self.sr.textCont2.state = uiconst.UI_DISABLED
   1493         else:
   1494             self.sr.textCont2.state = uiconst.UI_HIDDEN
   1495 
   1496     def GetLabelMenu(self, entry):
   1497         labelID = entry.sr.node.retval
   1498         m = []
   1499         if self.labelType == 'mail_labels':
   1500             m.append((MenuLabel('UI/Mail/AssignColor'), self.GetAssignColorWnd, (labelID,)))
   1501             if const.mailLabelsSystem & labelID == 0:
   1502                 m.append((MenuLabel('UI/Mail/LabelRename'), sm.GetService('mailSvc').RenameLabelFromUI, (labelID,)))
   1503                 m.append(None)
   1504                 m.append((MenuLabel('UI/Mail/Delete'), sm.GetService('mailSvc').DeleteLabelFromUI, (labelID, entry.sr.node.label)))
   1505         else:
   1506             m.append((MenuLabel('UI/Mail/LabelRename'), sm.GetService('addressbook').RenameContactLabelFromUI, (labelID,)))
   1507             m.append(None)
   1508             m.append((MenuLabel('UI/Mail/Delete'), sm.GetService('addressbook').DeleteContactLabelFromUI, (labelID, entry.sr.node.label)))
   1509         return m
   1510 
   1511     def GetAssignColorWnd(self, labelID):
   1512         blue.pyos.synchro.Yield()
   1513         doneCallBack = sm.StartService('mailSvc').ChangeLabelColorFromUI
   1514         doneArgs = (labelID,)
   1515         sm.GetService('mailSvc').GetAssignColorWnd(labelID, doneCallBack=doneCallBack, doneArgs=doneArgs)
   1516 
   1517 
   1518 class ManageLabelsExistingMails(ManageLabelsBase):
   1519     __guid__ = 'form.ManageLabelsExistingMails'
   1520     default_windowID = 'ManageLabelsExistingMails'
   1521 
   1522     def ApplyAttributes(self, attributes):
   1523         attributes.labelType = 'mail_labels'
   1524         ManageLabelsBase.ApplyAttributes(self, attributes)
   1525         self.storedSelection = []
   1526         self.sr.textCont.state = uiconst.UI_DISABLED
   1527         eveLabel.EveLabelMedium(text=localization.GetByLabel('UI/Mail/LabelText'), parent=self.sr.textCont, padLeft=10, state=uiconst.UI_DISABLED, align=uiconst.TOTOP)
   1528         ButtonGroup(btns=[[localization.GetByLabel('UI/Mail/AssignLabel'),
   1529           self.AssignLabelFromBtn,
   1530           None,
   1531           81], [localization.GetByLabel('UI/Mail/LabelRemove'),
   1532           self.RemoveLabelFromBtn,
   1533           None,
   1534           81]], parent=self.sr.bottom, idx=0)
   1535         self.LoadScroll()
   1536 
   1537     def AssignLabelFromBtn(self, *args):
   1538         self.ManageLabel(assign=1)
   1539 
   1540     def RemoveLabelFromBtn(self, *args):
   1541         self.ManageLabel(assign=0)
   1542 
   1543     def ManageLabel(self, assign = 1):
   1544         labelsChecked = self.FindLabelsChecked()
   1545         numLabels = len(labelsChecked)
   1546         if numLabels < 1:
   1547             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/PeopleAndPlaces/NoLabelsSelected')})
   1548         wnd = MailWindow.GetIfOpen()
   1549         if not wnd:
   1550             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/NoMailsSelected')})
   1551         scroll = wnd.FindChild('msgScroll')
   1552         if scroll is None:
   1553             selectedMails = []
   1554         else:
   1555             selectedMails = scroll.GetSelected()
   1556         mailIDs = [ mail.messageID for mail in selectedMails ]
   1557         sum = 0
   1558         for labelID in labelsChecked:
   1559             sum = sum + labelID
   1560 
   1561         if assign == 1:
   1562             sm.StartService('mailSvc').AssignLabels(mailIDs, sum)
   1563         else:
   1564             sm.StartService('mailSvc').RemoveLabels(mailIDs, sum)
   1565         numLabels = len(labelsChecked)
   1566         numMails = len(mailIDs)
   1567         if numMails > 0:
   1568             if assign:
   1569                 text = localization.GetByLabel('UI/Mail/LabelsAssignedToMails', numLabels=numLabels, numMails=numMails)
   1570             else:
   1571                 text = localization.GetByLabel('UI/Mail/LabelsRemovedFromMails', numLabels=numLabels, numMails=numMails)
   1572             prompt_player_fsd_dialog('CustomNotify', {'notify': text})
   1573             wnd.sr.mail.RefreshLabels(selectedMails, mailIDs)
   1574         else:
   1575             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/NoMailsSelected')})
   1576 
   1577 
   1578 class ManageLabelsNewMails(ManageLabelsBase):
   1579     __guid__ = 'form.ManageLabelsNewMails'
   1580     default_windowID = 'ManageLabelsNewMails'
   1581 
   1582     def ApplyAttributes(self, attributes):
   1583         self.result = None
   1584         attributes.labelType = 'mail_labels'
   1585         ManageLabelsBase.ApplyAttributes(self, attributes)
   1586         labels = attributes.labels
   1587         btns = ButtonGroup(btns=[[localization.GetByLabel('UI/Mail/Apply'),
   1588           self.Apply,
   1589           None,
   1590           81]], parent=self.sr.bottom, idx=0, line=1)
   1591         self.storedSelection = labels
   1592         self.LoadScroll()
   1593 
   1594     def Apply(self, *args):
   1595         labelsChecked = self.FindLabelsChecked()
   1596         if labelsChecked is None or labelsChecked == []:
   1597             if prompt_player_fsd_dialog('NoLabelApplied', {}, uiconst.YESNO, suppress=uiconst.ID_YES) != uiconst.ID_YES:
   1598                 return
   1599         self.result = labelsChecked
   1600         if getattr(self, 'isModal', None):
   1601             self.SetModalResult(1)
   1602 
   1603 
   1604 class NewNewMessage(Window):
   1605     __guid__ = 'form.NewNewMessage'
   1606     __nonpersistvars__ = ['messageedit',
   1607      'buddy',
   1608      'input',
   1609      'receivers']
   1610     default_toCharacterIDs = []
   1611     default_toListID = None
   1612     default_toCorpOrAllianceID = None
   1613     default_isForwardedFrom = False
   1614     default_isReplyTo = False
   1615     default_subject = None
   1616     default_body = None
   1617     default_width = 300
   1618     default_height = 350
   1619     default_minSize = (250, 250)
   1620     default_captionLabelPath = 'UI/Mail/NewMessage'
   1621     default_iconNum = 'res:/ui/Texture/WindowIcons/evemailcompose.png'
   1622 
   1623     def ApplyAttributes(self, attributes):
   1624         super(NewNewMessage, self).ApplyAttributes(attributes)
   1625         toCharacterIDs = attributes.toCharacterIDs or self.default_toCharacterIDs
   1626         toListID = attributes.toListID
   1627         toCorpOrAllianceID = attributes.toCorpOrAllianceID
   1628         isForwardedFrom = attributes.isForwardedFrom or self.default_isForwardedFrom
   1629         isReplyTo = attributes.isReplyTo or self.default_isReplyTo
   1630         subject = attributes.subject
   1631         body = attributes.body
   1632         self.messageedit = None
   1633         self.parsingReceivers = 0
   1634         self.labels = []
   1635         self.toChars = {}
   1636         self.toCorpAlliance = {}
   1637         self.toListID = None
   1638         self.isForwardedFrom = 0
   1639         self.isReplyTo = 0
   1640         self.buddies = []
   1641         self.isForwardedFrom = isForwardedFrom
   1642         self.isReplyTo = isReplyTo
   1643         self.main = self.content
   1644         self.configname = self.__hash__()
   1645         self.buddies = [ buddy for buddy in sm.GetService('addressbook').GetAddressBook() if idCheckers.IsNPC(buddy) == False and idCheckers.IsCharacter(buddy) ]
   1646         self.name = 'newmessage'
   1647         self.ConstructTopContainer()
   1648         self.receiver.blockSetValue = 1
   1649         self.receiver.registerHistory = 0
   1650         self.receiver.GetAll = self.GetAllOptions
   1651         self.receiver.OnHistoryClick = self.OnReceiverHistoryClick
   1652         self.receiver.OnDropData = self.OnDropReceiver
   1653         self.receiver.OnInsert = self.ValidateReceiver
   1654         self.receiver.OnFocusLost = self.ValidateReceivers
   1655         self.receiver.receiverText = ''
   1656         self.sendBtn = Button(parent=ContainerAutoSize(parent=self.main, align=uiconst.TOBOTTOM, padTop=8), align=uiconst.BOTTOMLEFT, texturePath='res:/ui/Texture/WindowIcons/evemail.png', iconSize=48, label=localization.GetByLabel('UI/Mail/SendMail'), hint=localization.GetByLabel('UI/Mail/SendMail'), func=self.ClickSend, args=())
   1657         self.messageedit = EditPlainText(parent=self.main, pos=(0, 0, 0, 0), padding=None, align=uiconst.TOALL, maxLength=const.mailMaxBodySize, showattributepanel=1)
   1658         buttonCont = self.messageedit.sr.attribPanel
   1659         if buttonCont is not None:
   1660             ButtonIcon(name='channelWndIcon', texturePath='res:/UI/Texture/icons/73_16_9.png', parent=buttonCont, align=uiconst.TOLEFT, hint=localization.GetByLabel('UI/Mail/LabelMail'), func=self.Label)
   1661         if subject is not None:
   1662             self.subjecField.SetValue(subject)
   1663         if body is not None:
   1664             self.messageedit.SetValue(body)
   1665         fontCombo = self.messageedit.FindChild('fontsize')
   1666         if fontCombo:
   1667             fontCombo.isTabStop = 0
   1668         if toCharacterIDs:
   1669             sm.GetService('mailSvc').PrimeOwners(toCharacterIDs)
   1670             for each in toCharacterIDs:
   1671                 if each is not None:
   1672                     self.AddCharacterReceiver(each)
   1673 
   1674         if toCorpOrAllianceID:
   1675             for each in toCorpOrAllianceID:
   1676                 if each is not None:
   1677                     self.AddCorpAllianceReciver(each)
   1678 
   1679         if toListID is not None:
   1680             myLists = sm.GetService('mailinglists').GetMyMailingLists()
   1681             if toListID in myLists:
   1682                 list = myLists.get(toListID)
   1683                 name = list.displayName
   1684                 self.AddList(toListID, name)
   1685         if isReplyTo:
   1686             uicore.registry.SetFocus(self.messageedit)
   1687         else:
   1688             uicore.registry.SetFocus(self.receiver)
   1689         self.ValidateReceivers()
   1690 
   1691     def ConstructTopContainer(self):
   1692         topParent = Container(name='topParent', parent=self.GetMainArea(), align=uiconst.TOTOP, height=64 + 16, clipChildren=True)
   1693         toCont = ContainerAutoSize(parent=topParent, align=uiconst.TOTOP, padBottom=8, alignMode=uiconst.TOTOP)
   1694         subjectCont = ContainerAutoSize(parent=topParent, align=uiconst.TOTOP, alignMode=uiconst.TOTOP)
   1695         buttonCont = Container(parent=toCont, align=uiconst.TOLEFT)
   1696         toBtn = Button(parent=buttonCont, align=uiconst.TOPLEFT, label=localization.GetByLabel('UI/Mail/To'), func=self.OpenReceiverSearch)
   1697         self.sr.receiver = self.receiver = self.GetReceiverEdit('toField', toCont, maxLength=const.mailMaxRecipients * 24, label='', align=uiconst.TOTOP)
   1698         labelCont = Container(parent=subjectCont, align=uiconst.TOLEFT)
   1699         self.subjectLabel = eveLabel.EveLabelSmall(text=localization.GetByLabel('UI/Mail/Subject'), parent=labelCont, state=uiconst.UI_NORMAL, align=uiconst.CENTERLEFT)
   1700         self.sr.subjecField = self.subjecField = SingleLineEditText(name='subjecField', parent=subjectCont, maxLength=const.mailMaxSubjectSize, label='', align=uiconst.TOTOP)
   1701         labelCont.width = buttonCont.width = max(self.subjectLabel.textwidth + 16, toBtn.width + 4)
   1702 
   1703     def ConstructTopContainerOld(self):
   1704         topParent = Container(name='topParent', parent=self.GetMainArea(), align=uiconst.TOTOP, height=64, clipChildren=True)
   1705         sendCont = Container(name='sendCont', parent=topParent, align=uiconst.TOLEFT, pos=(0, 0, 64, 0))
   1706         labelCont = Container(name='labelCont', parent=topParent, align=uiconst.TOLEFT, pos=(0, 0, 50, 0))
   1707         editCont = Container(name='editCont', parent=topParent, align=uiconst.TOALL, pos=(0, 0, 0, 0))
   1708         Container(name='push', parent=editCont, align=uiconst.TORIGHT, pos=(0, 0, 5, 0))
   1709         self.sendBtn = Button(parent=sendCont, align=uiconst.TOPLEFT, top=8, left=8, texturePath='res:/ui/Texture/WindowIcons/evemail.png', iconSize=48, hint=localization.GetByLabel('UI/Mail/SendMail'), func=self.ClickSend, args=())
   1710         Container(name='push', parent=topParent, align=uiconst.TORIGHT, pos=(0, 0, 4, 0))
   1711         Container(name='push', parent=topParent, align=uiconst.TOTOP, pos=(0, 0, 0, 4))
   1712         toBtn = Button(parent=labelCont, label=localization.GetByLabel('UI/Mail/To'), pos=(0, 7, 0, 0), func=self.OpenReceiverSearch)
   1713         toBtn.height = 23
   1714         self.sr.receiver = self.receiver = self.GetReceiverEditOld('toField', editCont, maxLength=const.mailMaxRecipients * 24, left=0, top=10, label='', align=uiconst.TOTOP)
   1715         self.sr.subjecField = self.subjecField = SingleLineEditText(name='subjecField', parent=editCont, maxLength=const.mailMaxSubjectSize, pos=(0, 10, 0, 0), label='', align=uiconst.TOTOP)
   1716         self.subjectLabel = eveLabel.EveLabelSmall(text=localization.GetByLabel('UI/Mail/Subject'), parent=labelCont, top=40, left=10, state=uiconst.UI_NORMAL)
   1717         labelCont.width = max(self.subjectLabel.textwidth + 15, toBtn.width + 5)
   1718 
   1719     def GetReceiverEditOld(self, configname, where, setvalue = None, left = 0, width = 80, ints = None, top = 2, height = 18, floats = None, callback = None, label = None, maxLength = None, passwordChar = None, align = 0, readonly = 0, adjustWidth = False):
   1720         edit = ReceiverEdit(name=configname, parent=where, height=height, width=width, left=left, top=top, align=align)
   1721         edit.SetMaxLength(maxLength)
   1722         if setvalue is not None:
   1723             edit.SetValue(setvalue)
   1724         if label:
   1725             _label = eveLabel.EveHeaderSmall(text=label, parent=edit, align=uiconst.TOPLEFT, width=1000, height=13, left=0, top=-13)
   1726             edit.sr.label = _label
   1727         return edit
   1728 
   1729     def GetReceiverEdit(self, configname, where, setvalue = None, width = 80, label = None, maxLength = None, align = 0):
   1730         edit = ReceiverEdit(name=configname, parent=where, width=width, align=align)
   1731         edit.SetMaxLength(maxLength)
   1732         if setvalue is not None:
   1733             edit.SetValue(setvalue)
   1734         if label:
   1735             _label = eveLabel.EveHeaderSmall(text=label, parent=edit, align=uiconst.TOPLEFT, width=1000)
   1736             edit.sr.label = _label
   1737         return edit
   1738 
   1739     def _OnClose(self, *args):
   1740         self.messageedit = None
   1741         self.parsingReceivers = 0
   1742         wnd = OwnerSearchWindow.GetIfOpen()
   1743         if wnd and wnd.configname == self.configname:
   1744             wnd.CloseByUser()
   1745 
   1746     def AddCharacterReceiver(self, id, partly = 0):
   1747         if not idCheckers.IsCharacter(id):
   1748             return self.AddCorpAllianceReciver(id)
   1749         name = cfg.eveowners.Get(id).name
   1750         if len(self.toChars) >= const.mailMaxRecipients:
   1751             prompt_player_fsd_dialog('EvemailMaxRecipients', {'max': const.mailMaxRecipients,
   1752              'name': name})
   1753             return False
   1754         self.toChars[name] = id
   1755         if partly:
   1756             return True
   1757         self.AddReceiver(id, name)
   1758         sm.ScatterEvent('OnSearcedUserAdded', id, self.configname)
   1759         return True
   1760 
   1761     def ValidateCorpOrAlliance(self, id):
   1762         if idCheckers.IsCorporation(id):
   1763             if id != session.corpid:
   1764                 prompt_player_fsd_dialog('EvemailCantSendToOtherCorp', {})
   1765                 return False
   1766             if idCheckers.IsNPC(id):
   1767                 prompt_player_fsd_dialog('EvemailCantSendToNPCCorp', {})
   1768                 return False
   1769         elif idCheckers.IsAlliance(id):
   1770             if id != session.allianceid:
   1771                 prompt_player_fsd_dialog('EvemailCantSendToOtherAlliance', {})
   1772                 return False
   1773             if not const.corpRoleChatManager & session.corprole == const.corpRoleChatManager:
   1774                 prompt_player_fsd_dialog('EvemailCantSendToAllianceNoRole', {})
   1775                 return False
   1776         else:
   1777             return False
   1778         return True
   1779 
   1780     def AddCorpAllianceReciver(self, id, partly = 0):
   1781         if not self.ValidateCorpOrAlliance(id):
   1782             return False
   1783         name = cfg.eveowners.Get(id).name
   1784         if self.TotalNumberOfGroups() >= const.mailMaxGroups:
   1785             self.GetMaxGroupText(name)
   1786             return False
   1787         self.toCorpAlliance[name] = id
   1788         if partly:
   1789             return True
   1790         self.AddReceiver(id, name)
   1791         return True
   1792 
   1793     def AddList(self, id, name, partly = 0):
   1794         if self.TotalNumberOfGroups() >= const.mailMaxGroups:
   1795             self.GetMaxGroupText(name)
   1796             return False
   1797         self.toListID = id
   1798         if partly:
   1799             return True
   1800         name = localization.GetByLabel('UI/Mail/MailEntry', entryName=name, entryType=localization.GetByLabel('UI/Mail/ML'))
   1801         self.AddReceiver(id, name, checkNPC=False)
   1802         return True
   1803 
   1804     def AddReceiver(self, id, name, checkNPC = True):
   1805         if checkNPC and idCheckers.IsNPC(id):
   1806             return
   1807         c = self.sr.receiver.GetValue()
   1808         if c:
   1809             c += ', '
   1810         if self.name == localization.GetByLabel('UI/Common/Unknown'):
   1811             self.name = name
   1812         c += name
   1813         self.sr.receiver.SetValue(c)
   1814         self.ValidateReceivers()
   1815 
   1816     def NewParseReceiver(self, name, *args):
   1817         listReceiver = self.GetMailinglistReceiver(name.strip())
   1818         if listReceiver is not None:
   1819             if self.TotalNumberOfGroups() >= const.mailMaxGroups:
   1820                 self.GetMaxGroupText(name)
   1821                 return
   1822             self.toListID = listReceiver
   1823             ret = utillib.KeyVal(name=name, group=GROUP_LIST, id=listReceiver)
   1824             return ret
   1825         name = name.strip()
   1826         if name.lower() in [cfg.eveowners.Get(session.corpid).ownerName.lower(), CORPTEXT]:
   1827             valid = self.ValidateCorpOrAlliance(session.corpid)
   1828             if not valid:
   1829                 return
   1830             name = cfg.eveowners.Get(session.corpid).ownerName
   1831             if self.TotalNumberOfGroups() >= const.mailMaxGroups:
   1832                 self.GetMaxGroupText(name)
   1833                 return
   1834             self.toCorpAlliance[name] = session.corpid
   1835             ret = utillib.KeyVal(name=name, group=GROUP_CORP, id=listReceiver)
   1836             return ret
   1837         if session.allianceid:
   1838             if name.lower() in [cfg.eveowners.Get(session.allianceid).ownerName.lower(), ALLIANCTEXT]:
   1839                 valid = self.ValidateCorpOrAlliance(session.allianceid)
   1840                 if not valid:
   1841                     return
   1842                 name = cfg.eveowners.Get(session.allianceid).ownerName
   1843                 if self.TotalNumberOfGroups() >= const.mailMaxGroups:
   1844                     self.GetMaxGroupText(name)
   1845                     return
   1846                 self.toCorpAlliance[name] = session.allianceid
   1847                 ret = utillib.KeyVal(name=name, group=GROUP_CORP, id=listReceiver)
   1848                 return ret
   1849         nme, id = self.GetReceiver(name)
   1850         if nme and id:
   1851             if len(self.toChars) >= const.mailMaxRecipients:
   1852                 prompt_player_fsd_dialog('EvemailMaxRecipients', {'max': const.mailMaxRecipients,
   1853                  'name': nme})
   1854                 return
   1855             self.toChars[nme] = id
   1856             sm.ScatterEvent('OnSearcedUserAdded', id, self.configname)
   1857             ret = utillib.KeyVal(name=nme, group=GROUP_CHAR, id=id)
   1858             return ret
   1859 
   1860     def GetMailinglistReceiver(self, name):
   1861         lists = sm.GetService('mailinglists').GetMyMailingLists()
   1862         for key, value in lists.iteritems():
   1863             if name == value.displayName:
   1864                 if prompt_player_fsd_dialog('CustomQuestion', {'header': localization.GetByLabel('UI/Mail/SendToMailingListQ'),
   1865                  'question': localization.GetByLabel('UI/Mail/SendToMailingListQ2', listName=name)}, uiconst.YESNO) == uiconst.ID_YES:
   1866                     return key
   1867 
   1868     def GetReceiver(self, string):
   1869         if string in self.toChars:
   1870             id = self.toChars[string]
   1871             if id:
   1872                 return (string, id)
   1873         ownerID = searchOld.Search(string, const.groupCharacter, hideNPC=1, exact=MatchBy.exact_phrase, searchWndName='newMessageReceiverSearch', getError=1)
   1874         if ownerID:
   1875             if type(ownerID) in [types.StringType, types.UnicodeType]:
   1876                 mailSettings = sm.GetService('mailSvc').GetMailSettings()
   1877                 if mailSettings.GetSingleValue(cSettings.MAIL_GET_SEARCH_WND, True):
   1878                     self.GetSearchWnd(input=string)
   1879                 else:
   1880                     prompt_player_fsd_dialog('EveMailNoCharFound', {'name': string})
   1881                 return (string, None)
   1882             return (cfg.eveowners.Get(ownerID).name, ownerID)
   1883         return (string, None)
   1884 
   1885     def GetAllOptions(self):
   1886         buddies = self.buddies
   1887         mailingLists = sm.GetService('mailinglists').GetMyMailingLists()
   1888         myCorpAndAllicane = [session.corpid]
   1889         if session.allianceid:
   1890             myCorpAndAllicane.append(session.allianceid)
   1891         ret = utillib.KeyVal()
   1892         ret.buddies = buddies
   1893         ret.mailingLists = mailingLists
   1894         ret.corpAll = myCorpAndAllicane
   1895         return ret
   1896 
   1897     def OnReceiverHistoryClick(self, rest, string, info, *args):
   1898         if info:
   1899             string = string.strip()
   1900             group, id = info
   1901             canAdd = False
   1902             if group == GROUP_CHAR:
   1903                 canAdd = self.AddCharacterReceiver(id, partly=1)
   1904             elif group == GROUP_LIST:
   1905                 canAdd = self.AddList(id, string, partly=1)
   1906                 if canAdd:
   1907                     string = localization.GetByLabel('UI/Mail/MailEntry', entryName=string, entryType=localization.GetByLabel('UI/Mail/ML'))
   1908             elif group == GROUP_CORP:
   1909                 canAdd = self.AddCorpAllianceReciver(id, partly=1)
   1910             if canAdd:
   1911                 if rest:
   1912                     rest += ' '
   1913                 self.sr.receiver.SetValue(rest + string)
   1914             else:
   1915                 self.sr.receiver.SetValue(rest)
   1916 
   1917     def OnDropReceiver(self, dragObj, nodes):
   1918         for node in nodes:
   1919             charID = GetCharIDFromTextLink(node)
   1920             if charID and idCheckers.IsCharacter(charID):
   1921                 self.AddCharacterReceiver(charID)
   1922             elif node.__guid__ in AllUserEntries():
   1923                 self.AddCharacterReceiver(node.charID)
   1924             elif node.__guid__ == 'listentry.CorpAllianceEntry':
   1925                 itemID = getattr(node, 'itemID', None)
   1926                 if itemID is None:
   1927                     mailingListID = GetAttrs(node, 'sr', 'node', 'mailingListID')
   1928                     if mailingListID is not None:
   1929                         self.AddList(mailingListID, node.Get('name', ''))
   1930                 else:
   1931                     self.AddCorpAllianceReciver(node.itemID)
   1932 
   1933     def TotalNumberOfGroups(self):
   1934         return len(self.toCorpAlliance) + int(self.toListID is not None)
   1935 
   1936     def GetMaxGroupText(self, name, corpNamesUsed = None, listNamesUsed = None):
   1937         if corpNamesUsed is None:
   1938             corpNamesUsed = self.toCorpAlliance
   1939         if listNamesUsed is None and self.toListID is not None:
   1940             listNamesUsed = sm.GetService('mailinglists').GetMyMailingLists()[self.toListID]
   1941         groupName = localization.GetByLabel('UI/Common/Unknown')
   1942         groups = corpNamesUsed.keys()
   1943         if listNamesUsed is not None:
   1944             groups.append(listNamesUsed.displayName)
   1945         if len(groups) >= const.mailMaxGroups:
   1946             groupName = groups[0]
   1947         return prompt_player_fsd_dialog('EvemailMaxListOrCorp', {'name': name,
   1948          'groupName': groupName})
   1949 
   1950     def OnDropData(self, dragObj, nodes):
   1951         pass
   1952 
   1953     def ValidateReceiver(self, char, *args):
   1954         text = unichr(char)
   1955         if text != ',' and self.sr.receiver.GetValue().strip() != '':
   1956             return None
   1957         if not self or self.destroyed:
   1958             return None
   1959         uthread.new(self.ValidateReceivers)
   1960 
   1961     def ValidateReceivers(self, *args):
   1962         if not self or self.destroyed or getattr(self, 'parsingReceivers', 0):
   1963             return
   1964         self.parsingReceivers = 1
   1965         inp = self.sr.receiver.GetValue()
   1966         all = inp.split(',')
   1967         charNamesUsed = {}
   1968         corpNamesUsed = {}
   1969         listNamesUsed = {}
   1970         allReceivers = self.toChars.keys() + self.toCorpAlliance.keys()
   1971         myLists = sm.GetService('mailinglists').GetMyMailingLists()
   1972         myListsNames = [ each.displayName.lower() for each in myLists.itervalues() ]
   1973         if self.toListID in myLists:
   1974             allReceivers.append(myLists[self.toListID].displayName)
   1975         finalString = ''
   1976         for name in all:
   1977             name = name.strip()
   1978             if not name:
   1979                 continue
   1980             cleanNameAndGroup = self.GetCleanNameAndGroup(name)
   1981             cleanName = cleanNameAndGroup.name
   1982             group = cleanNameAndGroup.group
   1983             if cleanName not in allReceivers:
   1984                 add = self.AddUnknownToValidate(cleanName, listNamesUsed, corpNamesUsed, charNamesUsed)
   1985                 if add is None:
   1986                     prompt_player_fsd_dialog('EvemailCantFindRecipient', {'name': cleanName})
   1987                     continue
   1988                 else:
   1989                     group = add.group
   1990                     cleanName = add.name
   1991             elif group == GROUP_LIST:
   1992                 if cleanName.lower() in myListsNames:
   1993                     if cleanName not in listNamesUsed:
   1994                         listNamesUsed[cleanName] = True
   1995                     else:
   1996                         continue
   1997             elif cleanName in self.toChars and cleanName not in charNamesUsed:
   1998                 charNamesUsed[cleanName] = True
   1999             elif cleanName in self.toCorpAlliance and cleanName not in corpNamesUsed:
   2000                 corpNamesUsed[cleanName] = True
   2001             else:
   2002                 add = self.AddUnknownToValidate(cleanName, listNamesUsed, corpNamesUsed, charNamesUsed)
   2003                 if add is None:
   2004                     continue
   2005                 else:
   2006                     group = add.group
   2007                     cleanName = add.name
   2008             nameToAdd = cleanName
   2009             if group == GROUP_LIST:
   2010                 nameToAdd = localization.GetByLabel('UI/Mail/MailEntry', entryName=nameToAdd, entryType=localization.GetByLabel('UI/Mail/ML'))
   2011             finalString += '%s, ' % nameToAdd
   2012 
   2013         if not self or self.destroyed:
   2014             self.parsingReceivers = 0
   2015             return
   2016         self.sr.receiver.SetValue(finalString)
   2017         toChars = self.toChars.copy()
   2018         toCorpAlliance = self.toCorpAlliance.copy()
   2019         charsPopped = []
   2020         for each in toChars:
   2021             if each not in charNamesUsed:
   2022                 charsPopped.append(self.toChars.get(each, None))
   2023                 self.toChars.pop(each, None)
   2024 
   2025         sm.ScatterEvent('OnSearcedUserRemoved', charsPopped, self.configname)
   2026         for each in toCorpAlliance:
   2027             if each not in corpNamesUsed:
   2028                 self.toCorpAlliance.pop(each, None)
   2029 
   2030         if self.toListID is not None:
   2031             myLists = sm.GetService('mailinglists').GetMyMailingLists()
   2032             if self.toListID not in myLists or len(listNamesUsed) < 1:
   2033                 self.toListID = None
   2034         self.parsingReceivers = 0
   2035 
   2036     def GetCleanNameAndGroup(self, name):
   2037         name = name.strip()
   2038         ret = utillib.KeyVal(name=name, group=None)
   2039         strippedMaillistLabel = StripTags(localization.GetByLabel('UI/Mail/ML'))
   2040         if name.endswith(strippedMaillistLabel):
   2041             ret.name = name.replace(strippedMaillistLabel, '')
   2042             if ret.name[-1] == ' ':
   2043                 ret.name = ret.name[:-1]
   2044             ret.group = GROUP_LIST
   2045         return ret
   2046 
   2047     def AddUnknownToValidate(self, name, listNamesUsed, corpNamesUsed, charNamesUsed):
   2048         keyVal = self.NewParseReceiver(name)
   2049         if keyVal is None:
   2050             return
   2051         name = keyVal.name
   2052         group = keyVal.group
   2053         corpAndListsNum = len(corpNamesUsed) + len(listNamesUsed)
   2054         ret = keyVal.copy()
   2055         if group == GROUP_LIST:
   2056             if corpAndListsNum >= const.mailMaxGroups:
   2057                 self.GetMaxGroupText(name, corpNamesUsed, listNamesUsed)
   2058             elif name not in listNamesUsed:
   2059                 listNamesUsed[name] = True
   2060                 return ret
   2061         elif group == GROUP_CORP:
   2062             if corpAndListsNum >= const.mailMaxGroups:
   2063                 self.GetMaxGroupText(name, corpNamesUsed, listNamesUsed)
   2064             elif name not in corpNamesUsed:
   2065                 corpNamesUsed[name] = True
   2066                 return ret
   2067         elif group == GROUP_CHAR:
   2068             if len(charNamesUsed) >= const.mailMaxRecipients:
   2069                 prompt_player_fsd_dialog('EvemailMaxRecipients', {'max': const.mailMaxRecipients,
   2070                  'name': name})
   2071             elif name not in charNamesUsed:
   2072                 charNamesUsed[name] = True
   2073                 return ret
   2074 
   2075     def ClickSend(self, *args):
   2076         bannedwords.check_chat_character_allowed(session.charid)
   2077         self.SetSendBtnState(disable=1)
   2078         self.ValidateReceivers()
   2079         allReceivers = self.toChars.keys() + self.toCorpAlliance.keys()
   2080         if self.toListID is not None:
   2081             myLists = sm.GetService('mailinglists').GetMyMailingLists()
   2082             if self.toListID in myLists:
   2083                 allReceivers.append(myLists[self.toListID])
   2084         if len(allReceivers) < 1:
   2085             prompt_player_fsd_dialog('CustomInfo', {'info': localization.GetByLabel('UI/Mail/NoRecipientForMessage')})
   2086             self.SetSendBtnState(disable=0)
   2087             return
   2088         if len(allReceivers) > const.mailMaxRecipients + 1:
   2089             info = localization.GetByLabel('UI/Mail/TooManyRecipients', max=const.mailMaxRecipients)
   2090             prompt_player_fsd_dialog('CustomInfo', {'info': info})
   2091             self.SetSendBtnState(disable=0)
   2092             return
   2093         subject = self.sr.subjecField.GetValue()
   2094         if subject.strip() == '':
   2095             self.SetSendBtnState(disable=0)
   2096             raise UserError('NoSubject')
   2097         elif len(subject) > const.mailMaxSubjectSize:
   2098             self.SetSendBtnState(disable=0)
   2099             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/NameIsTooLong')})
   2100         body = self.messageedit.GetValue()
   2101         values = self.toCorpAlliance.values()
   2102         corpAlliance = None
   2103         if values:
   2104             corpAlliance = values[0]
   2105             if not self.ValidateCorpOrAlliance(corpAlliance):
   2106                 self.SetSendBtnState(disable=0)
   2107                 raise UserError('EvemailSendingFailed')
   2108         labels = self.labels
   2109         try:
   2110             messageID = sm.GetService('mailSvc').SendMail(toCharacterIDs=self.toChars.values(), toListID=self.toListID, toCorpOrAllianceID=corpAlliance, title=subject, body=body, isReplyTo=self.isReplyTo, isForwardedFrom=self.isForwardedFrom)
   2111         except:
   2112             self.SetSendBtnState(disable=0)
   2113             raise
   2114 
   2115         if messageID is None:
   2116             self.SetSendBtnState(disable=0)
   2117             return
   2118         sum = 0
   2119         for labelID in labels:
   2120             sum = sum + labelID
   2121 
   2122         sm.GetService('mailSvc').AssignLabels([messageID], sum)
   2123         setattr(sm.StartService('mailSvc'), 'lastMessageTime', blue.os.GetWallclockTime())
   2124         if self and not self.destroyed:
   2125             self.Close()
   2126 
   2127     def SetSendBtnState(self, disable = 0):
   2128         if disable:
   2129             self.sendBtn.state = uiconst.UI_DISABLED
   2130             self.sendBtn.opacity = 0.3
   2131         else:
   2132             self.sendBtn.state = uiconst.UI_NORMAL
   2133             self.sendBtn.opacity = 1.0
   2134 
   2135     def Label(self, *args):
   2136         wnd = ManageLabelsNewMails.Open(labels=self.labels)
   2137         if wnd.ShowModal() == 1:
   2138             self.labels = wnd.result
   2139 
   2140     def OpenReceiverSearch(self, *args):
   2141         self.GetSearchWnd()
   2142 
   2143     def AddReceiverFromSearch(self, func, *args):
   2144         sel = apply(func)
   2145         for each in sel:
   2146             if not self or self.destroyed:
   2147                 return
   2148             itemID = getattr(each, 'itemID', None)
   2149             guid = getattr(each, '__guid__', None)
   2150             if guid in AllUserEntries():
   2151                 self.AddCharacterReceiver(itemID)
   2152             elif guid == 'listentry.CorpAllianceEntry':
   2153                 if itemID is None:
   2154                     if getattr(each, 'mailingListID', None) is not None:
   2155                         self.AddList(each.mailingListID, getattr(each, 'name', ''))
   2156                 else:
   2157                     self.AddCorpAllianceReciver(itemID)
   2158 
   2159     def GetSearchWnd(self, input = ''):
   2160         actionBtn = [(localization.GetByLabel('UI/Mail/Add'), self.AddReceiverFromSearch, 1)]
   2161         caption = localization.GetByLabel('UI/Mail/SearchForRecipients')
   2162         wnd = OwnerSearchWindow.GetIfOpen()
   2163         if wnd:
   2164             wnd.CloseByUser()
   2165         extraIconHintFlag = ['ui_73_16_13', localization.GetByLabel('UI/Mail/CharacterAdded'), False]
   2166         wnd = MailSearchWindow.Open(actionBtns=actionBtn, caption=caption, input=input, showContactList=True, extraIconHintFlag=extraIconHintFlag, configname=self.configname)
   2167         if wnd is not None:
   2168             wnd.IsAdded = self.IsAddedToMail
   2169             wnd.Maximize()
   2170             searchBtn = GetAttrs(wnd, 'sr', 'searchBtn')
   2171             if searchBtn is not None and input:
   2172                 wnd.Search()
   2173                 uicore.registry.SetFocus(searchBtn)
   2174 
   2175     def IsAddedToMail(self, charID, *args):
   2176         if not self or self.destroyed:
   2177             return False
   2178         return charID in self.toChars.values()
   2179 
   2180     def CloseByUser(self, *args):
   2181         body = self.messageedit.GetValue()
   2182         if body.strip() and prompt_player_fsd_dialog('DiscardMailMessage', {}, uiconst.YESNO) != uiconst.ID_YES:
   2183             return False
   2184         Window.CloseByUser(self, *args)
   2185 
   2186 
   2187 class ReceiverEdit(SingleLineEditText):
   2188 
   2189     def ApplyAttributes(self, attributes):
   2190         SingleLineEditText.ApplyAttributes(self, attributes)
   2191         self.blockSetValue = 1
   2192 
   2193     def RegisterHistory(self, value = None):
   2194         pass
   2195 
   2196     def ClearHistory(self, *args):
   2197         pass
   2198 
   2199     def TryDeleteFromHistory(self):
   2200         pass
   2201 
   2202     def GetValid(self):
   2203         current = self.GetValue(registerHistory=0)
   2204         rest = ''
   2205         lastComma = current.rfind(',')
   2206         if lastComma > -1:
   2207             rest = current[:lastComma + 1]
   2208             current = current[lastComma + 1:]
   2209             current.strip()
   2210         self.current = current
   2211         self.rest = rest
   2212         id, mine = self.GetHistory()
   2213         buddies = mine.buddies
   2214         lists = mine.mailingLists
   2215         corpAll = mine.corpAll
   2216         valid = []
   2217         sm.GetService('mailSvc').PrimeOwners(buddies)
   2218         for each in buddies:
   2219             name = cfg.eveowners.Get(each).ownerName
   2220             if name.lower().startswith(current.lower().strip()) and name != current:
   2221                 valid.append((GROUP_CHAR,
   2222                  name,
   2223                  name,
   2224                  each))
   2225 
   2226         for key, value in lists.iteritems():
   2227             if value.displayName.lower().startswith(current.lower().strip()) and value.displayName != current:
   2228                 valid.append((GROUP_LIST,
   2229                  localization.GetByLabel('UI/Mail/MailEntry', entryName=value.displayName, entryType=localization.GetByLabel('UI/Mail/ML')),
   2230                  value.displayName,
   2231                  key))
   2232 
   2233         for each in corpAll:
   2234             if idCheckers.IsNPC(each):
   2235                 continue
   2236             if idCheckers.IsAlliance(each) and session.corprole & const.corpRoleChatManager != const.corpRoleChatManager:
   2237                 continue
   2238             name = cfg.eveowners.Get(each).ownerName
   2239             if name.lower().startswith(current.lower().strip()) and name != current:
   2240                 text = ''
   2241                 if each == session.corpid:
   2242                     text = localization.GetByLabel('UI/Mail/LabelCorp')
   2243                 elif each == session.allianceid:
   2244                     text = localization.GetByLabel('UI/Mail/LabelAlliance')
   2245                 valid.append((GROUP_CORP,
   2246                  localization.GetByLabel('UI/Mail/MailEntry', entryName=name, entryType=text),
   2247                  name,
   2248                  each))
   2249 
   2250         valid = SortListOfTuples([ (len(name), (group,
   2251           displayName,
   2252           name,
   2253           (group, id))) for group, displayName, name, id in valid ])
   2254         return valid
   2255 
   2256     def HEMouseDown(self, entry, *args):
   2257         rest = getattr(self, 'rest', '')
   2258         info = getattr(entry, 'info', None)
   2259         self.OnHistoryClick(rest, entry.string, info)
   2260 
   2261     def GetHistory(self, getAll = 0):
   2262         id = 0
   2263         all = self.GetAll()
   2264         if getAll:
   2265             return (id, all, all)
   2266         return (id, all)
   2267 
   2268     def GetAll(self, *args):
   2269         return []
   2270 
   2271     def GetMenu(self):
   2272         return BaseSingleLineEdit.GetMenu(self)
   2273 
   2274     def PopulateHistoryMenu(self, menuParent, history):
   2275         historyFormatted = []
   2276         for historyEntry in history:
   2277             _, displayText, editText, info = historyEntry
   2278             b = Bundle(displayText=displayText, editText=editText, info=info, historyEntry=historyEntry, removeable=False)
   2279             historyFormatted.append(b)
   2280 
   2281         menuParent.PopulateHistoryMenu(historyFormatted)
   2282 
   2283     def Confirm(self, *args):
   2284         if getattr(self, 'historyMenu', None) is None:
   2285             return
   2286         hm = self.historyMenu()
   2287         entry = getattr(self, 'active', None)
   2288         if entry:
   2289             rest = getattr(self, 'rest', '')
   2290             self.OnHistoryClick(rest, entry.string, entry.info)
   2291         self.CloseHistoryMenu()
   2292         return False
   2293 
   2294 
   2295 class MailReadingWnd(Window):
   2296     __guid__ = 'form.MailReadingWnd'
   2297     __notifyevents__ = ['OnMessageChanged']
   2298     default_mail = None
   2299     default_msgID = None
   2300     default_txt = ''
   2301     default_toolbar = True
   2302     default_trashed = False
   2303     default_type = None
   2304     default_windowID = 'mailReadingWnd'
   2305 
   2306     def ApplyAttributes(self, attributes):
   2307         Window.ApplyAttributes(self, attributes)
   2308         mail = attributes.mail
   2309         msgID = attributes.msgID
   2310         txt = attributes.get('txt', self.default_txt)
   2311         toolbar = attributes.get('toolbar', self.default_toolbar)
   2312         trashed = attributes.get('trashed', self.default_trashed)
   2313         type = attributes.type
   2314         self.messageedit = None
   2315         self.scope = uiconst.SCOPE_INGAME
   2316         sm.RegisterNotify(self)
   2317         self.SetMinSize([250, 250])
   2318         self.SetCaption(localization.GetByLabel('UI/Mail/Message'))
   2319         main = self.content
   2320         self.mail = mail
   2321         self.type = type
   2322         self.messageID = msgID
   2323         actions = utillib.KeyVal()
   2324         actions.replyClicked = self.ReplyClicked
   2325         actions.replyAllClicked = self.ReplyAllClicked
   2326         actions.forwardClicked = self.ForwardClicked
   2327         actions.trashClicked = self.TrashClicked
   2328         actions.deleteClicked = self.DeleteClicked
   2329         if toolbar:
   2330             self.mailActions = MailActionPanel(name='mailActionCont', parent=main, align=uiconst.TOTOP, pos=(0,
   2331              0,
   2332              250,
   2333              Button.default_height), padding=(0, 8, 0, 8))
   2334             self.mailActions.Startup(actions, showCompose=0)
   2335             self.mailActions.SetDeleteVisibility(disabled=0, showDelete=trashed)
   2336             if mail.statusMask & const.mailStatusMaskAutomated == const.mailStatusMaskAutomated:
   2337                 self.mailActions.SingleMsgBtnStateAllowFwd()
   2338             else:
   2339                 self.mailActions.SingleMsgBtnsState(disabled=0)
   2340         self.sr.rightCont = Container(name='rightCont', parent=main, align=uiconst.TOALL, pos=(const.defaultPadding,
   2341          const.defaultPadding,
   2342          const.defaultPadding,
   2343          const.defaultPadding))
   2344         self.sr.readingPane = EditPlainText(setvalue=txt, parent=self.sr.rightCont, align=uiconst.TOALL, readonly=1)
   2345 
   2346     def SetText(self, text):
   2347         self.sr.readingPane.SetValue(text)
   2348 
   2349     def _OnClose(self, *args):
   2350         sm.UnregisterNotify(self)
   2351         Window._OnClose(self, *args)
   2352 
   2353     def ReplyClicked(self, *args):
   2354         sm.GetService('mailSvc').GetReplyWnd(self.mail, all=0)
   2355 
   2356     def ReplyAllClicked(self, *args):
   2357         sm.GetService('mailSvc').GetReplyWnd(self.mail, all=1)
   2358 
   2359     def ForwardClicked(self, *args):
   2360         sm.GetService('mailSvc').GetForwardWnd(self.mail)
   2361 
   2362     def TrashClicked(self, *arsg):
   2363         if self.type == const.mailTypeMail:
   2364             mailCopy = self.mail.copy()
   2365             sm.GetService('mailSvc').MoveMessagesToTrash([self.mail.messageID])
   2366             self.mailActions.SetDeleteVisibility(disabled=0, showDelete=1)
   2367             sm.ScatterEvent('OnMailTrashedDeleted', mailCopy)
   2368 
   2369     def DeleteClicked(self, *args):
   2370         if self.type == const.mailTypeMail:
   2371             mailCopy = self.mail.copy()
   2372             sm.GetService('mailSvc').DeleteMails([self.mail.messageID])
   2373             sm.ScatterEvent('OnMailTrashedDeleted', mailCopy)
   2374             self.CloseByUser()
   2375 
   2376     def OnMessageChanged(self, type, messageIDs, what):
   2377         if type == self.type and self.messageID in messageIDs:
   2378             if type == const.mailTypeMail:
   2379                 if what == 'trashed':
   2380                     self.mailActions.SetDeleteVisibility(disabled=0, showDelete=1)
   2381                 elif what == 'deleted':
   2382                     self.CloseByUser()
   2383             elif type == const.mailTypeNotifications:
   2384                 if what == 'deleted':
   2385                     self.CloseByUser()
   2386 
   2387 
   2388 class MailActionPanel(Container):
   2389     __guid__ = 'xtriui.MailActionPanel'
   2390 
   2391     def ApplyAttributes(self, attributes):
   2392         Container.ApplyAttributes(self, attributes)
   2393         self.sr.data = None
   2394         self.topOffset = top = 0
   2395         self.size = size = 32
   2396         self.leftOffset = left = 0
   2397         self.space = 35
   2398         self.extraSpace = 15
   2399         self.sr.composeBtn = Button(parent=self, align=uiconst.TOPLEFT, top=top, left=left, texturePath='res:/ui/Texture/WindowIcons/evemailcompose.png', iconSize=size, hint=localization.GetByLabel('UI/Mail/Compose'))
   2400         left += self.space + self.extraSpace
   2401         self.sr.replyBtn = Button(parent=self, align=uiconst.TOPLEFT, top=top, left=left, texturePath='res:/ui/Texture/Icons/94_64_2.png', iconSize=size, hint=localization.GetByLabel('UI/Mail/Reply'))
   2402         left += self.space
   2403         self.sr.replyAllBtn = Button(parent=self, align=uiconst.TOPLEFT, top=top, left=left, texturePath='res:/ui/Texture/Icons/94_64_3.png', iconSize=size, hint=localization.GetByLabel('UI/Mail/ReplyAll'))
   2404         left += self.space
   2405         self.sr.forwardBtn = Button(parent=self, align=uiconst.TOPLEFT, top=top, left=left, texturePath='res:/ui/Texture/Icons/94_64_4.png', iconSize=size, hint=localization.GetByLabel('UI/Mail/Forward'))
   2406         left += self.space + self.extraSpace
   2407         self.sr.trashBtn = Button(parent=self, align=uiconst.TOPLEFT, top=top, left=left, texturePath='res:/ui/Texture/Icons/94_64_5.png', iconSize=size, hint=localization.GetByLabel('UI/Mail/Trash'))
   2408         self.sr.deleteBtn = Button(parent=self, align=uiconst.TOPLEFT, top=top, left=left, texturePath='res:/ui/Texture/WindowIcons/terminate.png', iconSize=size, hint=localization.GetByLabel('UI/Mail/Delete'))
   2409         left += self.space + self.extraSpace
   2410         self.sr.singleMsgBtn = [self.sr.replyBtn, self.sr.replyAllBtn, self.sr.forwardBtn]
   2411         self.width = left
   2412 
   2413     def Startup(self, data, showCompose = 1):
   2414         self.sr.data = data
   2415         self.sr.composeBtn.func = data.Get('composeClicked', self.ComposeClicked)
   2416         self.sr.replyBtn.func = data.Get('replyClicked', self.ReplyClicked)
   2417         self.sr.replyAllBtn.func = data.Get('replyAllClicked', self.ReplyAllClicked)
   2418         self.sr.forwardBtn.func = data.Get('forwardClicked', self.ForwardClicked)
   2419         self.sr.trashBtn.func = data.Get('trashClicked', self.TrashClicked)
   2420         self.sr.deleteBtn.func = data.Get('deleteClicked', self.DeleteClicked)
   2421         if not showCompose:
   2422             self.sr.composeBtn.state = uiconst.UI_HIDDEN
   2423             self.left -= self.space + self.leftOffset + self.extraSpace
   2424 
   2425     def DisableWhenManySelected(self, *args):
   2426         pass
   2427 
   2428     def DisableDelete(self, *args):
   2429         pass
   2430 
   2431     def ComposeClicked(self, *args):
   2432         pass
   2433 
   2434     def ReplyClicked(self, *args):
   2435         pass
   2436 
   2437     def ReplyAllClicked(self, *args):
   2438         pass
   2439 
   2440     def ForwardClicked(self, *args):
   2441         pass
   2442 
   2443     def TrashClicked(self, *args):
   2444         pass
   2445 
   2446     def DeleteClicked(self, *args):
   2447         pass
   2448 
   2449     def SetDeleteVisibility(self, disabled = 0, showDelete = 0):
   2450         if showDelete:
   2451             hiddenParent = self.sr.trashBtn
   2452             visibleBtn = self.sr.deleteBtn
   2453         else:
   2454             hiddenParent = self.sr.deleteBtn
   2455             visibleBtn = self.sr.trashBtn
   2456         if hiddenParent is not None:
   2457             self.SetDeleteState(disabled, hiddenParent, visibleBtn)
   2458 
   2459     def SetDeleteState(self, disabled, hiddenParent, visibleBtn):
   2460         btnState = [uiconst.UI_NORMAL, uiconst.UI_DISABLED][disabled]
   2461         opacity = [1.0, 0.3][disabled]
   2462         parentState = [uiconst.UI_PICKCHILDREN, uiconst.UI_NORMAL][disabled]
   2463         hiddenParent.state = uiconst.UI_HIDDEN
   2464         visibleBtn.state = btnState
   2465         visibleBtn.opacity = opacity
   2466         visibleBtn.parent.state = parentState
   2467 
   2468     def SingleMsgBtnsState(self, disabled = 0, btns = None):
   2469         if disabled:
   2470             state = uiconst.UI_DISABLED
   2471             alpha = 0.3
   2472             parentState = uiconst.UI_NORMAL
   2473         else:
   2474             state = uiconst.UI_NORMAL
   2475             alpha = 1.0
   2476             parentState = uiconst.UI_PICKCHILDREN
   2477         if btns is None:
   2478             btns = self.sr.singleMsgBtn
   2479         for btn in btns:
   2480             if btn.parent is None:
   2481                 return
   2482             btn.state = state
   2483             btn.opacity = alpha
   2484             btn.parent.state = parentState
   2485 
   2486     def SingleMsgBtnStateAllowFwd(self, *args):
   2487         btns = self.sr.singleMsgBtn[:]
   2488         btns.remove(self.sr.forwardBtn)
   2489         self.SingleMsgBtnsState(disabled=1, btns=btns)
   2490         self.SingleMsgBtnsState(disabled=0, btns=[self.sr.forwardBtn])
   2491 
   2492     def AddExtraButton(self, btn, withSpace = 1, size = None, hint = ''):
   2493         left = self.width
   2494         if withSpace:
   2495             left += self.extraSpace
   2496         if size is None:
   2497             size = self.size
   2498         cont = Container(name='cont', parent=self, align=uiconst.TOPLEFT, pos=(left,
   2499          self.topOffset,
   2500          size,
   2501          size), hint=hint)
   2502         cont.children.append(btn)
   2503         self.width = left + self.space
   2504 
   2505 
   2506 class MailSettings(Window):
   2507     __guid__ = 'form.MailSettings'
   2508     default_windowID = 'mailSettings'
   2509     CHECKBOX_ACTIVE_ICON = 'res:/UI/Texture/classes/UtilMenu/checkBoxActive.png'
   2510     CHECKBOX_INACTIVE_ICON = 'res:/UI/Texture/classes/UtilMenu/checkBoxInactive.png'
   2511     default_iconNum = MailWindow.default_iconNum
   2512     default_captionLabelPath = 'UI/Mail/CommunicationSettings'
   2513     default_fixedWidth = 380
   2514 
   2515     def ApplyAttributes(self, attributes):
   2516         Window.ApplyAttributes(self, attributes)
   2517         self.mailSettingObjectCopy = copy.deepcopy(sm.GetService('mailSvc').GetMailSettings())
   2518         self.mainCont = ContainerAutoSize(parent=self.content, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, padding=const.defaultPadding, callback=self.OnMainSizeChanged)
   2519         cost = sm.GetService('account').GetDefaultContactCost()
   2520         uix.GetContainerHeader(localization.GetByLabel('UI/Mail/IncomingCommunications'), self.mainCont, bothlines=0)
   2521         self.sr.accessCb1 = RadioButton(text=localization.GetByLabel('UI/Mail/RequireCSPNFromUnknown'), parent=self.mainCont, settingsKey='accessCb1', retval=0, checked=cost != -1, groupname='communications', callback=self.OnCheckboxChange, padding=(6, 6, 6, 0), align=uiconst.TOTOP, hint=localization.GetByLabel('UI/Mail/CSPAHint'))
   2522         self.sr.accessCb2 = RadioButton(text=localization.GetByLabel('UI/Mail/BlockUnknown'), parent=self.mainCont, settingsKey='accessCb1', retval=1, checked=cost == -1, groupname='communications', callback=self.OnCheckboxChange, padding=(6, 0, 6, 6), align=uiconst.TOTOP, hint=localization.GetByLabel('UI/Mail/CSPAHint2'))
   2523         self.sr.chargeCont = Container(name='chargeCont', parent=self.mainCont, align=uiconst.TOTOP, pos=(0, 0, 0, 20), padding=(0, 0, 0, 6))
   2524         if cost == -1:
   2525             self.sr.chargeCont.state = uiconst.UI_HIDDEN
   2526             cost = 0
   2527         self.sr.chargeEdit = SingleLineEditInteger(name='chargeField', parent=self.sr.chargeCont, setvalue=cost, maxLength=32, pos=(150, 0, 60, 0), label='', align=uiconst.TOPLEFT, maxValue=1000000)
   2528         eveLabel.EveLabelSmall(text=localization.GetByLabel('UI/Mail/CSPACharge'), parent=self.sr.chargeCont, align=uiconst.CENTERLEFT, width=150, left=8)
   2529         uix.GetContainerHeader(localization.GetByLabel('UI/Mail/MailSettings'), self.mainCont)
   2530         perPageCont = Container(name='perPageCont', parent=self.mainCont, align=uiconst.TOTOP, pos=(0, 0, 0, 20), padding=(0, 0, 0, 6))
   2531         perPageNumer = self.mailSettingObjectCopy.GetSingleValue(cSettings.MAILS_PER_PAGE, DEFAULTNUMMAILS)
   2532         self.sr.perPageEdit = SingleLineEditInteger(name='perPageEdit', parent=perPageCont, setvalue=perPageNumer, maxLength=32, pos=(150, 4, 60, 0), label='', align=uiconst.TOPLEFT, minValue=MINNUMMAILS, maxValue=MAXNUMMAILS)
   2533         eveLabel.EveLabelSmall(text=localization.GetByLabel('UI/Mail/MailsPerPage'), parent=perPageCont, align=uiconst.CENTERLEFT, width=150, left=8)
   2534         getSearchWnd = self.mailSettingObjectCopy.GetSingleValue(cSettings.MAIL_GET_SEARCH_WND, True)
   2535         self.sr.getSearchWnd = Checkbox(text=localization.GetByLabel('UI/Mail/ShowSearch'), parent=self.mainCont, settingsKey='getSearchWnd', checked=getSearchWnd, align=uiconst.TOTOP, padding=(6, 0, 0, 0))
   2536         eveLabel.EveLabelSmall(text=localization.GetByLabel('UI/Mail/WhenReceived'), parent=self.mainCont, align=uiconst.TOTOP, padding=(8, 10, 8, 0), state=uiconst.UI_DISABLED)
   2537         isNeocomBlinkOnForMail = self.mailSettingObjectCopy.GetSingleValue(cSettings.MAIL_BLINK_NEOCOM, True)
   2538         isTabBlinkOnForMail = self.mailSettingObjectCopy.GetSingleValue(cSettings.MAIL_BLINK_TAB, True)
   2539         isPopupOnForMail = self.mailSettingObjectCopy.GetSingleValue(cSettings.MAIL_SHOW_POPUP, True)
   2540         self.sr.mailBlinkNeocomCB = Checkbox(text=localization.GetByLabel('UI/Mail/BlinkMailNeoComButton'), parent=self.mainCont, settingsKey='mailBlinkNeocomCB', checked=bool(isNeocomBlinkOnForMail), align=uiconst.TOTOP, padding=(16, 0, 0, 0))
   2541         self.sr.mailBlinkTabCB = Checkbox(text=localization.GetByLabel('UI/Mail/BlinkTab'), parent=self.mainCont, settingsKey='mailBlinkTabCB', checked=bool(isTabBlinkOnForMail), align=uiconst.TOTOP, padding=(16, 0, 0, 0))
   2542         self.sr.mailNotificationCB = Checkbox(text=localization.GetByLabel('UI/Mail/ShowNotification'), parent=self.mainCont, settingsKey='mailNotificationCB', checked=bool(isPopupOnForMail), align=uiconst.TOTOP, padding=(16, 0, 0, 0))
   2543         self.GetWindowSizeForContentSize()
   2544         self.settingCb = {}
   2545         self.sr.standardBtns = ButtonGroup(parent=self.mainCont, align=uiconst.TOTOP, padTop=16, btns=((localization.GetByLabel('UI/Mail/Apply'),
   2546           self.OnApply,
   2547           (),
   2548           81), (localization.GetByLabel('UI/Commands/Cancel'),
   2549           self.CloseByUser,
   2550           (),
   2551           81)))
   2552         self.mainCont.SetSizeAutomatically()
   2553 
   2554     def OnMainSizeChanged(self, *args, **kwds):
   2555         if self.mainCont:
   2556             _, height = self.GetWindowSizeForContentSize(height=self.mainCont.height)
   2557             self.SetFixedHeight(height)
   2558 
   2559     def OpenMenuFunc(self, menuParent, settingKey, *args):
   2560         disabledGroups = self.mailSettingObjectCopy.GetListForSettingKey(settingKey)
   2561         headerChecked = not bool(disabledGroups)
   2562         if headerChecked:
   2563             icon = self.CHECKBOX_ACTIVE_ICON
   2564         else:
   2565             icon = self.CHECKBOX_INACTIVE_ICON
   2566         menuParent.AddHeader(text=localization.GetByLabel('UI/Common/All'), callback=(self.ToggleAll, settingKey), icon=icon)
   2567         menuParent.AddSpace()
   2568         checkboxes = []
   2569         for groupID, labelPath in notificationGroupNamePaths.iteritems():
   2570             checked = groupID not in disabledGroups
   2571             groupName = localization.GetByLabel(labelPath)
   2572             checkboxes.append((groupName, groupID, checked))
   2573 
   2574         checkboxes.sort()
   2575         for groupName, groupID, checked in checkboxes:
   2576             menuParent.AddCheckBox(text=groupName, checked=checked, callback=(self.ToggleGroup, groupID, settingKey), indentation=10)
   2577 
   2578         menuParent.AddSpace()
   2579         self.RefreshIcon(settingKey)
   2580 
   2581     def RefreshIcon(self, settingKey):
   2582         iconOwner = self.settingCb.get(settingKey)
   2583         if not iconOwner:
   2584             return
   2585         numGroups = len(notificationGroupNamePaths)
   2586         disabledGroups = self.mailSettingObjectCopy.GetListForSettingKey(settingKey)
   2587         if not disabledGroups:
   2588             path = 'res:/UI/Texture/Shared/checkboxChecked.png'
   2589         elif len(disabledGroups) < numGroups:
   2590             path = 'res:/UI/Texture/Shared/checkboxMinus.png'
   2591         else:
   2592             iconOwner.iconCheckmark.display = False
   2593             return
   2594         iconOwner.iconCheckmark.SetTexturePath(path)
   2595         iconOwner.iconCheckmark.display = True
   2596 
   2597     def ToggleAll(self, settingKey):
   2598         disabledGroups = self.mailSettingObjectCopy.GetListForSettingKey(settingKey)
   2599         if disabledGroups:
   2600             newGroupList = []
   2601         else:
   2602             newGroupList = [ groupID for groupID in notificationGroupNamePaths.iterkeys() ]
   2603         self.mailSettingObjectCopy.UpdateSettingListWithNewValues(settingKey, newGroupList)
   2604 
   2605     def ToggleGroup(self, groupID, settingKey):
   2606         if groupID in self.mailSettingObjectCopy.GetListForSettingKey(settingKey):
   2607             self.mailSettingObjectCopy.RemoveValueFromListSetting(settingKey, groupID)
   2608         else:
   2609             self.mailSettingObjectCopy.AddValueToListSetting(settingKey, groupID)
   2610 
   2611     def OnCheckboxChange(self, radioButton):
   2612         config = radioButton.GetSettingsKey()
   2613         if config == None:
   2614             return
   2615         value = radioButton.GetReturnValue()
   2616         if value is None:
   2617             return
   2618         if value == 1:
   2619             self.sr.chargeCont.state = uiconst.UI_HIDDEN
   2620         else:
   2621             self.sr.chargeCont.state = uiconst.UI_PICKCHILDREN
   2622         settings.char.ui.Set('mail_accessCombo', value)
   2623 
   2624     def OnApply(self, *args):
   2625         oldCost = sm.GetService('account').GetDefaultContactCost()
   2626         if self.sr.accessCb1.checked:
   2627             cost = self.sr.chargeEdit.GetValue()
   2628             if cost != oldCost:
   2629                 sm.GetService('account').SetDefaultContactCost(self.sr.chargeEdit.GetValue())
   2630         elif oldCost != -1:
   2631             sm.GetService('account').BlockAll()
   2632         mailBlinkNeocom = self.sr.mailBlinkNeocomCB.GetValue()
   2633         mailBlinkTab = self.sr.mailBlinkTabCB.GetValue()
   2634         mailNotification = self.sr.mailNotificationCB.GetValue()
   2635         getSearchWnd = self.sr.getSearchWnd.GetValue()
   2636         self.mailSettingObjectCopy.SetSingleValue(cSettings.MAIL_BLINK_NEOCOM, mailBlinkNeocom)
   2637         self.mailSettingObjectCopy.SetSingleValue(cSettings.MAIL_BLINK_TAB, mailBlinkTab)
   2638         self.mailSettingObjectCopy.SetSingleValue(cSettings.MAIL_SHOW_POPUP, mailNotification)
   2639         self.mailSettingObjectCopy.SetSingleValue(cSettings.MAIL_GET_SEARCH_WND, getSearchWnd)
   2640         perPage = self.sr.perPageEdit.GetValue()
   2641         oldPerPage = self.mailSettingObjectCopy.GetSingleValue(cSettings.MAILS_PER_PAGE, DEFAULTNUMMAILS)
   2642         self.mailSettingObjectCopy.SetSingleValue(cSettings.MAILS_PER_PAGE, perPage)
   2643         sm.GetService('mailSvc').SaveMailSettingsOnServer(self.mailSettingObjectCopy)
   2644         if perPage != oldPerPage:
   2645             sm.ScatterEvent('OnMailSettingsChanged')
   2646         self.CloseByUser()
   2647 
   2648 
   2649 class MailinglistWnd(Window):
   2650     __guid__ = 'form.MailinglistWnd'
   2651     default_windowID = 'MailinglistWnd'
   2652     default_iconNum = MailWindow.default_iconNum
   2653     default_captionLabelPath = 'UI/Mail/CreateOrJoinML'
   2654     default_minSize = (300, 164)
   2655 
   2656     def ApplyAttributes(self, attributes):
   2657         Window.ApplyAttributes(self, attributes)
   2658         self.MakeUnResizeable()
   2659         buttons = ButtonGroup(parent=ContainerAutoSize(parent=self.GetMainArea(), align=uiconst.TOBOTTOM, padTop=16))
   2660         buttons.AddButton(label=localization.GetByLabel('UI/Mail/Join'), func=self.JoinMaillist, args=(0,), isDefault=True)
   2661         buttons.AddButton(label=localization.GetByLabel('UI/Mail/Create'), func=self.CreateMaillist, args=(1,))
   2662         self.sr.inpt = SingleLineEditText(name='input', parent=Container(parent=self.GetMainArea(), align=uiconst.TOALL), align=uiconst.TOBOTTOM, maxLength=const.mailingListMaxNameSize, label=localization.GetByLabel('UI/Mail/MailingListName'))
   2663 
   2664     def CreateMaillist(self, *args):
   2665         name = self.sr.inpt.GetValue()
   2666         if name.strip() == '':
   2667             prompt_player_fsd_dialog('LookupStringMinimum', {'minimum': 1})
   2668             return
   2669         if len(name) > const.mailingListMaxNameSize:
   2670             raise UserError('CustomNotify', {'notify': localization.GetByLabel('UI/Mail/NameIsTooLong')})
   2671         ret = sm.GetService('mailinglists').CreateMailingList(name)
   2672         if ret is not None:
   2673             self.CloseByUser()
   2674 
   2675     def JoinMaillist(self, *args):
   2676         name = self.sr.inpt.GetValue()
   2677         if name.strip() == '':
   2678             prompt_player_fsd_dialog('LookupStringMinimum', {'minimum': 1})
   2679             return
   2680         ret = sm.GetService('mailinglists').JoinMailingList(name)
   2681         if ret is not None:
   2682             self.CloseByUser()
   2683 
   2684 
   2685 class MailSearchWindow(OwnerSearchWindow):
   2686     __guid__ = 'form.MailSearchWindow'
   2687     default_windowID = 'searchWindow_mail'
   2688     default_ownerGroups = [const.groupCharacter]
   2689 
   2690     def GetExtraSearchEntries(self, searchTerm, searchBy):
   2691         extraEntries = []
   2692         myLists = sm.GetService('mailinglists').GetMyMailingLists()
   2693         for key, value in myLists.iteritems():
   2694             if searchUtil.IsMatch(searchTerm, value.displayName, searchBy):
   2695                 entry = self.GetCorpAllianceMailingListEntry(None, 1, key, value.displayName)
   2696                 extraEntries.append((value.displayName.lower(), entry))
   2697 
   2698         extraEntries = SortListOfTuples(extraEntries)
   2699         if session.allianceid and session.corprole & const.corpRoleChatManager == const.corpRoleChatManager:
   2700             allianceName = cfg.eveowners.Get(session.allianceid).ownerName
   2701             if searchUtil.IsMatch(searchTerm, allianceName, searchBy):
   2702                 entry = self.GetCorpAllianceMailingListEntry(const.typeAlliance, 0, session.allianceid, allianceName)
   2703                 extraEntries.insert(0, entry)
   2704         if not idCheckers.IsNPC(session.corpid):
   2705             corpName = cfg.eveowners.Get(session.corpid).ownerName
   2706             if searchUtil.IsMatch(searchTerm, corpName, searchBy):
   2707                 entry = self.GetCorpAllianceMailingListEntry(const.typeCorporation, 0, session.corpid, corpName)
   2708                 extraEntries.insert(0, entry)
   2709         return extraEntries
   2710 
   2711     def GetCorpAllianceMailingListEntry(self, type, mailingList, id, name):
   2712         data = utillib.KeyVal()
   2713         data.confirmOnDblClick = 1
   2714         if type is None:
   2715             if mailingList:
   2716                 data.label = localization.GetByLabel('UI/Mail/MailEntry', entryName=name, entryType=localization.GetByLabel('UI/Mail/ML'))
   2717                 data.itemID = None
   2718                 data.typeID = None
   2719                 data.mailingListID = id
   2720                 data.name = name
   2721             else:
   2722                 return
   2723         else:
   2724             if type == const.typeCorporation:
   2725                 data.label = localization.GetByLabel('UI/Mail/MailEntry', entryName=name, entryType=localization.GetByLabel('UI/Mail/LabelCorp'))
   2726             elif type == const.typeAlliance:
   2727                 data.label = localization.GetByLabel('UI/Mail/MailEntry', entryName=name, entryType=localization.GetByLabel('UI/Mail/LabelAlliance'))
   2728             data.itemID = id
   2729             data.typeID = type
   2730             data.name = name
   2731         data.OnClick = self.ClickEntry
   2732         data.OnDblClick = self.DblClickEntry
   2733         entry = GetFromClass(CorpAllianceEntry, data)
   2734         return entry
   2735 
   2736 
   2737 class MailAssignColorWnd(Container):
   2738     __guid__ = 'xtriui.MailAssignColorWnd'
   2739 
   2740     def Startup(self, labelID, doneCallback = None, doneArgs = (), *args):
   2741         self.mouseCookie = None
   2742         container = Container(name='headercontainer', parent=self, align=uiconst.TOTOP, pos=(0, 0, 0, 18), idx=0)
   2743         t = eveLabel.EveHeaderSmall(text=localization.GetByLabel('UI/Mail/Select Color'), parent=container, left=8, align=uiconst.TOALL, top=5, state=uiconst.UI_DISABLED)
   2744         Line(parent=container, align=uiconst.TOBOTTOM, top=-1)
   2745         colorCont = Container(name='colorCont', parent=self, align=uiconst.TOALL, padding=(const.defaultPadding,
   2746          const.defaultPadding,
   2747          const.defaultPadding,
   2748          const.defaultPadding))
   2749         self.sr.underlay = WindowUnderlay(parent=self)
   2750         self.sr.underlay.padding = (0, -18, 0, -2)
   2751         self.labelID = labelID
   2752         colorSwatch = ColorSwatch(name='colorSwatch', parent=colorCont, align=uiconst.TOALL, pos=(0, 0, 0, 0))
   2753         colorSwatch.OnPickColor = self.PickCol
   2754         colorSwatch.swatches = sm.StartService('mailSvc').GetSwatchColors().values()
   2755         colorSwatch.Startup(frameColor=(0.0, 0.0, 0.0, 0.0), padding=1)
   2756         self.top = uicore.uilib.y - 35
   2757         self.left = uicore.uilib.x - 20
   2758         self.doneCallback = doneCallback
   2759         self.doneArgs = doneArgs
   2760         self.mouseCookie = uicore.event.RegisterForTriuiEvents(uiconst.UI_MOUSEUP, self.OnGlobalMouseUp)
   2761 
   2762     def PickCol(self, obj, *args):
   2763         if getattr(obj, 'swatchID', None) is not None:
   2764             if self.doneCallback is not None:
   2765                 args = tuple([obj.swatchID]) + self.doneArgs
   2766                 self.doneCallback(*args)
   2767             self.Close()
   2768 
   2769     def OnGlobalMouseUp(self, obj, msgID, param):
   2770         if uicore.uilib.mouseOver == self or obj.IsUnder(self):
   2771             return 1
   2772         self.Close()
   2773         return 1
   2774 
   2775     def Close(self):
   2776         if getattr(self, 'mouseCookie', None):
   2777             uicore.event.UnregisterForTriuiEvents(self.mouseCookie)
   2778             self.mouseCookie = None
   2779         Container.Close(self)