Passed
Pull Request — master (#291)
by Marek
01:46
created

ProblemsDlg._addProblemsResearch()   F

Complexity

Conditions 14

Size

Total Lines 39
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 34
nop 2
dl 0
loc 39
rs 3.6
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like osci.dialog.ProblemsDlg.ProblemsDlg._addProblemsResearch() 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
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable prodQueueProblems does not seem to be defined.
Loading history...
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):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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)))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable bio does not seem to be defined.
Loading history...
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],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable items does not seem to be defined.
Loading history...
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):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable xrange does not seem to be defined.
Loading history...
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