notepad.py (29255B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\notepad.py 2 import blue 3 import evelink 4 import uthread 5 import localization 6 from bannedwords.client import bannedwords 7 from carbonui import uiconst 8 from carbon.common.script.util.timerstuff import AutoTimer 9 from carbonui.primitives.container import Container 10 from carbonui.util.various_unsorted import SortListOfTuples 11 from carbonui.uicore import uicore 12 from carbonui.control.button import Button 13 from eve.client.script.ui.control.divider import Divider 14 from eve.client.script.ui.control.entries.generic import Generic 15 from eve.client.script.ui.control.entries.util import GetFromClass 16 from eve.client.script.ui.control.eveEditPlainText import EditPlainText 17 from eve.client.script.ui.control.eveIcon import Icon 18 from eve.client.script.ui.control.eveLabel import EveLabelMedium 19 from eve.client.script.ui.control.eveScroll import Scroll 20 from carbonui.control.window import Window 21 from eve.client.script.ui.control.listgroup import ListGroup 22 from eve.client.script.ui.shared.userentry import User 23 from eve.client.script.ui.util.utilWindows import NamePopup 24 from menu import MenuLabel 25 from player_messaging.client.ui_message import prompt_player_fsd_dialog 26 from utillib import KeyVal 27 from eve.common.lib import appConst as const 28 29 class NotepadWindow(Window): 30 __guid__ = 'form.Notepad' 31 __notifyevents__ = [] 32 default_width = 400 33 default_height = 300 34 default_windowID = 'notepad' 35 default_captionLabelPath = 'UI/Notepad/Notepad' 36 default_iconNum = 'res:/ui/Texture/WindowIcons/notepad.png' 37 38 def ApplyAttributes(self, attributes): 39 Window.ApplyAttributes(self, attributes) 40 self.SetMinSize((350, 200)) 41 self.sr.main.padding = const.defaultPadding 42 self.sr.nav = Container(name='nav', align=uiconst.TOLEFT, width=settings.user.ui.Get('notepadscrollistwidth', 128), parent=self.sr.main, idx=0) 43 divider = Divider(name='divider', align=uiconst.TOLEFT, idx=1, width=const.defaultPadding, parent=self.sr.main, state=uiconst.UI_NORMAL) 44 divider.Startup(self.sr.nav, 'width', 'x', 100, 256) 45 self.sr.navbuttons = Container(name='navbuttons', align=uiconst.TOBOTTOM, parent=self.sr.nav, height=38) 46 self.sr.newfolder = Button(parent=self.sr.navbuttons, label=localization.GetByLabel('UI/Notepad/NewFolder'), padTop=4, align=uiconst.TOTOP, func=self.NewFolderClick) 47 self.sr.newnote = Button(parent=self.sr.navbuttons, label=localization.GetByLabel('UI/Notepad/NewNote'), padTop=4, align=uiconst.TOTOP, func=self.NewNote, args=(0,)) 48 self.sr.navbuttons.height = sum([ each.height + each.padTop + each.padBottom for each in self.sr.navbuttons.children ]) + 4 49 self.sr.senderlist = Scroll(name='senderlist', parent=self.sr.nav) 50 self.sr.senderlist.OnDelete = self.OnDelete 51 self.sr.senderlist.multiSelect = 0 52 self.sr.note = Container(name='notecontainer', align=uiconst.TOALL, parent=self.sr.main, pos=(0, 0, 0, 0)) 53 self.sr.titlecont = Container(name='titlecontainer', align=uiconst.TOTOP, height=48, parent=self.sr.note) 54 self.sr.icon = Icon(parent=self.sr.titlecont, pos=(0, 0, 32, 32)) 55 self.sr.titletext = EveLabelMedium(parent=self.sr.titlecont, align=uiconst.TOTOP, padding=(40, 5, 5, 0)) 56 self.sr.titletext.OnSizeChanged = self.OnTitleSizeChanged 57 self.sr.browser = EditPlainText(parent=self.sr.note, showattributepanel=1, counterMax=3900, countWithTags=True) 58 self.sr.browser.sr.window = self 59 self.sr.browser.allowPrivateDrops = 1 60 self.OnScale_ = self._OnResize 61 divider.OnSizeChanging = self.OnDividerMove 62 self.starting = 1 63 import log 64 log.LogInfo('Starting Notepad') 65 self.folders = {} 66 self.notes = {} 67 self.charnotes = {} 68 self.settings = {} 69 self.settingStrs = {} 70 self.notedata = {} 71 self.lastid = 0 72 uthread.new(self.LoadNotesData) 73 74 def OnTitleSizeChanged(self, *args, **kwds): 75 self.sr.titlecont.height = max(48, self.sr.titletext.textheight + self.sr.titletext.padTop * 2) 76 77 def LoadNotesData(self): 78 notes = sm.RemoteSvc('charMgr').GetOwnerNoteLabels() 79 self.folderIDs = [] 80 badNotes = [ note for note in notes if note.label[0] not in ('I', 'N', 'S') ] 81 for entry in notes: 82 if entry.label[0] in ('I', 'N') and entry.label[1] == ':': 83 n = KeyVal() 84 n.noteID = entry.noteID 85 n.text = None 86 if entry.label[0] == 'N': 87 n.label = entry.label[2:] 88 self.notes['N:' + str(entry.noteID)] = n 89 if entry.label.startswith('S:'): 90 label = entry.label[2:] 91 if label in self.settings: 92 self.settings[label].append(entry.noteID) 93 else: 94 self.settings[label] = [entry.noteID] 95 96 parallelCalls = [] 97 for note in badNotes: 98 parallelCalls.append((sm.RemoteSvc('charMgr').RemoveOwnerNote, (note.noteID,))) 99 100 if len(parallelCalls): 101 uthread.parallel(parallelCalls) 102 folders = self.GetSetting('Folders') 103 if folders is not None: 104 for entry in folders.split('|'): 105 tmp = entry.split('::') 106 if len(tmp) != 4: 107 continue 108 id, _type, parentID, label = tmp 109 n = KeyVal() 110 n.type = _type 111 if parentID == 'None': 112 parentID = 0 113 n.parent = int(parentID) 114 n.data = label 115 self.folders[int(id)] = n 116 self.lastid = max(self.lastid, int(id)) 117 118 else: 119 n = KeyVal() 120 n.type = 'F' 121 n.parent = 0 122 n.data = localization.GetByLabel('UI/Notepad/Main') 123 self.folders[1] = n 124 self.lastid = 1 125 self.starting = 0 126 self.LoadNotes() 127 self.sr.autosaveTimer = AutoTimer(60000, self.SaveNote) 128 self.activeNode = None 129 self.ShowNote(settings.char.notepad.Get('activeNote', None)) 130 131 def CloseByUser(self, *args): 132 if not self.SaveNote(): 133 return 134 settings.user.ui.Set('notepadscrollistwidth', self.sr.nav.width) 135 self.SaveFolders() 136 Window.CloseByUser(self) 137 138 def SaveFolders(self): 139 folderstr = '' 140 for key, value in self.folders.items(): 141 folderstr += '%s::%s::%s::%s|' % (key, 142 value.type, 143 value.parent, 144 value.data) 145 146 uthread.new(self.SetSetting, 'Folders', folderstr) 147 148 def SetSetting(self, id, string): 149 if id in self.settingStrs and self.settingStrs[id] == string: 150 return 151 if id in self.settings: 152 dbIDs = self.settings[id] 153 dbIDs.sort() 154 else: 155 dbIDs = [] 156 idStr = 'S:' + str(id) 157 newIDs = [] 158 while len(string) > 0: 159 part = string[:6000] 160 string = string[6000:] 161 if len(dbIDs): 162 noteID = int(dbIDs.pop(0)) 163 sm.RemoteSvc('charMgr').EditOwnerNote(noteID, idStr, part) 164 else: 165 noteID = sm.RemoteSvc('charMgr').AddOwnerNote(idStr, part) 166 newIDs.append(noteID) 167 168 parallelCalls = [] 169 for noteID in dbIDs: 170 parallelCalls.append((sm.RemoteSvc('charMgr').RemoveOwnerNote, (int(noteID),))) 171 172 if len(parallelCalls): 173 uthread.parallel(parallelCalls) 174 self.settings[id] = newIDs 175 176 def GetSetting(self, id): 177 if id in self.settingStrs: 178 return self.settingStrs[id] 179 if id not in self.settings: 180 return None 181 parallelCalls = [] 182 for noteID in self.settings[id]: 183 parallelCalls.append((sm.RemoteSvc('charMgr').GetOwnerNote, (int(noteID),))) 184 185 if len(parallelCalls): 186 notes = uthread.parallel(parallelCalls) 187 self.settingStrs[id] = '' 188 for note in notes: 189 self.settingStrs[id] += note[0].note 190 191 return self.settingStrs[id] 192 193 def WriteNote(self, name, text, folderID, noteID = None): 194 if not noteID: 195 noteID = sm.RemoteSvc('charMgr').AddOwnerNote('N:' + name, '<br>') 196 self.AddNote(folderID, 'N', noteID) 197 n = KeyVal() 198 n.noteID = noteID 199 n.label = name 200 n.text = text 201 self.notes['N:' + str(noteID)] = n 202 uthread.pool('notepad::SetNote', sm.RemoteSvc('charMgr').EditOwnerNote, int(noteID), 'N:' + self.notes['N:' + str(noteID)].label, text) 203 return noteID 204 205 def GetNotesByType(self, t = 'N'): 206 notes = [] 207 for n in self.notes: 208 if n.find(t + ':') == 0: 209 v = self.notes[n] 210 v.parentID = self.GetParentFolder(v.noteID) 211 v.parentName = '' 212 parent = self.folders.get(v.parentID) 213 if parent: 214 v.parentName = parent.data 215 notes.append(v) 216 217 return notes 218 219 def GetFolders(self): 220 folders = [] 221 for f in self.folders: 222 folder = self.folders[f] 223 if folder.type == 'F': 224 v = KeyVal() 225 v.noteID = f 226 v.label = folder.data 227 folders.append(v) 228 229 return folders 230 231 def GetNoteText(self, noteID): 232 ret = None 233 ret = note = self.notes.get('N:' + str(noteID), None) 234 if not note or note.text is None: 235 _note = sm.RemoteSvc('charMgr').GetOwnerNote(noteID) 236 note = KeyVal() 237 note.text = _note[0].note.strip() 238 note.label = _note[0].label[2:] 239 self.notes['N:' + str(noteID)].text = note.text 240 self.notes['N:' + str(noteID)].label = note.label 241 ret = note 242 return ret 243 244 def _OnResize(self, *etc): 245 self.OnDividerMove() 246 247 def OnDividerMove(self, *etc): 248 if not self.destroyed: 249 self.sr.nav.width = max(100, min(self.sr.nav.width, self.displayWidth - 154)) 250 251 def GoTo(self, URL, data = None, args = {}, scrollTo = None): 252 uicore.cmd.OpenBrowser(URL, data=data, args=args) 253 254 def LoadNotes(self): 255 while self.starting: 256 blue.pyos.BeNice() 257 258 scrolllist = [] 259 notes = self.GetNotes(0) 260 for id, n in notes.items(): 261 groupID = ('notepad', id) 262 scrolllist.append((n.data.lower(), GetFromClass(ListGroup, {'GetSubContent': self.GetGroupSubContent, 263 'label': n.data, 264 'id': groupID, 265 'groupItems': self.GroupGetContentIDList(groupID), 266 'iconMargin': 18, 267 'showlen': 1, 268 'state': 0, 269 'sublevel': 0, 270 'MenuFunction': self.GroupMenu, 271 'allowGuids': ['listentry.User', 272 'listentry.Sender', 273 'listentry.PlaceEntry', 274 'listentry.NoteItem'], 275 'DropData': self.GroupDropNode, 276 'ChangeLabel': self.GroupChangeLabel, 277 'DeleteFolder': self.GroupDeleteFolder, 278 'GetContentIDList': self.GroupGetContentIDList, 279 'CreateEntry': self.GroupCreateEntry, 280 'RefreshScroll': self.RefreshNotes}))) 281 282 scrolllist = SortListOfTuples(scrolllist) 283 scrolllist.append(GetFromClass(ListGroup, {'GetSubContent': self.GetAllFolderContent, 284 'label': localization.GetByLabel('UI/Notepad/AllNotes'), 285 'id': ('All Notes', 0), 286 'groupItems': self.notes, 287 'iconMargin': 18, 288 'showlen': 1, 289 'state': 0, 290 'sublevel': 0, 291 'showicon': 'res:/ui/Texture/WindowIcons/notegroup.png', 292 'state': 'locked'})) 293 if not self.destroyed: 294 self.sr.senderlist.Load(fixedEntryHeight=17, contentList=scrolllist, scrollTo=self.sr.senderlist.GetScrollProportion()) 295 self.sr.senderlist.hiliteSorted = 0 296 297 def RefreshNotes(self): 298 self.LoadNotes() 299 300 def GetAllFolderContent(self, nodedata, newitems = 0): 301 scrolllist = [] 302 for key, note in self.notes.iteritems(): 303 noteID = 'N:' + str(note.noteID) 304 entry = GetFromClass(NoteItem, self.GetNoteItemData(noteID=noteID, noteType='NA')) 305 if entry is not None: 306 scrolllist.append((note.label.lower(), entry)) 307 308 scrolllist = SortListOfTuples(scrolllist) 309 return scrolllist 310 311 def GetGroupSubContent(self, nodedata, newitems = 0): 312 scrolllist = [] 313 notelist = self.GetNotes(nodedata.id[1]) 314 if len(notelist): 315 qi = 1 316 NoteListLength = len(notelist) 317 for id, note in notelist.items(): 318 entry = self.GroupCreateEntry((note.data, id), nodedata.sublevel + 1) 319 if entry is not None: 320 scrolllist.append((entry.label.lower(), entry)) 321 322 if len(nodedata.groupItems) != len(scrolllist): 323 nodedata.groupItems = self.GroupGetContentIDList(nodedata.id) 324 scrolllist = SortListOfTuples(scrolllist) 325 return scrolllist 326 327 def GroupMenu(self, node): 328 m = [] 329 if node.sublevel < 5: 330 m.append((MenuLabel('UI/Notepad/NewFolder'), self.NewFolder, (node.id[1], node))) 331 m.append((MenuLabel('UI/Notepad/NewNote'), self.NewNote, (node.id[1], node))) 332 return m 333 334 def GroupDropNode(self, id, nodes): 335 for node in nodes: 336 nodeMoved = False 337 if node.__guid__ in ('listentry.User', 'listentry.Sender') and node.charID != session.charid: 338 self.AddNote(id[1], 'I', node.charID) 339 nodeMoved = True 340 if node.__guid__ == 'listentry.NoteItem' and not self.NoteAlreadyExistsInFolder(node.noteID, id[1]): 341 noteID = node.noteID 342 if noteID in self.notes: 343 noteID = self.notes[noteID].noteID 344 self.AddNote(id[1], 'N', str(noteID)) 345 nodeMoved = True 346 if nodeMoved and not uicore.uilib.Key(uiconst.VK_SHIFT): 347 if node.id: 348 self.RemoveFolder(node.id[1], ask=0) 349 350 self.LoadNotes() 351 352 def GroupChangeLabel(self, id, newname): 353 self.RenameFolder(id[1], name=newname) 354 355 def GroupDeleteFolder(self, id): 356 noteID = id[1] 357 parentID = self.GetParentFolder(noteID) 358 notes = self.GetNotes(noteID) 359 for id, note in notes.items(): 360 if note.type == 'F': 361 self.GroupDeleteFolder((0, id)) 362 continue 363 self.DeleteFolderNote(id) 364 365 self.DeleteFolderNote(noteID) 366 self.LoadNotes() 367 self.SaveFolders() 368 369 def GroupCreateEntry(self, id, sublevel): 370 note, id = self.folders[id[1]], id[1] 371 if note.type == 'F': 372 groupID = ('notepad', id) 373 return GetFromClass(ListGroup, {'GetSubContent': self.GetGroupSubContent, 374 'label': note.data, 375 'id': groupID, 376 'groupItems': self.GroupGetContentIDList(groupID), 377 'iconMargin': 18, 378 'showlen': 1, 379 'state': 0, 380 'sublevel': sublevel, 381 'MenuFunction': self.GroupMenu, 382 'allowGuids': ['listentry.User', 'listentry.Sender', 'listentry.NoteItem'], 383 'DropData': self.GroupDropNode, 384 'ChangeLabel': self.GroupChangeLabel, 385 'DeleteFolder': self.GroupDeleteFolder, 386 'GetContentIDList': self.GroupGetContentIDList, 387 'CreateEntry': self.GroupCreateEntry, 388 'RefreshScroll': self.RefreshNotes}) 389 if note.type == 'I': 390 charinfo = cfg.eveowners.Get(note.data) 391 return GetFromClass(User, {'charID': int(note.data), 392 'id': (note.data, id), 393 'info': charinfo, 394 'color': None, 395 'GetMenu': self.GetCharMenu, 396 'OnClick': self.OnCharClick, 397 'sublevel': sublevel, 398 'noteID': 'I:' + str(note.data), 399 'label': charinfo.name}) 400 if note.type == 'N': 401 noteID = 'N:' + str(note.data) 402 if noteID in self.notes: 403 return GetFromClass(NoteItem, self.GetNoteItemData(noteID=noteID, noteType='N', sublevel=sublevel, folderID=id)) 404 del self.folders[id] 405 406 def GetNoteItemData(self, noteID, noteType, sublevel = 1, folderID = None): 407 note = self.notes[noteID] 408 return {'itemID': None, 409 'typeID': None, 410 'id': (note.label, folderID or noteID), 411 'label': note.label, 412 'sublevel': sublevel, 413 'noteID': noteID, 414 'type': noteType, 415 'ignoreRightClick': 1, 416 'get_link': lambda : evelink.Link(url=format_note_url(noteID), text=note.label), 417 'is_private': True} 418 419 def GroupGetContentIDList(self, id): 420 ids = self.GetNotes(id[1]) 421 return [ (self.folders[id].data, id) for id in ids ] 422 423 def GetCharMenu(self, node): 424 m = [None] + [(localization.GetByLabel('UI/Notepad/RemoveCharacter'), self.RemoveFolder, (node.id[1],))] 425 return m 426 427 def OnDelete(self, *args): 428 if not self.destroyed: 429 sel = self.sr.senderlist.GetSelected() 430 for entry in sel[:]: 431 if not entry.noteID: 432 continue 433 if entry.noteID.startswith('F'): 434 self.GroupDeleteFolder(entry.id) 435 elif entry.noteID.startswith('N') and entry.type == 'NA': 436 self.DeleteNote(entry.id[1]) 437 else: 438 self.RemoveFolder(entry.id[1]) 439 440 self.LoadNotes() 441 442 def OnCharClick(self, entry): 443 self.ShowNote(entry.sr.node.noteID) 444 445 def OnBookmarkClick(self, entry): 446 self.ShowNote(entry.sr.node.noteID) 447 448 def ShowNote(self, id, force = 0): 449 while getattr(self.sr.browser, 'loading', 0): 450 blue.pyos.synchro.Yield() 451 452 if not force and hasattr(self, 'activeNode') and id is not None and self.activeNode == id: 453 return True 454 if not force and not self.SaveNote(): 455 return False 456 if id is None or not id.upper().startswith('I:') and str(id) not in self.notes: 457 self.sr.titletext.text = (localization.GetByLabel('UI/Notepad/GeneralInformation'),) 458 self.sr.icon.LoadIcon('res:/ui/Texture/WindowIcons/notepad.png') 459 self.sr.icon.width = self.sr.icon.height = 32 460 self.sr.browser.SetValue(localization.GetByLabel('UI/Notepad/NotepadIntro')) 461 self.sr.browser.ReadOnly() 462 self.activeNote = None 463 return True 464 self.sr.browser.Editable() 465 noteID = id.split(':') 466 if len(noteID) != 2: 467 return True 468 t, id = noteID 469 if not force and self.activeNode == t + ':' + str(id): 470 return True 471 if t == 'I': 472 charid = int(id) 473 note = sm.RemoteSvc('charMgr').GetNote(charid) 474 charinfo = cfg.eveowners.Get(charid) 475 sm.GetService('photo').GetPortrait(charid, 64, self.sr.icon) 476 self.sr.titletext.text = charinfo.name 477 self.sr.browser.SetValue(note) 478 if t == 'N': 479 if 'N:' + str(id) in self.notes: 480 noteID = int(id) 481 if self.notes['N:' + str(id)].text is None: 482 note = sm.RemoteSvc('charMgr').GetOwnerNote(noteID) 483 self.notes['N:' + str(id)].text = note[0].note.strip() 484 self.notes['N:' + str(id)].label = note[0].label[2:] 485 self.sr.icon.LoadIcon('res:/ui/Texture/WindowIcons/note.png') 486 self.sr.icon.SetSize(32, 32) 487 self.sr.titletext.text = self.notes['N:' + str(id)].label 488 self.sr.browser.SetValue(self.notes['N:' + str(id)].text) 489 self.activeNode = t + ':' + str(id) 490 settings.char.notepad.Set('activeNote', self.activeNode) 491 uicore.registry.SetFocus(self.sr.browser) 492 return True 493 494 def SaveNote(self, *args): 495 if self.destroyed: 496 self.sr.autosaveTimer = None 497 return 498 if getattr(self, 'activeNode', None) is not None: 499 t, id = self.activeNode.split(':') 500 txt = self.sr.browser.GetValue() 501 if len(txt) > 3900: 502 return not prompt_player_fsd_dialog('NoteTooLong', {'total': len(txt)}, uiconst.YESNO) == uiconst.ID_YES 503 if t == 'I': 504 uthread.pool('notepad::SetNote', sm.RemoteSvc('charMgr').SetNote, int(id), txt) 505 if t == 'N': 506 if 'N:' + str(id) in self.notes and self.notes['N:' + str(id)].text != txt: 507 self.notes['N:' + str(id)].text = txt 508 uthread.pool('notepad::SetNote', sm.RemoteSvc('charMgr').EditOwnerNote, int(id), 'N:' + self.notes['N:' + str(id)].label, txt) 509 return True 510 511 def GetNotes(self, folderID): 512 notes = {} 513 for id, n in self.folders.iteritems(): 514 if n.parent != folderID: 515 continue 516 notes[id] = n 517 518 return notes 519 520 def GetNote(self, noteID): 521 if noteID in self.folders.keys(): 522 return self.folders[noteID] 523 524 def GetParentFolder(self, nodeID): 525 n = self.folders.get(nodeID, None) 526 if n: 527 return n.parent 528 else: 529 return 530 531 def RenameFolder(self, folderID = 0, entry = None, name = None, *args): 532 if name is None: 533 ret = NamePopup(localization.GetByLabel('UI/Notepad/FolderName'), localization.GetByLabel('UI/Notepad/TypeNewFolderName'), maxLength=20) 534 if ret is None: 535 return self.folders[folderID].data 536 name = ret 537 bannedwords.check_words_allowed(name) 538 if self.AlreadyExists('F', name): 539 prompt_player_fsd_dialog('CustomInfo', {'info': localization.GetByLabel('UI/Notepad/FolderAlreadyExists')}) 540 return 541 self.folders[folderID].data = name 542 return name 543 544 def NewFolder(self, folderID = 0, node = None, *args): 545 ret = NamePopup(localization.GetByLabel('UI/Notepad/FolderName'), localization.GetByLabel('UI/Notepad/TypeNewFolderName'), maxLength=20) 546 if ret is not None: 547 name = ret 548 bannedwords.check_words_allowed(name) 549 if self.AlreadyExists('F', name): 550 prompt_player_fsd_dialog('CustomInfo', {'info': localization.GetByLabel('UI/Notepad/FolderAlreadyExists')}) 551 return 552 self.AddNote(folderID, 'F', name) 553 data = {'label': name, 554 'folderid': self.lastid, 555 'parent': folderID} 556 self.LoadNotes() 557 self.SaveFolders() 558 return data 559 560 def NewFolderClick(self, *args): 561 self.NewFolder() 562 563 def RemoveFolder(self, folderID = 0, entry = None, ask = 1): 564 if folderID in self.folders: 565 if not ask or prompt_player_fsd_dialog('DeleteEntry', {}, uiconst.YESNO) == uiconst.ID_YES: 566 if self.activeNode == self.folders[folderID].type + ':' + str(self.folders[folderID].data): 567 self.activeNode = None 568 self.ShowNote(None) 569 parent = self.GetParentFolder(folderID) 570 del self.folders[folderID] 571 self.LoadNotes() 572 573 def NewNote(self, folderID = 0, node = None, *args): 574 ret = NamePopup(localization.GetByLabel('UI/Notepad/NoteName'), localization.GetByLabel('UI/Notepad/TypeNewNoteLabel'), maxLength=80) 575 if ret is not None: 576 name = ret 577 if self.AlreadyExists('N', name): 578 prompt_player_fsd_dialog('CustomInfo', {'info': localization.GetByLabel('UI/Notepad/NoteAlreadyExists')}) 579 return 580 noteID = sm.RemoteSvc('charMgr').AddOwnerNote('N:' + name, '<br>') 581 if folderID: 582 self.AddNote(folderID, 'N', noteID) 583 n = KeyVal() 584 n.noteID = noteID 585 n.label = name 586 n.text = '<br>' 587 self.notes['N:' + str(noteID)] = n 588 self.LoadNotes() 589 self.ShowNote('N:' + str(noteID)) 590 591 def RenameNote(self, noteID): 592 if noteID in self.folders: 593 noteID = self.folders[noteID].type + ':' + str(self.folders[noteID].data) 594 if noteID not in self.notes: 595 return 596 ret = NamePopup(localization.GetByLabel('UI/Notepad/NoteName'), localization.GetByLabel('UI/Notepad/TypeNewNoteLabel'), self.notes[noteID].label, maxLength=80) 597 if ret is not None: 598 if self.AlreadyExists('N', ret): 599 prompt_player_fsd_dialog('CustomInfo', {'info': localization.GetByLabel('UI/Notepad/NoteAlreadyExists')}) 600 return 601 self.notes[noteID].label = ret 602 sm.RemoteSvc('charMgr').EditOwnerNote(self.notes[noteID].noteID, 'N:' + ret) 603 self.LoadNotes() 604 if getattr(self, 'activeNode', None) == noteID: 605 self.sr.titletext.text = ret 606 607 def NoteAlreadyExistsInFolder(self, noteID, folderID): 608 notesInFolder = self.GetNotes(folderID) 609 noteIdsInFolder = [ n.data for n in notesInFolder.itervalues() ] 610 actualId = noteID 611 if noteID in self.notes: 612 actualId = self.notes[noteID].noteID 613 if str(actualId) in noteIdsInFolder: 614 return True 615 else: 616 return False 617 618 def AlreadyExists(self, type, name): 619 if type == 'N': 620 for key, value in self.notes.iteritems(): 621 if value.label == name: 622 return True 623 624 if type == 'F': 625 for key, value in self.folders.iteritems(): 626 if value.type == type and value.data == name: 627 return True 628 629 return False 630 631 def AddNote(self, parent, type, data): 632 self.lastid += 1 633 n = KeyVal() 634 n.type = type 635 n.parent = parent 636 n.data = data 637 self.folders[self.lastid] = n 638 639 def DeleteFolderNote(self, noteID): 640 del self.folders[noteID] 641 642 def DeleteNote(self, noteID): 643 if noteID in self.notes: 644 if prompt_player_fsd_dialog('DeleteNote', {}, uiconst.YESNO) == uiconst.ID_YES: 645 if self.activeNode == noteID: 646 self.activeNode = None 647 self.ShowNote(None) 648 t, id = noteID.split(':') 649 for key, value in self.folders.items(): 650 if value.type == t and str(value.data) == id: 651 del self.folders[key] 652 653 note = self.notes[noteID] 654 sm.RemoteSvc('charMgr').RemoveOwnerNote(int(note.noteID)) 655 del self.notes[noteID] 656 self.LoadNotes() 657 658 659 class NoteItem(Generic): 660 __guid__ = 'listentry.NoteItem' 661 isDragObject = True 662 663 def Startup(self, *args): 664 Generic.Startup(self, *args) 665 self.sr.icon = Icon(icon='res:/ui/Texture/WindowIcons/note.png', parent=self, left=0, top=-4, size=24, ignoreSize=True) 666 667 def Load(self, node): 668 Generic.Load(self, node) 669 sublevelCorrection = self.sr.node.scroll.sr.get('sublevelCorrection', 0) 670 sublevel = max(0, node.Get('sublevel', 0) - sublevelCorrection) 671 self.sr.icon.state = uiconst.UI_NORMAL 672 self.sr.label.left = 24 + max(0, sublevel * 16) 673 self.sr.icon.left = 0 + max(0, sublevel * 16) 674 self.sr.label.text = node.label 675 self.sr.label.Update() 676 677 def OnClick(self, *args): 678 if self.sr.node: 679 if not uicore.uilib.Key(uiconst.VK_CONTROL): 680 noteWindow = NotepadWindow.GetIfOpen() 681 if noteWindow and not noteWindow.ShowNote(self.sr.node.noteID): 682 return 683 self.sr.node.scroll.SelectNode(self.sr.node) 684 685 def GetMenu(self): 686 m = Generic.GetMenu(self) 687 noteWindow = NotepadWindow.Open() 688 if self.sr.node.type == 'N': 689 m += [(MenuLabel('UI/Notepad/RenameNote'), noteWindow.RenameNote, (self.sr.node.id[1],))] 690 m += [(MenuLabel('UI/Notepad/RemoveNote'), noteWindow.RemoveFolder, (self.sr.node.id[1],))] 691 if self.sr.node.type == 'NA': 692 m += [(MenuLabel('UI/Notepad/RenameNote'), noteWindow.RenameNote, (self.sr.node.id[1],))] 693 m += [(MenuLabel('UI/Notepad/DeleteNote'), noteWindow.DeleteNote, (self.sr.node.id[1],))] 694 return m 695 696 def GetHeight(self, *args): 697 return 18 698 699 def GetDragData(self, *args): 700 nodes = [self.sr.node] 701 return nodes 702 703 704 LINK_SCHEME = 'note' 705 706 def register_link_handlers(registry): 707 registry.register(LINK_SCHEME, handle_note_link, hint='UI/Notepad/ShowNote') 708 709 710 def handle_note_link(url): 711 note_id = parse_note_url(url) 712 note_window = NotepadWindow.Open() 713 note_window.ShowNote(note_id) 714 715 716 def parse_note_url(url): 717 return url[url.index(':') + 1:] 718 719 720 def format_note_url(note_id): 721 return u'{}:{}'.format(LINK_SCHEME, note_id)