| Total Complexity | 138 |
| Total Lines | 527 |
| Duplicated Lines | 6.45 % |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
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 | |||
| 21 | import pygameui as ui |
||
| 22 | import re |
||
| 23 | from osci import gdata, client, res |
||
| 24 | import ige.ospace.Const as Const |
||
| 25 | from ige.ospace import Utils, Rules |
||
| 26 | import string, math, copy |
||
| 27 | |||
| 28 | class ProblemsDlg: |
||
| 29 | """Displays 'Problem locator' dialog. |
||
| 30 | |||
| 31 | """ |
||
| 32 | def __init__(self, app): |
||
| 33 | self.app = app |
||
| 34 | self.createUI() |
||
| 35 | |||
| 36 | def display(self): |
||
| 37 | self.show() |
||
| 38 | self.win.show() |
||
| 39 | # register for updates |
||
| 40 | if self not in gdata.updateDlgs: |
||
| 41 | gdata.updateDlgs.append(self) |
||
| 42 | |||
| 43 | def hide(self): |
||
| 44 | self.win.setStatus(_("Ready.")) |
||
| 45 | self.win.hide() |
||
| 46 | # unregister updates |
||
| 47 | if self in gdata.updateDlgs: |
||
| 48 | gdata.updateDlgs.remove(self) |
||
| 49 | |||
| 50 | def update(self): |
||
| 51 | self.show() |
||
| 52 | |||
| 53 | class Problems: |
||
| 54 | def __init__(self, win): |
||
| 55 | self.items = [] |
||
| 56 | self.checkboxes = {gdata.CRI : win.vCritical.checked, |
||
| 57 | gdata.MAJ : win.vMajor.checked, |
||
| 58 | gdata.MIN : win.vMinor.checked, |
||
| 59 | gdata.INFO: win.vInfo.checked} |
||
| 60 | |||
| 61 | def append(self, severity, item): |
||
| 62 | if self.checkboxes[severity]: |
||
| 63 | item.foreground = gdata.sevColors[severity] |
||
| 64 | self.items.append(item) |
||
| 65 | |||
| 66 | def _getProblemsProdQueues(self, objects): |
||
| 67 | return prodQueueProblems |
||
|
|
|||
| 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 < 48: |
||
| 83 | severity = gdata.MAJ |
||
| 84 | if turnsToDestroy < 24: |
||
| 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, ui.Item(planet.name, tOID = planet.oid, tType = Const.T_PLANET, |
||
| 92 | vDescription = _('Structure (%s) is off and will be destroyed in %s turns.') % (tech.name, res.formatTime(turnsToDestroy)))) |
||
| 93 | |||
| 94 | if status & Const.STRUCT_STATUS_DETER: |
||
| 95 | problems.append(gdata.MAJ, ui.Item(planet.name, tOID = planet.oid, tType = Const.T_PLANET, |
||
| 96 | vDescription = _('Structure (%s) is deteriorating.') % (tech.name,))) |
||
| 97 | if status & Const.STRUCT_STATUS_NOBIO: |
||
| 98 | problems.append(gdata.INFO, ui.Item(planet.name, tOID = planet.oid, tType = Const.T_PLANET, |
||
| 99 | vDescription = _('Structure (%s) has insufficient supply of biomatter.') % (tech.name,))) |
||
| 100 | if status & Const.STRUCT_STATUS_NOEN: |
||
| 101 | problems.append(gdata.INFO, ui.Item(planet.name, tOID = planet.oid, tType = Const.T_PLANET, |
||
| 102 | vDescription = _('Structure (%s) has insufficient supply of energy.') % (tech.name,))) |
||
| 103 | if status & Const.STRUCT_STATUS_NOPOP: |
||
| 104 | problems.append(gdata.INFO, ui.Item(planet.name, tOID = planet.oid, tType = Const.T_PLANET, |
||
| 105 | vDescription = _('Structure (%s) has insufficient supply of workers.') % (tech.name,))) |
||
| 106 | if status & Const.STRUCT_STATUS_REPAIRING: |
||
| 107 | problems.append(gdata.INFO, ui.Item(planet.name, tOID = planet.oid, tType = Const.T_PLANET, |
||
| 108 | vDescription = _('Structure (%s) is repairing.') % (tech.name,))) |
||
| 109 | |||
| 110 | def _addProblemsFleets(self, problems, fleet): |
||
| 111 | player = client.getPlayer() |
||
| 112 | energyReserve = fleet.storEn * 100 / fleet.maxEn |
||
| 113 | system = None |
||
| 114 | |||
| 115 | maxRefuelMax = 0 |
||
| 116 | if hasattr(fleet, 'orbiting') and fleet.orbiting: |
||
| 117 | system = client.get(fleet.orbiting, noUpdate = 1) |
||
| 118 | if hasattr(system, 'planets'): |
||
| 119 | for planetID in system.planets: |
||
| 120 | planet = client.get(planetID, noUpdate = 1) |
||
| 121 | if hasattr(planet, 'owner') and hasattr(planet, 'refuelMax'): |
||
| 122 | if player.diplomacyRels.has_key(planet.owner): |
||
| 123 | dipl = client.getDiplomacyWith(planet.owner) |
||
| 124 | if dipl.pacts.has_key(Const.PACT_ALLOW_TANKING) and dipl.pacts[Const.PACT_ALLOW_TANKING][0] == Const.PACT_ACTIVE: |
||
| 125 | maxRefuelMax = max(maxRefuelMax, planet.refuelMax) |
||
| 126 | else: |
||
| 127 | if planet.owner == player.oid: |
||
| 128 | maxRefuelMax = max(maxRefuelMax, planet.refuelMax) |
||
| 129 | else: |
||
| 130 | # we do not report fleets in flight |
||
| 131 | return |
||
| 132 | |||
| 133 | systemName = res.getUnknownName() |
||
| 134 | if system and hasattr(system, "name"): |
||
| 135 | systemName = system.name |
||
| 136 | |||
| 137 | # is fleet named? |
||
| 138 | if hasattr(fleet,'customname') and fleet.customname: |
||
| 139 | name = fleet.customname |
||
| 140 | else: |
||
| 141 | name = getattr(fleet, "name", None) |
||
| 142 | |||
| 143 | note = _(' and is NOT refueling') |
||
| 144 | if maxRefuelMax: |
||
| 145 | severity = gdata.INFO |
||
| 146 | if maxRefuelMax <= energyReserve: |
||
| 147 | note = _(' and CAN refuel, but reached planet maximum refuel amount') |
||
| 148 | else: |
||
| 149 | note = _(' and IS refueling') |
||
| 150 | elif energyReserve < 25: |
||
| 151 | severity = gdata.CRI |
||
| 152 | elif energyReserve < 50: |
||
| 153 | severity = gdata.MAJ |
||
| 154 | elif energyReserve == 100: |
||
| 155 | problems.append(gdata.INFO, ui.Item(systemName, tOID = fleet.oid, tType = Const.T_FLEET, |
||
| 156 | vDescription = _('Fleet "%s" has full fuel tanks.') % (name))) |
||
| 157 | return |
||
| 158 | else: |
||
| 159 | severity = gdata.INFO |
||
| 160 | problems.append(severity, ui.Item(systemName, tOID = fleet.oid, tType = Const.T_FLEET, |
||
| 161 | vDescription = _('Fleet "%s" is low on fuel [%d %%]%s.') % (name, energyReserve, note))) |
||
| 162 | |||
| 163 | View Code Duplication | def _addProblemsBio(self, problems, system, bio, totalBio): |
|
| 164 | if bio >= 0: |
||
| 165 | return |
||
| 166 | surplusTurns = totalBio / (-bio) |
||
| 167 | if surplusTurns < Rules.turnsPerDay * 7: |
||
| 168 | severity = gdata.MAJ |
||
| 169 | elif surplusTurns < Rules.turnsPerDay * 2: |
||
| 170 | severity = gdata.CRI |
||
| 171 | else: |
||
| 172 | severity = gdata.MIN |
||
| 173 | |||
| 174 | if totalBio > 0: |
||
| 175 | note = _(' surplus %d (%s)' % (totalBio, res.formatTime(surplusTurns))) |
||
| 176 | else: |
||
| 177 | note = _(' with no surplus left!') |
||
| 178 | problems.append(ui.Item(system.name, tOID = system.oid, tType = Const.T_SYSTEM, |
||
| 179 | vDescription = _('Bio decreasing - last turn change %d, %s.') % (bio, note))) |
||
| 180 | |||
| 181 | View Code Duplication | def _addProblemsEn(self, problems, system, en, totalEn): |
|
| 182 | if en >= 0: |
||
| 183 | return |
||
| 184 | surplusTurns = totalEn / (-en) |
||
| 185 | if surplusTurns < Rules.turnsPerDay * 7: |
||
| 186 | severity = gdata.MAJ |
||
| 187 | elif surplusTurns < Rules.turnsPerDay * 2: |
||
| 188 | severity = gdata.CRI |
||
| 189 | else: |
||
| 190 | severity = gdata.MIN |
||
| 191 | |||
| 192 | if totalEn > 0: |
||
| 193 | note = _(' surplus %d (%s)' % (totalEn, res.formatTime(surplusTurns))) |
||
| 194 | else: |
||
| 195 | note = _(' with no surplus left!') |
||
| 196 | problems.append(ui.Item(system.name, tOID = system.oid, tType = Const.T_SYSTEM, |
||
| 197 | vDescription = _('Energy decreasing - last turn change %d, %s.') % (bio, note))) |
||
| 198 | |||
| 199 | def _addProblemsResearch(self, problems): |
||
| 200 | player = client.getPlayer() |
||
| 201 | totalEtc = 0 |
||
| 202 | # compute length of research queue |
||
| 203 | for task in player.rsrchQueue: |
||
| 204 | tech = client.getTechInfo(task.techID) |
||
| 205 | fulltech = client.getFullTechInfo(task.techID) |
||
| 206 | researchSci = Utils.getTechRCost(player, task.techID, task.improvement) |
||
| 207 | maxImprovement = min(Rules.techMaxImprovement,fulltech.maxImprovement) |
||
| 208 | maxImpTotalSci = 0 |
||
| 209 | if task.improveToMax and task.improvement < maxImprovement: |
||
| 210 | for impr in range(task.improvement+1,maxImprovement+1): |
||
| 211 | maxImpTotalSci += Utils.getTechRCost(player, task.techID, impr) |
||
| 212 | if task.changeSci > 0: |
||
| 213 | value = float(researchSci - task.currSci) / max(task.changeSci, player.effSciPoints) |
||
| 214 | totalEtc += int(value + 1) |
||
| 215 | if player.effSciPoints != 0: |
||
| 216 | totalEtc += float(maxImpTotalSci) / player.effSciPoints |
||
| 217 | elif task.changeSci < 0: |
||
| 218 | totalEtc -= float(task.currSci) / min(task.changeSci, player.effSciPoints) |
||
| 219 | elif player.effSciPoints > 0: |
||
| 220 | value = float(researchSci) / player.effSciPoints |
||
| 221 | totalEtc += int(value + 1) |
||
| 222 | totalEtc += float(maxImpTotalSci) / player.effSciPoints |
||
| 223 | else: |
||
| 224 | totalEtc = 99999 |
||
| 225 | break |
||
| 226 | |||
| 227 | # check empty research queue |
||
| 228 | if totalEtc == 0 and len(player.rsrchQueue) == 0 and player.effSciPoints > 0: |
||
| 229 | problems.append(gdata.CRI, ui.Item(_('Research'), tType = Const.T_TECHNOLOGY, |
||
| 230 | vDescription = _('Research queue is empty.'))) |
||
| 231 | # check short reseach queue |
||
| 232 | elif totalEtc < Rules.turnsPerDay * 2: |
||
| 233 | severity = gdata.MIN |
||
| 234 | if totalEtc < Rules.turnsPerDay: |
||
| 235 | severity = gdata.MAJ |
||
| 236 | problems.append(severity, ui.Item(_('Research'), tType = Const.T_TECHNOLOGY, |
||
| 237 | vDescription = _('Research queue ends in %s turns, %d item(s) on list.') % (res.formatTime(totalEtc), len(player.rsrchQueue)))) |
||
| 238 | |||
| 239 | def show(self): |
||
| 240 | critical = self.win.vCritical.checked |
||
| 241 | major = self.win.vMajor.checked |
||
| 242 | minor = self.win.vMinor.checked |
||
| 243 | info = self.win.vInfo.checked |
||
| 244 | |||
| 245 | disp = 1 |
||
| 246 | |||
| 247 | player = client.getPlayer() |
||
| 248 | problems = self.Problems(self.win) |
||
| 249 | # object list (all player's objects + systems) |
||
| 250 | objects = player.fleets[:] |
||
| 251 | objects += player.planets[:] |
||
| 252 | systems = {} |
||
| 253 | for planetID in player.planets: |
||
| 254 | planet = client.get(planetID) |
||
| 255 | if planet.compOf not in systems: |
||
| 256 | systems[planet.compOf] = None |
||
| 257 | objects += systems.keys() |
||
| 258 | |||
| 259 | # counting construction points value of each global production queue |
||
| 260 | # holder for (number , eff production) of planets set to each queue |
||
| 261 | globalQueueStats=[(0,0), (0,0), (0,0), (0,0), (0,0)] |
||
| 262 | prodQueueProblems = [] |
||
| 263 | |||
| 264 | # go through all objects |
||
| 265 | for objID in objects: |
||
| 266 | if objID < Const.OID_FREESTART: |
||
| 267 | continue |
||
| 268 | obj = client.get(objID, noUpdate = 1) |
||
| 269 | if not hasattr(obj, "type"): |
||
| 270 | continue |
||
| 271 | if obj.type == Const.T_SYSTEM: |
||
| 272 | if not hasattr(obj, 'planets'): |
||
| 273 | continue |
||
| 274 | bio = 0 |
||
| 275 | totalBio = 0 |
||
| 276 | en = 0 |
||
| 277 | totalEn = 0 |
||
| 278 | buildingQuantity = {} |
||
| 279 | buildingInfo = {} |
||
| 280 | # holds modified planets |
||
| 281 | planetCopies = {} |
||
| 282 | |||
| 283 | for planetID in obj.planets: |
||
| 284 | planet = client.get(planetID, noUpdate = 1) |
||
| 285 | # copy of planet to change plSlots count |
||
| 286 | if not planetID in planetCopies: |
||
| 287 | cPlanet = copy.deepcopy(planet) |
||
| 288 | planetCopies[planetID] = cPlanet |
||
| 289 | else: |
||
| 290 | cPlanet = planetCopies[planetID] |
||
| 291 | if hasattr(planet, 'owner') and planet.owner == player.oid: |
||
| 292 | queuePlanetNumber, queueEffProd = globalQueueStats[planet.globalQueue] |
||
| 293 | queuePlanetNumber += 1 |
||
| 294 | queueEffProd += planet.effProdProd |
||
| 295 | globalQueueStats[planet.globalQueue] = (queuePlanetNumber, queueEffProd) |
||
| 296 | # compute bio and en for system |
||
| 297 | bio += planet.changeBio |
||
| 298 | totalBio += max(0, planet.storBio - planet.minBio) |
||
| 299 | en += planet.changeEn |
||
| 300 | totalEn += max(0, planet.storEn - planet.minEn) |
||
| 301 | # the planet needs to have global queue 0 - the default one - to have its queue reported |
||
| 302 | if hasattr(planet, 'prodQueue') and self.win.vPlanets.checked and not planet.globalQueue: |
||
| 303 | totalEtc = 0 |
||
| 304 | # compute length of production queue |
||
| 305 | if cPlanet.prodQueue and cPlanet.effProdProd > 0: |
||
| 306 | for task in cPlanet.prodQueue: |
||
| 307 | if task.isShip: |
||
| 308 | tech = player.shipDesigns[task.techID] |
||
| 309 | else: |
||
| 310 | tech = client.getFullTechInfo(task.techID) |
||
| 311 | if tech.isStructure and hasattr(task, "demolishStruct") and task.demolishStruct == 0: |
||
| 312 | # total count of constructing buildings on target |
||
| 313 | if buildingQuantity.has_key(task.targetID): |
||
| 314 | buildingQuantity[task.targetID] += task.quantity |
||
| 315 | else: |
||
| 316 | buildingQuantity[task.targetID] = task.quantity |
||
| 317 | |||
| 318 | # information about source and target of constructing |
||
| 319 | if buildingInfo.has_key((planetID, task.targetID)): |
||
| 320 | buildingInfo[(planetID, task.targetID)] += task.quantity |
||
| 321 | else: |
||
| 322 | buildingInfo[(planetID, task.targetID)] = task.quantity |
||
| 323 | elif tech.isProject and tech.id == 3802: |
||
| 324 | # we are constructing Habitable Surface Expansion |
||
| 325 | # so after construction we got some new slots on planet |
||
| 326 | if not task.targetID in planetCopies: |
||
| 327 | targetPlanet = client.get(task.targetID, noUpdate = 1) |
||
| 328 | cPlanet = copy.deepcopy(targetPlanet) |
||
| 329 | planetCopies[task.targetID] = cPlanet |
||
| 330 | |||
| 331 | planetCopies[task.targetID].plSlots += task.quantity |
||
| 332 | |||
| 333 | if task.targetID != planetID: |
||
| 334 | totalEtc += math.ceil(float(tech.buildProd * Rules.buildOnAnotherPlanetMod - task.currProd) / planet.effProdProd) |
||
| 335 | totalEtc += math.ceil((task.quantity - 1) * float(tech.buildProd * Rules.buildOnAnotherPlanetMod) / planet.effProdProd) |
||
| 336 | else: |
||
| 337 | totalEtc += math.ceil(task.quantity * float(tech.buildProd - task.currProd) / planet.effProdProd) |
||
| 338 | totalEtc += math.ceil((task.quantity - 1) * float(tech.buildProd) / planet.effProdProd) |
||
| 339 | else: |
||
| 340 | totalEtc = 99999 |
||
| 341 | |||
| 342 | prodQueueProblems.append((planetID, totalEtc, len(planet.prodQueue))) |
||
| 343 | |||
| 344 | |||
| 345 | if hasattr(planet, 'slots') and self.win.vPlanets.checked: |
||
| 346 | for struct in planet.slots: |
||
| 347 | self._addProblemsStructStatus(problems, struct, planet) |
||
| 348 | |||
| 349 | for planetID, quantity in buildingQuantity.items(): |
||
| 350 | planet = planetCopies[planetID] |
||
| 351 | # test, if there is total quantity of building as target for this planet |
||
| 352 | if planet.plSlots < len(planet.slots) + quantity and major: |
||
| 353 | # walk infos and search for all planets, that are building |
||
| 354 | # on planet found above |
||
| 355 | for (sourceID, targetID), quantity in buildingInfo.items(): |
||
| 356 | if planetID == targetID: |
||
| 357 | source = client.get(sourceID, noUpdate = 1) |
||
| 358 | items.append(ui.Item(source.name, tOID = sourceID, tType = Const.T_PLANET, foreground = gdata.sevColors[gdata.MAJ], |
||
| 359 | vDescription = _('There is no space for all constructed buildings on %s.') % (planet.name))) |
||
| 360 | |||
| 361 | # check bio for system |
||
| 362 | if self.win.vSystems.checked: |
||
| 363 | self._addProblemsBio(problems, obj, bio, totalBio) |
||
| 364 | self._addProblemsEn(problems, obj, en, totalEn) |
||
| 365 | |||
| 366 | # check fleets |
||
| 367 | elif obj.type == Const.T_FLEET and self.win.vFleets.checked: |
||
| 368 | if hasattr(obj, 'owner') and obj.owner == player.oid: |
||
| 369 | self._addProblemsFleets(problems, obj) |
||
| 370 | |||
| 371 | |||
| 372 | queConstValues = [0, 0, 0, 0, 0] |
||
| 373 | queEtc = [0, 0, 0, 0, 0] |
||
| 374 | for queue in xrange(5): |
||
| 375 | quePlanets, queEffProd = globalQueueStats[queue] |
||
| 376 | for task in player.prodQueues[queue]: |
||
| 377 | if task.isShip: |
||
| 378 | tech = player.shipDesigns[task.techID] |
||
| 379 | else: |
||
| 380 | tech = client.getFullTechInfo(task.techID) |
||
| 381 | queConstValues[queue] += task.quantity * tech.buildProd |
||
| 382 | if queEffProd > 0: |
||
| 383 | queEtc[queue] = math.ceil(float(queConstValues[queue])/queEffProd) |
||
| 384 | else: |
||
| 385 | queEtc[queue] = 99999 |
||
| 386 | |||
| 387 | # creation of items with production queue [default one] problems |
||
| 388 | for planetID, totalEtc, queueLen in prodQueueProblems: |
||
| 389 | planet = client.get(planetID, noUpdate = 1) |
||
| 390 | |||
| 391 | # check empty production queue |
||
| 392 | if queueLen == 0 and planet.effProdProd > 0 and queConstValues[0] == 0 and critical: |
||
| 393 | items.append(ui.Item(planet.name, tOID = planetID, tType = Const.T_PLANET, |
||
| 394 | foreground = gdata.sevColors[gdata.CRI], |
||
| 395 | vDescription = _('Production queue is empty.'))) |
||
| 396 | |||
| 397 | # check end of production queue |
||
| 398 | if totalEtc+queEtc[0] < 48: |
||
| 399 | fgColor = None |
||
| 400 | disp = minor |
||
| 401 | if totalEtc+queEtc[0] < 24: |
||
| 402 | disp = major |
||
| 403 | fgColor = gdata.sevColors[gdata.MAJ] |
||
| 404 | if disp: |
||
| 405 | items.append(ui.Item(planet.name, tOID = planetID, tType = Const.T_PLANET, foreground = fgColor, |
||
| 406 | vDescription = _('Production queue may end in {0} turns ({1} directly in planet queue), {2} item(s) on list.'.format(res.formatTime(totalEtc+queEtc[0]), res.formatTime(totalEtc), queueLen)))) |
||
| 407 | |||
| 408 | # creation of items with global queue problems |
||
| 409 | for queue in xrange(1, 5): |
||
| 410 | queName = res.globalQueueName(queue) |
||
| 411 | quePlanets = globalQueueStats[queue][0] |
||
| 412 | # check empty global production queue with at least one planet [so its relevant] |
||
| 413 | if queConstValues[queue] == 0 and quePlanets > 0 and critical: |
||
| 414 | items.append(ui.Item(_('Global queue ' + queName), tType = Const.T_QUEUE, |
||
| 415 | foreground = gdata.sevColors[gdata.CRI], |
||
| 416 | vDescription = _('Global production queue {0} used by {1} planet(s) is empty.'.format(queName, quePlanets)))) |
||
| 417 | |||
| 418 | # check end of global production queue |
||
| 419 | elif queEtc[queue] < 48: |
||
| 420 | fgColor = None |
||
| 421 | disp = minor |
||
| 422 | if queEtc[queue] < 24: |
||
| 423 | disp = major |
||
| 424 | fgColor = gdata.sevColors[gdata.MAJ] |
||
| 425 | if disp: |
||
| 426 | items.append(ui.Item(_('Global queue ' + queName), tType = Const.T_QUEUE, foreground = fgColor, |
||
| 427 | vDescription = _('Global production queue {0} used by {1} planet(s) runs out in {2} turns.'.format(queName, quePlanets, res.formatTime(queEtc[queue]))))) |
||
| 428 | |||
| 429 | # check research queue |
||
| 430 | if self.win.vResearch.checked: |
||
| 431 | self._addProblemsResearch(problems) |
||
| 432 | |||
| 433 | |||
| 434 | self.win.vProblems.items = problems.items |
||
| 435 | self.win.vProblems.itemsChanged() |
||
| 436 | |||
| 437 | def onClose(self, widget, action, data): |
||
| 438 | self.hide() |
||
| 439 | |||
| 440 | def onShowSource(self, widget, action, data): |
||
| 441 | item = self.win.vProblems.selection[0] |
||
| 442 | if item.tType == Const.T_FLEET: |
||
| 443 | object = client.get(item.tOID, noUpdate = 1) |
||
| 444 | # center on map |
||
| 445 | if hasattr(object, "x"): |
||
| 446 | gdata.mainGameDlg.win.vStarMap.highlightPos = (object.x, object.y) |
||
| 447 | gdata.mainGameDlg.win.vStarMap.setPos(object.x, object.y) |
||
| 448 | self.hide() |
||
| 449 | return |
||
| 450 | elif item.tType in (Const.T_SYSTEM, Const.T_PLANET): |
||
| 451 | if item.tOID != Const.OID_NONE: |
||
| 452 | gdata.mainGameDlg.onSelectMapObj(None, None, item.tOID) |
||
| 453 | return |
||
| 454 | elif item.tType == Const.T_TECHNOLOGY: |
||
| 455 | gdata.mainGameDlg.researchDlg.display() |
||
| 456 | return |
||
| 457 | elif item.tType == Const.T_QUEUE: |
||
| 458 | gdata.mainGameDlg.globalQueuesDlg.display() |
||
| 459 | self.win.setStatus(_("Cannot show location.")) |
||
| 460 | |||
| 461 | def onShowLocation(self, widget, action, data): |
||
| 462 | item = self.win.vProblems.selection[0] |
||
| 463 | if item.tType in (Const.T_SYSTEM, Const.T_PLANET, Const.T_FLEET): |
||
| 464 | object = client.get(item.tOID, noUpdate = 1) |
||
| 465 | # center on map |
||
| 466 | if hasattr(object, "x"): |
||
| 467 | gdata.mainGameDlg.win.vStarMap.highlightPos = (object.x, object.y) |
||
| 468 | gdata.mainGameDlg.win.vStarMap.setPos(object.x, object.y) |
||
| 469 | self.hide() |
||
| 470 | return |
||
| 471 | self.win.setStatus(_("Cannot show location.")) |
||
| 472 | |||
| 473 | def onToggleCondition(self, widget, action, data): |
||
| 474 | self.update() |
||
| 475 | |||
| 476 | def createUI(self): |
||
| 477 | screenWidth, screenHeight = gdata.scrnSize |
||
| 478 | # size of dialog in layout metrics (for SimpleGridLM) |
||
| 479 | cols = 40 |
||
| 480 | rows = 29 |
||
| 481 | # dialog width and height in pixels |
||
| 482 | isSmallWin = screenHeight == 600 and screenWidth == 800 |
||
| 483 | width = cols * 20 + 4 * (not isSmallWin) |
||
| 484 | height = rows * 20 + 4 * (not isSmallWin) |
||
| 485 | #creating dialog window |
||
| 486 | self.win = ui.Window(self.app, |
||
| 487 | modal = 1, |
||
| 488 | escKeyClose = 1, |
||
| 489 | movable = 0, |
||
| 490 | title = _("Problems Locator"), |
||
| 491 | titleOnly = isSmallWin, |
||
| 492 | #rect = ui.Rect((screenWidth - width) / 2, ((screenHeight - height) / 2) * (not isSmallWin), width, height), |
||
| 493 | rect = ui.Rect((screenWidth - 800 - 4 * (not isSmallWin)) / 2, (screenHeight - 600 - 4 * (not isSmallWin)) / 2, width, height), |
||
| 494 | layoutManager = ui.SimpleGridLM(), |
||
| 495 | ) |
||
| 496 | self.win.subscribeAction('*', self) |
||
| 497 | # first row is window title |
||
| 498 | rows -= 1 |
||
| 499 | |||
| 500 | ui.Listbox(self.win, layout = (0, 0, cols, rows - 2), id = 'vProblems', |
||
| 501 | columns = [(_('System'), 'text', 10, ui.ALIGN_W), |
||
| 502 | (_('Problem description'), 'vDescription', 30, ui.ALIGN_W)], |
||
| 503 | columnLabels = 1, action='onShowSource', rmbAction='onShowLocation') |
||
| 504 | |||
| 505 | btnWidth = 4 |
||
| 506 | ui.Check(self.win, layout = (btnWidth * 0, rows - 2, btnWidth, 1), id = 'vSystems', |
||
| 507 | text = _('Systems'), action = 'onToggleCondition', checked = 1) |
||
| 508 | ui.Check(self.win, layout = (btnWidth * 1, rows - 2, btnWidth, 1), id = 'vPlanets', |
||
| 509 | text = _('Planets'), action = 'onToggleCondition', checked = 1) |
||
| 510 | ui.Check(self.win, layout = (btnWidth * 2, rows - 2, btnWidth, 1), id = 'vFleets', |
||
| 511 | text = _('Fleets'), action = 'onToggleCondition', checked = 1) |
||
| 512 | ui.Check(self.win, layout = (btnWidth * 3, rows - 2, btnWidth, 1), id = 'vResearch', |
||
| 513 | text = _('Research'), action = 'onToggleCondition', checked = 1) |
||
| 514 | |||
| 515 | ui.Check(self.win, layout = (btnWidth * 6, rows - 2, btnWidth, 1), id = 'vCritical', |
||
| 516 | text = _('Critical'), action = 'onToggleCondition', checked = 1) |
||
| 517 | ui.Check(self.win, layout = (btnWidth * 7, rows - 2, btnWidth, 1), id = 'vMajor', |
||
| 518 | text = _('Major'), action = 'onToggleCondition', checked = 1) |
||
| 519 | ui.Check(self.win, layout = (btnWidth * 8, rows - 2, btnWidth, 1), id = 'vMinor', |
||
| 520 | text = _('Minor'), action = 'onToggleCondition', checked = 1) |
||
| 521 | ui.Check(self.win, layout = (btnWidth * 9, rows - 2, btnWidth, 1), id = 'vInfo', |
||
| 522 | text = _('Info'), action = 'onToggleCondition', checked = 0) |
||
| 523 | |||
| 524 | # dialog bottom line |
||
| 525 | ui.Title(self.win, layout = (0, rows - 1, cols - 5, 1)) |
||
| 526 | ui.TitleButton(self.win, layout = (cols - 5, rows - 1, 5, 1), text = _("Close"), action = 'onClose') |
||
| 527 |