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
|
# Copyright (C) 2018 Red Hat, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
from gi.repository import Gdk, Gtk
import virtinst
from virtinst import xmlutil
from .baseclass import vmmGObjectUI
def _always_show(osobj):
return bool(osobj.is_generic() or osobj.is_linux_generic())
class vmmOSList(vmmGObjectUI):
__gsignals__ = {
"os-selected": (vmmGObjectUI.RUN_FIRST, None, [object])
}
def __init__(self):
vmmGObjectUI.__init__(self, "oslist.ui", "vmm-oslist")
self._cleanup_on_app_close()
self._filter_name = None
self._filter_eol = True
self._selected_os = None
self.search_entry = self.widget("os-name")
self.search_entry.set_placeholder_text(_("Type to start searching..."))
self.eol_text = self.widget("eol-warn").get_text()
self.builder.connect_signals({
"on_include_eol_toggled": self._eol_toggled_cb,
"on_os_name_activate": self._entry_activate_cb,
"on_os_name_key_press_event": self._key_press_cb,
"on_os_name_search_changed": self._search_changed_cb,
"on_os_name_stop_search": self._stop_search_cb,
"on_os_list_row_activated": self._os_selected_cb,
})
self._init_state()
def _cleanup(self):
pass
###########
# UI init #
###########
def _init_state(self):
os_list = self.widget("os-list")
# (os object, label)
os_list_model = Gtk.ListStore(object, str)
all_os = virtinst.OSDB.list_os(sortkey="label")
# Always put the generic entries at the end of the list
all_os = list(sorted(all_os, key=_always_show))
for os in all_os:
os_list_model.append([os, "%s (%s)" % (os.label, os.name)])
model_filter = Gtk.TreeModelFilter(child_model=os_list_model)
model_filter.set_visible_func(self._filter_os_cb)
os_list.set_model(model_filter)
nameCol = Gtk.TreeViewColumn(_("Name"))
nameCol.set_spacing(6)
text = Gtk.CellRendererText()
nameCol.pack_start(text, True)
nameCol.add_attribute(text, 'text', 1)
os_list.append_column(nameCol)
markup = "<small>%s</small>" % xmlutil.xml_escape(
self.widget("eol-warn").get_text())
self.widget("eol-warn").set_markup(markup)
###################
# Private helpers #
###################
def _set_default_selection(self):
os_list = self.widget("os-list")
sel = os_list.get_selection()
if not self.is_visible():
return
if not len(os_list.get_model()):
return # pragma: no cover
sel.select_iter(os_list.get_model()[0].iter)
def _refilter(self):
os_list = self.widget("os-list")
sel = os_list.get_selection()
sel.unselect_all()
os_list.get_model().refilter()
self._set_default_selection()
def _filter_by_name(self, partial_name):
self._filter_name = partial_name.lower()
self._refilter()
def _clear_filter(self):
self._filter_by_name("")
self.widget("os-scroll").get_vadjustment().set_value(0)
def _sync_os_selection(self):
model, titer = self.widget("os-list").get_selection().get_selected()
self._selected_os = None
if titer:
self._selected_os = model[titer][0]
self.search_entry.set_text(self._selected_os.label)
self.emit("os-selected", self._selected_os)
def _show_popover(self):
# Match width to the search_entry width. Height is based on
# whatever we can fit into the hardcoded create wizard sizes
r = self.search_entry.get_allocation()
self.topwin.set_size_request(r.width, 350)
self.topwin.set_relative_to(self.search_entry)
self.topwin.popup()
self._set_default_selection()
################
# UI Callbacks #
################
def _entry_activate_cb(self, src):
os_list = self.widget("os-list")
if not os_list.is_visible():
return # pragma: no cover
sel = os_list.get_selection()
model, rows = sel.get_selected_rows()
if rows:
self.select_os(model[rows[0]][0])
def _key_press_cb(self, src, event):
if Gdk.keyval_name(event.keyval) != "Down":
return
self._show_popover()
self.widget("os-list").grab_focus()
def _eol_toggled_cb(self, src):
self._filter_eol = not src.get_active()
self._refilter()
def _search_changed_cb(self, src):
"""
Called text in search_entry is changed
"""
searchname = src.get_text().strip()
selected_label = None
if self._selected_os:
selected_label = self._selected_os.label
if (not src.get_sensitive() or
not searchname or
selected_label == searchname):
self.topwin.popdown()
self._clear_filter()
return
self._filter_by_name(searchname)
self._show_popover()
def _stop_search_cb(self, src):
"""
Called when the search window is closed, like with Escape key
"""
if self._selected_os:
self.search_entry.set_text(self._selected_os.label)
else:
self.search_entry.set_text("")
def _os_selected_cb(self, src, path, column):
self._sync_os_selection()
def _filter_os_cb(self, model, titer, ignore1):
osobj = model.get(titer, 0)[0]
if self._filter_eol:
if osobj.eol:
return False
if _always_show(osobj):
return True
if self._filter_name is not None and self._filter_name != "":
label = osobj.label.lower()
name = osobj.name.lower()
if (label.find(self._filter_name) == -1 and
name.find(self._filter_name) == -1):
return False
return True
###############
# Public APIs #
###############
def reset_state(self):
self._selected_os = None
self.search_entry.set_text("")
self._clear_filter()
self._sync_os_selection()
def select_os(self, vmosobj):
self._clear_filter()
os_list = self.widget("os-list")
if vmosobj.eol and not self.widget("include-eol").get_active():
self.widget("include-eol").set_active(True)
for row in os_list.get_model():
osobj = row[0]
if osobj.name != vmosobj.name:
continue
os_list.get_selection().select_iter(row.iter)
self._sync_os_selection()
return
def get_selected_os(self):
return self._selected_os
def set_sensitive(self, sensitive):
if sensitive == self.search_entry.get_sensitive():
return
if not sensitive:
self.search_entry.set_sensitive(False)
self.reset_state()
else:
if self._selected_os:
self.select_os(self._selected_os)
else:
self.reset_state()
self.search_entry.set_sensitive(True)
|