osci.dialog.ProblemsDlg   F
last analyzed

Complexity

Total Complexity 112

Size/Duplication

Total Lines 511
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 390
dl 0
loc 511
rs 2
c 0
b 0
f 0
wmc 112

21 Methods

Rating   Name   Duplication   Size   Complexity  
A ProblemsDlg.update() 0 2 1
A ProblemsDlg.hide() 0 6 2
A ProblemsDlg._addProblemsMaterial() 0 18 5
C ProblemsDlg._getSystemRefuel() 0 19 10
A ProblemsDlg.append() 0 4 2
A ProblemsDlg.display() 0 6 2
A ProblemsDlg._getTaskSciValue() 0 11 3
C ProblemsDlg._addProblemsStructStatus() 0 46 10
A ProblemsDlg.__init__() 0 3 1
B ProblemsDlg._addProblemsFleets() 0 31 7
A ProblemsDlg.onToggleCondition() 0 2 1
C ProblemsDlg._addProblemsGlobalQueues() 0 44 11
B ProblemsDlg.createUI() 0 52 1
B ProblemsDlg.onShowSource() 0 20 7
D ProblemsDlg.show() 0 62 13
A ProblemsDlg.onClose() 0 2 1
C ProblemsDlg._addProblemsSlots() 0 27 9
B ProblemsDlg._getTargetSlotDict() 0 25 8
B ProblemsDlg._addProblemsResearch() 0 26 6
A ProblemsDlg.onShowLocation() 0 11 3
B ProblemsDlg._addProblemsDefaultQueue() 0 31 8

How to fix   Complexity   

Complexity

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
        if player.effSciPoints < 0:
202
            problems.append(gdata.CRI,
203
                            ui.Item(_('Research'), tType=Const.T_TECHNOLOGY,
204
                                    vDescription=_('We are losing our researched knowledge by %d pts per turn!') % (player.effSciPoints,)))
205
            return
206
        elif player.effSciPoints == 0:
207
            return
208
        elif len(player.rsrchQueue) == 0:
209
            problems.append(gdata.CRI,
210
                            ui.Item(_('Research'), tType=Const.T_TECHNOLOGY,
211
                                    vDescription=_('Research queue is empty.')))
212
            return
213
214
        queueValue = sum(self._getTaskSciValue(task) for task in player.rsrchQueue)
215
        totalEtc = math.ceil(float(queueValue) / player.effSciPoints)
216
217
        # check short reseach queue
218
        if totalEtc < Rules.turnsPerDay * 2:
219
            severity = gdata.MIN
220
            if totalEtc < Rules.turnsPerDay:
221
                severity = gdata.MAJ
222
            problems.append(severity,
223
                            ui.Item(_('Research'), tType=Const.T_TECHNOLOGY,
224
                                    vDescription=_('Research queue ends in %s turns, %d item(s) on list.') % (res.formatTime(totalEtc), len(player.rsrchQueue))))
225
226
    def _addProblemsGlobalQueues(self, problems):
227
        # go through all planets to understand the state of global queues
228
        player = client.getPlayer()
229
        # holder for (number , eff production) of planets set to each queue
230
        globalQueueStats = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
231
        queConstValues = [0, 0, 0, 0, 0]
232
        queEtc = [0, 0, 0, 0, 0]
233
234
        for planetID in player.planets:
235
            planet = client.get(planetID, noUpdate=1)
236
            globalQueueStats[planet.globalQueue] = tuple([sum(x) for x in zip(globalQueueStats[planet.globalQueue], (1, planet.effProdProd))])
237
238
        # evaluate depletion rate of the global queue
239
        for queue in range(5):
240
            quePlanets, queEffProd = globalQueueStats[queue]
241
            for task in player.prodQueues[queue]:
242
                if task.isShip:
243
                    tech = player.shipDesigns[task.techID]
244
                else:
245
                    tech = client.getFullTechInfo(task.techID)
246
                queConstValues[queue] += task.quantity * tech.buildProd
247
            if queEffProd > 0:
248
                queEtc[queue] = math.ceil(float(queConstValues[queue])/queEffProd)
249
            else:
250
                queEtc[queue] = 99999
251
252
        # creation of items with global queue problems
253
        for queue in range(1, 5):
254
            queName = res.globalQueueName(queue)
255
            quePlanets = globalQueueStats[queue][0]
256
            # check empty global production queue with at least one planet [so its relevant]
257
            if queConstValues[queue] == 0 and quePlanets > 0:
258
                problems.append(gdata.CRI,
259
                                ui.Item(_('Global queue ' + queName), tType=Const.T_QUEUE,
260
                                        vDescription=_('Global production queue {0} used by {1} planet(s) is empty.'.format(queName, quePlanets))))
261
            # check end of global production queue
262
            elif queEtc[queue] < Rules.turnsPerDay * 2:
263
                severity = gdata.MIN
264
                if queEtc[queue] < Rules.turnsPerDay:
265
                    severity = gdata.MAJ
266
                problems.append(severity,
267
                                ui.Item(_('Global queue ' + queName), tType=Const.T_QUEUE,
268
                                        vDescription=_('Global production queue {0} used by {1} planet(s) runs out in {2} turns.'.format(queName, quePlanets, res.formatTime(queEtc[queue])))))
269
        return queEtc[0]  # time of depletion of the default queue will be reused later
270
271
    def _getTargetSlotDict(self, planetID):
272
        assert planetID in client.getPlayer().planets
273
        targets = {}
274
        planet = client.get(planetID, noUpdate=1)
275
        if planet.effProdProd <= 0:
276
            return targets
277
278
        nonShipTasks = (task for task in planet.prodQueue if not task.isShip)
279
        for task in nonShipTasks:
280
            tech = client.getFullTechInfo(task.techID)
281
            if tech.isStructure and task.demolishStruct == 0:
282
                quantity = task.quantity
283
            elif tech.isProject and tech.id == 3802:
284
                # we are constructing Habitable Surface Expansion
285
                # so after construction we will have new slot on the planet
286
                quantity = -1
287
            else:
288
                continue
289
            assert quantity != 0
290
291
            try:
292
                targets[task.targetID] += quantity
293
            except KeyError:
294
                targets[task.targetID] = quantity
295
        return targets
296
297
    def _addProblemsSlots(self, problems, system):
298
        player = client.getPlayer()
299
        playerPlanets = set(system.planets) & set(player.planets)
300
        freeSlots = {}
301
        structSources = dict.fromkeys(system.planets)
302
        for planetID in system.planets:
303
            planet = client.get(planetID, noUpdate=1)
304
            freeSlots[planetID] = planet.plSlots - len(planet.slots)
305
306
        for planetID in playerPlanets:
307
            for targetID, quantity in self._getTargetSlotDict(planetID).items():
308
                freeSlots[targetID] -= quantity
309
                if quantity > 0:
310
                    try:
311
                        structSources[targetID].add(planetID)
312
                    except AttributeError:
313
                        structSources[targetID] = set([planetID])
314
315
        for planetID, free in freeSlots.items():
316
            if free < 0:
317
                # not enough space, report for every planet that builds on this one
318
                planet = client.get(planetID, noUpdate=1)
319
                for sourceID in structSources[planetID]:
320
                    source = client.get(sourceID, noUpdate=1)
321
                    problems.append(gdata.MAJ,
322
                                    ui.Item(source.name, tOID=sourceID, tType=Const.T_PLANET,
323
                                            vDescription=_('There is no space for all constructed buildings on %s.') % (planet.name)))
324
325
    def _addProblemsDefaultQueue(self, problems, planet, defaultQueueEtc):
326
        player = client.getPlayer()
327
        if not planet.effProdProd > 0:
328
            return
329
        planetEtc = 0
330
        # compute length of production queue
331
        for task in planet.prodQueue:
332
            if task.isShip:
333
                tech = player.shipDesigns[task.techID]
334
            else:
335
                tech = client.getFullTechInfo(task.techID)
336
            modifier = Rules.buildOnAnotherPlanetMod if task.targetID != planet.oid else 1
337
            planetEtc += math.ceil(float(task.quantity * tech.buildProd * modifier - task.currProd) / planet.effProdProd)
338
339
        etc = planetEtc + defaultQueueEtc
340
        # check empty production queue
341
        if not etc:
342
            problems.append(gdata.CRI,
343
                            ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET,
344
                                    vDescription=_('Production queue is empty.')))
345
            return
346
        if etc < Rules.turnsPerDay:
347
            severity = gdata.MAJ
348
        elif etc < Rules.turnsPerDay * 2:
349
            severity = gdata.MIN
350
        else:
351
            severity = gdata.INFO
352
353
        problems.append(severity,
354
                        ui.Item(planet.name, tOID=planet.oid, tType=Const.T_PLANET,
355
                                vDescription=_('Production queue may end in {0} turns ({1} directly in planet queue).'.format(res.formatTime(etc), res.formatTime(planetEtc)))))
356
357
    def show(self):
358
        critical = self.win.vCritical.checked
359
        major = self.win.vMajor.checked
360
        minor = self.win.vMinor.checked
361
        info = self.win.vInfo.checked
362
363
        disp = 1
364
365
        player = client.getPlayer()
366
        problems = self.Problems(self.win)
367
        systems = set([])
368
        for planetID in player.planets:
369
            planet = client.get(planetID, noUpdate=1)
370
            systems.add(planet.compOf)
371
372
        defaultQueueEtc = self._addProblemsGlobalQueues(problems)
373
374
        for systemID in systems:
375
            system = client.get(systemID, noUpdate=1)
376
            bio = 0
377
            totalBio = 0
378
            en = 0
379
            totalEn = 0
380
            # holds modified planets
381
            planetCopies = {}
382
383
            for planetID in system.planets:
384
                planet = client.get(planetID, noUpdate=1)
385
                # copy of planet to change plSlots count
386
                if hasattr(planet, 'owner') and planet.owner == player.oid:
387
                    # add planet to the global queue stats
388
                    # compute bio and en for system
389
                    bio += planet.changeBio
390
                    totalBio += max(0, planet.storBio - planet.minBio)
391
                    en += planet.changeEn
392
                    totalEn += max(0, planet.storEn - planet.minEn)
393
                    # the planet needs to have global queue 0 - the default one - to have its queue reported
394
                    if self.win.vPlanets.checked:
395
                        if not planet.globalQueue:
396
                            self._addProblemsDefaultQueue(problems, planet, defaultQueueEtc)
397
                        for struct in planet.slots:
398
                            self._addProblemsStructStatus(problems, struct, planet)
399
400
            # free slots within the system
401
            self._addProblemsSlots(problems, system)
402
            # check bio for system
403
            if self.win.vSystems.checked:
404
                self._addProblemsMaterial(problems, system, bio, totalBio, 'Bio')
405
                self._addProblemsMaterial(problems, system, en, totalEn, 'En')
406
407
        # check fleets
408
        if self.win.vFleets.checked:
409
            for fleetID in player.fleets:
410
                fleet = client.get(fleetID, noUpdate=1)
411
                self._addProblemsFleets(problems, fleet)
412
413
        # check research queue
414
        if self.win.vResearch.checked:
415
            self._addProblemsResearch(problems)
416
417
        self.win.vProblems.items = problems.items
418
        self.win.vProblems.itemsChanged()
419
420
    def onClose(self, widget, action, data):
421
        self.hide()
422
423
    def onShowSource(self, widget, action, data):
424
        item = self.win.vProblems.selection[0]
425
        if item.tType == Const.T_FLEET:
426
            object = client.get(item.tOID, noUpdate=1)
427
            # center on map
428
            if hasattr(object, "x"):
429
                gdata.mainGameDlg.win.vStarMap.highlightPos = (object.x, object.y)
430
                gdata.mainGameDlg.win.vStarMap.setPos(object.x, object.y)
431
                self.hide()
432
                return
433
        elif item.tType in (Const.T_SYSTEM, Const.T_PLANET):
434
            if item.tOID != Const.OID_NONE:
435
                gdata.mainGameDlg.onSelectMapObj(None, None, item.tOID)
436
                return
437
        elif item.tType == Const.T_TECHNOLOGY:
438
            gdata.mainGameDlg.researchDlg.display()
439
            return
440
        elif item.tType == Const.T_QUEUE:
441
            gdata.mainGameDlg.globalQueuesDlg.display()
442
        self.win.setStatus(_("Cannot show location."))
443
444
    def onShowLocation(self, widget, action, data):
445
        item = self.win.vProblems.selection[0]
446
        if item.tType in (Const.T_SYSTEM, Const.T_PLANET, Const.T_FLEET):
447
            object = client.get(item.tOID, noUpdate=1)
448
            # center on map
449
            if hasattr(object, "x"):
450
                gdata.mainGameDlg.win.vStarMap.highlightPos = (object.x, object.y)
451
                gdata.mainGameDlg.win.vStarMap.setPos(object.x, object.y)
452
                self.hide()
453
                return
454
        self.win.setStatus(_("Cannot show location."))
455
456
    def onToggleCondition(self, widget, action, data):
457
        self.update()
458
459
    def createUI(self):
460
        screenWidth, screenHeight = gdata.scrnSize
461
        # size of dialog in layout metrics (for SimpleGridLM)
462
        cols = 40
463
        rows = 29
464
        # dialog width and height in pixels
465
        isSmallWin = screenHeight == 600 and screenWidth == 800
466
        width = cols * 20 + 4 * (not isSmallWin)
467
        height = rows * 20 + 4 * (not isSmallWin)
468
        #creating dialog window
469
        self.win = ui.Window(self.app,
470
                             modal=1,
471
                             escKeyClose=1,
472
                             movable=0,
473
                             title=_("Problems Locator"),
474
                             titleOnly=isSmallWin,
475
                             rect=ui.Rect((screenWidth - 800 - 4 * (not isSmallWin)) / 2,
476
                                          (screenHeight - 600 - 4 * (not isSmallWin)) / 2,
477
                                          width,
478
                                          height),
479
                             layoutManager=ui.SimpleGridLM())
480
        self.win.subscribeAction('*', self)
481
        # first row is window title
482
        rows -= 1
483
484
        ui.Listbox(self.win, layout=(0, 0, cols, rows - 2), id='vProblems',
485
                   columns=[(_('Location'), 'text', 10, ui.ALIGN_W),
486
                   (_('Problem description'), 'vDescription', 30, ui.ALIGN_W)],
487
                   columnLabels=1, action='onShowSource', rmbAction='onShowLocation')
488
489
        btnWidth = 4
490
        ui.Check(self.win, layout=(btnWidth * 0, rows - 2, btnWidth, 1), id='vSystems',
491
                 text=_('Systems'), action='onToggleCondition', checked=1)
492
        ui.Check(self.win, layout=(btnWidth * 1, rows - 2, btnWidth, 1), id='vPlanets',
493
                 text=_('Planets'), action='onToggleCondition', checked=1)
494
        ui.Check(self.win, layout=(btnWidth * 2, rows - 2, btnWidth, 1), id='vFleets',
495
                 text=_('Fleets'), action='onToggleCondition', checked=1)
496
        ui.Check(self.win, layout=(btnWidth * 3, rows - 2, btnWidth, 1), id='vResearch',
497
                 text=_('Research'), action='onToggleCondition', checked=1)
498
499
        ui.Check(self.win, layout=(btnWidth * 6, rows - 2, btnWidth, 1), id='vCritical',
500
                 text=_('Critical'), action='onToggleCondition', checked=1)
501
        ui.Check(self.win, layout=(btnWidth * 7, rows - 2, btnWidth, 1), id='vMajor',
502
                 text=_('Major'), action='onToggleCondition', checked=1)
503
        ui.Check(self.win, layout=(btnWidth * 8, rows - 2, btnWidth, 1), id='vMinor',
504
                 text=_('Minor'), action='onToggleCondition', checked=1)
505
        ui.Check(self.win, layout=(btnWidth * 9, rows - 2, btnWidth, 1), id='vInfo',
506
                 text=_('Info'), action='onToggleCondition', checked=0)
507
508
        # dialog bottom line
509
        ui.Title(self.win, layout=(0, rows - 1, cols - 5, 1))
510
        ui.TitleButton(self.win, layout=(cols - 5, rows - 1, 5, 1), text=_("Close"), action='onClose')
511