/usr/lib/python3/dist-packages/ginga/rv/plugins/Contents.py is in python3-ginga 2.6.1-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | #
# Contents.py -- Table of Contents plugin for fits viewer
#
# This is open-source software licensed under a BSD license.
# Please see the file LICENSE.txt for details.
#
from ginga.util.six import itervalues
from ginga.util.six.moves import map
from ginga import GingaPlugin
from ginga.misc import Bunch
from ginga.gw import Widgets
import time
class Contents(GingaPlugin.GlobalPlugin):
def __init__(self, fv):
# superclass defines some variables for us, like logger
super(Contents, self).__init__(fv)
columns = [ ('Name', 'NAME'), ('Object', 'OBJECT'),
('Date', 'DATE-OBS'), ('Time UT', 'UT'),
('Modified', 'MODIFIED')
]
prefs = self.fv.get_preferences()
self.settings = prefs.createCategory('plugin_Contents')
self.settings.addDefaults(columns=columns,
always_expand=True,
highlight_tracks_keyboard_focus=True,
color_alternate_rows=True,
row_font_color='green',
max_rows_for_col_resize=100)
self.settings.load(onError='silent')
# For table-of-contents pane
self.name_dict = Bunch.caselessDict()
# TODO: this ought to be customizable by channel
self.columns = self.settings.get('columns', columns)
self.treeview = None
# paths of highlighted entries, by channel
self.highlight_tracks_keyboard_focus = self.settings.get(
'highlight_tracks_keyboard_focus', True)
self._hl_path = set([])
fv.add_callback('add-image', self.add_image_cb)
fv.add_callback('add-image-info', self.add_image_info_cb)
fv.add_callback('remove-image', self.remove_image_cb)
fv.add_callback('add-channel', self.add_channel_cb)
fv.add_callback('delete-channel', self.delete_channel_cb)
fv.add_callback('channel-change', self.focus_cb)
self.gui_up = False
def build_gui(self, container):
# create the Treeview
always_expand = self.settings.get('always_expand', False)
color_alternate = self.settings.get('color_alternate_rows', True)
treeview = Widgets.TreeView(auto_expand=always_expand,
sortable=True,
use_alt_row_color=color_alternate)
self.treeview = treeview
treeview.setup_table(self.columns, 2, 'NAME')
treeview.add_callback('selected', self.switch_image)
container.add_widget(treeview, stretch=1)
self.gui_up = True
def stop(self):
self.gui_up = False
def switch_image(self, widget, res_dict):
if len(res_dict) == 0:
return
chname = list(res_dict.keys())[0]
img_dict = res_dict[chname]
if len(img_dict) == 0:
return
imname = list(img_dict.keys())[0]
bnch = img_dict[imname]
path = bnch.path
self.logger.debug("chname=%s name=%s path=%s" % (
chname, imname, path))
self.fv.switch_name(chname, imname, path=path,
image_future=bnch.image_future)
def get_info(self, chname, name, image, info):
path = info.get('path', None)
future = info.get('image_future', None)
bnch = Bunch.Bunch(CHNAME=chname, imname=name, path=path,
image_future=future)
# Get header keywords of interest
if image is not None:
header = image.get_header()
else:
header = {}
for hdr, key in self.columns:
bnch[key] = str(header.get(key, 'N/A'))
# name should always be available
bnch.NAME = name
# Modified timestamp will be set if image data is modified
timestamp = info.time_modified
if timestamp is not None:
# Z: Zulu time, GMT, UTC
timestamp = timestamp.strftime('%Y-%m-%d %H:%M:%SZ')
bnch.MODIFIED = timestamp
return bnch
def recreate_toc(self):
self.logger.debug("Recreating table of contents...")
self.treeview.set_tree(self.name_dict)
# re-highlight as necessary
if self.highlight_tracks_keyboard_focus:
new_highlight = self._hl_path
else:
new_highlight = set([])
for chname in self.name_dict:
channel = self.fv.get_channel_info(chname)
new_highlight |= channel.extdata.contents_old_highlight
self.update_highlights(set([]), new_highlight)
# Resize column widths
n_rows = sum(map(len, self.name_dict.values()))
if n_rows < self.settings.get('max_rows_for_col_resize', 100):
self.treeview.set_optimal_column_widths()
self.logger.debug("Resized columns for {0} row(s)".format(n_rows))
def is_in_contents(self, chname, imname):
if not chname in self.name_dict:
return False
file_dict = self.name_dict[chname]
if not imname in file_dict:
return False
return True
def add_image_cb(self, viewer, chname, image, image_info):
if not self.gui_up:
return False
name = image_info.name
self.logger.debug("name=%s" % (name))
if image is not None:
nothumb = image.get('nothumb', False)
if nothumb:
return
bnch = self.get_info(chname, name, image, image_info)
if not chname in self.name_dict:
# channel does not exist yet in contents
# Note: this typically shouldn't happen, because add_channel_cb()
# will have added an empty dict
file_dict = {}
self.name_dict[chname] = file_dict
else:
file_dict = self.name_dict[chname]
if not name in file_dict:
# new image
file_dict[name] = bnch
else:
# old image
file_dict[name].update(bnch)
# TODO: either make add_tree() merge updates or make an
# update_tree() method--shouldn't need to recreate entire
# tree, just add new entry and possibly rehighlight
## tree_dict = { chname: { name: bnch } }
## self.treeview.add_tree(tree_dict)
self.recreate_toc()
self.logger.debug("%s added to Contents" % (name))
def add_image_info_cb(self, viewer, channel, image_info):
"""Almost the same as add_image_info(), except that the image
may not be loaded in memory.
"""
chname = channel.name
name = image_info.name
self.logger.debug("name=%s" % (name))
# Updates of any extant information
try:
image = channel.get_loaded_image(name)
except KeyError:
# images that are not yet loaded will show "N/A" for keywords
image = None
self.add_image_cb(viewer, chname, image, image_info)
def remove_image_cb(self, viewer, chname, name, path):
if not self.gui_up:
return False
if chname not in self.name_dict:
return
file_dict = self.name_dict[chname]
if name not in file_dict:
return
del file_dict[name]
# Unhighlight
channel = self.fv.get_channel_info(chname)
key = (chname, name)
self._hl_path.discard(key)
channel.extdata.contents_old_highlight.discard(key)
self.recreate_toc()
self.logger.debug("%s removed from Contents" % (name))
def clear(self):
self.name_dict = Bunch.caselessDict()
self._hl_path = set([])
self.recreate_toc()
def add_channel_cb(self, viewer, channel):
"""Called when a channel is added from the main interface.
Parameter is a channel (a Channel object)."""
chname = channel.name
# add old highlight set to channel external data
channel.extdata.setdefault('contents_old_highlight', set([]))
# Add the channel to the treeview
file_dict = {}
self.name_dict.setdefault(chname, file_dict)
if not self.gui_up:
return False
tree_dict = { chname: { } }
self.treeview.add_tree(tree_dict)
def delete_channel_cb(self, viewer, channel):
"""Called when a channel is deleted from the main interface.
Parameter is a channel (a Channel object)."""
chname = channel.name
del self.name_dict[chname]
# Unhighlight
un_hilite_set = set([])
for path in self._hl_path:
if path[0] == chname:
un_hilite_set.add(path)
self._hl_path -= un_hilite_set
if not self.gui_up:
return False
self.recreate_toc()
def _get_hl_key(self, chname, image):
return (chname, image.get('name', 'none'))
def _highlight_path(self, hl_path, tf):
"""Highlight or unhighlight a single entry.
Examples
--------
>>> hl_path = self._get_hl_key(chname, image)
>>> self._highlight_path(hl_path, True)
"""
fc = self.settings.get('row_font_color', 'green')
try:
self.treeview.highlight_path(hl_path, tf, font_color=fc)
except Exception as e:
self.logger.error('Error changing highlight on treeview path '
'({0}): {1}'.format(hl_path, str(e)))
def update_highlights(self, old_highlight_set, new_highlight_set):
"""Unhighlight the entries represented by ``old_highlight_set``
and highlight the ones represented by ``new_highlight_set``.
Both are sets of keys.
"""
un_hilite_set = old_highlight_set - new_highlight_set
re_hilite_set = new_highlight_set - old_highlight_set
# unhighlight entries that should NOT be highlighted any more
for key in un_hilite_set:
self._highlight_path(key, False)
# highlight new entries that should be
for key in re_hilite_set:
self._highlight_path(key, True)
def redo(self, channel, image):
"""This method is called when an image is set in a channel."""
imname = image.get('name', 'none')
chname = channel.name
# is image in contents tree yet?
in_contents = self.is_in_contents(chname, imname)
# get old highlighted entries for this channel -- will be
# an empty set or one key
old_highlight = channel.extdata.contents_old_highlight
# calculate new highlight keys -- again, an empty set or one key
if image is not None:
key = self._get_hl_key(chname, image)
new_highlight = set([key])
else:
# no image has the focus
new_highlight = set([])
# Only highlights active image in the current channel
if self.highlight_tracks_keyboard_focus:
if in_contents:
self.update_highlights(self._hl_path, new_highlight)
self._hl_path = new_highlight
# Highlight all active images in all channels
else:
if in_contents:
self.update_highlights(old_highlight, new_highlight)
channel.extdata.contents_old_highlight = new_highlight
return True
def focus_cb(self, viewer, channel):
chname = channel.name
image = channel.get_current_image()
if image is not None:
key = self._get_hl_key(chname, image)
new_highlight = set([key])
else:
# no image has the focus
new_highlight = set([])
if self.highlight_tracks_keyboard_focus:
self.update_highlights(self._hl_path, new_highlight)
self._hl_path = new_highlight
def __str__(self):
return 'contents'
#END
|