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

osci.dialog.NewTaskDlg.NewTaskDlg._showShips()   F

Complexity

Conditions 16

Size

Total Lines 34
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 27
nop 1
dl 0
loc 34
rs 2.4
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like osci.dialog.NewTaskDlg.NewTaskDlg._showShips() 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 math
22
23
import pygameui as ui
24
25
from ige import GameException
26
from ige.ospace import Rules
27
import ige.ospace.Const as Const
28
29
from osci import gdata, client, res
30
from TechInfoDlg import TechInfoDlg
31
from ConstructionDlg import ConstructionDlg
32
from ConfirmDlg import ConfirmDlg
33
import Utils
34
import Filter
35
36
37
class NewTaskDlg:
38
39
    def __init__(self, app):
40
        self.app = app
41
        self.showStructures = 1
42
        self.showShips = 0
43
        self.showOther = 0
44
        self.techID = 0
45
        self.showLevels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 99]
46
        self.techInfoDlg = TechInfoDlg(app)
47
        self.constructionDlg = ConstructionDlg(app)
48
        self.confirmDlg = ConfirmDlg(app)
49
        self.createUI()
50
        self.win.setTagAttr('struct', 'visible', 1)
51
        self.win.setTagAttr('ship', 'visible', 0)
52
        # set default sorting for technologies
53
        self.win.vTechs.setSort("text")
54
55
    def display(self, caller, prodProd, structToDemolish=Const.OID_NONE):
56
        if gdata.config.defaults.reportfinalization != None:
57
            val = gdata.config.defaults.reportfinalization
58
            self.win.vReportFin.checked = val == 'yes'
59
60
        self.caller = caller
61
        self.systemID = caller.systemID
62
        self.planetID = caller.planetID
63
        self.playerID = client.getPlayerID()
64
        self.targetID = caller.planetID
65
        self.maxTechLevel = 0
66
        self.quantity = 1
67
        self.govTransferConfirm = False
68
        self.govTransferData = None
69
        self.prodProd = prodProd
70
        self.structToDemolish = structToDemolish
71
        self.showTechs()
72
        self.showSlots()
73
        self.win.show()
74
        gdata.updateDlgs.append(self)
75
76
    def hide(self):
77
        self.win.setStatus(_("Ready."))
78
        if self in gdata.updateDlgs:
79
            gdata.updateDlgs.remove(self)
80
        self.win.hide()
81
82
    def update(self):
83
        if self.win.visible:
84
            self.quantity = int(self.win.vQuantity.text)
85
            if self.showShips:
86
                self.win.vInfo.enabled = Utils.enableConstruction(client)
87
            self.showTechs()
88
            self.showSlots()
89
90
    def _processNonShips(self, tech):
91
        if self.prodProd > 0:
92
            etc = math.ceil(float(tech.buildProd) / self.prodProd)
93
            if self.targetID != self.planetID:
94
                etc *= Rules.buildOnAnotherPlanetMod
95
            etc = res.formatTime(etc)
96
        else:
97
            etc = _("N/A")
98
99
        item = ui.Item(tech.name,
100
                       tLevel=tech.level,
101
                       tProd=tech.buildProd,
102
                       techID=tech.id,
103
                       tIsShip=0,
104
                       tETC=etc,
105
                      )
106
        self.maxTechLevel = max(self.maxTechLevel, tech.level)
107
108
        return item
109
110
    def _showStructures(self):
111
        items = []
112
        _filterStructure = Filter.Filter()
113
        _filterStructure.add((lambda x: x.isMilitary) if self.win.vMilitary.checked else Filter.false)
114
        _filterStructure.add((lambda x: getattr(x, "prodBio", 0)) if self.win.vBioProduction.checked else Filter.false)
115
        # prodEnv can be negative for structures destroying environment
116
        _filterStructure.add((lambda x: getattr(x, "prodEnv", 0) > 0) if self.win.vBioProduction.checked else Filter.false)
117
        _filterStructure.add((lambda x: getattr(x, "prodEn", 0)) if self.win.vEnProduction.checked else Filter.false)
118
        _filterStructure.add((lambda x: getattr(x, "prodProd", 0)) if self.win.vCPProduction.checked else Filter.false)
119
        _filterStructure.add((lambda x: getattr(x, "prodSci", 0)) if self.win.vRPProduction.checked else Filter.false)
120
        _filterStructure.add((lambda x: getattr(x, "moraleTrgt", 0)) if self.win.vMorale.checked else Filter.false)
121
122
        for techID in client.getPlayer().techs.keys():
123
            tech = client.getTechInfo(techID)
124
            if not tech.isStructure or tech.level not in self.showLevels or \
125
               (tech.isStructure and not _filterStructure.OR(tech)):
126
                continue
127
            items.append(self._processNonShips(tech))
128
129
        return items
130
131
    def _showProjects(self):
132
        items = []
133
        for techID in client.getPlayer().techs.keys():
134
            tech = client.getTechInfo(techID)
135
            if tech.level not in self.showLevels or not tech.isProject:
136
                continue
137
            items.append(self._processNonShips(tech))
138
139
        return items
140
141
    def _showShips(self):
142
        items = []
143
        _filterShipSize = Filter.Filter()
144
        _filterShipSize.add((lambda x: x.combatClass == 0) if self.win.vSmall.checked else Filter.false)
145
        _filterShipSize.add((lambda x: x.combatClass == 1) if self.win.vMedium.checked else Filter.false)
146
        _filterShipSize.add((lambda x: x.combatClass == 2) if self.win.vLarge.checked else Filter.false)
147
        _filterShipMilitary = Filter.Filter()
148
        _filterShipMilitary.add((lambda x: x.isMilitary) if self.win.vMilShip.checked else Filter.false)
149
        _filterShipMilitary.add((lambda x: not x.isMilitary) if self.win.vCivShip.checked else Filter.false)
150
151
        # special handling for ships
152
        player = client.getPlayer()
153
154
        for designID in player.shipDesigns.keys():
155
            tech = player.shipDesigns[designID]
156
            if not _filterShipSize.OR(tech) or not _filterShipMilitary.OR(tech):
157
                continue
158
159
            if tech.upgradeTo != Const.OID_NONE:
160
                # skip ships that are set to upgrade
161
                continue
162
            if self.prodProd > 0:
163
                etc = res.formatTime(math.ceil(float(tech.buildProd) / self.prodProd))
164
            else:
165
                etc = _("N/A")
166
            item = ui.Item(tech.name,
167
                           tLevel=tech.level,
168
                           tProd=tech.buildProd,
169
                           techID=designID,
170
                           tIsShip=1,
171
                           tETC=etc,
172
            )
173
            items.append(item)
174
        return items
175
176
    def _processTarget(self, planet):
177
        ownerName = res.getUnknownName()
178
        ownerID = Const.OID_NONE
179
        if hasattr(planet, 'owner'):
180
            ownerID = planet.owner
181
            if planet.owner != Const.OID_NONE:
182
                ownerName = client.get(planet.owner, noUpdate=1).name
183
        if planet.plType in ("A", "G"):
184
            color = gdata.sevColors[gdata.DISABLED]
185
        else:
186
            color = res.getPlayerColor(ownerID)
187
        plname = getattr(planet, 'name', res.getUnknownName())
188
        item = ui.Item(plname,
189
                       text_raw=getattr(planet, 'plEn', plname),
190
                       planetID=planet.oid,
191
                       plOwner=ownerName,
192
                       foreground=color,
193
                      )
194
        return item
195
196
    def showTechs(self):
197
        # techs
198
        items = []
199
200
        if self.showStructures:
201
            items += self._showStructures()
202
        if self.showShips:
203
            items += self._showShips()
204
        if self.showOther:
205
            items += self._showProjects()
206
207
        # sort it by level and then by name
208
        items.sort(key=lambda a: (100 - a.tLevel, a.text))
209
        self.win.vTechs.items = items
210
        self.win.vTechs.itemsChanged()
211
        # preserve selection
212
        for item in items:
213
            if self.techID == item.techID:
214
                self.win.vTechs.selectItem(item)
215
                break
216
        # tech level filter
217
        for i in range(1, 7):
218
            widget = getattr(self.win, 'vLevel%d' % i)
219
            if i in self.showLevels and i <= self.maxTechLevel:
220
                widget.visible = 1
221
                widget.pressed = 1
222
            elif i not in self.showLevels and i <= self.maxTechLevel:
223
                widget.visible = 1
224
                widget.pressed = 0
225
            else:
226
                widget.visible = 0
227
        self.win.vStructuresToggle.pressed = self.showStructures
228
        self.win.vShipsToggle.pressed = self.showShips
229
        self.win.vOtherToggle.pressed = self.showOther
230
        # targets
231
        info = []
232
        system = client.get(self.systemID, noUpdate=1)
233
        for planetID in system.planets:
234
            planet = client.get(planetID, noUpdate=1)
235
            info.append(self._processTarget(planet))
236
        self.win.vTargets.items = info
237
        self.win.vTargets.itemsChanged()
238
        for item in info:
239
            if self.targetID == item.planetID:
240
                self.win.vTargets.selectItem(item)
241
                break
242
        # quantity
243
        self.win.vQuantity.text = str(self.quantity)
244
245 View Code Duplication
    def showSlots(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
246
        # techs
247
        items = []
248
        techs = {}
249
        if self.showStructures:
250
            player = client.getPlayer()
251
            target = client.get(self.targetID, noUpdate=1)
252
            if hasattr(target, 'slots') and target.owner == player.oid:
253
                if len(target.slots) < target.plSlots:
254
                    item = ui.Item(_("Free slot"), techID=0)
255
                    items.append(item)
256
                for struct in target.slots:
257
                    if not struct[Const.STRUCT_IDX_TECHID] in techs:
258
                        techs[struct[Const.STRUCT_IDX_TECHID]] = 1
259
                    else:
260
                        techs[struct[Const.STRUCT_IDX_TECHID]] += 1
261
                for tech in techs.keys():
262
                    techInfo = client.getTechInfo(tech)
263
                    item = ui.Item("%s (%d)" % (techInfo.name, techs[tech]), techID=tech)
264
                    items.append(item)
265
266
        self.win.vTSlots.items = items
267
        self.win.vTSlots.itemsChanged()
268
        self.structToDemolish = Const.OID_NONE
269
270
    def onSelectPlanet(self, widget, action, data):
271
        self.quantity = int(self.win.vQuantity.text)
272
        self.targetID = data.planetID
273
        self.showTechs()
274
        self.showSlots()
275
276
    def onSelectSlot(self, widget, action, data):
277
        self.structToDemolish = data.techID
278
279
    def onSelectTech(self, widget, action, data):
280
        self.techID = data.techID
281
282
    def onToggleLevel(self, widget, action, data):
283
        i = widget.data
284
        if i in self.showLevels:
285
            self.showLevels.remove(i)
286
        else:
287
            self.showLevels.append(i)
288
        self.update()
289
290
    def onCancel(self, widget, action, data):
291
        self.hide()
292
293
    def onGovTransferConfirmed(self):
294
        # we assume player wants to build just one center - in opposite case, he may change quantity in the task itself
295
        self.win.vQuantity.text = str(1)
296
        self.govTransferConfirm = True
297
        self.onConstruct(*self.govTransferData)
298
299
    def onConstruct(self, widget, action, data):
300
        planet = client.get(self.planetID, noUpdate=1)
301
        player = client.getPlayer()
302
        if not self.techID:
303
            self.win.setStatus(_('Select technology to construct.'))
304
            return
305
        if not self.targetID:
306
            self.win.setStatus(_('Select planet to construct on.'))
307
            return
308
        try:
309
            self.quantity = int(self.win.vQuantity.text)
310
        except ValueError:
311
            self.win.setStatus(_('Specify quantity (1, 2, 3, ...).'))
312
            return
313
        # government centers have additional query and if confirmed, another round of this function is called
314
        if self.techID < 1000:
315
            tech = player.shipDesigns[self.techID]
316
        else:
317
            tech = client.getTechInfo(self.techID)
318
        if not getattr(tech, 'govPwr', 0) == 0 and not self.govTransferConfirm:
319
            # confirm dialog doesn't send through parameters, so we have to save them
320
            self.govTransferData = (widget, action, data)
321
            self.confirmDlg.display(_("Do you want to issue relocation of your government?"),
322
                _("Yes"), _("No"), self.onGovTransferConfirmed)
323
        else:
324
            try:
325
                self.win.setStatus(_('Executing START CONSTRUCTION command...'))
326
                planet.prodQueue, player.stratRes = client.cmdProxy.startConstruction(self.planetID,
327
                    self.techID, self.quantity, self.targetID, self.techID < 1000,
328
                    self.win.vReportFin.checked, self.structToDemolish)
329
                self.win.setStatus(_('Command has been executed.'))
330
            except GameException, e:
331
                self.win.setStatus(e.args[0])
332
                return
333
        self.hide()
334
        self.caller.update()
335
336
    def onToggleStructures(self, widget, action, data):
337
        self.showStructures = 1
338
        self.showShips = 0
339
        self.showOther = 0
340
        self.win.setTagAttr('struct', 'visible', 1)
341
        self.win.setTagAttr('ship', 'visible', 0)
342
        self.update()
343
344
    def onToggleShips(self, widget, action, data):
345
        self.showStructures = 0
346
        self.showShips = 1
347
        self.showOther = 0
348
        self.win.setTagAttr('struct', 'visible', 0)
349
        self.win.setTagAttr('ship', 'visible', 1)
350
        self.update()
351
352
    def onToggleOther(self, widget, action, data):
353
        self.showStructures = 0
354
        self.showShips = 0
355
        self.showOther = 1
356
        self.win.setTagAttr('struct', 'visible', 0)
357
        self.win.setTagAttr('ship', 'visible', 0)
358
        self.update()
359
360
    def onInfo(self, widget, action, data):
361
        if len(self.win.vTechs.selection) == 0:
362
            return
363
        task = self.win.vTechs.selection[0]
364
        if not task.tIsShip:
365
            self.techInfoDlg.display(task.techID)
366
        else:
367
            self.constructionDlg.selectedDesignID = task.techID;
368
            self.constructionDlg.display()
369
370
    def onFilter(self, widget, action, data):
371
        self.update()
372
373
    def createUI(self):
374
        w, h = gdata.scrnSize
375
        cols = 38
376
        rows = 24 #was 23
377
        dlgWidth = cols * 20 + 4
378
        dlgHeight = rows * 20 + 4
379
        self.win = ui.Window(self.app,
380
                             modal=1,
381
                             escKeyClose=1,
382
                             movable=0,
383
                             title=_('Select new task'),
384
                             rect=ui.Rect((w - dlgWidth) / 2, (h - dlgHeight) / 2, dlgWidth, dlgHeight),
385
                             layoutManager=ui.SimpleGridLM(),
386
                             tabChange=True
387
        )
388
        self.win.subscribeAction('*', self)
389
        ui.Title(self.win, layout=(0, 0, 22, 1), text=_('Technology'),
390
                 align=ui.ALIGN_W, font='normal-bold')
391
        ui.Listbox(self.win, layout=(0, 1, 22, 19), id='vTechs',
392
                   columns=((_('Name'), 'text', 13, ui.ALIGN_W), (_('Lvl'), 'tLevel', 2, ui.ALIGN_E),
393
                   (_('Constr'), 'tProd', 3, ui.ALIGN_E), (_('ETC'), 'tETC', 3, ui.ALIGN_E)),
394
                   columnLabels=1, action='onSelectTech')
395
        # filter
396
        ui.Button(self.win, layout=(0, 20, 3, 1), text=_('Stucts'), toggle=1,
397
                  id='vStructuresToggle', action='onToggleStructures')
398
        ui.Button(self.win, layout=(3, 20, 3, 1), text=_('Ships'), toggle=1,
399
                  id='vShipsToggle', action='onToggleShips')
400
        ui.Button(self.win, layout=(6, 20, 3, 1), text=_('Misc'), toggle=1,
401
                  id='vOtherToggle', action='onToggleOther')
402
        ui.Button(self.win, layout=(9, 20, 1, 1), text=_('1'), id='vLevel1',
403
                  toggle=1, action='onToggleLevel', data=1)
404
        ui.Button(self.win, layout=(10, 20, 1, 1), text=_('2'), id='vLevel2',
405
                  toggle=1, action='onToggleLevel', data=2)
406
        ui.Button(self.win, layout=(11, 20, 1, 1), text=_('3'), id='vLevel3',
407
                  toggle=1, action='onToggleLevel', data=3)
408
        ui.Button(self.win, layout=(12, 20, 1, 1), text=_('4'), id='vLevel4',
409
                  toggle=1, action='onToggleLevel', data=4)
410
        ui.Button(self.win, layout=(13, 20, 1, 1), text=_('5'), id='vLevel5',
411
                  toggle=1, action='onToggleLevel', data=5)
412
        ui.Button(self.win, layout=(14, 20, 1, 1), text=_('6'), id='vLevel6',
413
                  toggle=1, action='onToggleLevel', data=6)
414
        ui.Button(self.win, layout=(18, 20, 4, 1), text=_('Info'), action='onInfo',
415
                  id='vInfo')
416
        # targets
417
        ui.Title(self.win, layout=(22, 0, 16, 1), text=_('Target planet'),
418
                 align=ui.ALIGN_W, font='normal-bold')
419
        ui.Listbox(self.win, layout=(22, 1, 16, 10), id='vTargets',
420
                   columns=((_('Planet'), 'text', 10, ui.ALIGN_W), (_('Owner'), 'plOwner', 5, ui.ALIGN_W)), columnLabels=1,
421
                   action='onSelectPlanet')
422
        ui.Listbox(self.win, layout=(22, 11, 16, 7), id='vTSlots',
423
                   columns=((_('Target slots'), 'text', 15, ui.ALIGN_W), ), columnLabels=1,
424
                   action='onSelectSlot')
425
        # prod types
426
        ui.Check(self.win, layout=(0, 21, 6, 1), text=_('Bio production'), tags=['struct'],
427
                 id='vBioProduction', checked=1, align=ui.ALIGN_W, action='onFilter')
428
        ui.Check(self.win, layout=(6, 21, 6, 1), text=_('En production'), tags=['struct'],
429
                 id='vEnProduction', checked=1, align=ui.ALIGN_W, action='onFilter')
430
        ui.Check(self.win, layout=(12, 21, 6, 1), text=_('CP production'), tags=['struct'],
431
                 id='vCPProduction', checked=1, align=ui.ALIGN_W, action='onFilter')
432
        ui.Check(self.win, layout=(18, 21, 6, 1), text=_('RP production'), tags=['struct'],
433
                 id='vRPProduction', checked=1, align=ui.ALIGN_W, action='onFilter')
434
        ui.Check(self.win, layout=(24, 21, 6, 1), text=_('Military'), tags=['struct'],
435
                 id='vMilitary', checked=1, align=ui.ALIGN_W, action='onFilter')
436
        ui.Check(self.win, layout=(30, 21, 6, 1), text=_('Morale'), tags=['struct'],
437
                 id='vMorale', checked=1, align=ui.ALIGN_W, action='onFilter')
438
        # ship types
439
        ui.Check(self.win, layout=(0, 21, 6, 1), text=_('Small'), tags=['ship'],
440
                 id='vSmall', checked=1, align=ui.ALIGN_W, action='onFilter')
441
        ui.Check(self.win, layout=(6, 21, 6, 1), text=_('Medium'), tags=['ship'],
442
                 id='vMedium', checked=1, align=ui.ALIGN_W, action='onFilter')
443
        ui.Check(self.win, layout=(12, 21, 6, 1), text=_('Large'), tags=['ship'],
444
                 id='vLarge', checked=1, align=ui.ALIGN_W, action='onFilter')
445
        ui.Check(self.win, layout=(18, 21, 6, 1), text=_('Civilian'), tags=['ship'],
446
                 id='vCivShip', checked=1, align=ui.ALIGN_W, action='onFilter')
447
        ui.Check(self.win, layout=(24, 21, 6, 1), text=_('Military'), tags=['ship'],
448
                 id='vMilShip', checked=1, align=ui.ALIGN_W, action='onFilter')
449
        # build
450
        ui.Title(self.win, layout=(22, 18, 16, 1), text=_('Options'),
451
                 align=ui.ALIGN_W, font='normal-bold')
452
        ui.Label(self.win, layout=(22, 19, 10, 1), text=_('Quantity'), align=ui.ALIGN_W)
453
        ui.Entry(self.win, layout=(33, 19, 5, 1), id='vQuantity', align=ui.ALIGN_E, orderNo=1)
454
        ui.Check(self.win, layout=(31, 20, 7, 1), id='vReportFin', text=_('Report finalization'))
455
        ui.Title(self.win, layout=(0, 22, 28, 1), id='vStatusBar', align=ui.ALIGN_W)
456
        ui.TitleButton(self.win, layout=(28, 22, 5, 1), text=_('Cancel'), action='onCancel')
457
        ui.TitleButton(self.win, layout=(33, 22, 5, 1), text=_('Construct'), action='onConstruct')
458