svc_copycat2.py (48177B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\devtools\script\svc_copycat2.py 2 from __future__ import print_function 3 from future.utils import raise_ 4 import cPickle 5 import sys 6 import blue 7 import triui 8 import evetypes 9 import os 10 import random 11 import types 12 import urllib 13 import uthread 14 import xml.parsers.expat 15 from carbon.common.script.sys.service import Service, ROLE_WORLDMOD, ROLEMASK_ELEVATEDPLAYER, ROLE_GML, ROLE_PLAYER, ROLE_HEALSELF, ROLE_SPAWN, SERVICE_RUNNING, SERVICE_START_PENDING 16 from carbon.common.script.util import timerstuff 17 from carbonui import uiconst 18 from carbonui.control import tabGroup 19 from carbonui.control.window import Window 20 from carbonui.primitives.container import Container 21 from carbonui.primitives.containerAutoSize import ContainerAutoSize 22 from carbonui.primitives.fill import Fill 23 from carbonui.primitives.line import Line 24 from carbonui.primitives.sprite import Sprite 25 from carbonui.uicore import uicore 26 from eve.client.script.ui.control import eveLabel, eveScroll, eveWindowDropDownMenu 27 from eve.client.script.ui.control.entries.generic import Generic 28 from eve.client.script.ui.control.entries.util import GetFromClass 29 from eve.client.script.ui.control.listgroup import ListGroup 30 from eve.client.script.ui.util import utilWindows 31 from eve.common.lib import appConst as const 32 from eve.common.script.sys import eveCfg 33 from eve.devtools.script import dna, spiffy, param 34 from eveprefs import Handler 35 from eveprefs.iniformat import IniIniFile 36 from player_messaging.client.ui_message import prompt_player 37 CFG_USEONLINE = 0 38 myversion = '2.4' 39 SERVICENAME = 'copycat' 40 DEFAULTDBNAME = 'copycat.xml' 41 VIEW_USER = 0 42 VIEW_GROUPED = 1 43 VIEW_MARKET = 2 44 45 def GetTypeName(typeID): 46 return evetypes.GetName(typeID) 47 48 49 Progress = lambda title, text, current, total: sm.GetService('loading').ProgressWnd(title, text, current, total) 50 Slash = lambda command: sm.RemoteSvc('slash').SlashCmd(command) 51 Message = lambda title, body, icon = triui.INFO: prompt_player(body, title, options=uiconst.OK, icon=icon) 52 AUTOSAVE_IMMEDIATE = 3 53 AUTOSAVE_TIMED = 2 54 AUTOSAVE_EXITONLY = 1 55 AUTOSAVE_DISABLED = 0 56 UI_WBIG = 'copycat_width_big' 57 UI_WSMALL = 'copycat_width_small' 58 UI_WINFO = 'copycat_width_infopanel' 59 UI_USEINFO = 'copycat_infopanel' 60 61 def IsRepeatable(module): 62 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 63 if module.IsOnline() is False: 64 return False 65 for effectID in dogmaLocation.dogmaStaticMgr.effectsByType[module.typeID]: 66 effect = dogmaLocation.dogmaStaticMgr.effects[effectID] 67 if effect.effectCategory not in [const.dgmEffActivation, const.dgmEffTarget]: 68 continue 69 if effect.durationAttributeID is None: 70 continue 71 if effectID == const.effectOnline: 72 continue 73 return True 74 75 return False 76 77 78 def AskFile(title = 'Title goes here', body = 'Enter name of file:', setvalue = '', mustexist = True): 79 while True: 80 ret = utilWindows.NamePopup(caption=title, label=body, setvalue=setvalue, maxLength=256) 81 if not ret: 82 return None 83 filename = ret 84 if mustexist: 85 if os.path.exists(filename): 86 return filename 87 Message('File not found', 'Could not locate the file:<br> %s' % filename, icon=triui.WARNING) 88 continue 89 return filename 90 91 92 def EscapeString(unescaped): 93 unescaped = str(unescaped) 94 escaped = unescaped.replace('&', '&') 95 escaped = escaped.replace('<', '<') 96 escaped = escaped.replace('>', '>') 97 return escaped 98 99 100 def UnEscapeString(escaped): 101 escaped = str(escaped) 102 unescaped = escaped.replace('<', '<') 103 unescaped = unescaped.replace('>', '>') 104 unescaped = unescaped.replace('&', '&') 105 return unescaped 106 107 108 class CCItem(object): 109 110 def __init__(self): 111 self.parent = None 112 113 def __repr__(self): 114 if hasattr(self, 'name'): 115 return '<Item name="%s">' % self.name 116 return '<Item name=Unspecified>' 117 118 def Remove(self): 119 if self.parent: 120 self.parent.RemoveItem(self) 121 122 123 class CCFolder(CCItem): 124 125 def __init__(self): 126 CCItem.__init__(self) 127 self.content = [] 128 129 def AddItem(self, this): 130 self.content.append(this) 131 this.parent = self 132 133 def RemoveItem(self, this): 134 self.content.remove(this) 135 this.parent = None 136 137 def ContainsItem(self, this): 138 while this.parent: 139 this = this.parent 140 if this == self: 141 return True 142 143 return False 144 145 def __repr__(self): 146 return '<CCFolder>' 147 148 149 def CreateTreeFromDict(dict): 150 f = CCFolder() 151 for k, v in dict.iteritems(): 152 if type(v) == types.DictType: 153 node = CreateTreeFromDict(v) 154 else: 155 node = CCItem() 156 node.dna = v 157 node.name = k 158 f.AddItem(node) 159 160 return f 161 162 163 racial = {'Caldari': 1, 164 'Minmatar': 2, 165 'Gallente': 3, 166 'Amarr': 4} 167 168 class CopycatService(Service): 169 __slashhook__ = True 170 __notifyevents__ = ['ProcessRestartUI'] 171 __dependencies__ = [] 172 __guid__ = 'svc.copycat' 173 __servicename__ = SERVICENAME 174 __displayname__ = SERVICENAME.capitalize() 175 176 def cmd_cc(self, p): 177 try: 178 dnaKey, qty = p.Parse('s?i') 179 if qty is None: 180 qty = 1 181 dna.Ship(dnaKey=dnaKey).AssembleMany(qty) 182 return 'Ok' 183 except param.Error: 184 if not p.line.strip(): 185 uthread.new(self.Show) 186 return 'Ok' 187 raise 188 189 def cmd_getshipsetup(self, p): 190 dnaKey = sm.RemoteSvc('slash').SlashCmd('/getshipsetup ' + p.line) 191 dna.Ship(dnaKey=dnaKey).ShowInfo() 192 return 'Ok' 193 194 def igb(self, action = '', key = '', name = None): 195 if not session.role & ROLEMASK_ELEVATEDPLAYER: 196 return 197 action = action.lower() 198 if action == 'open': 199 dna.Popup(key, name) 200 201 def AddDestroyedShip(self, dnaKey, name): 202 now = blue.os.GetWallclockTime() 203 for info in self.last10killed: 204 if info[0] == dnaKey: 205 self.last10killed.remove(info) 206 break 207 208 self.last10killed = [(dnaKey, now, name)] + self.last10killed[:9] 209 self.WriteKilled() 210 211 def GetSetupsByTypeID(self, typeID): 212 hits = [] 213 typeID = str(typeID) 214 215 def Scan(folder): 216 for item in folder.content: 217 if isinstance(item, CCFolder): 218 Scan(item) 219 else: 220 parts = item.dna.split(':', 2) 221 if len(parts) == 3 and typeID == parts[1]: 222 hits.append((item.name, item.dna)) 223 224 Scan(self.tree) 225 return hits 226 227 def ShowInfo(self, what = None, name = None): 228 dna.Popup(what, name, buttons=False) 229 230 def GetInsiderDir(self): 231 return sm.GetService('insider').GetInsiderDir() 232 233 def Run(self, memStream = None): 234 self.state = SERVICE_START_PENDING 235 try: 236 self.lockout = False 237 self.wnd = None 238 self.dbchanged = False 239 INSIDERDIR = self.GetInsiderDir() 240 self.prefs = Handler(IniIniFile('copycat', INSIDERDIR)) 241 dbpath = os.path.join(INSIDERDIR, DEFAULTDBNAME) 242 for key, value in [('database', DEFAULTDBNAME), ('autosave', AUTOSAVE_IMMEDIATE)]: 243 if not self.prefs.HasKey(key): 244 self.prefs.SetValue(key, value) 245 246 TARGET = os.path.join(INSIDERDIR, self.prefs.database) 247 self.dbfilename = TARGET 248 self.dbautosave = self.prefs.autosave 249 self.last10killed = self.ReadKilled() 250 if not os.path.exists(dbpath): 251 self.RetrieveDefaultDatabase(dbpath) 252 self.tree = self.ReadDatabase() 253 if not self.tree: 254 self.tree = CreateTreeFromDict({'There is no data to display': {'': ''}}) 255 self.SetAutoSave(0) 256 self.SetAutoSave(self.dbautosave) 257 finally: 258 self.state = SERVICE_RUNNING 259 260 def Stop(self, memStream = None): 261 self.Hide() 262 if self.dbautosave: 263 self.SaveDatabaseIfChanged() 264 Service.Stop(self, memStream) 265 266 def ReadKilled(self): 267 self.last10killed = [] 268 try: 269 for line in open(os.path.join(self.GetInsiderDir(), 'destroyed.txt'), 'r'): 270 line = line.strip() 271 if line.startswith('DNA:'): 272 dnaKey, lostAt, name = line.split('=', 2) 273 self.last10killed.append([dnaKey, long(lostAt), name]) 274 275 except: 276 sys.exc_clear() 277 278 return self.last10killed 279 280 def WriteKilled(self): 281 try: 282 out = open(os.path.join(self.GetInsiderDir(), 'destroyed.txt'), 'w') 283 for line in self.last10killed: 284 print('%s=%d=%s' % line, file=out) 285 286 out.close() 287 except: 288 sys.exc_clear() 289 290 def SetAutoSave(self, mode): 291 self.dbautosave = mode 292 if mode == AUTOSAVE_TIMED: 293 self.dbautosavetimer = timerstuff.AutoTimer(300000, self.SaveDatabaseIfChanged) 294 else: 295 self.dbautosavetimer = None 296 self.prefs.autosave = self.dbautosave = mode 297 self.SaveDatabaseIfChanged() 298 self.UpdateStatus() 299 300 def SaveDatabaseIfChanged(self): 301 if self.dbchanged: 302 self.WriteDatabase(self.tree) 303 self.dbchanged = False 304 self.UpdateStatus() 305 306 def ReadDatabaseOLD(self, filename): 307 folder = CCFolder() 308 db = blue.classes.CreateInstance('blue.ResFile') 309 if db.Open(filename) and db.size > 0: 310 crud = str(db.Read()) 311 try: 312 stuff = cPickle.loads(crud) 313 for k, v in stuff: 314 item = CCItem() 315 item.name = k 316 item.dna = v 317 folder.AddItem(item) 318 319 except: 320 for line in crud.replace('\r', '').split('\n'): 321 if len(line) > 2: 322 if line[0] == '[' and line[-1] == ']': 323 pass 324 elif line[:4] == 'DNA:': 325 line = line.split('=') 326 item = CCItem() 327 item.name = line[1] 328 item.dna = line[0] 329 folder.AddItem(item) 330 331 if folder.content: 332 return folder 333 334 def ReadDatabase(self, filename = None): 335 self._root = None 336 if filename is None or filename == '': 337 filename = self.dbfilename 338 339 def XMLTagStart(tag, attrs): 340 if tag == 'data': 341 if self._root: 342 raise RuntimeError('Craptastic!') 343 self._root = self.currentfolder = self.currentitem = CCFolder() 344 elif tag == 'group': 345 folder = CCFolder() 346 self.currentfolder.AddItem(folder) 347 self.currentfolder = self.currentitem = folder 348 elif tag == 'item': 349 self.currentitem = CCItem() 350 else: 351 self.currenttag = tag 352 353 def XMLTagEnd(tag): 354 if tag == 'group': 355 if not hasattr(self.currentfolder, 'name'): 356 self.currentfolder.name = 'Unnamed group' 357 self.currentfolder = self.currentfolder.parent 358 elif tag == 'item': 359 if not hasattr(self.currentitem, 'name'): 360 self.currentitem.name = 'Unnamed setup' 361 if hasattr(self.currentitem, 'dna'): 362 self.currentfolder.AddItem(self.currentitem) 363 364 def XMLTagData(data): 365 if not self.currenttag: 366 return 367 data = data.replace('\n', '').replace('\r', '') 368 if not data: 369 return 370 if self.currenttag == 'name': 371 self.currentitem.name = UnEscapeString(eval("'" + data.replace("'", "\\'") + "'")) 372 elif self.currenttag == 'dna': 373 self.currentitem.dna = data 374 self.currenttag = None 375 376 try: 377 f = open(filename, 'r') 378 except: 379 return 380 381 self.currenttag = 'Kittens!' 382 self.currentfolder = None 383 p = xml.parsers.expat.ParserCreate() 384 p.StartElementHandler = XMLTagStart 385 p.EndElementHandler = XMLTagEnd 386 p.CharacterDataHandler = XMLTagData 387 p.buffer_text = True 388 p.returns_unicode = False 389 p.ParseFile(f) 390 root = self._root 391 self._root = None 392 return root 393 394 def WriteDatabase(self, tree, filename = None): 395 if not filename: 396 filename = self.dbfilename 397 list = [] 398 399 def XMLTag(key, value): 400 return '<%s>%s</%s>\r\n' % (key, repr(EscapeString(value))[1:-1], key) 401 402 def XMLDumpItem(f, item, tag, indent): 403 deeper = indent + '\t' 404 f.write('%s<%s>\r\n' % (indent, tag)) 405 f.write(deeper + XMLTag('name', item.name)) 406 f.write(deeper + XMLTag('dna', item.dna)) 407 f.write('%s</%s>\r\n' % (indent, tag)) 408 if item in list: 409 (RuntimeError, 'Endless cycle detected: %s' % item) 410 list.append(item) 411 412 def XMLDumpFolder(f, folder, tag = 'data', indent = ''): 413 deeper = indent + '\t' 414 if not indent: 415 f.write("<?xml version='1.0' encoding='utf-8'?>\r\n") 416 if hasattr(folder, 'name') and folder.name: 417 f.write('%s<%s>\r\n' % (indent, tag)) 418 f.write(deeper + XMLTag('name', folder.name)) 419 else: 420 f.write('%s<%s>\r\n' % (indent, tag)) 421 for item in folder.content: 422 if isinstance(item, CCFolder): 423 XMLDumpFolder(f, item, 'group', deeper) 424 else: 425 XMLDumpItem(f, item, 'item', deeper) 426 427 f.write('%s</%s>\r\n' % (indent, tag)) 428 429 XMLDumpFolder(open(filename, 'wb'), tree) 430 431 def ProcessRestartUI(self): 432 if self.wnd: 433 self.Hide() 434 self.Show() 435 436 def Hide(self, *args): 437 if self.wnd: 438 self.wnd.Close() 439 self.wnd = None 440 self.infotemplate = None 441 442 def RetrieveDefaultDatabase(self, dbpath): 443 try: 444 src = 'http://content.eveonline.com/QA/insider/copycat.xml' 445 urllib.urlretrieve(src, dbpath) 446 self.ReadDatabase() 447 except urllib.URLError: 448 prompt_player('There was a problem retrieving the default copycat db', 'Error', options=uiconst.OK, icon=triui.ERROR) 449 450 def Show(self): 451 if not (hasattr(session, 'solarsystemid') and session.solarsystemid2): 452 Message('Hold your horses!', 'The copycat UI requires you to be logged in.') 453 return 454 if self.wnd: 455 self.wnd.Maximize() 456 return 457 initing = True 458 self.wnd = wnd = Window.Open(windowID=SERVICENAME) 459 wnd._OnClose = self.Hide 460 wnd.SetCaption('Copycat') 461 wnd.sr.main = main = wnd.GetChild('main') 462 top = Container(name='push', align=uiconst.TOTOP, height=14, parent=main) 463 Line(parent=top, align=uiconst.TOBOTTOM) 464 push = Container(name='push', parent=top, align=uiconst.TOLEFT, width=const.defaultPadding, state=uiconst.UI_DISABLED) 465 Line(parent=push, align=uiconst.TORIGHT) 466 for label, func in [('File', self.GetMenu_File), ('My Ship', self.GetMenu_Ship)]: 467 menu = eveWindowDropDownMenu.WindowDropDownMenu(name='menu', parent=top, align=uiconst.TOLEFT, state=uiconst.UI_NORMAL) 468 menu.Setup(label, func) 469 470 Container(name='bottompush', parent=main, state=uiconst.UI_DISABLED, align=uiconst.TOBOTTOM, height=const.defaultPadding) 471 c = ContainerAutoSize(name='', parent=main, state=uiconst.UI_PICKCHILDREN, align=uiconst.TOBOTTOM) 472 wnd.sr.filenamelabel = eveLabel.Label(text='', parent=c, align=uiconst.TOPLEFT, padLeft=const.defaultPadding, color=None, state=uiconst.UI_NORMAL) 473 self.UpdateStatus() 474 wnd.sr.tabs = tabGroup.TabGroup(name='tabsparent', parent=main) 475 body = Container(name='scroll', parent=main, pos=(const.defaultPadding, 476 const.defaultPadding, 477 const.defaultPadding, 478 const.defaultPadding)) 479 wnd.sr.info = info = dna.InfoPanel(name='infopanel', parent=body, align=uiconst.TORIGHT) 480 info.Setup(readonly=True) 481 info.width = settings.user.ui.Get(UI_WINFO, 288) 482 self.scaling = 0 483 wnd.sr.div = Container(name='meow', parent=body, align=uiconst.TORIGHT) 484 Fill(parent=body, color=(1.0, 1.0, 1.0, 0.5), width=2, align=uiconst.TORIGHT) 485 wnd.sr.scroll = eveScroll.Scroll(parent=body) 486 wnd.sr.scroll.sr.sortBy = 'Name' 487 wnd.sr.scroll.Startup() 488 wnd.sr.scroll.sr.id = 'Copycat2Scroll' 489 wnd.sr.scroll.sr.content.OnDropData = self.OnDropData 490 wnd.OnDropData = self.OnDropData 491 492 def toggleview(*args): 493 x = settings.user.ui.Get(UI_USEINFO, 0) 494 if not initing: 495 x = not x 496 settings.user.ui.Set(UI_USEINFO, x) 497 b.state = uiconst.UI_HIDDEN 498 self.wnd.width = (self.smallwidth, self.bigwidth)[x] 499 self.UpdateInfoPanelStuff() 500 501 icon = Sprite(parent=main, width=16, height=16, align=uiconst.TOPRIGHT, top=14, left=const.defaultPadding, texturePath='res:/UI/Texture/classes/Browser/backIdle.png') 502 icon.OnClick = toggleview 503 self.wnd.sr.infotoggle = b = icon 504 self.viewmode = VIEW_USER 505 self.fixedgroups = {} 506 wnd.sr.tabs.Startup([['Normal', 507 self.wnd.sr.scroll, 508 self, 509 VIEW_USER], ['Grouped', 510 self.wnd.sr.scroll, 511 self, 512 VIEW_GROUPED], ['Market', 513 self.wnd.sr.scroll, 514 self, 515 VIEW_MARKET]], 'copycattabs') 516 self.smallwidth = settings.user.ui.Get(UI_WSMALL, 200) 517 self.bigwidth = settings.user.ui.Get(UI_WBIG, 400) 518 self.lastdna = None 519 toggleview() 520 if info.state != uiconst.UI_HIDDEN: 521 wnd.width = self.bigwidth 522 else: 523 wnd.width = self.smallwidth 524 wnd.Maximize(1) 525 wnd.OnEndScale_ = self.UpdateInfoPanelStuff 526 if session.role > 1: 527 self.ShowContent() 528 initing = False 529 530 def ScaleStart(self, *args): 531 self.wnd.sr.info.state = uiconst.UI_DISABLED 532 self.scaling = 1 533 self.ss_w = self.wnd.sr.info.width 534 self.ss_x = uicore.uilib.x 535 536 def ScaleMove(self, *args): 537 if self.scaling: 538 minW = 256 539 maxW = max(self.wnd.width - 100, minW) 540 diffx = uicore.uilib.x - self.ss_x 541 try: 542 self.wnd.sr.info.width = min(maxW, max(minW, self.ss_w - diffx)) 543 except: 544 pass 545 546 def ScaleEnd(self, *args): 547 settings.user.ui.Set(UI_WINFO, self.wnd.sr.info.width) 548 self.UpdateInfoPanelStuff() 549 550 def UpdateInfoPanelStuff(self, *args): 551 self.scaling = 0 552 b = self.wnd.sr.infotoggle 553 info = self.wnd.sr.info 554 info.state = self.wnd.sr.div.state = (uiconst.UI_HIDDEN, uiconst.UI_NORMAL)[settings.user.ui.Get(UI_USEINFO, 0)] 555 info.hideBackground = 0 556 if info.state == uiconst.UI_HIDDEN: 557 b.flag = b.hint = b.name = 'Show Info Panel' 558 b.texturePath = 'res:/UI/Texture/classes/Browser/nextIdle.png' 559 self.wnd.SetMinSize((256, 220)) 560 self.smallwidth = self.wnd.width 561 settings.user.ui.Set(UI_WSMALL, self.smallwidth) 562 else: 563 b.flag = b.hint = b.name = 'Hide Info Panel' 564 b.texturePath = 'res:/UI/Texture/classes/Browser/backIdle.png' 565 self.wnd.SetMinSize((max(400, info.width + 100), 220)) 566 self.bigwidth = self.wnd.width 567 settings.user.ui.Set(UI_WBIG, self.bigwidth) 568 b.state = uiconst.UI_HIDDEN 569 b.state = uiconst.UI_NORMAL 570 self.ShowDNA(force=True) 571 572 def ShowInfo(self, dnaKey = None, shipID = None, name = None): 573 if dnaKey: 574 dna.Ship(dnaKey=dnaKey, name=name).ShowInfo() 575 elif shipID: 576 dna.Ship(shipID=shipID).ShowInfo() 577 578 def ShowDNA(self, name = None, dnaKey = None, force = False): 579 info = self.wnd.sr.info 580 if not force: 581 if info.state == uiconst.UI_HIDDEN: 582 return 583 if self.lastdna == dnaKey: 584 return 585 self.lastdna = dnaKey 586 t = None 587 if name is None and dnaKey is None: 588 t = getattr(self, 'infotemplate', None) 589 elif dnaKey: 590 self.infotemplate = t = dna.Ship(dnaKey=dnaKey, name=name) 591 if t: 592 info.Load(t) 593 594 def Load(self, viewmode): 595 s = self.wnd.sr.scroll 596 if self.viewmode != viewmode: 597 self.viewmode = viewmode 598 self.ShowContent() 599 600 def Refresh(self): 601 self.wnd.sr.scroll.Refresh() 602 603 def ShowContent(self, resetPos = True): 604 if not self.wnd: 605 return 606 s = self.wnd.sr.scroll 607 p = s.sr.position 608 tree = self.tree 609 if self.viewmode == VIEW_USER: 610 h = ['Name', 'Type', 'Group'] 611 elif self.viewmode == VIEW_GROUPED: 612 tree = self.ReorganisedByInvGroup(self.tree) 613 h = ['Name', 'Type'] 614 elif self.viewmode == VIEW_MARKET: 615 tree = self.ReorganisedByMarketGroup(self.tree) 616 h = ['Name', 'Type'] 617 else: 618 raise RuntimeError('Unrecognized View Mode: %s' % tree) 619 self.LogInfo('ShowContent calling self.BuildTreeList') 620 s.Load(contentList=self.BuildTreeList(tree), fixedEntryHeight=None, headers=h) 621 if not resetPos: 622 s.sr.position = p 623 s.UpdatePosition() 624 625 def UpdateStatus(self): 626 if not self.wnd: 627 return 628 self.wnd.sr.filenamelabel.text = 'File: <color=0xff%s>%s' % (('00ff00', 'ff0000')[self.dbchanged], os.path.basename(self.dbfilename)) 629 status = 'Current database:<br> %s<br><br>' % os.path.abspath(self.dbfilename) 630 if self.dbautosave != AUTOSAVE_IMMEDIATE: 631 status += '%sModified.<br><br>' % ('Not ', '')[self.dbchanged] 632 if self.dbautosave == AUTOSAVE_DISABLED: 633 status += "Changes to the database are not automatically saved. Select 'SAVE' from the database menu to make any changes permanent." 634 elif self.dbautosave == AUTOSAVE_IMMEDIATE: 635 status += 'Any changes to the database are permanent.' 636 elif self.dbautosave == AUTOSAVE_TIMED: 637 status += 'Changes to the database are automatically saved every 5 minutes.' 638 elif self.dbautosave == AUTOSAVE_EXITONLY: 639 status += "Changes to the database are saved at exit or by selecting 'SAVE' from the database menu." 640 else: 641 status += 'wtf?' 642 self.wnd.sr.filenamelabel.hint = status 643 644 def UpdateContent(self, everything = True): 645 self.ShowContent(False) 646 self.dbchanged = True 647 if self.dbautosave == AUTOSAVE_IMMEDIATE: 648 self.SaveDatabaseIfChanged() 649 self.UpdateStatus() 650 651 def CopyFromItem(self, fromItem): 652 item = CCItem() 653 item.name = fromItem.name 654 item.dna = fromItem.dna 655 item.fromItem = fromItem 656 return item 657 658 def ReorganisedByMarketGroup(self, sourcetree): 659 temp = {} 660 661 def _CollectItem(fromItem): 662 if isinstance(fromItem, CCFolder): 663 for x in fromItem.content: 664 _CollectItem(x) 665 666 return 667 item = self.CopyFromItem(fromItem) 668 typeID = int(item.dna.split(':')[1]) 669 if typeID in temp: 670 temp[typeID].append(item) 671 else: 672 temp[typeID] = [item] 673 674 _CollectItem(sourcetree) 675 676 def _WalkMarket(marketGroups): 677 items = [] 678 for info in marketGroups: 679 grouplist = sm.GetService('marketutils').GetMarketGroups()[info.marketGroupID] 680 if grouplist: 681 subitems = _WalkMarket(grouplist) 682 if subitems: 683 folder = CCFolder() 684 folder.name = info.marketGroupName 685 for item in subitems: 686 folder.AddItem(item) 687 688 items.append(folder) 689 else: 690 for typeID in info.types: 691 if typeID in temp: 692 folder = CCFolder() 693 folder.name = info.marketGroupName 694 for item in temp[typeID]: 695 folder.AddItem(item) 696 697 items.append(folder) 698 del temp[typeID] 699 700 return items 701 702 tree = _WalkMarket(sm.GetService('marketutils').GetMarketGroups()[None])[0] 703 if temp: 704 folder = CCFolder() 705 folder.name = 'Other' 706 for itemlist in temp.itervalues(): 707 for item in itemlist: 708 folder.AddItem(item) 709 710 tree.AddItem(folder) 711 return tree 712 713 def ReorganisedByInvGroup(self, sourcetree): 714 715 def _CollectItem(fromItem): 716 if isinstance(fromItem, CCFolder): 717 for x in fromItem.content: 718 _CollectItem(x) 719 720 return 721 typeID = int(fromItem.dna.split(':')[1]) 722 if evetypes.Exists(typeID): 723 groupname = evetypes.GetGroupName(typeID) 724 else: 725 groupname = 'Unknown' 726 if groupname in self.fixedgroups: 727 folder = self.fixedgroups[groupname] 728 else: 729 folder = self.fixedgroups[groupname] = CCFolder() 730 folder.name = groupname 731 folder.AddItem(self.CopyFromItem(fromItem)) 732 733 for groupname in self.fixedgroups.iterkeys(): 734 self.fixedgroups[groupname].content = [] 735 736 _CollectItem(sourcetree) 737 newtree = CCFolder() 738 for groupname in self.fixedgroups.iterkeys(): 739 folder = self.fixedgroups[groupname] 740 if folder.content: 741 newtree.AddItem(folder) 742 743 return newtree 744 745 def BuildTreeList(self, folder, sublevel = 0): 746 ret = [] 747 self.LogInfo('folder: %s' % folder) 748 for this in folder.content: 749 self.LogInfo('this: %s' % this) 750 if isinstance(this, CCFolder): 751 raceID = racial.get(this.name, 0) 752 node = {'raceID': raceID, 753 'label': this.name, 754 'iconMargin': 18, 755 'showlen': self.viewmode != VIEW_MARKET or raceID, 756 'groupItems': this.content, 757 'state': 0, 758 'allowCopy': 0, 759 'allowGuids': ['listentry.DNAGroup', 'listentry.DNAEntry'], 760 'RefreshScroll': self.ShowContent, 761 'GetSubContent': self.GroupGetSubContent, 762 'typeID': 3296, 763 'selected': 0, 764 'hideFill': True, 765 'id': ('dna', this), 766 'sublevel': sublevel} 767 if self.viewmode == VIEW_USER: 768 node.update({'ChangeLabel': self.GroupChangeLabel, 769 'DeleteFolder': self.GroupDelete, 770 'DropData': self.GroupAdoptNodes}) 771 entry = GetFromClass(DNAGroup, node) 772 else: 773 typeID = int(this.dna.split(':')[1]) 774 tgroupname = 'Unknown' 775 okay = False 776 if session.role & ROLE_PLAYER: 777 typeName = evetypes.GetNameOrNone(typeID) 778 if typeName: 779 tname = typeName 780 tgroupname = evetypes.GetGroupName(typeID) 781 okay = True 782 else: 783 tname = '[%s]' % typeID 784 typeID = 0 785 else: 786 inv = None 787 tname = '%s' % typeID 788 node = {'typename': 'Type:%s' % typeID, 789 'typeID': typeID, 790 'invitem': typeName, 791 'showinfo': okay, 792 'id': ('dna', this), 793 'sublevel': sublevel} 794 if self.viewmode == VIEW_USER: 795 node['label'] = '%s<t>%s<t>%s' % (this.name, tname, tgroupname) 796 else: 797 node['label'] = '%s<t>%s' % (this.name, tname) 798 entry = GetFromClass(DNAEntry, node) 799 node['sublevel'] = sublevel 800 node['id'] = (str(id(this)), this) 801 node['locked'] = self.viewmode 802 node[SERVICENAME] = None 803 self.LogInfo('node: %s' % node) 804 ret.append(entry) 805 806 return ret 807 808 def GroupGetSubContent(self, node, newitems = 0): 809 if not len(node.groupItems): 810 return [] 811 sublevel = node.get('sublevel', 0) 812 self.LogInfo('GroupGetSubContent calling self.BuildTreeList') 813 self.LogInfo('node: %s' % node) 814 if not isinstance(node.id[1], CCFolder): 815 return [] 816 return self.BuildTreeList(node.id[1], sublevel + 1) 817 818 def GroupChangeLabel(self, id, newlabel): 819 id[1].name = newlabel 820 self.UpdateContent() 821 822 def GroupAdd(self, name = None, parent = None): 823 if not name: 824 ret = utilWindows.NamePopup(caption='New folder', label='Enter name for new folder:', setvalue='New Folder', maxLength=64) 825 if ret: 826 name = ret 827 if not name: 828 return None 829 f = CCFolder() 830 f.name = name 831 if not parent: 832 parent = self.tree 833 parent.AddItem(f) 834 self.UpdateContent() 835 return f 836 837 def GroupDelete(self, id): 838 id[1].Remove() 839 self.UpdateContent() 840 841 def GroupAdoptNodes(self, folderid, these, *args): 842 self.FolderAdoptNodes(folderid[1], these) 843 844 def OnDropData(self, dragObj, these): 845 self.FolderAdoptNodes(self.tree, these) 846 847 def FolderAdoptNodes(self, targetfolder, these): 848 changed = False 849 for node in these: 850 if node.Get(SERVICENAME, None): 851 item = node.id[1] 852 if isinstance(item, CCFolder): 853 if item == targetfolder or item.ContainsItem(targetfolder): 854 continue 855 elif item.parent == targetfolder: 856 continue 857 item.Remove() 858 targetfolder.AddItem(item) 859 changed = True 860 861 if changed: 862 self.UpdateContent() 863 864 def GetMenu_File(self): 865 mutexgfx = (('ui_9_64_14', 1.0 / 4.0), ('ui_38_16_193', 1.0 / 16.0)) 866 m = [(('Open...', 'ui_34_64_5'), self.DoImport, ('open',)), 867 None, 868 (('New Folder', 'res:/ui/Texture/WindowIcons/smallfolder.png', 0.125), (None, self.GroupAdd)[self.viewmode == VIEW_USER]), 869 None, 870 (('Save', 'ui_41_64_1'), self.DoSave), 871 (('Save As...', 'ui_41_64_1'), self.DoSave, ('as',)), 872 None, 873 (('Import', 'ui_7_64_16'), [(('DNA from clipboard', 'ui_10_64_16'), self.DoImport, ('clipboard',)), 874 None, 875 (('XML Database (Copycat 2.x)', 'ui_34_64_5'), self.DoImport, ('import',)), 876 (('DNA Database (Copycat 1.x)', 'ui_34_64_6'), self.DoImport, ('importold',))]), 877 None, 878 (('Autosave?', 'res:/ui/Texture/WindowIcons/assets.png'), [(('Immediately on every change',) + mutexgfx[self.dbautosave == AUTOSAVE_IMMEDIATE], self.SetAutoSave, (AUTOSAVE_IMMEDIATE,)), 879 (('Every 5 minutes, if changed',) + mutexgfx[self.dbautosave == AUTOSAVE_TIMED], self.SetAutoSave, (AUTOSAVE_TIMED,)), 880 (('At copycat/client exit only',) + mutexgfx[self.dbautosave == AUTOSAVE_EXITONLY], self.SetAutoSave, (AUTOSAVE_EXITONLY,)), 881 (('Never (Manual only)',) + mutexgfx[self.dbautosave == AUTOSAVE_DISABLED], self.SetAutoSave, (AUTOSAVE_DISABLED,))])] 882 return m 883 884 def DoImport(self, mode): 885 if mode == 'clipboard': 886 self.DoStore(dnaKey=blue.clipboard.GetClipboardString()) 887 return 888 verb = 'Import' 889 importfunc = self.ReadDatabase 890 if mode == 'importold': 891 filename = 'copycat.dna' 892 title = 'Import Copycat 1.x DNA Database' 893 importfunc = self.ReadDatabaseOLD 894 elif mode == 'import': 895 filename = 'copycat.xml' 896 title = 'Import XML Database' 897 elif mode == 'reload': 898 filename = self.dbfilename 899 verb = 'Reload' 900 elif mode == 'open': 901 filename = self.dbfilename 902 title = 'Open Database' 903 verb = 'Open' 904 else: 905 raise_(ValueError, "'%s' is not a DoImport mode" % mode) 906 if mode != 'reload': 907 filename = AskFile(title, 'Enter name of file to %s' % verb, setvalue=filename) 908 if not filename: 909 return 910 item = importfunc(filename) 911 if item: 912 if mode in ('reload', 'open'): 913 append = False 914 text = 'This operation will clear the currently loaded database!<br><br>Proceed?' 915 result = prompt_player(title='%s Database' % verb, text=text, options=uiconst.OKCANCEL, icon=uiconst.WARNING) 916 else: 917 append = True 918 text = 'Do you want to append to current database, or replace it?<br><br>Select <color=0xff00ff00>YES<color=0xffffffff> to <color=0xff00ff00>APPEND<color=0xffffffff> to current database.<br>Select <color=0xffff0000>NO<color=0xffffffff> to <color=0xffff0000>REPLACE<color=0xffffffff> current database.<br>Select <color=0xffffff00>CANCEL<color=0xffffffff> to abort the import.' 919 result = prompt_player(title='Import Database', text=text, options=uiconst.YESNOCANCEL) 920 if result in (uiconst.ID_CANCEL, uiconst.ID_CLOSE): 921 return 922 if result == uiconst.ID_NO: 923 append = False 924 if append: 925 item.name = 'Imported (%s)' % os.path.basename(filename) 926 self.tree.AddItem(item) 927 else: 928 self.tree = item 929 if mode == 'open': 930 self.prefs.database = self.dbfilename = filename 931 self.dbchanged = not append 932 self.UpdateContent() 933 else: 934 Message('Database %s Error' % verb, 'The file is not a valid Copycat DNA Database, or contained no entries.', icon=triui.WARNING) 935 936 def DoSave(self, mode = 'default'): 937 if mode == 'default': 938 self.WriteDatabase(self.tree) 939 self.dbchanged = False 940 elif mode == 'as': 941 ret = utilWindows.NamePopup(caption='Save database as...', label='Enter filename', setvalue=self.dbfilename, maxLength=256) 942 if ret: 943 self.WriteDatabase(self.tree, ret) 944 self.dbchanged = False 945 self.prefs.database = self.dbfilename = ret 946 elif mode == 'selection': 947 pass 948 else: 949 raise_(ValueError, 'Unknown save mode: %s' % mode) 950 self.UpdateStatus() 951 952 def GetMenu_Ship(self): 953 HaveShip = eveCfg.GetActiveShip() is not None 954 HaveGML = session.role & ROLE_GML 955 CanSpawn = session.role & (ROLE_WORLDMOD | ROLE_SPAWN) 956 HaveHEALSELF = session.role & ROLE_HEALSELF 957 s = dna.Ship(shipID=eveCfg.GetActiveShip()) 958 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 959 ship = dogmaLocation.GetDogmaItem(eveCfg.GetActiveShip()) 960 pod = False 961 if HaveShip: 962 if ship.groupID == 29: 963 if not CanSpawn: 964 uthread.new(Message, "Haha! You're in a pod :)", "How did that happen?<br>Wait, never mind, I don't care.<br><br><br>Menu not available because you:<br>- are in a capsule<br>- don't have WORLDMOD or SPAWN role.") 965 return 966 pod = True 967 m = s.GetMenuInline(disabled=True, info=False, store=False, assemble=False, fit=False, refit=False) 968 else: 969 m = s.GetMenuInline(disabled=not HaveShip, store=True, assemble=False, refit=True) 970 else: 971 uthread.new(Message, 'No ship... No pod...', "You might want to get into a ship, it's cold out there.") 972 return 973 974 def cf(func, condition = True): 975 if condition and HaveShip: 976 return func 977 return False 978 979 if not pod: 980 m += [None, 981 ('Clone', cf(self.DoClone, HaveGML and not pod)), 982 ('<color=0xff708090>Clone Perfect', cf(self.DoClonePerfect, session.role & ROLE_WORLDMOD and session.stationid and not pod)), 983 None, 984 ('Online Modules', cf(self.DoOnline, (HaveHEALSELF or session.stationid) and not pod)), 985 ('Autorepeat Modules', cf(self.DoRepeat, not pod))] 986 m.insert(0, None) 987 m.insert(0, ('<color=0xff708090>My %s' % evetypes.GetName(s.typeID), None)) 988 m += [None, 989 ('<color=0xff708090>Extras', None), 990 None, 991 ('Recover Ship', cf(('isDynamic', self.ResurrectMenu, ()), CanSpawn or HaveShip and session.role & ROLE_GML))] 992 m += [None, ('T3 Subsystems', cf(('isDynamic', self.T3SubsystemsMenu, ()), CanSpawn or session.role & ROLE_GML))] 993 return m 994 995 def T3SubsystemsMenu(self): 996 m = [] 997 m.append(('/Load me subsystems for...', None)) 998 999 def _LoadRandomT3Subsystems(shipTypeID): 1000 slashSvc = sm.RemoteSvc('slash') 1001 godmaSvc = sm.GetService('godma') 1002 for subsystemGroupID in evetypes.GetGroupIDsByCategory(const.categorySubSystem): 1003 validTypes = [] 1004 for typeID in evetypes.GetTypeIDsByGroup(subsystemGroupID): 1005 validShipTypeID = int(godmaSvc.GetTypeAttribute2(typeID, const.attributeFitsToShipType)) 1006 if validShipTypeID == shipTypeID and evetypes.IsPublished(typeID): 1007 validTypes.append(typeID) 1008 1009 choice = random.choice(validTypes) 1010 slashSvc.SlashCmd('/load me %d' % choice) 1011 1012 for typeID in evetypes.GetTypeIDsByGroup(const.groupStrategicCruiser): 1013 m.append((evetypes.GetName(typeID), _LoadRandomT3Subsystems, (typeID,))) 1014 1015 return m 1016 1017 def ResurrectMenu(self): 1018 m = [] 1019 1020 def _Resurrect(dnaKey, name): 1021 dna.Ship().ImportFromDNA(dnaKey, name).Assemble() 1022 1023 for dnaKey, lostAt, name in self.last10killed: 1024 ship = dna.Ship().ImportFromDNA(dnaKey, name) 1025 m.append((name, _Resurrect, (dnaKey, name))) 1026 1027 if m: 1028 m.insert(0, ('Recently lost ships', None)) 1029 return m 1030 1031 def DoOnline(self, shipID = None): 1032 if CFG_USEONLINE: 1033 if session.role & ROLE_GML: 1034 sm.RemoteSvc('slash').SlashCmd('/online me') 1035 return 1036 roles = 'ROLE_GML or ROLE_HEALSELF' 1037 else: 1038 roles = 'ROLE_HEALSELF' 1039 if shipID is None: 1040 shipID = eveCfg.GetActiveShip() 1041 if shipID is None: 1042 return 1043 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 1044 ship = dogmaLocation.GetDogmaItem(shipID) 1045 onlined = 0 1046 offlinemods = [] 1047 if session.stationid: 1048 title = 'Turbo Power Up' 1049 else: 1050 if not session.role & ROLE_HEALSELF: 1051 prompt_player('To use this function in space, you need %s.' % roles, 'Function not available', options=uiconst.OK, icon=triui.INFO) 1052 return 1053 title = 'Power up' 1054 c = 0 1055 for slot in (const.flagLoSlot0, const.flagMedSlot0, const.flagHiSlot0): 1056 for flag in xrange(slot + 7, slot - 1, -1): 1057 c += 1 1058 Progress(title, 'Checking for offline modules...', c, 24) 1059 for module in ship.GetFittedItems().itervalues(): 1060 if module.flagID == flag and module.categoryID is not const.categoryCharge: 1061 if not module.IsOnline(): 1062 offlinemods.append(module) 1063 break 1064 1065 def ONLINE(state, control): 1066 try: 1067 dogmaLocation.OnlineModule(control.itemID) 1068 except: 1069 pass 1070 1071 state[0] += 1 1072 Progress(title, 'Activating module %s of %s' % (state[0], state[1]), state[0], state[1]) 1073 1074 offlinemodcount = len(offlinemods) 1075 if offlinemodcount > 0: 1076 state = [0, offlinemodcount] 1077 w = sm.RemoteSvc('slash') 1078 if session.stationid: 1079 parallelCalls = [] 1080 for control in offlinemods: 1081 parallelCalls.append((ONLINE, (state, control))) 1082 1083 uthread.parallel(parallelCalls) 1084 else: 1085 for control in offlinemods: 1086 w.SlashCmd('/heal me capac=1') 1087 ONLINE(state, control) 1088 1089 w.SlashCmd('/heal me capac=1') 1090 Progress(title, 'Done', 1, 1) 1091 return offlinemodcount 1092 1093 def DoRepeat(self, *args): 1094 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 1095 ship = dogmaLocation.GetDogmaItem(eveCfg.GetActiveShip()) 1096 try: 1097 modules = uicore.layer.shipui.slotsContainer.modulesByID 1098 except: 1099 modules = [] 1100 1101 for module in ship.GetFittedItems().itervalues(): 1102 if module and IsRepeatable(module): 1103 if not session.stationid and module.itemID in modules: 1104 modules[module.itemID].SetRepeat(1000) 1105 else: 1106 settings.char.autorepeat.Set(module.itemID, 1000) 1107 1108 def DoStore(self, dnaKey = None, name = None, shipID = None): 1109 if dnaKey: 1110 template = dna.Ship(dnaKey=dnaKey) 1111 action = 'Import' 1112 if not name: 1113 name = 'Imported %s' % GetTypeName(template.typeID) 1114 else: 1115 template = dna.Ship(shipID=shipID) 1116 dnaKey = template.ExportAsDNA() 1117 action = 'Store' 1118 name = template.name 1119 ret = utilWindows.NamePopup(caption='%s %s DNA' % (action, GetTypeName(template.typeID)), label='Enter name for this entry', setvalue=name, maxLength=64) 1120 if ret: 1121 item = CCItem() 1122 item.name = ret 1123 item.dna = dnaKey 1124 self.tree.AddItem(item) 1125 self.UpdateContent() 1126 return 1 1127 1128 def DoClonePerfect(self): 1129 if session.stationid: 1130 if session.role & ROLE_WORLDMOD: 1131 ship = sm.GetService('clientDogmaIM').GetDogmaLocation().GetDogmaItem(eveCfg.GetActiveShip()) 1132 if ship is None: 1133 return 1134 tname = GetTypeName(ship.typeID) 1135 Progress('Clone %s' % tname, 'Executing copyship command...', 0, 1) 1136 Slash('/copyship %s 1' % eveCfg.GetActiveShip()) 1137 Progress('Clone %s' % tname, 'Done', 1, 1) 1138 return 1139 1140 def DoClone(self): 1141 dna.Ship().ImportFromShip().Assemble(clone=1) 1142 1143 def DoShowInfo(self, node = None): 1144 dna.Ship().ImportFromShip().ShowInfo() 1145 1146 1147 class DNAGroup(ListGroup): 1148 __guid__ = 'listentry.DNAGroup' 1149 __update_on_reload__ = 1 1150 1151 def Load(self, node): 1152 ListGroup.Load(self, node) 1153 if node.raceID: 1154 self.sr.icon.LoadIcon('ui_19_128_%d' % node.raceID, ignoreSize=True) 1155 self.sr.icon.SetSize(16, 16) 1156 self.sr.icon.state = uiconst.UI_DISABLED 1157 1158 def GetMenu(self): 1159 node = self.sr.node 1160 m = [] 1161 if not node.open: 1162 m += [(('Expand', '25_11'), self.Toggle, ())] 1163 else: 1164 m += [(('Collapse', '25_12'), self.Toggle, ())] 1165 if node.Get('state', None) != 'locked': 1166 m += [None, 1167 (('New Folder', 'res:/ui/Texture/WindowIcons/smallfolder.png', 0.125), (None, self.CreateFolder)[not node.locked]), 1168 None, 1169 (('Change Label', 'ui_7_64_15'), (None, self.ChangeLabel)[not node.locked]), 1170 (('Delete Folder', '04_16'), self.DeleteFolder)] 1171 spiffy.CreateMenu(m) 1172 1173 def GetDragData(self, *args): 1174 if self.sr.node.locked: 1175 return [] 1176 nodes = self.sr.node.scroll.GetSelectedNodes(self.sr.node) 1177 if session.role & ROLE_PLAYER: 1178 for node in nodes: 1179 node.__guid__ = 'xtriui.TypeIcon' 1180 1181 else: 1182 for node in nodes: 1183 node.__guid__ = DNAGroup.__guid__ 1184 1185 if len(nodes) == 1: 1186 return nodes 1187 return [] 1188 1189 def CreateFolder(self): 1190 node = self.sr.node 1191 if not node.open: 1192 self.Toggle() 1193 sm.GetService(SERVICENAME).GroupAdd(parent=node.id[1]) 1194 1195 1196 class DNAEntry(Generic): 1197 __guid__ = 'listentry.DNAEntry' 1198 __update_on_reload__ = 1 1199 1200 def Load(self, *args, **kwargs): 1201 Generic.Load(self, *args, **kwargs) 1202 self.hint = '' 1203 1204 def GetDragData(self, *args): 1205 if self.sr.node.locked: 1206 return [] 1207 nodes = self.sr.node.scroll.GetSelectedNodes(self.sr.node) 1208 if session.role & ROLE_PLAYER: 1209 for node in nodes: 1210 node.__guid__ = 'xtriui.TypeIcon' 1211 1212 else: 1213 for node in nodes: 1214 node.__guid__ = DNAEntry.__guid__ 1215 1216 if len(nodes): 1217 return filter(lambda n: not isinstance(n.panel, ListGroup), nodes) 1218 else: 1219 return nodes 1220 1221 def GetMenu(self): 1222 1223 def cf(func, condition = True): 1224 if condition: 1225 return func 1226 return False 1227 1228 node = self.sr.node 1229 selected = node.scroll.GetSelectedNodes(node) 1230 multi = len(selected) > 1 1231 m = [] 1232 if multi: 1233 m += [(('Delete Setups...', '04_16'), self.Delete, (selected,))] 1234 else: 1235 item = node.id[1] 1236 m += dna.Ship(dnaKey=item.dna, name=item.name).GetMenuInline(store=False) 1237 m += [None, (('Rename Setup...', 'ui_7_64_15'), self.Rename), (('Delete Setup...', '04_16'), self.Delete)] 1238 spiffy.CreateMenu(m) 1239 1240 def OnMouseUp(self, *args): 1241 try: 1242 item = self.sr.node.id[1] 1243 sm.GetService(SERVICENAME).ShowDNA(name=item.name, dnaKey=item.dna) 1244 except: 1245 sys.exc_clear() 1246 1247 def Delete(self, nodes = None): 1248 if not nodes: 1249 nodes = [self.sr.node] 1250 text = 'You are about to delete the setup(s):<br>' 1251 for node in nodes: 1252 text += ' %s<br>' % node.id[1].name 1253 1254 text += '<br>Are you sure?' 1255 result = prompt_player(title='Delete Stuff', text=text, options=uiconst.OKCANCEL, icon=uiconst.WARNING) 1256 if result != uiconst.ID_OK: 1257 return 1258 for node in nodes: 1259 if node.locked: 1260 node.id[1].fromItem.Remove() 1261 else: 1262 node.id[1].Remove() 1263 1264 sm.GetService(SERVICENAME).UpdateContent() 1265 1266 def Rename(self): 1267 item = self.sr.node.id[1] 1268 if self.sr.node.locked: 1269 item = item.fromItem 1270 ret = utilWindows.NamePopup(caption='Rename %s DNA' % self.sr.node.typename, label='Enter new name', setvalue=item.name, maxLength=32) 1271 if ret: 1272 newname = ret 1273 if item.name != newname: 1274 item.name = newname 1275 sm.GetService(SERVICENAME).UpdateContent() 1276 1277 def OnDropData(self, dragObj, these, *args): 1278 if self.sr.node.locked: 1279 return 1280 sm.GetService(SERVICENAME).FolderAdoptNodes(self.sr.node.id[1].parent, these)