scanResults.py (12237B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\scannerFiles\scanResults.py 2 import blue 3 from carbon.common.script.sys.service import ROLE_QA 4 from carbon.common.script.util.timerstuff import AutoTimer 5 import carbonui.const as uiconst 6 from carbonui.control.basicDynamicScroll import BasicDynamicScroll 7 from carbonui.uianimations import animations 8 from eve.common.script.sys.eveCfg import IsControllingStructure 9 from eve.client.script.ui.control.entries.util import GetFromClass 10 from eve.client.script.ui.control.scrollColumnHeader import ScrollColumnHeader 11 from eve.client.script.ui.inflight.scannerFiles.swipeAnimation import SwipeAnimator 12 from eve.client.script.ui.inflight.scannerListEntries import ScanResultNew 13 from eve.client.script.ui.shared.mapView.markers.mapMarkerUtil import GetResultTexturePath 14 from gametime import GetSimTime, GetTimeDiff 15 from localization import GetByLabel 16 from logging import getLogger 17 from menu import MenuLabel 18 from probescanning.const import probeScanGroupAnomalies 19 from sensorsuite.overlay.controllers.probescanner import SiteDataFromScanResult 20 from uthread2 import call_after_wallclocktime_delay 21 from utillib import KeyVal 22 logger = getLogger(__name__) 23 24 class ScanResults(BasicDynamicScroll): 25 __notifyevents__ = ['OnSiteSelectionChanged', 'OnCosmicAnomalyAdded', 'OnCosmicSignatureAdded'] 26 27 def ApplyAttributes(self, attributes): 28 self._scan_service = None 29 self._michelle = None 30 super(ScanResults, self).ApplyAttributes(attributes) 31 sm.RegisterNotify(self) 32 self.palette = attributes.palette 33 self.swipe_animator = SwipeAnimator(parent=self, name='scanAnimator', align=uiconst.TOLEFT_PROP, clipChildren=True) 34 self.sort_headers = ScrollColumnHeader(parent=self, settingsID='probescannerwindow_resultScrollList', idx=0, scroll=self, entryClass=ScanResultNew, padBottom=4) 35 for header in self.sort_headers.headers: 36 header.OnClick = (self.on_header_clicked, header) 37 38 self.highlighted_target_ids = set() 39 self.update_timer = AutoTimer(interval=1500, method=self.update_results) 40 41 def Close(self, *args): 42 sm.UnregisterNotify(self) 43 if self.update_timer: 44 self.update_timer.KillTimer() 45 self.update_timer = None 46 super(ScanResults, self).Close(*args) 47 48 @property 49 def scan_service(self): 50 if self._scan_service is None: 51 self._scan_service = sm.GetService('scanSvc') 52 return self._scan_service 53 54 @property 55 def michelle(self): 56 if self._michelle is None: 57 self._michelle = sm.GetService('michelle') 58 return self._michelle 59 60 def OnSelectionChange(self, *args): 61 selected = self.GetSelected() 62 self.scan_service.SetSelectedSites([ site.id for site in selected ]) 63 64 def OnSiteSelectionChanged(self): 65 nodes = self.GetNodes() 66 for node in nodes: 67 if not node.panel: 68 continue 69 if self.scan_service.IsSiteSelected(node.id): 70 node.panel.Select() 71 else: 72 node.panel.Deselect() 73 74 def on_system_scan_started(self): 75 current_scan = self.scan_service.GetCurrentScan() 76 if current_scan is None: 77 return 78 dilation_multiplier = 1.0 / max(blue.os.desiredSimDilation, 0.1) 79 swipe_duration = dilation_multiplier * current_scan.duration / 1000 + 0.5 80 self._start_animation(resultsFadeDuration=0.5, swipeDuration=swipe_duration, swipeFadeInDuration=0.5, swipeFadeOutDuration=0.5, swipeHighlightDuration=0.3) 81 82 def on_system_scan_ended(self): 83 self._end_animation(resultsFadeDuration=0.7) 84 85 def OnCosmicAnomalyAdded(self, anomaly): 86 target_id = anomaly.targetID 87 self.highlight_entry(target_id) 88 89 def OnCosmicSignatureAdded(self, target_id): 90 self.highlight_entry(target_id) 91 92 def highlight_entry(self, target_id): 93 self._add_highlight(target_id) 94 if self.IsVisible(): 95 self._show_quick_swipe(callback=self.palette.Refresh) 96 else: 97 self.palette.Refresh() 98 99 def _show_quick_swipe(self, callback = None): 100 swipe_duration = 1.0 101 results_fade_in_duration = 0.15 * swipe_duration 102 results_fade_out_duration = 0.21 * swipe_duration 103 end_delay = 0.8 * swipe_duration 104 callback_delay = 0.6 * swipe_duration 105 self._start_animation(results_fade_in_duration, swipe_duration) 106 call_after_wallclocktime_delay(self._end_animation, delay=end_delay, resultsFadeDuration=results_fade_out_duration) 107 if callable(callback): 108 call_after_wallclocktime_delay(callback, delay=callback_delay) 109 110 def _start_animation(self, resultsFadeDuration, swipeDuration, swipeFadeInDuration = None, swipeFadeOutDuration = None, swipeHighlightDuration = None): 111 animations.FadeTo(self, duration=resultsFadeDuration, startVal=1.0, endVal=0.5) 112 self.swipe_animator.start(swipeDuration, swipeFadeInDuration, swipeHighlightDuration, swipeFadeOutDuration) 113 114 def _end_animation(self, resultsFadeDuration): 115 animations.FadeIn(self, duration=resultsFadeDuration, curveType=uiconst.ANIM_OVERSHOT5) 116 117 def on_header_clicked(self, header): 118 self.load_results() 119 self.sort_headers.ClickHeader(header) 120 121 def get_result_entry(self, columnWidths, myPos, result): 122 displayName = self.scan_service.GetDisplayName(result) 123 scanGroupName = self.scan_service.GetScanGroupName(result) 124 groupName = self.scan_service.GetGroupName(result) 125 typeName = self.scan_service.GetTypeName(result) 126 distance = result.GetDistance(myPos) 127 sortValues = [GetResultTexturePath(result), 128 distance, 129 result.id, 130 displayName, 131 groupName, 132 min(1.0, result.certainty)] 133 data = KeyVal() 134 data.sortValues = sortValues 135 data.columnID = 'probeResultColumn' 136 data.displayName = displayName 137 data.scanGroupName = scanGroupName 138 data.groupName = groupName 139 data.typeName = typeName 140 data.result = result 141 data.GetMenu = self.result_menu 142 data.distance = distance 143 data.newResult = True 144 data.columnWidths = columnWidths 145 data.itemID = result.itemID 146 data.id = result.id 147 data.isSelected = self.scan_service.IsSiteSelected(result.id) 148 entry = GetFromClass(ScanResultNew, data) 149 return entry 150 151 def result_menu(self, panel, *args): 152 result = panel.sr.node.result 153 menu = [] 154 siteData = SiteDataFromScanResult(result) 155 menu.extend(self.scan_service.GetScanResultMenuWithoutIgnore(siteData)) 156 nodes = self.GetSelected() or [panel.sr.node] 157 idList = [] 158 nonAnomalyIdList = [] 159 for node in nodes: 160 if hasattr(node.result, 'id'): 161 idList.append(node.result.id) 162 if node.result.scanGroupID != probeScanGroupAnomalies: 163 nonAnomalyIdList.append(node.result.id) 164 165 menu.append((MenuLabel('UI/Inflight/Scanner/IngoreResult'), self.scan_service.IgnoreResult, idList)) 166 menu.append((MenuLabel('UI/Inflight/Scanner/IgnoreOtherResults'), self.scan_service.IgnoreOtherResults, idList)) 167 if session.role & ROLE_QA: 168 menu.append(('QA', [('Scan selected sites', self.scan_service.QAScanSites, idList), 169 None, 170 ('Dungeon ID: {}'.format(result.dungeonID), None), 171 ('Archetype ID: {}'.format(result.archetypeID), None)])) 172 return menu 173 174 def load_results(self): 175 if self.destroyed: 176 return 177 current_scan = self.scan_service.GetCurrentScan() 178 scanning_probes = self.scan_service.GetScanningProbes() 179 my_position = sm.GetService('michelle').GetMyPosition() 180 if not my_position: 181 return 182 results, ignored, filtered, filtered_anomalies = self.scan_service.GetResults() 183 column_widths = self.sort_headers.GetColumnWidths() 184 resultList = [] 185 if current_scan and GetTimeDiff(current_scan.startTime, GetSimTime()) < current_scan.duration: 186 return 187 if scanning_probes and session.shipid not in scanning_probes: 188 return 189 if results: 190 for result in results: 191 entry = self.get_result_entry(column_widths, my_position, result) 192 resultList.append(entry) 193 194 scroll_position = self.GetScrollProportion() 195 self.Clear() 196 sorted_results = self.get_sorted_results(resultList) 197 if IsControllingStructure(): 198 self.ShowHint(hint=GetByLabel('UI/Inflight/Scanner/ProbeScanDisabledInStructure')) 199 else: 200 self.AddNodes(0, sorted_results) 201 self._apply_highlights(sorted_results) 202 if scroll_position: 203 self.ScrollToProportion(scroll_position) 204 if sorted_results: 205 self.ShowHint() 206 self.sort_headers.Show() 207 else: 208 self.sort_headers.Hide() 209 self.ShowHint(hint=self.get_no_scan_results_text(filtered, ignored, filtered_anomalies)) 210 self.palette.ShowFilteredAndIgnored(filtered, ignored, filtered_anomalies) 211 self.palette.RefreshProbeResults() 212 213 def _apply_highlights(self, results): 214 for result in results: 215 self._apply_highlight(result) 216 217 def _apply_highlight(self, result): 218 result_id = getattr(result, 'id', None) 219 if result_id and result_id in self.highlighted_target_ids: 220 panel = getattr(result, 'panel', None) 221 if panel: 222 panel.ShowNewResultHighlight() 223 panel.RegisterForMouseExit(self._remove_highlight) 224 logger.debug('Scan result highlights: {} had highlight applied'.format(result_id)) 225 226 def _add_highlight(self, result_id): 227 self.highlighted_target_ids.add(result_id) 228 logger.debug('Scan result highlights: {} added to the list to highlight'.format(result_id)) 229 230 def _remove_highlight(self, panel, result_id): 231 self.highlighted_target_ids.discard(result_id) 232 panel.UnregisterForMouseExit(self._remove_highlight) 233 logger.debug('Scan result highlights: {} had highlight removed'.format(result_id)) 234 235 def update_results(self): 236 if not self.michelle.InWarp(): 237 return 238 nodes = self.GetNodes() 239 my_position = self.michelle.GetMyPosition() 240 if not nodes or not my_position: 241 return 242 for node in nodes: 243 if not node or not node.result: 244 continue 245 distance = node.result.GetDistance(my_position) 246 node.distance = distance 247 node.sortValues[1] = distance 248 if not node.panel: 249 continue 250 node.panel.UpdateDistanceText() 251 252 sorted_results = self.get_sorted_results(nodes) 253 self.SetOrderedNodes(sorted_results) 254 255 def get_sorted_results(self, results): 256 _, column_direction = self.sort_headers.GetActiveColumnAndDirection() 257 sorted_results = sorted(results, key=self.get_sort_value, reverse=not column_direction) 258 return sorted_results 259 260 def get_sort_value(self, node): 261 columns = ScanResultNew.GetColumns() 262 active_column, _ = self.sort_headers.GetActiveColumnAndDirection() 263 active_colum_index = columns.index(active_column) if active_column else 0 264 return node.sortValues[active_colum_index] 265 266 def get_no_scan_results_text(self, filtered, ignored, filteredAnomalies): 267 if IsControllingStructure(): 268 return GetByLabel('UI/Inflight/Scanner/ProbeScanDisabledInStructure') 269 if ignored and (filtered or filteredAnomalies): 270 text = GetByLabel('UI/Inflight/Scanner/FilteredAndIgnoredResults') 271 elif ignored: 272 text = GetByLabel('UI/Inflight/Scanner/IgnoredResults') 273 elif filtered or filteredAnomalies: 274 text = GetByLabel('UI/Inflight/Scanner/FilteredResults') 275 else: 276 text = GetByLabel('UI/Inflight/Scanner/NoScanResults') 277 return text