| Total Complexity | 112 | 
| Total Lines | 512 | 
| Duplicated Lines | 0 % | 
| Changes | 0 | ||
Complex classes like osci.dialog.ProblemsDlg often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # | ||
| 2 | # Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/] | ||
| 3 | # | ||
| 4 | # This file is part of Outer Space. | ||
| 5 | # | ||
| 6 | # Outer Space is free software; you can redistribute it and/or modify | ||
| 7 | # it under the terms of the GNU General Public License as published by | ||
| 8 | # the Free Software Foundation; either version 2 of the License, or | ||
| 9 | # (at your option) any later version. | ||
| 10 | # | ||
| 11 | # Outer Space is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License | ||
| 17 | # along with Outer Space; if not, write to the Free Software | ||
| 18 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | # | ||
| 20 | import bisect | ||
| 21 | import copy | ||
| 22 | import math | ||
| 23 | import re | ||
| 24 | import string | ||
| 25 | |||
| 26 | import pygameui as ui | ||
| 27 | from osci import gdata, client, res | ||
| 28 | import ige.ospace.Const as Const | ||
| 29 | from ige.ospace import Utils, Rules | ||
| 30 | |||
| 31 | class ProblemsDlg: | ||
| 32 | """Displays 'Problem locator' dialog. | ||
| 33 | |||
| 34 | """ | ||
| 35 | def __init__(self, app): | ||
| 36 | self.app = app | ||
| 37 | self.createUI() | ||
| 38 | |||
| 39 | def display(self): | ||
| 40 | self.show() | ||
| 41 | self.win.show() | ||
| 42 | # register for updates | ||
| 43 | if self not in gdata.updateDlgs: | ||
| 44 | gdata.updateDlgs.append(self) | ||
| 45 | |||
| 46 | def hide(self): | ||
| 47 |         self.win.setStatus(_("Ready.")) | ||
| 48 | self.win.hide() | ||
| 49 | # unregister updates | ||
| 50 | if self in gdata.updateDlgs: | ||
| 51 | gdata.updateDlgs.remove(self) | ||
| 52 | |||
| 53 | def update(self): | ||
| 54 | self.show() | ||
| 55 | |||
| 56 | class Problems: | ||
| 57 | def __init__(self, win): | ||
| 58 | self.items = [] | ||
| 59 |             self.checkboxes = {gdata.CRI: win.vCritical.checked, | ||
| 60 | gdata.MAJ: win.vMajor.checked, | ||
| 61 | gdata.MIN: win.vMinor.checked, | ||
| 62 | gdata.INFO: win.vInfo.checked} | ||
| 63 | |||
| 64 | def append(self, severity, item): | ||
| 65 | if self.checkboxes[severity]: | ||
| 66 | item.foreground = gdata.sevColors[severity] | ||
| 67 | self.items.append(item) | ||
| 68 | |||
| 69 | def _addProblemsStructStatus(self, problems, struct, planet): | ||
| 70 | player = client.getPlayer() | ||
| 71 | status = struct[Const.STRUCT_IDX_STATUS] | ||
| 72 | tech = client.getFullTechInfo(struct[Const.STRUCT_IDX_TECHID]) | ||
| 73 | |||
| 74 | if hasattr(player, 'techs'): | ||
| 75 | techEff = Rules.techImprEff[player.techs.get(struct[Const.STRUCT_IDX_TECHID], Rules.techBaseImprovement)] | ||
| 76 | else: | ||
| 77 | techEff = Rules.techImprEff[Rules.techBaseImprovement] | ||
| 78 | |||
| 79 | HPturn = max(1, int(0.02 * tech.maxHP * techEff)) | ||
| 80 | turnsToDestroy = math.ceil(struct[Const.STRUCT_IDX_HP] / HPturn) | ||
| 81 | |||
| 82 | if turnsToDestroy < Rules.turnsPerDay * 2: | ||
| 83 | severity = gdata.MAJ | ||
| 84 | if turnsToDestroy < Rules.turnsPerDay: | ||
| 85 | severity = gdata.CRI | ||
| 86 | else: | ||
| 87 | severity = gdata.MIN | ||
| 88 | |||
| 89 | if not status & Const.STRUCT_STATUS_ON: | ||
| 90 | # structure is off | ||
| 91 | problems.append(severity, | ||
| 92 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 93 |                                     vDescription=_('Structure (%s) is off and will be destroyed in %s turns.') % (tech.name, res.formatTime(turnsToDestroy)))) | ||
| 94 | |||
| 95 | if status & Const.STRUCT_STATUS_DETER: | ||
| 96 | problems.append(gdata.MAJ, | ||
| 97 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 98 |                                     vDescription=_('Structure (%s) is deteriorating.') % (tech.name,))) | ||
| 99 | if status & Const.STRUCT_STATUS_NOBIO: | ||
| 100 | problems.append(gdata.INFO, | ||
| 101 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 102 |                                     vDescription=_('Structure (%s) has insufficient supply of biomatter.') % (tech.name,))) | ||
| 103 | if status & Const.STRUCT_STATUS_NOEN: | ||
| 104 | problems.append(gdata.INFO, | ||
| 105 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 106 |                                     vDescription=_('Structure (%s) has insufficient supply of energy.') % (tech.name,))) | ||
| 107 | if status & Const.STRUCT_STATUS_NOPOP: | ||
| 108 | problems.append(gdata.INFO, | ||
| 109 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 110 |                                     vDescription=_('Structure (%s) has insufficient supply of workers.') % (tech.name,))) | ||
| 111 | if status & Const.STRUCT_STATUS_REPAIRING: | ||
| 112 | problems.append(gdata.INFO, | ||
| 113 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 114 |                                     vDescription=_('Structure (%s) is repairing.') % (tech.name,))) | ||
| 115 | |||
| 116 | def _getSystemRefuel(self, system): | ||
| 117 | player = client.getPlayer() | ||
| 118 | maxRefuelMax = 0 | ||
| 119 | hasRefuel = False | ||
| 120 | for planetID in system.planets: | ||
| 121 | planet = client.get(planetID, noUpdate=1) | ||
| 122 | if hasattr(planet, 'owner'): | ||
| 123 | if hasattr(planet, 'hasRefuel'): | ||
| 124 | hasRefuel = hasRefuel or planet.hasRefuel | ||
| 125 | if hasattr(planet, 'refuelMax'): | ||
| 126 | if planet.owner == player.oid: | ||
| 127 | maxRefuelMax = max(maxRefuelMax, planet.refuelMax) | ||
| 128 | elif planet.owner in player.diplomacyRels: | ||
| 129 | dipl = client.getDiplomacyWith(planet.owner) | ||
| 130 | if Const.PACT_ALLOW_TANKING in dipl.pacts and dipl.pacts[Const.PACT_ALLOW_TANKING][0] == Const.PACT_ACTIVE: | ||
| 131 | maxRefuelMax = max(maxRefuelMax, planet.refuelMax) | ||
| 132 | elif hasattr(planet, 'hasRefuel'): | ||
| 133 | maxRefuelMax | ||
| 134 | return hasRefuel, maxRefuelMax | ||
| 135 | |||
| 136 | def _addProblemsFleets(self, problems, fleet): | ||
| 137 | if not fleet.orbiting: | ||
| 138 | # we do not report fleets in flight | ||
| 139 | return | ||
| 140 | fleetName = fleet.customname if fleet.customname else fleet.name | ||
| 141 | energyReserve = fleet.storEn * 100 / fleet.maxEn | ||
| 142 | system = client.get(fleet.orbiting, noUpdate=1) | ||
| 143 | systemName = getattr(system, "name", res.getUnknownName()) | ||
| 144 | hasRefuel, maxRefuelMax = self._getSystemRefuel(system) | ||
| 145 | |||
| 146 | if energyReserve == 100: | ||
| 147 | problems.append(gdata.INFO, | ||
| 148 | ui.Item(systemName, tOID=fleet.oid, tType=Const.T_FLEET, | ||
| 149 |                                     vDescription=_('Fleet "%s" has full fuel tanks.') % (fleetName))) | ||
| 150 | return | ||
| 151 | |||
| 152 | if 0 < maxRefuelMax <= energyReserve: | ||
| 153 | severity = gdata.INFO | ||
| 154 | if maxRefuelMax <= energyReserve: | ||
| 155 |                 note = _(' and CAN refuel, but reached planet maximum refuel amount') | ||
| 156 | else: | ||
| 157 |                 note = _(' and IS refueling') | ||
| 158 | elif hasRefuel: | ||
| 159 | severity = gdata.INFO | ||
| 160 |             note = _(' and utilizes unknown refueling capacities') | ||
| 161 | else: | ||
| 162 |             note = _(' and is NOT refueling') | ||
| 163 | severity = [gdata.CRI, gdata.MAJ, gdata.MIN][bisect.bisect([25, 50], energyReserve)] | ||
| 164 | problems.append(severity, | ||
| 165 | ui.Item(systemName, tOID=fleet.oid, tType=Const.T_FLEET, | ||
| 166 |                                 vDescription=_('Fleet "%s" is low on fuel [%d %%]%s.') % (fleetName, energyReserve, note))) | ||
| 167 | |||
| 168 | def _addProblemsMaterial(self, problems, system, mat, totalMat, material): | ||
| 169 | if mat >= 0: | ||
| 170 | return | ||
| 171 | surplusTurns = totalMat / (-mat) | ||
| 172 | if surplusTurns < Rules.turnsPerDay * 7: | ||
| 173 | severity = gdata.MAJ | ||
| 174 | elif surplusTurns < Rules.turnsPerDay * 2: | ||
| 175 | severity = gdata.CRI | ||
| 176 | else: | ||
| 177 | severity = gdata.MIN | ||
| 178 | |||
| 179 | if totalMat > 0: | ||
| 180 |             note = _(' surplus %d (%s)' % (totalMat, res.formatTime(surplusTurns))) | ||
| 181 | else: | ||
| 182 |             note = _(' with no surplus left!') | ||
| 183 | problems.append(severity, | ||
| 184 | ui.Item(system.name, tOID=system.oid, tType=Const.T_SYSTEM, | ||
| 185 |                                 vDescription=_('%s decreasing - last turn change %d, %s.') % (material, mat, note))) | ||
| 186 | |||
| 187 | def _getTaskSciValue(self, task): | ||
| 188 | player = client.getPlayer() | ||
| 189 | fulltech = client.getFullTechInfo(task.techID) | ||
| 190 | researchSci = Utils.getTechRCost(player, task.techID, task.improvement) | ||
| 191 | maxImprovement = min(Rules.techMaxImprovement, fulltech.maxImprovement) | ||
| 192 | |||
| 193 | if task.improveToMax: | ||
| 194 | # account next levels | ||
| 195 | for impr in range(task.improvement + 1, maxImprovement + 1): | ||
| 196 | researchSci += Utils.getTechRCost(player, task.techID, impr) | ||
| 197 | return researchSci - task.currSci | ||
| 198 | |||
| 199 | def _addProblemsResearch(self, problems): | ||
| 200 | player = client.getPlayer() | ||
| 201 | sciProd = max(sum(task.changeSci for task in player.rsrchQueue), | ||
| 202 | player.effSciPoints) | ||
| 203 | if sciProd < 0: | ||
| 204 | problems.append(gdata.CRI, | ||
| 205 |                             ui.Item(_('Research'), tType=Const.T_TECHNOLOGY, | ||
| 206 |                                     vDescription=_('We are losing our researched knowledge by %d pts per turn!') % (sciProd,))) | ||
| 207 | return | ||
| 208 | elif sciProd == 0: | ||
| 209 | return | ||
| 210 | elif len(player.rsrchQueue) == 0: | ||
| 211 | problems.append(gdata.CRI, | ||
| 212 |                             ui.Item(_('Research'), tType=Const.T_TECHNOLOGY, | ||
| 213 |                                     vDescription=_('Research queue is empty.'))) | ||
| 214 | |||
| 215 | queueValue = sum(self._getTaskSciValue(task) for task in player.rsrchQueue) | ||
| 216 | totalEtc = math.ceil(float(queueValue) / sciProd) | ||
| 217 | |||
| 218 | # check short reseach queue | ||
| 219 | if totalEtc < Rules.turnsPerDay * 2: | ||
| 220 | severity = gdata.MIN | ||
| 221 | if totalEtc < Rules.turnsPerDay: | ||
| 222 | severity = gdata.MAJ | ||
| 223 | problems.append(severity, | ||
| 224 |                             ui.Item(_('Research'), tType=Const.T_TECHNOLOGY, | ||
| 225 |                                     vDescription=_('Research queue ends in %s turns, %d item(s) on list.') % (res.formatTime(totalEtc), len(player.rsrchQueue)))) | ||
| 226 | |||
| 227 | def _addProblemsGlobalQueues(self, problems): | ||
| 228 | # go through all planets to understand the state of global queues | ||
| 229 | player = client.getPlayer() | ||
| 230 | # holder for (number , eff production) of planets set to each queue | ||
| 231 | globalQueueStats = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)] | ||
| 232 | queConstValues = [0, 0, 0, 0, 0] | ||
| 233 | queEtc = [0, 0, 0, 0, 0] | ||
| 234 | |||
| 235 | for planetID in player.planets: | ||
| 236 | planet = client.get(planetID, noUpdate=1) | ||
| 237 | globalQueueStats[planet.globalQueue] = tuple([sum(x) for x in zip(globalQueueStats[planet.globalQueue], (1, planet.effProdProd))]) | ||
| 238 | |||
| 239 | # evaluate depletion rate of the global queue | ||
| 240 | for queue in range(5): | ||
| 241 | quePlanets, queEffProd = globalQueueStats[queue] | ||
| 242 | for task in player.prodQueues[queue]: | ||
| 243 | if task.isShip: | ||
| 244 | tech = player.shipDesigns[task.techID] | ||
| 245 | else: | ||
| 246 | tech = client.getFullTechInfo(task.techID) | ||
| 247 | queConstValues[queue] += task.quantity * tech.buildProd | ||
| 248 | if queEffProd > 0: | ||
| 249 | queEtc[queue] = math.ceil(float(queConstValues[queue])/queEffProd) | ||
| 250 | else: | ||
| 251 | queEtc[queue] = 99999 | ||
| 252 | |||
| 253 | # creation of items with global queue problems | ||
| 254 | for queue in range(1, 5): | ||
| 255 | queName = res.globalQueueName(queue) | ||
| 256 | quePlanets = globalQueueStats[queue][0] | ||
| 257 | # check empty global production queue with at least one planet [so its relevant] | ||
| 258 | if queConstValues[queue] == 0 and quePlanets > 0: | ||
| 259 | problems.append(gdata.CRI, | ||
| 260 |                                 ui.Item(_('Global queue ' + queName), tType=Const.T_QUEUE, | ||
| 261 |                                         vDescription=_('Global production queue {0} used by {1} planet(s) is empty.'.format(queName, quePlanets)))) | ||
| 262 | # check end of global production queue | ||
| 263 | elif queEtc[queue] < Rules.turnsPerDay * 2: | ||
| 264 | severity = gdata.MIN | ||
| 265 | if queEtc[queue] < Rules.turnsPerDay: | ||
| 266 | severity = gdata.MAJ | ||
| 267 | problems.append(severity, | ||
| 268 |                                 ui.Item(_('Global queue ' + queName), tType=Const.T_QUEUE, | ||
| 269 |                                         vDescription=_('Global production queue {0} used by {1} planet(s) runs out in {2} turns.'.format(queName, quePlanets, res.formatTime(queEtc[queue]))))) | ||
| 270 | return queEtc[0] # time of depletion of the default queue will be reused later | ||
| 271 | |||
| 272 | def _getTargetSlotDict(self, planetID): | ||
| 273 | assert planetID in client.getPlayer().planets | ||
| 274 |         targets = {} | ||
| 275 | planet = client.get(planetID, noUpdate=1) | ||
| 276 | if planet.effProdProd <= 0: | ||
| 277 | return targets | ||
| 278 | |||
| 279 | nonShipTasks = (task for task in planet.prodQueue if not task.isShip) | ||
| 1 ignored issue–
                            show | |||
| 280 | for task in nonShipTasks: | ||
| 281 | tech = client.getFullTechInfo(task.techID) | ||
| 282 | if tech.isStructure and task.demolishStruct == 0: | ||
| 283 | quantity = task.quantity | ||
| 284 | elif tech.isProject and tech.id == 3802: | ||
| 285 | # we are constructing Habitable Surface Expansion | ||
| 286 | # so after construction we will have new slot on the planet | ||
| 287 | quantity = -1 | ||
| 288 | else: | ||
| 289 | continue | ||
| 290 | assert quantity != 0 | ||
| 291 | |||
| 292 | try: | ||
| 293 | targets[task.targetID] += task.quantity | ||
| 294 | except KeyError: | ||
| 295 | targets[task.targetID] = task.quantity | ||
| 296 | return targets | ||
| 297 | |||
| 298 | def _addProblemsSlots(self, problems, system): | ||
| 299 | player = client.getPlayer() | ||
| 300 | playerPlanets = set(system.planets) & set(player.planets) | ||
| 301 |         freeSlots = {} | ||
| 302 | structSources = dict.fromkeys(system.planets) | ||
| 303 | for planetID in system.planets: | ||
| 304 | planet = client.get(planetID, noUpdate=1) | ||
| 305 | freeSlots[planetID] = planet.plSlots - len(planet.slots) | ||
| 306 | |||
| 307 | for planetID in playerPlanets: | ||
| 308 | for targetID, quantity in self._getTargetSlotDict(planetID).items(): | ||
| 309 | freeSlots[targetID] -= quantity | ||
| 310 | if quantity > 0: | ||
| 311 | try: | ||
| 312 | structSources[targetID].add(planetID) | ||
| 313 | except AttributeError: | ||
| 314 | structSources[targetID] = set([planetID]) | ||
| 315 | |||
| 316 | for planetID, free in freeSlots.items(): | ||
| 317 | if free < 0: | ||
| 318 | # not enough space, report for every planet that builds on this one | ||
| 319 | planet = client.get(planetID, noUpdate=1) | ||
| 320 | for sourceID in structSources[planetID]: | ||
| 321 | source = client.get(sourceID, noUpdate=1) | ||
| 322 | problems.append(gdata.MAJ, | ||
| 323 | ui.Item(source.name, tOID=sourceID, tType=Const.T_PLANET, | ||
| 324 |                                             vDescription=_('There is no space for all constructed buildings on %s.') % (planet.name))) | ||
| 325 | |||
| 326 | def _addProblemsDefaultQueue(self, problems, planet, defaultQueueEtc): | ||
| 327 | player = client.getPlayer() | ||
| 328 | if not planet.effProdProd > 0: | ||
| 329 | return | ||
| 330 | planetEtc = 0 | ||
| 331 | # compute length of production queue | ||
| 332 | for task in planet.prodQueue: | ||
| 333 | if task.isShip: | ||
| 334 | tech = player.shipDesigns[task.techID] | ||
| 335 | else: | ||
| 336 | tech = client.getFullTechInfo(task.techID) | ||
| 337 | modifier = Rules.buildOnAnotherPlanetMod if task.targetID != planet.oid else 1 | ||
| 338 | planetEtc += math.ceil(float(task.quantity * tech.buildProd * modifier - task.currProd) / planet.effProdProd) | ||
| 339 | |||
| 340 | etc = planetEtc + defaultQueueEtc | ||
| 341 | # check empty production queue | ||
| 342 | if not etc: | ||
| 343 | problems.append(gdata.CRI, | ||
| 344 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 345 |                                     vDescription=_('Production queue is empty.'))) | ||
| 346 | return | ||
| 347 | if etc < Rules.turnsPerDay: | ||
| 348 | severity = gdata.MAJ | ||
| 349 | elif etc < Rules.turnsPerDay * 2: | ||
| 350 | severity = gdata.MIN | ||
| 351 | else: | ||
| 352 | severity = gdata.INFO | ||
| 353 | |||
| 354 | problems.append(severity, | ||
| 355 | ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET, | ||
| 356 |                                 vDescription=_('Production queue may end in {0} turns ({1} directly in planet queue).'.format(res.formatTime(etc), res.formatTime(planetEtc))))) | ||
| 357 | |||
| 358 | def show(self): | ||
| 359 | critical = self.win.vCritical.checked | ||
| 360 | major = self.win.vMajor.checked | ||
| 361 | minor = self.win.vMinor.checked | ||
| 362 | info = self.win.vInfo.checked | ||
| 363 | |||
| 364 | disp = 1 | ||
| 365 | |||
| 366 | player = client.getPlayer() | ||
| 367 | problems = self.Problems(self.win) | ||
| 368 | systems = set([]) | ||
| 369 | for planetID in player.planets: | ||
| 370 | planet = client.get(planetID, noUpdate=1) | ||
| 371 | systems.add(planet.compOf) | ||
| 372 | |||
| 373 | defaultQueueEtc = self._addProblemsGlobalQueues(problems) | ||
| 374 | |||
| 375 | for systemID in systems: | ||
| 376 | system = client.get(systemID, noUpdate=1) | ||
| 377 | bio = 0 | ||
| 378 | totalBio = 0 | ||
| 379 | en = 0 | ||
| 380 | totalEn = 0 | ||
| 381 | # holds modified planets | ||
| 382 |             planetCopies = {} | ||
| 383 | |||
| 384 | for planetID in system.planets: | ||
| 385 | planet = client.get(planetID, noUpdate=1) | ||
| 386 | # copy of planet to change plSlots count | ||
| 387 | if hasattr(planet, 'owner') and planet.owner == player.oid: | ||
| 388 | # add planet to the global queue stats | ||
| 389 | # compute bio and en for system | ||
| 390 | bio += planet.changeBio | ||
| 391 | totalBio += max(0, planet.storBio - planet.minBio) | ||
| 392 | en += planet.changeEn | ||
| 393 | totalEn += max(0, planet.storEn - planet.minEn) | ||
| 394 | # the planet needs to have global queue 0 - the default one - to have its queue reported | ||
| 395 | if self.win.vPlanets.checked: | ||
| 396 | if not planet.globalQueue: | ||
| 397 | self._addProblemsDefaultQueue(problems, planet, defaultQueueEtc) | ||
| 398 | for struct in planet.slots: | ||
| 399 | self._addProblemsStructStatus(problems, struct, planet) | ||
| 400 | |||
| 401 | # free slots within the system | ||
| 402 | self._addProblemsSlots(problems, system) | ||
| 403 | # check bio for system | ||
| 404 | if self.win.vSystems.checked: | ||
| 405 | self._addProblemsMaterial(problems, system, bio, totalBio, 'Bio') | ||
| 406 | self._addProblemsMaterial(problems, system, en, totalEn, 'En') | ||
| 407 | |||
| 408 | # check fleets | ||
| 409 | if self.win.vFleets.checked: | ||
| 410 | for fleetID in player.fleets: | ||
| 411 | fleet = client.get(fleetID, noUpdate=1) | ||
| 412 | self._addProblemsFleets(problems, fleet) | ||
| 413 | |||
| 414 | # check research queue | ||
| 415 | if self.win.vResearch.checked: | ||
| 416 | self._addProblemsResearch(problems) | ||
| 417 | |||
| 418 | self.win.vProblems.items = problems.items | ||
| 419 | self.win.vProblems.itemsChanged() | ||
| 420 | |||
| 421 | def onClose(self, widget, action, data): | ||
| 422 | self.hide() | ||
| 423 | |||
| 424 | def onShowSource(self, widget, action, data): | ||
| 425 | item = self.win.vProblems.selection[0] | ||
| 426 | if item.tType == Const.T_FLEET: | ||
| 427 | object = client.get(item.tOID, noUpdate=1) | ||
| 428 | # center on map | ||
| 429 | if hasattr(object, "x"): | ||
| 430 | gdata.mainGameDlg.win.vStarMap.highlightPos = (object.x, object.y) | ||
| 431 | gdata.mainGameDlg.win.vStarMap.setPos(object.x, object.y) | ||
| 432 | self.hide() | ||
| 433 | return | ||
| 434 | elif item.tType in (Const.T_SYSTEM, Const.T_PLANET): | ||
| 435 | if item.tOID != Const.OID_NONE: | ||
| 436 | gdata.mainGameDlg.onSelectMapObj(None, None, item.tOID) | ||
| 437 | return | ||
| 438 | elif item.tType == Const.T_TECHNOLOGY: | ||
| 439 | gdata.mainGameDlg.researchDlg.display() | ||
| 440 | return | ||
| 441 | elif item.tType == Const.T_QUEUE: | ||
| 442 | gdata.mainGameDlg.globalQueuesDlg.display() | ||
| 443 |         self.win.setStatus(_("Cannot show location.")) | ||
| 444 | |||
| 445 | def onShowLocation(self, widget, action, data): | ||
| 446 | item = self.win.vProblems.selection[0] | ||
| 447 | if item.tType in (Const.T_SYSTEM, Const.T_PLANET, Const.T_FLEET): | ||
| 448 | object = client.get(item.tOID, noUpdate=1) | ||
| 449 | # center on map | ||
| 450 | if hasattr(object, "x"): | ||
| 451 | gdata.mainGameDlg.win.vStarMap.highlightPos = (object.x, object.y) | ||
| 452 | gdata.mainGameDlg.win.vStarMap.setPos(object.x, object.y) | ||
| 453 | self.hide() | ||
| 454 | return | ||
| 455 |         self.win.setStatus(_("Cannot show location.")) | ||
| 456 | |||
| 457 | def onToggleCondition(self, widget, action, data): | ||
| 458 | self.update() | ||
| 459 | |||
| 460 | def createUI(self): | ||
| 461 | screenWidth, screenHeight = gdata.scrnSize | ||
| 462 | # size of dialog in layout metrics (for SimpleGridLM) | ||
| 463 | cols = 40 | ||
| 464 | rows = 29 | ||
| 465 | # dialog width and height in pixels | ||
| 466 | isSmallWin = screenHeight == 600 and screenWidth == 800 | ||
| 467 | width = cols * 20 + 4 * (not isSmallWin) | ||
| 468 | height = rows * 20 + 4 * (not isSmallWin) | ||
| 469 | #creating dialog window | ||
| 470 | self.win = ui.Window(self.app, | ||
| 471 | modal=1, | ||
| 472 | escKeyClose=1, | ||
| 473 | movable=0, | ||
| 474 |                              title=_("Problems Locator"), | ||
| 475 | titleOnly=isSmallWin, | ||
| 476 | rect=ui.Rect((screenWidth - 800 - 4 * (not isSmallWin)) / 2, | ||
| 477 | (screenHeight - 600 - 4 * (not isSmallWin)) / 2, | ||
| 478 | width, | ||
| 479 | height), | ||
| 480 | layoutManager=ui.SimpleGridLM()) | ||
| 481 |         self.win.subscribeAction('*', self) | ||
| 482 | # first row is window title | ||
| 483 | rows -= 1 | ||
| 484 | |||
| 485 | ui.Listbox(self.win, layout=(0, 0, cols, rows - 2), id='vProblems', | ||
| 486 |                    columns=[(_('Location'), 'text', 10, ui.ALIGN_W), | ||
| 487 |                    (_('Problem description'), 'vDescription', 30, ui.ALIGN_W)], | ||
| 488 | columnLabels=1, action='onShowSource', rmbAction='onShowLocation') | ||
| 489 | |||
| 490 | btnWidth = 4 | ||
| 491 | ui.Check(self.win, layout=(btnWidth * 0, rows - 2, btnWidth, 1), id='vSystems', | ||
| 492 |                  text=_('Systems'), action='onToggleCondition', checked=1) | ||
| 493 | ui.Check(self.win, layout=(btnWidth * 1, rows - 2, btnWidth, 1), id='vPlanets', | ||
| 494 |                  text=_('Planets'), action='onToggleCondition', checked=1) | ||
| 495 | ui.Check(self.win, layout=(btnWidth * 2, rows - 2, btnWidth, 1), id='vFleets', | ||
| 496 |                  text=_('Fleets'), action='onToggleCondition', checked=1) | ||
| 497 | ui.Check(self.win, layout=(btnWidth * 3, rows - 2, btnWidth, 1), id='vResearch', | ||
| 498 |                  text=_('Research'), action='onToggleCondition', checked=1) | ||
| 499 | |||
| 500 | ui.Check(self.win, layout=(btnWidth * 6, rows - 2, btnWidth, 1), id='vCritical', | ||
| 501 |                  text=_('Critical'), action='onToggleCondition', checked=1) | ||
| 502 | ui.Check(self.win, layout=(btnWidth * 7, rows - 2, btnWidth, 1), id='vMajor', | ||
| 503 |                  text=_('Major'), action='onToggleCondition', checked=1) | ||
| 504 | ui.Check(self.win, layout=(btnWidth * 8, rows - 2, btnWidth, 1), id='vMinor', | ||
| 505 |                  text=_('Minor'), action='onToggleCondition', checked=1) | ||
| 506 | ui.Check(self.win, layout=(btnWidth * 9, rows - 2, btnWidth, 1), id='vInfo', | ||
| 507 |                  text=_('Info'), action='onToggleCondition', checked=0) | ||
| 508 | |||
| 509 | # dialog bottom line | ||
| 510 | ui.Title(self.win, layout=(0, rows - 1, cols - 5, 1)) | ||
| 511 |         ui.TitleButton(self.win, layout=(cols - 5, rows - 1, 5, 1), text=_("Close"), action='onClose') | ||
| 512 |