1
# Copyright (C) 2008 Canonical, Ltd.
3
# This program is free software: you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation, either version 3 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
from usbcreator.backend import Backend
20
#from usbcreator.frontend.base import Frontend
27
#class GtkFrontend(Frontend):
30
self.all_widgets = set()
33
self.glade = gtk.glade.XML('/usr/share/usb-creator/usbcreator.glade')
34
for widget in self.glade.get_widget_prefix(""):
35
self.all_widgets.add(widget)
36
setattr(self, widget.get_name(), widget)
37
# Taken from ubiquity:
38
# We generally want labels to be selectable so that people can
39
# easily report problems in them
40
# (https://launchpad.net/bugs/41618), but GTK+ likes to put
41
# selectable labels in the focus chain, and I can't seem to turn
42
# this off in glade and have it stick. Accordingly, make sure
43
# labels are unfocusable here.
44
if isinstance(widget, gtk.Label):
45
widget.set_property('can-focus', False)
47
# TODO: lots of i18n work.
48
# self.translate_widgets()
51
title = ('This utility must be run with administrative '
52
'privileges, and cannot continue without them.')
53
dialog = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL,
54
gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
59
self.backend = Backend(self)
60
self.glade.signal_autoconnect(self)
61
self.setup_source_combo()
62
self.setup_dest_combo()
63
# TODO: Implement persistence.
64
self.persist_vbox.set_sensitive(False)
65
self.backend.detect_devices()
66
if self.source_combo.get_active_iter() is None or \
67
self.dest_combo.get_active_iter() is None:
68
self.button_install.set_sensitive(False)
72
def quit(self, *args):
75
def add_source(self, source):
76
# TODO: As we didn't use the convenience function to set it up, we
77
# shouldn't use the same set of functions to manipulate it, according
78
# to the documentation.
79
self.source_combo.prepend_text(source)
81
def setup_source_combo(self):
82
# TODO: selecting a ISO from the menu should call into the backend
83
# which will mount it, then process the HAL event in a function that
84
# will, in the case of an ISO, tell the frontend to automatically
86
# TODO: The function in the frontend that will add a new item to the
87
# source combo will need to take care to insert above the 'Select a CD
88
# image...' option and the separator above it (ListStore.prepend).
89
cd_img = 'Select a CD image...'
90
def cell_data_func(celllayout, cell, model, iter):
91
val = model.get_value(iter, 0)
92
if (val != cd_img and val != '-') and val != None:
93
dev = self.backend.source_devices[val]
94
cell.set_property('text', dev['title'])
95
def row_separator_func(model, iter):
96
if model.get_value(iter, 0) == '-':
100
def selection_changed(combobox):
101
m = combobox.get_model()
102
val = m.get_value(combobox.get_active_iter(), 0)
104
filename = self.select_iso()
105
iterator = m.get_iter_first()
106
while iterator is not None:
107
if m.get_value(iterator, 0) == filename:
108
combobox.set_active_iter(iterator)
110
iterator = m.iter_next(iterator)
111
for val in self.backend.devices.itervalues():
112
s_val = self.backend.source_devices[filename]
113
if val['free'] < s_val['size']:
115
print 'target is too small for source.'
116
if self.source_combo.get_active_iter() is not None and \
117
self.dest_combo.get_active_iter() is not None:
118
self.button_install.set_sensitive(True)
119
renderer = gtk.CellRendererText()
120
self.source_combo.pack_start(renderer, True)
121
self.source_combo.add_attribute(renderer, 'text', 0)
122
list_store = gtk.ListStore(gobject.TYPE_STRING)
123
self.source_combo.set_model(list_store)
124
self.source_combo.set_cell_data_func(renderer, cell_data_func)
125
self.source_combo.set_row_separator_func(row_separator_func)
126
list_store.append(['-'])
128
list_store.append([cd_img])
129
self.source_combo.connect('changed', selection_changed)
131
def select_iso(self):
132
chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN,
133
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
134
filter = gtk.FileFilter()
135
filter.add_pattern('*.iso')
137
filter.set_name('ISO Files')
138
chooser.add_filter(filter)
139
response = chooser.run()
140
if response == gtk.RESPONSE_OK:
141
filename = chooser.get_filename()
142
self.backend.mount_iso(filename)
146
def add_dest(self, dest):
147
self.dest_combo.append_text(dest)
148
if self.dest_combo.get_active_iter() is None:
149
m = self.dest_combo.get_model()
150
iterator = m.get_iter_first()
151
while iterator is not None:
152
if m.get_value(iterator, 0) == dest:
153
self.dest_combo.set_active_iter(iterator)
155
iterator = m.iter_next(iterator)
157
def setup_dest_combo(self):
158
def selection_changed(combobox):
159
# TODO: Ensure a vfat filesystem is present. Make sure there is
161
if self.source_combo.get_active_iter() is not None and \
162
self.dest_combo.get_active_iter() is not None:
163
self.button_install.set_sensitive(True)
164
def cell_data_func(celllayout, cell, model, iter):
165
model_val = model.get_value(iter, 0)
167
val = self.backend.devices[model_val]
169
cell.set_property('text', '%s %s (%s)' % \
170
(val['label'], val['device'], val['uuid']))
172
cell.set_property('text', '%s (%s)' % \
173
(val['device'], val['uuid']))
174
renderer = gtk.CellRendererText()
175
self.dest_combo.pack_start(renderer, True)
176
self.dest_combo.add_attribute(renderer, 'text', 0)
177
list_store = gtk.ListStore(gobject.TYPE_STRING)
178
self.dest_combo.set_model(list_store)
179
self.dest_combo.set_cell_data_func(renderer, cell_data_func)
180
self.dest_combo.connect('changed', selection_changed)
182
def install(self, widget):
183
print 'Installing...'
184
# TODO: Need to do more to tear down. Kill watches, etc.
186
self.install_window.show()
187
val = self.source_combo.get_model().get_value( \
188
self.source_combo.get_active_iter(), 0)
189
self.backend.set_install_source(val)
190
val = self.dest_combo.get_model().get_value( \
191
self.dest_combo.get_active_iter(), 0)
192
self.backend.set_install_target(val)
193
self.backend.install_bootloader()
194
self.backend.copy_files()
196
def progress(self, val):
197
self.progress_bar.set_value(val)
199
# vim: set ai et sts=4 tabstop=4 sw=4: