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

bookmarksPanel.py (34344B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\addressBook\bookmarksPanel.py
      2 import itertools
      3 import eve.common.lib.appConst as appConst
      4 import blue
      5 import eveicon
      6 import localization
      7 import telemetry
      8 import threadutils
      9 import uthread
     10 from carbonui import TextColor, uiconst
     11 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     12 from carbonui.util.color import Color
     13 from eve.client.script.ui import eveColor
     14 from eve.client.script.ui.control.entries.util import GetFromClass
     15 from eve.client.script.ui.shared.addressBookEntries import PlaceEntry
     16 from eve.client.script.ui.shared.bookmarks.standaloneBookmarkWnd import StandaloneBookmarkWnd
     17 from menu import MenuLabel
     18 from caching.memoize import Memoize
     19 from carbon.common.script.sys.serviceConst import ROLE_GML, ROLE_WORLDMOD
     20 from carbon.common.script.util.format import FmtDate
     21 from carbonui.control.scrollentries import SE_GenericCore
     22 from carbonui.primitives.container import Container
     23 from carbonui.primitives.sprite import Sprite
     24 from carbonui.control.buttonIcon import ButtonIcon
     25 from eve.client.script.ui.control.entries.generic import Generic
     26 from eve.client.script.ui.control.listgroup import ListGroup
     27 from eve.client.script.ui.shared.bookmarks.bookmarkContainerWindow import BookmarkContainerWindow
     28 from eve.client.script.ui.shared.bookmarks.bookmarkSubfolderWindow import BookmarkSubfolderWindow
     29 from eve.client.script.util.bookmarkUtil import IsCoordinateBookmark, IsBookmarkAvailable, ConvertSubfolderName
     30 from inventorycommon.const import ownerSystem
     31 from localization import GetByLabel, GetByMessageID
     32 from localization.util import Sort
     33 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     34 from sensorsuite.overlay.bookmarkvisibilitymanager import GetBookmarkFolderVisibilityManager
     35 from eve.client.script.ui.control import eveIcon, eveScroll
     36 from evePathfinder.core import IsUnreachableJumpCount
     37 import evetypes
     38 from carbonui.uicore import uicore
     39 from utillib import KeyVal
     40 import inventorycommon.const as invConst
     41 COLOR_SELECTED = eveColor.LEAFY_GREEN
     42 COLOR_POSTTEXT = Color(*TextColor.SECONDARY).GetHex()
     43 COLOR_WARNING_POSTTEXT = Color(*TextColor.WARNING).GetHex()
     44 MAX_BOOKMARKS_DISPLAYED_IN_GROUP = 3000
     45 placesHeaders = [GetByLabel('UI/PeopleAndPlaces/Label'),
     46  GetByLabel('UI/Common/Type'),
     47  GetByLabel('UI/PeopleAndPlaces/Jumps'),
     48  GetByLabel('UI/PeopleAndPlaces/Sol'),
     49  GetByLabel('UI/PeopleAndPlaces/Con'),
     50  GetByLabel('UI/PeopleAndPlaces/Reg'),
     51  GetByLabel('UI/Common/Date'),
     52  GetByLabel('UI/AclBookmarks/Expiry'),
     53  GetByLabel('UI/PeopleAndPlaces/Creator')]
     54 
     55 class BookmarksPanel(Container):
     56     __guid__ = 'BookmarksPanel'
     57     default_name = 'BookmarksPanel'
     58 
     59     def ApplyAttributes(self, attributes):
     60         Container.ApplyAttributes(self, attributes)
     61         self.semaphore = uthread.Semaphore()
     62         self.scroll = BookmarksScroll(parent=self, id='bookmarksPanelScroll', pushContent=True)
     63         self.adminFolderId = ('bookmarks', 'adminFolders')
     64         uicore.registry.SetListGroupOpenState(self.adminFolderId, 0)
     65 
     66     def Setup(self):
     67         self.ShowPlaces()
     68 
     69     def DropInPlacesFolder(self, folderKey, nodes, *args):
     70         folderID, subfolderID = folderKey[1]
     71         forceCopy = uicore.uilib.Key(uiconst.VK_SHIFT)
     72         bookmarkIDsToMove = set()
     73         for node in nodes:
     74             guid = getattr(node, '__guid__', None)
     75             if guid == 'listentry.PlaceEntry':
     76                 if node.bm is not None:
     77                     bookmarkIDsToMove.add(node.bm.bookmarkID)
     78 
     79         if bookmarkIDsToMove:
     80             sm.GetService('bookmarkSvc').MoveOrCopyBookmarks(folderID, subfolderID, bookmarkIDsToMove, forceCopy)
     81 
     82     def BookmarkCurrentLocation(self, *args):
     83         sm.GetService('addressbook').BookmarkCurrentLocation(*args)
     84 
     85     def RefreshScroll(self):
     86         if not self.destroyed:
     87             self.ShowPlaces()
     88 
     89     @threadutils.threaded
     90     def ShowPlaces(self):
     91         with self.semaphore:
     92             self.scroll.ShowLoading()
     93             locations = set()
     94             for bm in sm.GetService('bookmarkSvc').GetAllBookmarks().itervalues():
     95                 if bm.itemID is not None:
     96                     locations.add(bm.itemID)
     97                 if bm.locationID is not None:
     98                     locations.add(bm.locationID)
     99 
    100             if len(locations):
    101                 cfg.evelocations.Prime(locations, 0)
    102             scrolllist = self.GetFolderSectionList()
    103             scrolllist.extend(self.GetAgentPlacesScrollList())
    104             self.scroll.sr.iconMargin = 18
    105             scrollToProportion = self.scroll.GetScrollProportion()
    106             self.scroll.Load(contentList=scrolllist, fixedEntryHeight=None, headers=placesHeaders, scrollTo=scrollToProportion, noContentHint=GetByLabel('UI/PeopleAndPlaces/NoKnownPlaces'), showCollapseIcon=True)
    107             self.scroll.HideLoading()
    108 
    109     def GetAgentPlacesScrollList(self):
    110         missiongroupState = uicore.registry.GetListGroupOpenState(('missiongroups', 'agentmissions'))
    111         agentGroup = uicore.registry.GetLockedGroup('missiongroups', 'agentmissions', GetByLabel('UI/PeopleAndPlaces/AgentMissions'), openState=missiongroupState)
    112         groupEntry = GetFromClass(ListGroup, {'GetSubContent': self.GetPlacesSubContent_AgentMissions,
    113          'RefreshScroll': self.RefreshScroll,
    114          'label': agentGroup['label'],
    115          'id': agentGroup['id'],
    116          'groupItems': sm.GetService('bookmarkSvc').GetAgentBookmarks(),
    117          'headers': placesHeaders,
    118          'showlen': 0,
    119          'state': 'locked',
    120          'showicon': eveicon.agent_mission})
    121         scrolllist = []
    122         Sort(scrolllist, key=lambda x: x.label)
    123         return [groupEntry] + scrolllist
    124 
    125     def GetPlacesSubContent_AgentMissions(self, nodedata, newitems = 0):
    126         if newitems:
    127             nodedata.groupItems = sm.GetService('bookmarkSvc').GetAgentBookmarks()
    128         agentMenu = sm.GetService('journal').GetMyAgentJournalBookmarks()
    129         scrolllist = []
    130         headers = [GetByLabel('UI/PeopleAndPlaces/Label'),
    131          GetByLabel('UI/Common/Type'),
    132          GetByLabel('UI/Common/Date'),
    133          GetByLabel('UI/PeopleAndPlaces/Sol'),
    134          GetByLabel('UI/PeopleAndPlaces/Con'),
    135          GetByLabel('UI/PeopleAndPlaces/Reg')]
    136         if agentMenu:
    137             for missionNameID, bms, agentID in agentMenu:
    138                 if bms:
    139                     if isinstance(missionNameID, basestring):
    140                         missionName = missionNameID
    141                     else:
    142                         missionName = GetByMessageID(missionNameID)
    143                     missionID = unicode(missionNameID) + unicode(agentID)
    144                     scrolllist.append(GetFromClass(ListGroup, {'GetSubContent': self.GetPlacesSubContent_AgentMissions2,
    145                      'RefreshScroll': self.RefreshScroll,
    146                      'label': missionName,
    147                      'id': (missionID, missionName),
    148                      'groupItems': nodedata.groupItems,
    149                      'headers': headers,
    150                      'iconMargin': 18,
    151                      'showlen': 0,
    152                      'state': 'locked',
    153                      'sublevel': 1,
    154                      'showicon': None}))
    155 
    156         return scrolllist
    157 
    158     def GetPlacesSubContent_AgentMissions2(self, nodedata, newitems = 0):
    159         if newitems:
    160             nodedata.groupItems = sm.GetService('bookmarkSvc').GetAgentBookmarks()
    161         groupID = nodedata.id
    162         places = [ bm for bm in nodedata.groupItems.itervalues() if bm.missionName == groupID[0] ]
    163         return self.GetPlacesScrollList(places, groupID, sublevel=2)
    164 
    165     @telemetry.ZONE_METHOD
    166     def GetFolderSectionList(self):
    167         contList = []
    168         self.bookmarksBySubfolderByFolder = sm.GetService('bookmarkSvc').GetBookmarksBySubfolderByFolder()
    169         folders = sm.GetService('bookmarkSvc').GetFolders().values()
    170         personalBookmarkCount = 0
    171         sharedBookmarkCount = 0
    172         for folder in folders:
    173             if not folder.isActive:
    174                 continue
    175             if folder.isPersonal:
    176                 personalBookmarkCount += sum((len(subfolder) for subfolder in self.bookmarksBySubfolderByFolder[folder.folderID].itervalues()))
    177             else:
    178                 sharedBookmarkCount += sum((len(subfolder) for subfolder in self.bookmarksBySubfolderByFolder[folder.folderID].itervalues()))
    179 
    180         contList.append(GetFromClass(LocalLocationsFolder, {'label': GetByLabel('UI/AclBookmarks/LocationsInSystem', system=cfg.evelocations.Get(session.solarsystemid2).name),
    181          'id': ('myPlaces', 'localLocations'),
    182          'headers': placesHeaders,
    183          'GetSubContent': self.GetLocalLocationsScrollList,
    184          'open': False,
    185          'state': 'locked',
    186          'showicon': eveicon.folder,
    187          'showlen': False}))
    188         for isPersonal in [True, False]:
    189             if isPersonal:
    190                 iconPath = eveicon.folder
    191                 label = GetByLabel('UI/PeopleAndPlaces/PersonalLocations')
    192                 id = ('myPlaces', 'personalFolders')
    193                 count = personalBookmarkCount
    194             else:
    195                 iconPath = eveicon.shared_folder
    196                 label = GetByLabel('UI/PeopleAndPlaces/SharedLocations')
    197                 id = ('myPlaces', 'sharedFolders')
    198                 count = sharedBookmarkCount
    199             groupEntry = GetFromClass(ListGroup, {'GetSubContent': self.GetLocationFolderScrollList,
    200              'label': label,
    201              'id': id,
    202              'groupItems': [],
    203              'folders': folders,
    204              'isPersonal': isPersonal,
    205              'headers': placesHeaders,
    206              'open': False,
    207              'posttext': '<color=%s>[%d]</color>' % (COLOR_POSTTEXT, count),
    208              'showlen': False,
    209              'state': 'locked',
    210              'showicon': iconPath})
    211             contList.append(groupEntry)
    212 
    213         return contList
    214 
    215     def GetLocalLocationsScrollList(self, nodedata, newitems = 0):
    216         bookmark_service = sm.GetService('bookmarkSvc')
    217         bookmarks = bookmark_service.GetBookmarksForLocationID(session.solarsystemid2)
    218         return self.GetPlacesScrollList(places=bookmarks, groupID=nodedata.id, sublevel=1, isGroupPersonal=True)
    219 
    220     @telemetry.ZONE_METHOD
    221     def GetLocationFolderScrollList(self, nodedata, newitems = 0):
    222         if newitems:
    223             self.bookmarksBySubfolderByFolder = sm.GetService('bookmarkSvc').GetBookmarksBySubfolderByFolder()
    224         contList = []
    225         folders = nodedata.folders
    226         isPersonal = nodedata.isPersonal
    227         maxCount = appConst.MAX_BOOKMARKS_IN_PERSONAL_FOLDER if isPersonal else appConst.MAX_BOOKMARKS_IN_SHARED_FOLDER
    228         activeFolders = [ f for f in folders if f.isActive ]
    229         activeFolders.sort(key=lambda fld: (-fld.isPersonal, fld.folderName.lower()))
    230         for folder in activeFolders:
    231             if folder.isPersonal != isPersonal:
    232                 continue
    233             folderID = folder.folderID
    234             count = sum((len(subfolder) for subfolder in self.bookmarksBySubfolderByFolder[folderID].itervalues()))
    235             if count > maxCount:
    236                 postText = '<color=%s>[%d]</color>' % (COLOR_WARNING_POSTTEXT, count)
    237                 hint = GetByLabel('UI/AclBookmarks/TooManyBookmarksInFolderHint', currentBookmarks=count, maxBookmarks=maxCount)
    238             else:
    239                 postText = '<color=%s>[%d]</color>' % (COLOR_POSTTEXT, count)
    240                 hint = None
    241             if isPersonal:
    242                 iconPath = eveicon.folder
    243             else:
    244                 iconPath = eveicon.shared_folder
    245             entry = GetFromClass(BookmarkFolderGroup, {'GetSubContent': self.GetPlacesSubfolders,
    246              'DropData': self.DropInPlacesFolder,
    247              'hint': hint,
    248              'label': folder.folderName,
    249              'folderName': folder.folderName,
    250              'posttext': postText,
    251              'id': ('myPlaces', (folderID, None)),
    252              'groupItems': self.bookmarksBySubfolderByFolder[folderID],
    253              'folderID': folderID,
    254              'folder': folder,
    255              'state': 'locked',
    256              'showicon': iconPath,
    257              'showlen': False,
    258              'sublevel': 1,
    259              'isDragObject': True,
    260              'MenuFunction': self.BookmarkACLFolderMenu,
    261              'allowGuids': ['listentry.PlaceEntry', 'xtriui.InvItem', 'listentry.InvItem']})
    262             contList.append(entry)
    263 
    264         inactiveFolders = [ x for x in folders if not x.isActive and x.isPersonal == isPersonal ]
    265         if inactiveFolders:
    266             inactiveFolders.sort(key=lambda fl: fl.folderName.lower())
    267             inactiveFoldersEntry = self._GetEntryForInactiveFolders(inactiveFolders, self.bookmarksBySubfolderByFolder)
    268             contList.append(inactiveFoldersEntry)
    269         if not isPersonal:
    270             contList.extend(self.GetAdminFoldersScrollList())
    271         return contList
    272 
    273     def _GetEntryForInactiveFolders(self, inactiveFolders, bookmarksBySubfolderByFolder):
    274         entry = GetFromClass(ListGroup, {'GetSubContent': self._GetInactiveFolders,
    275          'label': GetByLabel('UI/AclBookmarks/InactiveFolders'),
    276          'id': ('inactiveFolders', None),
    277          'groupItems': inactiveFolders,
    278          'bookmarksBySubfolderByFolder': bookmarksBySubfolderByFolder,
    279          'state': 'locked',
    280          'showicon': 'hide',
    281          'showlen': False,
    282          'sublevel': 1})
    283         return entry
    284 
    285     def _GetInactiveFolders(self, nodedata, newitems = 0):
    286         scrollList = []
    287         for folder in nodedata.groupItems:
    288             if folder.isPersonal:
    289                 texturePath = eveicon.folder
    290                 iconHint = GetByLabel('UI/AclBookmarks/PersonalFolderType')
    291             else:
    292                 texturePath = eveicon.shared_folder
    293                 iconHint = GetByLabel('UI/AclBookmarks/SharedFolderType')
    294             entry = GetFromClass(InactiveFolderEntry, {'label': folder.folderName,
    295              'folderName': folder.folderName,
    296              'id': ('inactiveFolder_%s' % folder.folderID, None),
    297              'folderID': folder.folderID,
    298              'folder': folder,
    299              'state': 'locked',
    300              'texturePath': texturePath,
    301              'iconHint': iconHint,
    302              'GetMenu': self.GetMenuForInactiveFolders,
    303              'sublevel': 2})
    304             scrollList.append(entry)
    305 
    306         return scrollList
    307 
    308     def GetMenuForInactiveFolders(self, entry):
    309         return self.BookmarkACLFolderMenu(entry.sr.node)
    310 
    311     def BookmarkACLFolderMenu(self, node):
    312         menuList = [(MenuLabel('UI/AclBookmarks/FolderInformation'), self.ShowBookmarkFolderInfo, (node.folderID,))]
    313         if node.folder.accessLevel in (appConst.ACCESS_PERSONAL, appConst.ACCESS_ADMIN):
    314             menuList.append((MenuLabel('UI/AclBookmarks/EditBookmarkFolder'), self.EditACLFolder, (node.folderID,)))
    315             menuList.append((MenuLabel('UI/AclBookmarks/DeleteBookmarkFolder'), self.DeleteACLFolder, (node.folderID,)))
    316         if not node.folder.isPersonal:
    317             menuList.append((MenuLabel('UI/AclBookmarks/ForgetBookmarkFolder'), self.ForgetFolder, (node.folderID,)))
    318         if node.folder.isActive:
    319             menuList.append((MenuLabel('UI/AclBookmarks/MarkFolderAsInactive'), self.MarkFolderAsInactive, (node.folderID,)))
    320             if node.folder.accessLevel != appConst.ACCESS_VIEW:
    321                 menuList.append((MenuLabel('UI/AclBookmarks/CreateSubfolder'), self.CreateSubFolderInFolder, (node.folderID,)))
    322         else:
    323             menuList.append((MenuLabel('UI/AclBookmarks/MarkFolderActive'), self.MarkFolderAsActive, (node.folderID,)))
    324         if session.role & (ROLE_GML | ROLE_WORLDMOD):
    325             menuList.append(('GM: FolderID: ' + str(node.folderID), blue.pyos.SetClipboardData, (str(node.folderID),)))
    326         return menuList
    327 
    328     @telemetry.ZONE_METHOD
    329     def GetSubfolderEntry(self, subfolder, folderID, bookmarks, isPersonal):
    330         if isPersonal:
    331             iconPath = eveicon.folder
    332         else:
    333             iconPath = eveicon.shared_folder
    334         if subfolder.creatorID is not None:
    335             if subfolder.creatorID == invConst.ownerSystem:
    336                 label = GetByLabel(subfolder.subfolderName)
    337             else:
    338                 label = GetByLabel('UI/PeopleAndPlaces/FolderName', folderName=subfolder.subfolderName, creator=subfolder.creatorID)
    339         else:
    340             label = subfolder.subfolderName
    341         count = len(bookmarks)
    342         maxCount = MAX_BOOKMARKS_DISPLAYED_IN_GROUP
    343         if count > maxCount:
    344             text = GetByLabel('UI/AclBookmarks/TruncatedBookmarksInSubfolder', maxBookmarks=maxCount, currentBookmarks=count)
    345             postText = '<color=%s>[%s]</color>' % (COLOR_WARNING_POSTTEXT, text)
    346             hint = GetByLabel('UI/AclBookmarks/TooManyBookmarksInSubfolderHint', currentBookmarks=count, maxBookmarks=maxCount)
    347         else:
    348             postText = '<color=%s>[%d]</color>' % (COLOR_POSTTEXT, count)
    349             hint = None
    350         return GetFromClass(BaseFolderGroup, {'GetSubContent': self.GetPlacesSubEntries,
    351          'DropData': self.DropInPlacesFolder,
    352          'hint': hint,
    353          'label': label,
    354          'id': ('myPlaces', (folderID, subfolder.subfolderID)),
    355          'folderID': folderID,
    356          'groupItems': bookmarks,
    357          'posttext': postText,
    358          'showlen': False,
    359          'sublevel': 2,
    360          'subfolderID': subfolder.subfolderID,
    361          'subfolder': subfolder,
    362          'MenuFunction': self.BookmarkSubfolderMenu,
    363          'state': 'locked',
    364          'showicon': iconPath,
    365          'isPersonal': isPersonal,
    366          'allowGuids': ['listentry.PlaceEntry', 'xtriui.InvItem', 'listentry.InvItem']})
    367 
    368     @telemetry.ZONE_METHOD
    369     def GetPlacesSubEntries(self, nodedata, newitems = 0):
    370         if newitems:
    371             places = sm.GetService('bookmarkSvc').GetBookmarksBySubfolderByFolder()[nodedata.folderID][nodedata.subfolderID]
    372         else:
    373             places = nodedata.groupItems
    374         isPersonal = nodedata.isPersonal
    375         return self.GetPlacesScrollList(places, nodedata.subfolderID, sublevel=3, isGroupPersonal=isPersonal)
    376 
    377     @telemetry.ZONE_METHOD
    378     def GetPlacesSubfolders(self, nodedata, newitems = 0):
    379         folderID = nodedata.folderID
    380         bookmarkSvc = sm.GetService('bookmarkSvc')
    381         subfolders = bookmarkSvc.GetSubfoldersInFolder(folderID)
    382         if newitems:
    383             bookmarksBySubfolder = bookmarkSvc.GetBookmarksBySubfolderByFolder()[folderID]
    384         else:
    385             bookmarksBySubfolder = nodedata.groupItems
    386         entries = []
    387         isPersonal = nodedata.folder.isPersonal
    388         for subfolder in Sort(subfolders.values(), key=ConvertSubfolderName):
    389             entry = self.GetSubfolderEntry(subfolder, folderID, bookmarksBySubfolder[subfolder.subfolderID], isPersonal)
    390             entries.append(entry)
    391 
    392         entries.extend(self.GetPlacesScrollList(bookmarksBySubfolder[None], (folderID, None), sublevel=2, isGroupPersonal=isPersonal))
    393         return entries
    394 
    395     def BookmarkSubfolderMenu(self, node):
    396         folder = sm.GetService('bookmarkSvc').GetBookmarkFolder(node.subfolder.folderID)
    397         m = []
    398         if folder.accessLevel != appConst.ACCESS_VIEW and (folder.accessLevel != appConst.ACCESS_USE or node.subfolder.creatorID == session.charid):
    399             if node.subfolder.creatorID != ownerSystem:
    400                 m += [(MenuLabel('UI/AclBookmarks/EditSubfolder'), self.EditSubfolder, (node.subfolderID,))]
    401             m += [(MenuLabel('UI/AclBookmarks/DeleteSubfolder'), self.DeleteSubfolder, (node.subfolderID,))]
    402         if session.role & (ROLE_GML | ROLE_WORLDMOD):
    403             m += [('GM: subfolderID: ' + str(node.subfolderID), blue.pyos.SetClipboardData, (str(node.subfolderID),))]
    404         return m
    405 
    406     def CreateACLFolder(self, *args):
    407         wnd = BookmarkContainerWindow.Open()
    408         wnd.Maximize()
    409 
    410     def ShowBookmarkFolderInfo(self, folderID):
    411         sm.GetService('bookmarkSvc').ShowBookmarkFolderInfo(folderID)
    412 
    413     def EditACLFolder(self, folderID):
    414         folder = sm.GetService('bookmarkSvc').GetBookmarkFolder(folderID, refresh=True)
    415         windowID = '%s_%s' % (BookmarkContainerWindow.default_windowID, folderID)
    416         wnd = BookmarkContainerWindow.Open(folder=folder, windowID=windowID)
    417         wnd.Maximize()
    418 
    419     def DeleteACLFolder(self, folderID):
    420         if sm.GetService('bookmarkSvc').onlyPartiallyLoaded:
    421             msg = 'ConfirmDeleteFolderPartiallyLoaded'
    422         else:
    423             msg = 'ConfirmDeleteFolder'
    424         if prompt_player_fsd_dialog(msg, {}, uiconst.YESNO, uiconst.ID_YES) == uiconst.ID_YES:
    425             sm.GetService('bookmarkSvc').DeleteBookmarkFolder(folderID)
    426 
    427     def ForgetFolder(self, folderID):
    428         if prompt_player_fsd_dialog('ConfirmForgetFolder', {}, uiconst.YESNO, uiconst.ID_YES) == uiconst.ID_YES:
    429             sm.GetService('bookmarkSvc').RemoveFromKnownFolders(folderID)
    430 
    431     def MarkFolderAsInactive(self, folderID):
    432         sm.GetService('bookmarkSvc').UpdateFolderActiveState(folderID, False)
    433 
    434     def MarkFolderAsActive(self, folderID):
    435         sm.GetService('bookmarkSvc').UpdateFolderActiveState(folderID, True)
    436 
    437     def CreateSubFolderInFolder(self, folderID):
    438         windowID = '%s_newSub_%s' % (BookmarkSubfolderWindow.default_windowID, folderID)
    439         wnd = BookmarkSubfolderWindow.Open(folderID=folderID, windowID=windowID)
    440         wnd.Maximize()
    441 
    442     def CreateSubfolder(self, *args):
    443         validFolders = sm.GetService('bookmarkSvc').GetFilteredFolders()
    444         if len(validFolders) == 0:
    445             if prompt_player_fsd_dialog('CreateBookmarkFolderAsNoneValid', {}, uiconst.YESNO, uiconst.ID_YES) == uiconst.ID_YES:
    446                 wnd = BookmarkContainerWindow.Open()
    447                 wnd.Maximize()
    448             return
    449         wnd = BookmarkSubfolderWindow.Open()
    450         wnd.Maximize()
    451 
    452     def EditSubfolder(self, subfolderID):
    453         subfolder = sm.GetService('bookmarkSvc').GetSubfolder(subfolderID)
    454         windowID = '%s_%s' % (BookmarkSubfolderWindow.default_windowID, subfolderID)
    455         wnd = BookmarkSubfolderWindow.Open(subfolder=subfolder, windowID=windowID)
    456         wnd.Maximize()
    457 
    458     def DeleteSubfolder(self, subfolderID):
    459         if sm.GetService('bookmarkSvc').onlyPartiallyLoaded:
    460             msg = 'ConfirmDeleteSubfolderPartiallyLoaded'
    461         else:
    462             msg = 'ConfirmDeleteSubfolder'
    463         if prompt_player_fsd_dialog(msg, {}, uiconst.YESNO, uiconst.ID_YES) == uiconst.ID_YES:
    464             sm.GetService('bookmarkSvc').DeleteSubfolder(subfolderID)
    465 
    466     @telemetry.ZONE_METHOD
    467     def GetPlacesScrollList(self, places, groupID, sublevel, isGroupPersonal = False):
    468         addressbook = sm.GetService('addressbook')
    469         bookmarkSvc = sm.GetService('bookmarkSvc')
    470         scrolllist = []
    471         unreachabelText = GetByLabel('UI/Common/unreachable')
    472         coordinateText = GetByLabel('UI/PeopleAndPlaces/Coordinate')
    473         now = blue.os.GetWallclockTime()
    474         maxCount = MAX_BOOKMARKS_DISPLAYED_IN_GROUP
    475         if len(places) > maxCount:
    476             places = itertools.islice(places, maxCount)
    477         for bookmark in places:
    478             hint, comment = bookmarkSvc.UnzipMemo(bookmark.memo)
    479             sol, con, reg = addressbook.GetSolConReg(bookmark)
    480             typename = self.GetGroupName(bookmark.typeID)
    481             date = FmtDate(bookmark.created, 'ls')
    482             expiry = FmtDate(bookmark.expiry, 'ls') if bookmark.expiry else '-'
    483             if bookmark and IsCoordinateBookmark(bookmark):
    484                 typename = coordinateText
    485             jumps = 0
    486             if 40000000 > bookmark.itemID > 30000000:
    487                 jumps = self.GetJumpCount(session.solarsystemid2, bookmark.itemID)
    488                 if IsUnreachableJumpCount(jumps):
    489                     jumps = sm.GetService('clientPathfinderService').GetNoRouteFoundText(bookmark.itemID)
    490             elif 40000000 > bookmark.locationID > 30000000:
    491                 jumps = self.GetJumpCount(session.solarsystemid2, bookmark.locationID)
    492                 if IsUnreachableJumpCount(jumps):
    493                     jumps = sm.GetService('clientPathfinderService').GetNoRouteFoundText(bookmark.locationID)
    494             creatorID = getattr(bookmark, 'creatorID', None)
    495             creatorName = self.GetCreatorName(creatorID)
    496             isBookmarkAvailable = IsBookmarkAvailable(creatorID, bookmark.created, now)
    497             folderID = getattr(bookmark, 'folderID', None)
    498             if folderID is not None:
    499                 _, isPersonal = bookmarkSvc.GetFolderNamesAndType(folderID, subfolderID=getattr(bookmark, 'subfolderID', None))
    500             else:
    501                 isPersonal = creatorID == session.charid
    502             text = '<t>'.join((unicode(x) for x in (hint,
    503              typename,
    504              jumps,
    505              sol,
    506              con,
    507              reg,
    508              date,
    509              expiry,
    510              creatorName)))
    511             hintForBookmark = hint
    512             if getattr(bookmark, 'note', None):
    513                 truncatedNote = bookmark.note[:50] + '...' if len(bookmark.note) > 50 else bookmark.note
    514                 hintForBookmark += '<br>- %s' % truncatedNote
    515             scrolllist.append(GetFromClass(PlaceEntry, {'bm': bookmark,
    516              'DropData': lambda *args: self.DropOnBookmark(bookmark, *args),
    517              'itemID': bookmark.bookmarkID,
    518              'tabs': [],
    519              'hint': hintForBookmark,
    520              'comment': comment,
    521              'label': text,
    522              'sublevel': sublevel,
    523              'listGroupID': groupID,
    524              'isGroupPersonal': isPersonal,
    525              'isBookmarkAvailable': isBookmarkAvailable,
    526              'GetSortValue': self.GetLocationSortValue}))
    527             blue.pyos.BeNice()
    528 
    529         return scrolllist
    530 
    531     def GetLocationSortValue(self, node, by, sortDirection, idx):
    532         label = node.label
    533         strings = label.split('<t>')
    534         if idx is not None and len(strings) > idx:
    535             value = strings[idx].lower()
    536             try:
    537                 value = float(value)
    538                 return value
    539             except ValueError:
    540                 return value
    541 
    542         val = label.lower()
    543         return val
    544 
    545     @Memoize
    546     def GetCreatorName(self, creatorID):
    547         if creatorID is not None:
    548             creatorName = cfg.eveowners.Get(creatorID).name
    549         else:
    550             creatorName = ''
    551         return creatorName
    552 
    553     @Memoize
    554     def GetGroupName(self, typeID):
    555         return evetypes.GetGroupName(typeID)
    556 
    557     @Memoize(2)
    558     def GetJumpCount(self, solarsystemID, itemID):
    559         pathfinder = sm.GetService('clientPathfinderService')
    560         return pathfinder.GetAutopilotJumpCount(solarsystemID, itemID)
    561 
    562     def DropOnBookmark(self, bookmark, dragNode, nodes, *args):
    563         if not hasattr(bookmark, 'folderID'):
    564             return
    565         groupKey = (None, (bookmark.folderID, bookmark.subfolderID))
    566         self.DropInPlacesFolder(groupKey, nodes)
    567 
    568     @telemetry.ZONE_METHOD
    569     def GetAdminFoldersScrollList(self):
    570         iconPath = eveicon.corporation_folder
    571         id = self.adminFolderId
    572         hint = GetByLabel('UI/AclBookmarks/AdminFolderHint')
    573         groupEntry = GetFromClass(ListGroup, {'GetSubContent': self.GetAdminFolders,
    574          'RefreshScroll': self.RefreshScroll,
    575          'label': GetByLabel('UI/AclBookmarks/FolderWithAdminAccess'),
    576          'id': id,
    577          'groupItems': [],
    578          'headers': placesHeaders,
    579          'hint': hint,
    580          'open': False,
    581          'showlen': 0,
    582          'state': 'locked',
    583          'showicon': iconPath,
    584          'sublevel': 1})
    585         return [groupEntry]
    586 
    587     @telemetry.ZONE_METHOD
    588     def GetAdminFolders(self, *args):
    589         searchResults = self.FetchAdminSearchResults()
    590         scrollList = []
    591         knownFolders = sm.GetService('bookmarkSvc').foldersNew
    592         for folder in searchResults:
    593             name = folder.folderName
    594             if folder.folderID in knownFolders:
    595                 isKnown = True
    596                 if knownFolders[folder.folderID].isActive:
    597                     postText = GetByLabel('UI/AclBookmarks/SubscribedActive')
    598                 else:
    599                     postText = GetByLabel('UI/AclBookmarks/SubscribedInactive')
    600             else:
    601                 isKnown = False
    602                 postText = GetByLabel('UI/AclBookmarks/NotSubscribed')
    603             label = '%s  <color=%s>[%s]</color>' % (name, COLOR_POSTTEXT, postText)
    604             scrollList.append(GetFromClass(AdminFolder, {'hint': postText,
    605              'label': label,
    606              'OnDblClick': self.OnDblClickAdminFolder,
    607              'OnGetMenu': self.ShowMenuAdminFolders,
    608              'folderID': folder.folderID,
    609              'folderName': folder.folderName,
    610              'isKnown': isKnown,
    611              'sublevel': 2}))
    612 
    613         if not scrollList:
    614             scrollList.append(GetFromClass(SE_GenericCore, {'label': GetByLabel('UI/AclBookmarks/NoAdminFolderFound'),
    615              'sublevel': 2}))
    616         return scrollList
    617 
    618     def FetchAdminSearchResults(self):
    619         bookmarkSvc = sm.GetService('bookmarkSvc')
    620         resultFolders = bookmarkSvc.SearchFoldersWithAdminAccess()
    621         return resultFolders
    622 
    623     def OnDblClickAdminFolder(self, entry):
    624         node = entry.sr.node
    625         if node.isKnown:
    626             self.EditACLFolder(node.folderID)
    627         else:
    628             sm.GetService('bookmarkSvc').ShowBookmarkFolderInfo(node.folderID)
    629 
    630     def ShowMenuAdminFolders(self, entry):
    631         node = entry.sr.node
    632         menuList = []
    633         if node.isKnown:
    634             menuList += [(MenuLabel('UI/AclBookmarks/FolderInformation'), self.ShowBookmarkFolderInfo, (node.folderID,)), (MenuLabel('UI/AclBookmarks/ForgetBookmarkFolder'), self.ForgetFolder, (node.folderID,))]
    635         else:
    636             menuList += [(MenuLabel('UI/AclBookmarks/AddFolder'), self.ShowBookmarkFolderInfo, (node.folderID,))]
    637         if session.role & (ROLE_GML | ROLE_WORLDMOD):
    638             menuList += [('GM: FolderID: ' + str(node.folderID), blue.pyos.SetClipboardData, (str(node.folderID),))]
    639         return menuList
    640 
    641 
    642 class BookmarksScroll(eveScroll.Scroll):
    643 
    644     def CollectSubNodes(self, node, nodes = None, clear = 1):
    645         if nodes is None:
    646             nodes = []
    647         for subnode in node.get('subNodes', []):
    648             if subnode is None:
    649                 continue
    650             self.CollectSubNodes(subnode, nodes, clear)
    651             nodes.append(subnode)
    652 
    653         if clear:
    654             node.subNodes = []
    655         return nodes
    656 
    657 
    658 class BaseFolderGroup(ListGroup):
    659 
    660     def Startup(self, *etc):
    661         ListGroup.Startup(self, *etc)
    662         self.overlayButton = ButtonIcon(name='overlayButton', parent=self.sr.labelClipper, align=uiconst.CENTERLEFT, width=14, height=14, iconSize=16, left=200, texturePath=eveicon.visibility, func=self.OnChangeSensorOverlayVisibility, colorSelected=COLOR_SELECTED, isSelectedBgUsed=False)
    663 
    664     def Load(self, node):
    665         ListGroup.Load(self, node)
    666         self.folderKey = node.id[1]
    667         self.overlayButton.left = self.sr.label.width + self.sr.label.left + 8
    668         self.SetIsVisible(GetBookmarkFolderVisibilityManager().IsFolderVisible(self.folderKey))
    669 
    670     def OnChangeSensorOverlayVisibility(self):
    671         bmVisibilityMgr = GetBookmarkFolderVisibilityManager()
    672         isVisible = not bmVisibilityMgr.IsFolderVisible(self.folderKey)
    673         bmVisibilityMgr.SetFolderVisibility(self.folderKey, isVisible)
    674         sm.ScatterEvent('OnRefreshBookmarks')
    675         self.SetIsVisible(isVisible)
    676 
    677     def SetIsVisible(self, isVisible):
    678         if isVisible:
    679             hint = GetByLabel('UI/PeopleAndPlaces/RemoveLocationFolderFromSensorOverlay')
    680             self.overlayButton.SetSelected()
    681         else:
    682             hint = GetByLabel('UI/PeopleAndPlaces/ShowLocationFolderInSensorOverlay')
    683             self.overlayButton.SetDeselected()
    684         self.overlayButton.hint = hint
    685 
    686 
    687 class BookmarkFolderGroup(BaseFolderGroup):
    688     isDragObject = True
    689 
    690     def GetDragData(self):
    691         if self.sr.node.folder.isPersonal:
    692             return []
    693         ret = KeyVal(nodeType='BookmarkFolderEntry', folderID=self.sr.node.folderID, label=self.sr.node.folderName)
    694         return [ret]
    695 
    696 
    697 class InactiveFolderEntry(Generic):
    698     isDragObject = True
    699 
    700     def Startup(self, *args):
    701         Generic.Startup(self, *args)
    702         self.icon = Sprite(parent=self, align=uiconst.CENTERLEFT, pos=(60, 0, 16, 16), state=uiconst.UI_DISABLED)
    703 
    704     def Load(self, node):
    705         Generic.Load(self, node)
    706         sublevelCorrection = self.sr.node.scroll.sr.get('sublevelCorrection', 0)
    707         sublevel = max(0, node.Get('sublevel', 0) - sublevelCorrection)
    708         iconLeft = 5 + 16 * sublevel
    709         self.icon.texturePath = node.texturePath
    710         self.icon.hint = node.iconHint
    711         self.icon.left = iconLeft
    712         self.sr.label.left = self.icon.left + 20
    713         self.sr.label.opacity = self.icon.opacity = 0.6
    714 
    715     def GetDragData(self):
    716         if self.sr.node.folder.isPersonal:
    717             return []
    718         ret = KeyVal(nodeType='BookmarkFolderEntry', folderID=self.sr.node.folderID, label=self.sr.node.folderName)
    719         return [ret]
    720 
    721 
    722 class AdminFolder(SE_GenericCore):
    723     isDragObject = True
    724 
    725     def ApplyAttributes(self, attributes):
    726         SE_GenericCore.ApplyAttributes(self, attributes)
    727         self.sr.icon = eveIcon.Icon(icon=eveicon.corporation_folder, parent=self, pos=(37, 2, 16, 16), align=uiconst.RELATIVE, ignoreSize=True, state=uiconst.UI_DISABLED)
    728 
    729     def Load(self, node):
    730         SE_GenericCore.Load(self, node)
    731         sublevelCorrection = self.sr.node.scroll.sr.get('sublevelCorrection', 0)
    732         sublevel = max(0, node.Get('sublevel', 0) - sublevelCorrection)
    733         self.sr.icon.left = 5 + 16 * sublevel
    734         self.sr.label.left = self.sr.icon.left + 20
    735 
    736     def GetDragData(self):
    737         ret = KeyVal(nodeType='BookmarkFolderEntry', folderID=self.sr.node.folderID, label=self.sr.node.folderName)
    738         return [ret]
    739 
    740 
    741 class LocalLocationsFolder(ListGroup):
    742 
    743     def Startup(self, *etc):
    744         super(LocalLocationsFolder, self).Startup(*etc)
    745         ButtonIcon(parent=ContainerAutoSize(parent=self, align=uiconst.TORIGHT, idx=self.sr.labelClipper.GetOrder()), align=uiconst.CENTER, texturePath=eveicon.open_window, hint=localization.GetByLabel('UI/Common/OpenInWindow'), func=StandaloneBookmarkWnd.Open, args=())