~usb-creator-hackers/usb-creator/trunk

« back to all changes in this revision

Viewing changes to usbcreator/gtk_frontend.py

  • Committer: Evan Dandrea
  • Date: 2008-09-02 19:03:27 UTC
  • Revision ID: evan.dandrea@canonical.com-20080902190327-6bru0o17r3ht0w4i
Imported project.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008  Canonical, Ltd.
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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/>.
 
15
 
 
16
import sys
 
17
import os
 
18
 
 
19
from usbcreator.backend import Backend
 
20
#from usbcreator.frontend.base import Frontend
 
21
 
 
22
import pygtk
 
23
import gtk.glade
 
24
import gobject
 
25
import dbus
 
26
 
 
27
#class GtkFrontend(Frontend):
 
28
class GtkFrontend:
 
29
    def __init__(self):
 
30
        self.all_widgets = set()
 
31
 
 
32
        # TODO: Ick.
 
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)
 
46
 
 
47
        # TODO: lots of i18n work.
 
48
        # self.translate_widgets()
 
49
 
 
50
        if os.getuid() != 0:
 
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,
 
55
                                       title)
 
56
            dialog.run()
 
57
            sys.exit(1)
 
58
 
 
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)
 
69
        self.window.show()
 
70
        gtk.main()
 
71
 
 
72
    def quit(self, *args):
 
73
        sys.exit(0)
 
74
 
 
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)
 
80
 
 
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
 
85
        # select it.
 
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) == '-':
 
97
                return True
 
98
            else:
 
99
                return False
 
100
        def selection_changed(combobox):
 
101
            m = combobox.get_model()
 
102
            val = m.get_value(combobox.get_active_iter(), 0)
 
103
            if val == cd_img:
 
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)
 
109
                        break
 
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']:
 
114
                        # FIXME:
 
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(['-'])
 
127
        # TODO: i18n
 
128
        list_store.append([cd_img])
 
129
        self.source_combo.connect('changed', selection_changed)
 
130
 
 
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')
 
136
        # TODO: i18n
 
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)
 
143
        chooser.destroy()
 
144
        return filename
 
145
 
 
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)
 
154
                    break
 
155
                iterator = m.iter_next(iterator)
 
156
 
 
157
    def setup_dest_combo(self):
 
158
        def selection_changed(combobox):
 
159
            # TODO: Ensure a vfat filesystem is present.  Make sure there is
 
160
            # free space.
 
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)
 
166
            if model_val:
 
167
                val = self.backend.devices[model_val]
 
168
                if val['label']:
 
169
                    cell.set_property('text', '%s %s (%s)' % \
 
170
                        (val['label'], val['device'], val['uuid']))
 
171
                else:
 
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)
 
181
 
 
182
    def install(self, widget):
 
183
        print 'Installing...'
 
184
        # TODO: Need to do more to tear down.  Kill watches, etc.
 
185
        self.window.hide()
 
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()
 
195
 
 
196
    def progress(self, val):
 
197
        self.progress_bar.set_value(val)
 
198
 
 
199
# vim: set ai et sts=4 tabstop=4 sw=4: