notifications.py (16937B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\notifications.py 2 import eveformat 3 import utillib 4 from carbon.common.script.sys.serviceConst import ROLE_GML 5 from carbon.common.script.util import timerstuff 6 from carbon.common.script.util.commonutils import StripTags 7 from carbon.common.script.util.format import FmtDate 8 from carbonui.control.dragResizeCont import DragResizeCont 9 from carbonui.primitives.container import Container 10 from carbonui.util.various_unsorted import SortListOfTuples 11 from eve.client.script.ui.control import eveScroll 12 from carbonui.button.group import ButtonGroup 13 from eve.client.script.ui.control.divider import Divider 14 import blue 15 import eve.common.script.util.notificationconst as notificationConst 16 import uthread 17 import carbonui.const as uiconst 18 import eve.common.script.util.notificationUtil as notificationUtil 19 import localization 20 from carbonui.uicore import uicore 21 from eve.client.script.ui.control.entries.space import Space 22 from eve.client.script.ui.control.entries.util import GetFromClass 23 from eve.client.script.ui.control.eveEditPlainText import EditPlainText 24 from eve.client.script.ui.control.listgroup import ListGroup 25 from eve.client.script.ui.shared.neocom.evemail import MailEntry 26 from menu import MenuLabel 27 from globalConfig.getFunctions import IsPlayerBountyHidden 28 from player_messaging.client.ui_message import prompt_player_fsd_dialog 29 HINTCUTOFF = 100 30 DELETE_INTERVAL = 0.3 * const.SEC 31 32 class NotificationForm(Container): 33 __guid__ = 'form.NotificationForm' 34 __notifyevents__ = ['OnNotificationsRefresh', 'OnNewNotificationReceived', 'OnNotificationReadOutside'] 35 36 def Setup(self): 37 sm.RegisterNotify(self) 38 self.scrollHeight = 0 39 self.DrawStuff() 40 self.readTimer = 0 41 self.viewing = None 42 self.lastDeleted = 0 43 44 def DrawStuff(self, *args): 45 btns = ButtonGroup(btns=[[localization.GetByLabel('UI/Mail/Notifications/MarkAllAsRead'), 46 self.MarkAllRead, 47 None, 48 81], [localization.GetByLabel('UI/Mail/Notifications/DeleteAll'), 49 self.DeleteAll, 50 None, 51 81]], parent=self, idx=0) 52 leftContWidth = settings.user.ui.Get('notifications_leftContWidth', 200) 53 self.sr.leftCont = Container(name='leftCont', parent=self, align=uiconst.TOLEFT, width=leftContWidth) 54 self.sr.leftScroll = eveScroll.Scroll(name='leftScroll', parent=self.sr.leftCont) 55 self.sr.leftScroll.multiSelect = 0 56 divider = Divider(name='divider', align=uiconst.TOLEFT, width=const.defaultPadding, parent=self, state=uiconst.UI_NORMAL) 57 divider.Startup(self.sr.leftCont, 'width', 'x', 180, 250) 58 self.sr.rightCont = Container(name='rightCont', parent=self, align=uiconst.TOALL, pos=(0, 59 0, 60 const.defaultPadding, 61 const.defaultPadding)) 62 dividerCont = DragResizeCont(name='dividerCont', settingsID='notificationsSplitSize', parent=self.sr.rightCont, align=uiconst.TOTOP_PROP, minSize=0.1, maxSize=0.9, defaultSize=0.7, clipChildren=True) 63 self.sr.readingPaneCont = Container(name='readingPaneCont', parent=self.sr.rightCont, align=uiconst.TOALL) 64 self.sr.readingPane = EditPlainText(setvalue='', parent=self.sr.readingPaneCont, align=uiconst.TOALL, readonly=1) 65 self.sr.msgCont = Container(name='msgCont', parent=dividerCont) 66 self.sr.msgScroll = eveScroll.Scroll(name='msgScroll', parent=self.sr.msgCont) 67 self.sr.msgScroll.sr.id = 'notifications_msgs' 68 self.sr.msgScroll.sr.fixedColumns = {localization.GetByLabel('UI/Mail/Status'): 52} 69 self.sr.msgScroll.OnSelectionChange = self.MsgScrollSelectionChange 70 self.sr.msgScroll.OnDelete = self.DeleteFromKeyboard 71 self.inited = True 72 73 def LoadNotificationForm(self, *args): 74 self.LoadLeftSide() 75 76 def OnClose_(self, *args): 77 settings.user.ui.Set('notifications_leftContWidth', self.sr.leftCont.width) 78 settings.user.ui.Set('notifications_readingContHeight', self.sr.readingPaneCont.height) 79 sm.GetService('mailSvc').SaveChangesToDisk() 80 sm.UnregisterNotify(self) 81 82 def SelectGroupById(self, groupID): 83 for entry in self.sr.leftScroll.GetNodes(): 84 if entry.groupID == groupID: 85 panel = entry.panel 86 if panel is not None: 87 self.UpdateCounters() 88 panel.OnClick() 89 90 def LoadLeftSide(self): 91 scrolllist = self.GetStaticLabelsGroups() 92 self.sr.leftScroll.Load(contentList=scrolllist) 93 lastViewedID = settings.char.ui.Get('mail_lastnotification', None) 94 for entry in self.sr.leftScroll.GetNodes(): 95 if entry.groupID is None: 96 continue 97 if entry.groupID == lastViewedID: 98 panel = entry.panel 99 if panel is not None: 100 self.UpdateCounters() 101 panel.OnClick() 102 return 103 104 self.UpdateCounters() 105 if len(self.sr.leftScroll.GetNodes()) > 0: 106 entry = self.sr.leftScroll.GetNodes()[0] 107 panel = entry.panel 108 if panel is not None: 109 panel.OnClick() 110 111 def GetStaticLabelsGroups(self): 112 scrolllist = [] 113 lastViewedID = settings.char.ui.Get('mail_lastnotification', None) 114 for groupID, labelPath in notificationUtil.groupNamePaths.iteritems(): 115 if groupID == notificationUtil.groupBounties and IsPlayerBountyHidden(sm.GetService('machoNet')): 116 continue 117 label = localization.GetByLabel(labelPath) 118 entry = self.GetGroupEntry(groupID, label, groupID == lastViewedID) 119 strippedLabel = StripTags(label, stripOnly=['localized']) 120 scrolllist.append((strippedLabel.lower(), entry)) 121 122 scrolllist = SortListOfTuples(scrolllist) 123 entry = self.GetGroupEntry(const.notificationGroupUnread, localization.GetByLabel('UI/Mail/Unread'), const.notificationGroupUnread == lastViewedID) 124 scrolllist.insert(0, entry) 125 scrolllist.insert(1, GetFromClass(Space, {'height': 12})) 126 return scrolllist 127 128 def GetGroupEntry(self, groupID, label, selected = 0): 129 return GetFromClass(ListGroup, {'GetSubContent': self.GetLeftGroups, 130 'label': label, 131 'id': ('notification', id), 132 'state': 'locked', 133 'BlockOpenWindow': 1, 134 'disableToggle': 1, 135 'expandable': 0, 136 'showicon': 'hide', 137 'showlen': 0, 138 'groupItems': [], 139 'hideNoItem': 1, 140 'hideExpander': 1, 141 'hideExpanderLine': 1, 142 'selectGroup': 1, 143 'isSelected': selected, 144 'groupID': groupID, 145 'OnClick': self.LoadGroupFromEntry, 146 'MenuFunction': self.StaticMenu}) 147 148 def GetLeftGroups(self, *args): 149 return [] 150 151 def LoadGroupFromEntry(self, entry, *args): 152 group = entry.sr.node 153 self.LoadGroupFromNode(group) 154 155 def LoadGroupFromNode(self, node, refreshing = 0, selectedIDs = [], *args): 156 group = node 157 settings.char.ui.Set('mail_lastnotification', group.groupID) 158 notifications = [] 159 if group.groupID == const.notificationGroupUnread: 160 notifications = sm.GetService('notificationSvc').GetFormattedUnreadNotifications() 161 senders = [ value.senderID for value in sm.GetService('notificationSvc').GetUnreadNotifications() ] 162 else: 163 notifications = sm.GetService('notificationSvc').GetFormattedNotifications(group.groupID) 164 senders = [ value.senderID for value in sm.GetService('notificationSvc').GetNotificationsByGroupID(group.groupID) ] 165 sm.GetService('mailSvc').PrimeOwners(senders) 166 if not self or self.destroyed: 167 return 168 pos = self.sr.msgScroll.GetScrollProportion() 169 scrolllist = [] 170 for each in notifications: 171 senderName = '' 172 if each.senderID == -1: 173 senderName = cfg.eveowners.Get(const.ownerSystem).ownerName 174 elif each.senderID is not None: 175 senderName = cfg.eveowners.Get(each.senderID).ownerName 176 label = '<t>' + senderName + '<t>' + each.subject + '<t>' + FmtDate(each.created, 'ls') 177 if group.groupID == const.notificationGroupUnread: 178 typeGroup = notificationConst.GetTypeGroup(each.typeID) 179 labelPath = notificationUtil.groupNamePaths.get(typeGroup, None) 180 if labelPath is None: 181 typeName = '' 182 else: 183 typeName = localization.GetByLabel(labelPath) 184 label += '<t>' + typeName 185 hint = eveformat.truncate_text_ignoring_tags(string=each.body.replace('<br>', ' '), length=HINTCUTOFF, trail=localization.GetByLabel('UI/Common/MoreTrail')) 186 scrolllist.append(GetFromClass(MailEntry, {'cleanLabel': label, 187 'parentNode': node, 188 'label': label, 189 'hint': hint.strip(), 190 'id': each.notificationID, 191 'typeID': each.typeID, 192 'senderID': each.senderID, 193 'data': utillib.KeyVal(read=each.processed), 194 'info': each, 195 'OnClick': self.LoadReadingPaneFromEntry, 196 'OnDblClick': self.DblClickNotificationEntry, 197 'GetMenu': self.GetEntryMenu, 198 'ignoreRightClick': 1, 199 'isSelected': each.notificationID in selectedIDs, 200 'Draggable_blockDrag': 1, 201 'isNotification': True})) 202 203 scrollHeaders = [localization.GetByLabel('UI/Mail/Status'), 204 localization.GetByLabel('UI/Mail/Sender'), 205 localization.GetByLabel('UI/Mail/Subject'), 206 localization.GetByLabel('UI/Mail/Received')] 207 if group.groupID == const.notificationGroupUnread: 208 scrollHeaders.append(localization.GetByLabel('UI/Mail/Notifications/GroupName')) 209 if not self or self.destroyed: 210 return 211 self.sr.msgScroll.Load(contentList=scrolllist, headers=scrollHeaders, noContentHint=localization.GetByLabel('UI/Mail/Notifications/NoNotifications')) 212 if not refreshing: 213 self.ClearReadingPane() 214 else: 215 self.sr.msgScroll.ScrollToProportion(pos) 216 self.UpdateCounters() 217 218 def StaticMenu(self, node, *args): 219 m = [] 220 if node.groupID != const.notificationGroupUnread: 221 m.append((MenuLabel('UI/Mail/Notifications/MarkAllAsRead'), self.MarkAllReadInGroup, (node.groupID,))) 222 m.append(None) 223 m.append((MenuLabel('UI/Mail/Notifications/DeleteAll'), self.DeleteAllFromGroup, (node.groupID,))) 224 return m 225 226 def DeleteAll(self, *args): 227 if prompt_player_fsd_dialog('EvemailNotificationsDeleteAll', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 228 sm.GetService('notificationSvc').DeleteAll() 229 230 def MarkAllRead(self, *args): 231 if prompt_player_fsd_dialog('EvemailNotificationsMarkAllRead', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 232 sm.GetService('notificationSvc').MarkAllRead() 233 234 def DeleteAllFromGroup(self, groupID, *args): 235 if prompt_player_fsd_dialog('EvemailNotificationsDeleteGroup', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 236 sm.GetService('notificationSvc').DeleteAllFromGroup(groupID) 237 238 def MarkAllReadInGroup(self, groupID, *args): 239 sm.GetService('notificationSvc').MarkAllReadInGroup(groupID) 240 241 def GetEntryMenu(self, entry, *args): 242 m = [] 243 sel = self.sr.msgScroll.GetSelected() 244 selIDs = [ x.id for x in sel ] 245 msgID = entry.sr.node.id 246 if msgID not in selIDs: 247 selIDs = [msgID] 248 sel = [entry.sr.node] 249 unread = {} 250 for each in sel: 251 if not each.data.read: 252 unread[each.id] = each 253 254 if len(unread) > 0: 255 m.append((MenuLabel('UI/Mail/Notifications/MarkAsRead'), self.MarkAsRead, (unread.values(), unread.keys()))) 256 m.append(None) 257 if len(selIDs) > 0: 258 m.append((MenuLabel('UI/Mail/Notifications/Delete'), self.DeleteNotifications, (sel, selIDs))) 259 if session.role & ROLE_GML: 260 m.append(('GM: MessageID=%s' % msgID, blue.pyos.SetClipboardData, (str(msgID),))) 261 return m 262 263 def MarkAsRead(self, notifications, notificationIDs, *args): 264 sm.GetService('notificationSvc').MarkAsRead(notificationIDs) 265 self.UpdateCounters() 266 self.SetMsgEntriesAsRead(notifications) 267 268 def DblClickNotificationEntry(self, entry): 269 messageID = entry.sr.node.id 270 info = entry.sr.node.info 271 sm.GetService('notificationSvc').OpenNotificationReadingWnd(info) 272 273 def LoadReadingPaneFromEntry(self, entry): 274 uthread.new(self.LoadReadingPaneFromNode, entry.sr.node) 275 276 def LoadReadingPaneFromNode(self, node): 277 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 278 if not shift: 279 self.LoadReadingPane(node) 280 281 def LoadReadingPane(self, node): 282 self.readTimer = 0 283 info = node.info 284 txt = sm.GetService('notificationSvc').GetReadingText(node.senderID, info.subject, info.created, info.body) 285 self.sr.readingPane.SetText(txt) 286 self.viewing = node.id 287 if not node.data.read: 288 self.MarkAsRead([node], [node.id]) 289 290 def ClearReadingPane(self): 291 self.sr.readingPane.SetText('') 292 self.viewing = None 293 294 def SetMsgEntriesAsRead(self, nodes): 295 for node in nodes: 296 self.TryReloadNode(node) 297 298 def TryReloadNode(self, node): 299 node.data.read = 1 300 panel = node.Get('panel', None) 301 if panel is None: 302 return 303 panel.LoadMailEntry(node) 304 305 def MsgScrollSelectionChange(self, sel = [], *args): 306 if len(sel) == 0: 307 return 308 node = sel[0] 309 if self.viewing != node.id: 310 self.readTimer = timerstuff.AutoTimer(1000, self.LoadReadingPane, node) 311 312 def DeleteFromKeyboard(self, *args): 313 if blue.os.GetWallclockTime() - self.lastDeleted < DELETE_INTERVAL: 314 prompt_player_fsd_dialog('uiwarning03') 315 return 316 sel = self.sr.msgScroll.GetSelected() 317 ids = [ each.id for each in sel ] 318 self.DeleteNotifications(sel, ids) 319 self.lastDeleted = blue.os.GetWallclockTime() 320 321 def DeleteNotifications(self, notificationEntries, ids): 322 if len(notificationEntries) < 1: 323 return 324 idx = notificationEntries[0].idx 325 ids = [] 326 for entry in notificationEntries: 327 ids.append(entry.id) 328 329 sm.GetService('notificationSvc').DeleteNotifications(ids) 330 sm.ScatterEvent('OnMessageChanged', const.mailTypeNotifications, ids, 'deleted') 331 self.sr.msgScroll.RemoveEntries(notificationEntries) 332 if self.viewing in ids: 333 self.ClearReadingPane() 334 self.UpdateCounters() 335 if len(self.sr.msgScroll.GetNodes()) < 1: 336 self.sr.msgScroll.Load(contentList=[], headers=[], noContentHint=localization.GetByLabel('UI/Mail/Notifications/NoNotifications')) 337 return 338 numChildren = len(self.sr.msgScroll.GetNodes()) 339 newIdx = min(idx, numChildren - 1) 340 newSelectedNode = self.sr.msgScroll.GetNode(newIdx) 341 if newSelectedNode is not None: 342 self.sr.msgScroll.SelectNode(newSelectedNode) 343 344 def SelectNodeByNotificationID(self, notificationID): 345 nodes = self.sr.msgScroll.GetNodes() 346 for node in nodes: 347 if node.id == notificationID: 348 self.sr.msgScroll.SelectNode(node) 349 break 350 351 def OnNotificationsRefresh(self): 352 self.LoadLeftSide() 353 354 def OnNewNotificationReceived(self, *args): 355 self.UpdateCounters() 356 357 def OnNotificationReadOutside(self, notificationID): 358 self.UpdateCounters() 359 for node in self.sr.msgScroll.GetNodes(): 360 if node.id == notificationID: 361 self.SetMsgEntriesAsRead([node]) 362 return 363 364 def UpdateCounters(self): 365 unreadCounts = sm.GetService('notificationSvc').GetAllUnreadCount() 366 for each in self.sr.leftScroll.GetNodes(): 367 if each.groupID is None: 368 continue 369 count = unreadCounts.get(each.groupID, 0) 370 self.TryChangePanelLabel(each, count) 371 372 def TryChangePanelLabel(self, node, count): 373 panel = node.Get('panel', None) 374 if panel is None: 375 return 376 panelLabel = self.GetPanelLabel(node.cleanLabel, count) 377 panel.sr.label.text = panelLabel 378 379 def GetPanelLabel(self, label, count): 380 if count > 0: 381 return localization.GetByLabel('UI/Mail/Notifications/GroupUnreadLabel', groupName=label, unreadCount=count) 382 else: 383 return label