~ubuntu-branches/ubuntu/natty/jhbuild/natty

« back to all changes in this revision

Viewing changes to jhbuild/frontends/gtkui.py

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort, Loic Minier, Emilio Pozuelo Monfort
  • Date: 2009-11-09 20:28:48 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20091109202848-m9ec7dmzptqtchtj
Tags: 2.28.0-1
[ Loic Minier ]
* Cleanups.
* Ship scripts.
* Don't set GNOME_MODULE as it equals the name of the source package.

[ Emilio Pozuelo Monfort ]
* New upstream release. Closes: #524504.
  - Use 'git rev-parse' rather than 'git-rev-parse'. Closes: #544642.
* Ship install-check. Closes: #441008.
* Uploaders list regenerated. Closes: #523542, #554071.
* debian/control.in,
  debian/rules:
  - Stop shipping a copy of subprocess.py. Require python >= 2.4.
  - Switch to python-support.
* debian/control.in:
  - Bump Standards-Version to 3.8.3, no changes needed.
  - Build depend on intltool >= 0.35.0.
  - Build depend on pkg-config, gnome-doc-utils and rarian-compat to build
    the documentation.
  - Make jhbuild arch any since install-check is a binary. Depend on
    ${shlibs:Depends}.
  - Recommend, and not suggest, git-core. Also recommend mercurial.
* debian/watch:
  - Added.
* debian/patches/01_import_from_pkgdatadir.patch:
  - Added, import jhbuild from pkgdatadir if everything else fails.
    This way we can ship the jhbuild private modules in /usr/sharejhbuild.
* debian/jhbuild.docs:
  - Removed, the necessary docs are now installed by the upstream Makefile.
* debian/rules:
  - Include autotools.mk and gnome.mk.
  - Remove all the manual build process, autotools.mk does everything now.
  - Install the jhbuild modules in /usr/share/jhbuild.
* debian/install:
  - Install the modulesets and patches from here since the upstream build
    system doesn't install them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
import gobject
33
33
import gtk
34
 
import gtk.glade
35
 
 
36
 
#FIXME: would be nice if we ran w/o GConf, do a try...except block around
37
 
#       the import and then set have_gconf to false
38
 
import gconf
39
 
have_gconf = True
 
34
import pango
 
35
try:
 
36
    import vte
 
37
except ImportError:
 
38
    vte = None
40
39
 
41
40
import buildscript
42
41
import jhbuild.moduleset
43
42
from jhbuild.modtypes import MetaModule
44
43
from jhbuild.errors import CommandError
45
 
 
46
 
def get_glade_filename():
47
 
    return os.path.join(os.path.dirname(__file__), 'jhbuild.glade')
48
 
 
49
 
class Configuration:
50
 
    def __init__(self, config, args):
 
44
from jhbuild.utils import notify
 
45
 
 
46
from terminal import t_bold, t_reset
 
47
 
 
48
 
 
49
class ExitRequestedException(Exception):
 
50
    pass
 
51
 
 
52
 
 
53
class AppWindow(gtk.Window, buildscript.BuildScript):
 
54
    default_module_iter = None
 
55
    active_iter = None
 
56
    child_pid = None
 
57
    error_resolution = None
 
58
    preference_dialog = None
 
59
 
 
60
    def __init__(self, config, module_list=None):
 
61
        self.orig_modulelist = module_list
 
62
        buildscript.BuildScript.__init__(self, config)
51
63
        self.config = config
52
 
        self.args = args
53
 
 
54
 
        glade_filename = get_glade_filename()
55
 
 
56
 
        # Fetch widgets out of the Glade
57
 
        self.glade = gtk.glade.XML(glade_filename)        
58
 
        self.window               = self.glade.get_widget("ConfigWindow")
59
 
        self.meta_modules_list    = self.glade.get_widget("ConfigMetaModules")
60
 
        self.start_module_menu    = self.glade.get_widget("ConfigStartModule")
61
 
        self.run_autogen_checkbox = self.glade.get_widget("ConfigRunAutogen")
62
 
        self.cvs_update_checkbox  = self.glade.get_widget("ConfigCVSUpdate")
63
 
        self.no_build_checkbox    = self.glade.get_widget("ConfigNoBuild")
64
 
        self.start_build_button   = self.glade.get_widget("ConfigBuildButton")
65
 
        self.cancel_button        = self.glade.get_widget("ConfigCancelButton")
66
 
 
67
 
        # Get settings for the checkboxes, etc
68
 
        self._get_default_settings()
69
 
 
70
 
        # Hook up the buttons / checkboxes
71
 
        self.start_build_button.connect('clicked', lambda button: gtk.main_quit())
72
 
        self.cancel_button.connect('clicked', lambda button: sys.exit(-1))
73
 
        self.run_autogen_checkbox.connect('toggled', self._autogen_checkbox_toggled)
74
 
        self.cvs_update_checkbox.connect('toggled', self._cvs_update_checkbox_toggled)
75
 
        self.no_build_checkbox.connect('toggled', self._no_build_checkbox_toggled)
76
 
        #self.start_module_menu.connect('clicked', self._start_module_menu_clicked)
77
 
        
78
 
        # Get the list of meta modules
 
64
        gtk.Window.__init__(self)
 
65
        self.set_resizable(False)
 
66
        theme = gtk.icon_theme_get_default()
 
67
        gtk.window_set_default_icon_list(
 
68
                theme.load_icon('applications-development', 16, ()),
 
69
                theme.load_icon('applications-development', 24, ()),
 
70
                theme.load_icon('applications-development', 32, ()),
 
71
                theme.load_icon('applications-development', 48, ()),
 
72
                theme.load_icon('applications-development', 64, ()),
 
73
                theme.load_icon('applications-development', 128, ())
 
74
                )
 
75
        self.set_title('JHBuild')
 
76
 
79
77
        self.module_set = jhbuild.moduleset.load(config)
 
78
 
 
79
        self.create_modules_list_model()
 
80
        self.create_ui()
 
81
        self.notify = notify.Notify(config)
 
82
 
 
83
        if self.default_module_iter:
 
84
            self.module_combo.set_active_iter(self.default_module_iter)
 
85
 
 
86
        self.connect('delete-event', self.on_delete_event)
 
87
 
 
88
    def create_modules_list_model(self):
 
89
        # name, separator, startat
 
90
        self.modules_list_model = gtk.ListStore(str, bool, str)
80
91
        full_module_list = self.module_set.get_full_module_list()
81
 
        self.meta_modules = []
82
 
        self.name_to_meta_module = {}
83
 
        for possible_meta_module in full_module_list:
84
 
            if isinstance(possible_meta_module, MetaModule):
85
 
                print "Found meta module %s" % possible_meta_module.name
86
 
                self.meta_modules.append(possible_meta_module)
87
 
                self.name_to_meta_module[possible_meta_module.name] = possible_meta_module
88
 
 
89
 
        self._create_meta_modules_list_view(self.meta_modules)
90
 
        
91
 
        self._build_start_module_menu()
92
 
 
93
 
    def run(self):
94
 
        self.window.show_all()
95
 
        gtk.main()
96
 
        self.window.hide()
97
 
        self._set_default_settings()
98
 
        return (self.module_list, self.start_at_module, self.run_autogen, self.cvs_update,
99
 
                self.no_build)
100
 
 
101
 
    def _get_default_settings(self):
102
 
        if have_gconf:
103
 
            client = gconf.client_get_default()
104
 
            self.run_autogen      = client.get_bool("/apps/jhbuild/always_run_autogen")
105
 
            self.cvs_update       = client.get_bool("/apps/jhbuild/update_from_cvs")
106
 
            self.no_build         = client.get_bool("/apps/jhbuild/no_build")
107
 
            self.selected_modules = client.get_list("/apps/jhbuild/modules_to_build", gconf.VALUE_STRING)
108
 
            self.start_at_module  = client.get_string("/apps/jhbuild/start_at_module")
109
 
        else:
110
 
            self.run_autogen = False
111
 
            self.cvs_update  = True
112
 
            self.no_build    = False
113
 
 
114
 
        self.run_autogen_checkbox.set_active(self.run_autogen)
115
 
        self.cvs_update_checkbox.set_active(self.cvs_update)
116
 
        self.no_build_checkbox.set_active(self.no_build)
117
 
 
118
 
    def _set_default_settings(self):
119
 
        if have_gconf:
120
 
            client = gconf.client_get_default()
121
 
            client.set_bool("/apps/jhbuild/always_run_autogen", self.run_autogen)
122
 
            client.set_bool("/apps/jhbuild/update_from_cvs", self.cvs_update)
123
 
            client.set_bool("/apps/jhbuild/no_build", self.no_build)
124
 
            client.set_list("/apps/jhbuild/modules_to_build", gconf.VALUE_STRING, self.selected_modules)
125
 
            if self.start_at_module:
126
 
                client.set_string("/apps/jhbuild/start_at_module", self.start_at_module)
127
 
            else:
128
 
                client.set_string("/apps/jhbuild/start_at_module", "")
129
 
                
130
 
            print ("Gconf setting for update from CVS is %d" % self.cvs_update)
131
 
            
132
 
        
133
 
    def _meta_module_toggled(self, cell, path, model):
134
 
        iter = model.get_iter((int(path),))
135
 
        build = model.get_value(iter, 0)
136
 
        build = not build
137
 
        model.set(iter, 0, build)
138
 
        self.selected_modules = self._get_selected_meta_modules()
139
 
        self._build_start_module_menu()
140
 
        
141
 
    def _create_meta_modules_list_view(self, meta_modules):
142
 
        self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING)
143
 
        self.meta_modules_list.set_model(self.model)
144
 
        
145
 
        for module in meta_modules:
146
 
            iter = self.model.append()
147
 
            if self.selected_modules:
148
 
                selected = (module.name in self.selected_modules)
149
 
            else:
150
 
                selected = False
151
 
            self.model.set(iter, 0, selected, 1, module.name)
152
 
 
153
 
        renderer = gtk.CellRendererToggle()
154
 
        renderer.connect('toggled', self._meta_module_toggled, self.model)
155
 
        column = gtk.TreeViewColumn('Build', renderer, active=0)
156
 
        column.set_clickable(True)
157
 
        self.meta_modules_list.append_column(column)
158
 
 
159
 
        column = gtk.TreeViewColumn('Module Group', gtk.CellRendererText(), text=1)
160
 
        self.meta_modules_list.append_column(column)        
161
 
 
162
 
    def _get_selected_meta_modules(self):
163
 
        modules = []
164
 
        iter = self.model.get_iter_first()
165
 
 
166
 
        while iter:
167
 
            build = self.model.get_value(iter, 0)
168
 
            if build:
169
 
                name = self.model.get_value(iter, 1)
170
 
                module = self.name_to_meta_module[name]
171
 
                if module:
172
 
                    modules.append(module.name)
173
 
            iter = self.model.iter_next(iter)
174
 
 
175
 
        return modules
176
 
 
177
 
    
178
 
    def _build_start_module_menu(self):
179
 
        if not self.selected_modules:
180
 
            return
181
 
        
182
 
        self.module_list = self.module_set.get_module_list(self.selected_modules, self.config.skip)
183
 
 
184
 
        menu = gtk.Menu()
185
 
        menu.connect('selection-done', self._start_module_menu_clicked)
186
 
        
187
 
        selected_item_number = None
188
 
        i = 0
189
 
        for module in self.module_list:
190
 
            menu_item = gtk.MenuItem(module.name)
191
 
            menu.append(menu_item)
192
 
            if module.name == self.start_at_module:
193
 
                selected_item_number = i
194
 
            i = i + 1
195
 
            
196
 
        self.start_module_menu.set_menu (menu)
197
 
 
198
 
        if selected_item_number:
199
 
            self.start_module_menu.set_history(selected_item_number)
200
 
        else:
201
 
            if self.module_list:
202
 
                self.start_at_module = self.module_list[0].name
203
 
            else:
204
 
                self.start_at_module = None
205
 
            
206
 
        menu.show_all()
207
 
 
208
 
    def _start_module_menu_clicked(self, option_menu):
209
 
        number = self.start_module_menu.get_history()
210
 
        if self.module_list:
211
 
            item = self.module_list[number]
212
 
            self.start_at_module = item.name
213
 
        else:
214
 
            self.start_at_module = None
215
 
 
216
 
    def _autogen_checkbox_toggled(self, checkbox):
217
 
        self.run_autogen = not self.run_autogen
218
 
 
219
 
    def _cvs_update_checkbox_toggled(self, checkbox):
220
 
        self.cvs_update = not self.cvs_update
221
 
 
222
 
    def _no_build_checkbox_toggled(self, checkbox):
223
 
        self.no_build = not self.no_build
224
 
 
225
 
def optionmenu_get_history(self):
226
 
    menu = self.get_menu()
227
 
    children = menu.children()
228
 
    item = menu.get_active()
229
 
 
230
 
    for i in range(len(children)):
231
 
        if children[i] == item:
232
 
            break
233
 
 
234
 
    return i
235
 
 
236
 
class GtkBuildScript(buildscript.BuildScript):
237
 
    def __init__(self, config, module_list):
238
 
        buildscript.BuildScript.__init__(self, config, module_list)
239
 
        self.current_module = None
240
 
        self._createWindow()
241
 
        if have_gconf:
242
 
            self.terminal_command = self._getTerminalCommand()
243
 
        else:
244
 
            self.terminal_command = "gnome-terminal"
245
 
 
246
 
    def _getTerminalCommand(self):
247
 
        client = gconf.client_get_default()
248
 
        command = client.get_string("/desktop/gnome/applications/terminal/exec")
249
 
        return command
250
 
        
251
 
    def message(self, msg, module_num = -1):
252
 
        '''shows a message to the screen'''
253
 
        
254
 
        if module_num == -1:
255
 
            module_num = self.module_num
256
 
        dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_OK, message_format=msg)
257
 
        dialog.run()
258
 
        dialog.hide()        
259
 
        return
260
 
 
261
 
    def set_action(self, action, module, module_num=-1, action_target=None):
262
 
        if module_num == -1:
263
 
            module_num = self.module_num
264
 
        if not action_target:
265
 
            action_target = module.name
266
 
        if self.current_module != module and self.current_module != None:
267
 
            self.current_module._build_text_buffer = self.build_text
268
 
            self.build_text = gtk.TextBuffer(self.tag_table)
269
 
            self.build_text_view.set_buffer(self.build_text)
270
 
            self.iter = self.build_text.get_end_iter()            
271
 
        self.current_module = module
272
 
 
273
 
        num_modules = len(self.modulelist)
274
 
        if module_num > 0:
275
 
            self.build_progress.set_fraction(module_num / float(num_modules))
276
 
            self.build_progress.set_text('%d of %d modules'
277
 
                                         % (module_num, num_modules))
278
 
 
279
 
        self.window.set_title('[%d/%d] %s %s' % (module_num, num_modules, action, module.name))
280
 
        self.current_status_label.set_text('%s %s' % (action, module.name))
281
 
 
282
 
    def _runEventLoop(self):
283
 
        while gtk.events_pending():
284
 
            gtk.main_iteration()
285
 
 
286
 
    def _printToBuildOutput(self, output):
287
 
        self.iter = self.build_text.get_end_iter()
288
 
        self.build_text.insert(self.iter, output)
289
 
        self.build_text.move_mark (self.ins_mark, self.iter)
290
 
        self.build_text_view.scroll_to_mark (self.ins_mark, 0.0, True, 0.5, 0.5)
291
 
        
292
 
    def _printToWarningOutput(self, output):
293
 
        self.build_text.insert_with_tags_by_name(self.iter, output, "warning")
294
 
 
295
 
    def _pauseBuild(self):
296
 
        return self.pause_button.get_active()
297
 
 
298
 
    def _makeNonBlocking(self, fd):
299
 
        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
300
 
        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
301
 
        
302
 
 
303
 
    def execute(self, command, hint=None, cwd=None, extra_env=None):
304
 
        '''executes a command, and returns the error code'''
305
 
        return_code = -1
306
 
 
307
 
        kws = {
308
 
            'close_fds': True,
309
 
            'shell': isinstance(command, (str,unicode)),
310
 
            'stdin': subprocess.PIPE,
311
 
            'stdout': subprocess.PIPE,
312
 
            'stderr': subprocess.PIPE,
313
 
            }
314
 
 
315
 
        if cwd is not None:
316
 
            kws['cwd'] = cwd
317
 
 
318
 
        if extra_env is not None:
319
 
            kws['env'] = os.environ.copy()
320
 
            kws['env'].update(extra_env)
321
 
 
 
92
        for module in full_module_list:
 
93
            if isinstance(module, MetaModule):
 
94
                if module.name.endswith('-deprecations'):
 
95
                    # skip the deprecation meta modules, nobody want them
 
96
                    continue
 
97
                iter = self.modules_list_model.append((module.name, False, ''))
 
98
        self.modules_list_model.append(('', True, ''))
 
99
        self.modules_list_model.append((_('Others...'), False, ''))
 
100
 
 
101
        for module in self.config.modules:
 
102
            iter = self.add_extra_module_to_model(module)
 
103
            if not self.default_module_iter:
 
104
                self.default_module_iter = iter
 
105
 
 
106
    def add_extra_module_to_model(self, module, startat=''):
 
107
        # lookup selected module in current modules list
 
108
        for row in self.modules_list_model:
 
109
            row_value = self.modules_list_model.get(row.iter, 0)[0]
 
110
            if row_value == module:
 
111
                self.modules_list_model.set_value(row.iter, 2, startat)
 
112
                return row.iter
 
113
 
 
114
        # add selected module in the list
 
115
        if self.modules_list_model.get(self.modules_list_model[-3].iter, 1)[0] is False:
 
116
            # there is no user-added modules at the moment, add a separator row
 
117
            self.modules_list_model.insert_before(
 
118
                    self.modules_list_model[-2].iter, ('', True, ''))
 
119
        iter = self.modules_list_model.insert_before(
 
120
                self.modules_list_model[-2].iter, (module, False, startat))
 
121
        return iter
 
122
 
 
123
    quit = False
 
124
    def on_delete_event(self, *args):
 
125
        self.quit = True
 
126
        self.hide()
 
127
        if self.child_pid:
 
128
            os.kill(self.child_pid, signal.SIGKILL)
 
129
        if gtk.main_level():
 
130
            gtk.main_quit()
 
131
 
 
132
    def create_ui(self):
 
133
        self.set_border_width(5)
 
134
        app_vbox = gtk.VBox(spacing=5)
 
135
 
 
136
        self.module_hbox = gtk.HBox(spacing=5)
 
137
        app_vbox.pack_start(self.module_hbox, fill=False, expand=False)
 
138
 
 
139
        label = gtk.Label()
 
140
        label.set_markup('<b>%s</b>' % _('Choose Module:'))
 
141
        self.module_hbox.pack_start(label, fill=False, expand=False)
 
142
 
 
143
        self.module_combo = gtk.ComboBox(self.modules_list_model)
 
144
        cell = gtk.CellRendererText()
 
145
        self.module_combo.pack_start(cell, True)
 
146
        self.module_combo.add_attribute(cell, 'text', 0)
 
147
        self.module_combo.changed_signal_id = self.module_combo.connect(
 
148
                'changed', self.on_module_selection_changed_cb)
 
149
 
 
150
        self.module_combo.set_row_separator_func(lambda x,y: x.get(y, 1)[0])
 
151
        self.module_hbox.pack_start(self.module_combo, fill=True)
 
152
 
 
153
        separator = gtk.VSeparator()
 
154
        self.module_hbox.pack_start(separator, fill=False, expand=False)
 
155
        preferences = gtk.Button(stock=gtk.STOCK_PREFERENCES)
 
156
        preferences.connect('clicked', self.on_preferences_cb)
 
157
        self.module_hbox.pack_start(preferences, fill=False, expand=False)
 
158
 
 
159
        self.progressbar = gtk.ProgressBar()
 
160
        self.progressbar.set_text(_('Build Progress'))
 
161
        app_vbox.pack_start(self.progressbar, fill=False, expand=False)
 
162
 
 
163
        expander = gtk.Expander(_('Terminal'))
 
164
        expander.set_expanded(False)
 
165
        app_vbox.pack_start(expander, fill=False, expand=False)
 
166
        sclwin = gtk.ScrolledWindow()
 
167
        sclwin.set_size_request(-1, 300)
 
168
        sclwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
 
169
        expander.add(sclwin)
 
170
        if vte:
 
171
            self.terminal = vte.Terminal()
 
172
            self.terminal.connect('child-exited', self.on_vte_child_exit_cb)
 
173
        else:
 
174
            os.environ['TERM'] = 'dumb' # avoid commands printing vt sequences
 
175
            self.terminal = gtk.TextView()
 
176
            self.terminal.set_size_request(800, -1)
 
177
            textbuffer = self.terminal.get_buffer()
 
178
            terminal_bold_tag = textbuffer.create_tag('bold')
 
179
            terminal_bold_tag.set_property('weight', pango.WEIGHT_BOLD)
 
180
            terminal_mono_tag = textbuffer.create_tag('mono')
 
181
            terminal_mono_tag.set_property('family', 'Monospace')
 
182
            terminal_stdout_tag = textbuffer.create_tag('stdout')
 
183
            terminal_stdout_tag.set_property('family', 'Monospace')
 
184
            terminal_stderr_tag = textbuffer.create_tag('stderr')
 
185
            terminal_stderr_tag.set_property('family', 'Monospace')
 
186
            terminal_stderr_tag.set_property('foreground', 'red')
 
187
            terminal_stdin_tag = textbuffer.create_tag('stdin')
 
188
            terminal_stdin_tag.set_property('family', 'Monospace')
 
189
            terminal_stdin_tag.set_property('style', pango.STYLE_ITALIC)
 
190
            self.terminal.set_editable(False)
 
191
            self.terminal.set_wrap_mode(gtk.WRAP_CHAR)
 
192
        sclwin.add(self.terminal)
 
193
        self.terminal_sclwin = sclwin
 
194
 
 
195
        self.error_hbox = self.create_error_hbox()
 
196
        app_vbox.pack_start(self.error_hbox, fill=False, expand=False)
 
197
 
 
198
        buttonbox = gtk.HButtonBox()
 
199
        buttonbox.set_layout(gtk.BUTTONBOX_END)
 
200
        app_vbox.pack_start(buttonbox, fill=False, expand=False)
 
201
 
 
202
        # Translators: This is a button label (to start build)
 
203
        self.build_button = gtk.Button(_('Start'))
 
204
        self.build_button.connect('clicked', self.on_build_cb)
 
205
        buttonbox.add(self.build_button)
 
206
 
 
207
        button = gtk.Button(stock=gtk.STOCK_HELP)
 
208
        button.connect('clicked', self.on_help_cb)
 
209
        buttonbox.add(button)
 
210
        buttonbox.set_child_secondary(button, True)
 
211
 
 
212
        app_vbox.show_all()
 
213
        self.error_hbox.hide()
 
214
        self.add(app_vbox)
 
215
 
 
216
 
 
217
    def create_error_hbox(self):
 
218
        error_hbox = gtk.HBox(False, 8)
 
219
        image = gtk.Image()
 
220
        image.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_BUTTON)
 
221
        error_hbox.pack_start(image, fill=False, expand=False)
 
222
        image.set_alignment(0.5, 0.5)
 
223
 
 
224
        vbox = gtk.VBox(False, 6)
 
225
        error_hbox.pack_start (vbox, True, True, 0)
 
226
 
 
227
        self.error_label = gtk.Label()
 
228
        vbox.pack_start(self.error_label, fill=True, expand=True)
 
229
        self.error_label.set_use_markup(True)
 
230
        self.error_label.set_line_wrap(True)
 
231
        self.error_label.set_alignment(0, 0.5)
 
232
 
 
233
        # label, code
 
234
        second_hbox = gtk.HBox()
 
235
        vbox.pack_start(second_hbox)
 
236
 
 
237
        self.error_resolution_model = gtk.ListStore(str, str)
 
238
        self.error_combo = gtk.ComboBox(self.error_resolution_model)
 
239
        self.error_combo.connect('changed', self.on_error_resolution_changed_cb)
 
240
        self.error_combo.set_row_separator_func(lambda x,y: (x.get(y, 0)[0] == ''))
 
241
        cell = gtk.CellRendererText()
 
242
        self.error_combo.pack_start(cell, True)
 
243
        self.error_combo.add_attribute(cell, 'markup', 0)
 
244
        second_hbox.pack_start(self.error_combo)
 
245
 
 
246
        self.error_apply_button = gtk.Button(stock = gtk.STOCK_APPLY)
 
247
        self.error_apply_button.set_sensitive(False)
 
248
        self.error_apply_button.connect('clicked', self.on_resolution_apply_clicked)
 
249
        second_hbox.pack_start(self.error_apply_button, fill=False, expand=False)
 
250
 
 
251
        return error_hbox
 
252
 
 
253
    def on_error_resolution_changed_cb(self, *args):
 
254
        iter = self.error_combo.get_active_iter()
 
255
        if not iter:
 
256
            return
 
257
        if not self.error_resolution_model.get(iter, 1)[0]:
 
258
            return
 
259
        self.error_apply_button.set_sensitive(True)
 
260
 
 
261
    def on_resolution_apply_clicked(self, *args):
 
262
        self.error_apply_button.set_sensitive(False)
 
263
        iter = self.error_combo.get_active_iter()
 
264
        if not iter:
 
265
            return
 
266
        self.error_resolution = self.error_resolution_model.get(iter, 1)[0]
 
267
 
 
268
    def on_help_cb(self, *args):
 
269
        gtk.show_uri(gtk.gdk.screen_get_default(),
 
270
                'ghelp:jhbuild', gtk.get_current_event_time())
 
271
 
 
272
    def on_preferences_cb(self, *args):
 
273
        if not self.preference_dialog:
 
274
            self.preference_dialog = PreferencesDialog(self)
 
275
        self.preference_dialog.show()
 
276
        self.preference_dialog.present()
 
277
 
 
278
    def on_build_cb(self, *args):
 
279
        if self.preference_dialog:
 
280
            self.preference_dialog.hide()
 
281
        if not self.orig_modulelist:
 
282
            modules = [self.modules_list_model.get(
 
283
                    self.module_combo.get_active_iter(), 0)[0]]
 
284
 
 
285
            self.modulelist = self.module_set.get_module_list(modules,
 
286
                    self.config.skip, tags = self.config.tags,
 
287
                    ignore_suggests=self.config.ignore_suggests)
 
288
        else:
 
289
            self.orig_modulelist = None
 
290
 
 
291
        startat = self.modules_list_model.get(self.module_combo.get_active_iter(), 2)[0]
 
292
        if startat:
 
293
            while self.modulelist and self.modulelist[0].name != startat:
 
294
                del self.modulelist[0]
 
295
        self.build()
 
296
 
 
297
    def on_module_selection_changed_cb(self, *args):
 
298
        old_selected_iter = self.active_iter
 
299
        last_iter = self.modules_list_model[-1].iter
 
300
        self.active_iter = self.module_combo.get_active_iter()
 
301
        if self.modules_list_model.get_path(
 
302
                self.active_iter) != self.modules_list_model.get_path(last_iter):
 
303
            return
 
304
        # "Others..." got clicked, modal dialog to let the user select a
 
305
        # specific module
 
306
        current_module = self.modules_list_model.get(old_selected_iter, 0)[0]
 
307
        dlg = SelectModulesDialog(self, current_module)
 
308
        response = dlg.run()
 
309
        if response != gtk.RESPONSE_OK:
 
310
            dlg.destroy()
 
311
            self.module_combo.set_active_iter(old_selected_iter)
 
312
            return
 
313
        selected_module = dlg.selected_module
 
314
        startat = dlg.startat
 
315
        dlg.destroy()
 
316
 
 
317
        iter = self.add_extra_module_to_model(selected_module, startat)
 
318
        self.module_combo.set_active_iter(iter)
 
319
 
 
320
    def is_build_paused(self):
 
321
        return False
 
322
 
 
323
    def build(self):
 
324
        if gtk.main_level() == 0 and self.orig_modulelist:
 
325
            # gtkui called from a "normal" command, not from jhbuild gui
 
326
            self.modulelist = self.orig_modulelist
 
327
            self.show()
 
328
            self.build_button.emit('clicked')
 
329
            while gtk.events_pending():
 
330
                gtk.main_iteration()
 
331
            try:
 
332
                return self.rc
 
333
            except AttributeError:
 
334
                return 1
322
335
        try:
323
 
            p = subprocess.Popen(command, **kws)
324
 
        except OSError, e:
325
 
            raise CommandError(str(e))
326
 
 
327
 
        p.stdin.close()
328
 
        self._makeNonBlocking(p.stdout)
329
 
        self._makeNonBlocking(p.stderr)
330
 
 
331
 
        build_paused = False
332
 
        read_set = [p.stdout, p.stderr]
333
 
 
334
 
        while read_set:
335
 
            # Allow the frontend to get a little time
336
 
            self._runEventLoop()
337
 
 
338
 
            rlist, wlist, xlist = select.select(read_set, [], [], 0)
339
 
 
340
 
            if p.stdout in rlist:
341
 
                chunk = p.stdout.read()
342
 
                if chunk == '':
343
 
                    p.stdout.close()
344
 
                    read_set.remove(p.stdout)
345
 
                self._printToBuildOutput(chunk)
346
 
 
347
 
            if p.stderr in rlist:
348
 
                chunk = p.stderr.read()
349
 
                if chunk == '':
350
 
                    p.stderr.close()
351
 
                    read_set.remove(p.stderr)
352
 
                self._printToWarningOutput(chunk)
353
 
 
354
 
            # See if we should pause the current command
355
 
            if not build_paused and self._pauseBuild():
356
 
                print ("Pausing this guy, sending os.kill to %d", p.pid)
357
 
                os.kill(p.pid, signal.SIGSTOP)
358
 
                build_paused = True
359
 
            elif build_paused and not self._pauseBuild():
360
 
                print ("Continuing him")
361
 
                os.kill(p.pid, signal.SIGCONT)
362
 
                build_paused = False
363
 
 
364
 
            time.sleep(0.05)
365
 
 
366
 
        return p.wait()
 
336
            self.rc = buildscript.BuildScript.build(self)
 
337
        except ExitRequestedException:
 
338
            self.rc = 1
 
339
        return self.rc
367
340
 
368
341
    def start_build(self):
369
 
        self.window.show_all()
 
342
        self.build_button.set_sensitive(False)
 
343
        self.module_hbox.set_sensitive(False)
 
344
 
370
345
    def end_build(self, failures):
371
 
        if len(failures) == 0:
372
 
            self.message('success')
373
 
        else:
374
 
            self.message('the following modules were not built:\n%s'
375
 
                         % ', '.join(failures))
 
346
        self.progressbar.set_fraction(1)
 
347
        self.progressbar.set_text(_('Build Completed'))
 
348
        self.build_button.set_sensitive(True)
 
349
        self.module_hbox.set_sensitive(True)
 
350
 
376
351
    def start_module(self, module):
377
 
        # Remember where we are in case something fails
378
 
        if have_gconf:
379
 
            client = gconf.client_get_default()
380
 
            client.set_string("/apps/jhbuild/start_at_module", module)
381
 
 
382
 
    def handle_error(self, module, state, nextstate, error, altstates):
383
 
        '''Ask the user what to do about an error.
384
 
 
385
 
        Returns one of ERR_RERUN, ERR_CONT or ERR_GIVEUP.''' #"
386
 
 
387
 
        if not self.config.interact:
388
 
            return 'fail'
389
 
 
390
 
        dialog = gtk.Dialog('Error during %s for module %s' % (state, module.name))
391
 
        dialog.add_button('_Try %s Again' % state, 1)
392
 
        dialog.add_button('_Ignore Error', 2)
393
 
        dialog.add_button('_Skip Module', 3)
394
 
        dialog.add_button('_Terminal', 4)
395
 
 
396
 
        for i, altstate in enumerate(altstates):
397
 
            dialog.add_button('Go to %s' % altstate, i + 5)
398
 
 
399
 
        text_view = gtk.TextView()
400
 
        text_view.set_buffer(self.build_text)
401
 
        text_view.set_wrap_mode(gtk.WRAP_WORD)
402
 
 
403
 
        scroller = gtk.ScrolledWindow()
404
 
        scroller.add(text_view)
405
 
        dialog.vbox.pack_start(scroller)
406
 
 
407
 
        scroller.set_size_request(-1, 250)
408
 
        scroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
409
 
        scroller.set_shadow_type(gtk.SHADOW_IN)
410
 
        scroller.set_border_width(12)
411
 
        
 
352
        idx = [x.name for x in self.modulelist].index(module)
 
353
        self.progressbar.set_fraction((1.0*idx) / len(self.modulelist))
 
354
        if vte:
 
355
            self.terminal.feed('%s*** %s ***%s\n\r' % (t_bold, module, t_reset))
 
356
        else:
 
357
            textbuffer = self.terminal.get_buffer()
 
358
            textbuffer.insert_with_tags_by_name(
 
359
                    textbuffer.get_end_iter(), '*** %s ***\n' % module, 'bold')
 
360
            mark = textbuffer.create_mark('end', textbuffer.get_end_iter(), False)
 
361
            self.terminal.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
 
362
 
 
363
    def end_module(self, module, failed):
 
364
        self.error_hbox.hide()
 
365
 
 
366
    def set_action(self, action, module, module_num=-1, action_target=None):
 
367
        self.progressbar.set_text('%s %s' % (action, action_target or module.name))
 
368
 
 
369
    def message(self, msg, module_num=-1):
 
370
        pass
 
371
 
 
372
    def handle_error(self, module, phase, nextphase, error, altphases):
 
373
        summary = _('Error during phase %(phase)s of %(module)s') % {
 
374
            'phase': phase, 'module':module.name}
 
375
        try:
 
376
            error_message = error.args[0]
 
377
            self.message('%s: %s' % (summary, error_message))
 
378
        except:
 
379
            error_message = None
 
380
            self.message(summary)
 
381
 
 
382
        if not self.is_active():
 
383
            self.set_urgency_hint(True)
 
384
        self.notify.notify(summary=summary, body=error_message,
 
385
                icon=gtk.STOCK_DIALOG_ERROR, expire=5)
 
386
 
 
387
        self.error_label.set_markup('<b>%s</b>' % _(summary))
 
388
        self.error_resolution_model.clear()
 
389
        iter = self.error_resolution_model.append(
 
390
                ('<i>%s</i>' % _('Pick an Action'), ''))
 
391
        self.error_resolution_model.append(('', ''))
 
392
        self.error_resolution_model.append(
 
393
                (_('Rerun phase %s') % phase, phase))
 
394
        if nextphase:
 
395
            self.error_resolution_model.append(
 
396
                    (_('Ignore error and continue to %s') % nextphase, nextphase))
 
397
        else:
 
398
            self.error_resolution_model.append(
 
399
                    (_('Ignore error and continue to next module'), '_done'))
 
400
        self.error_resolution_model.append(
 
401
                (_('Give up on module'), 'fail'))
 
402
        for altphase in altphases:
 
403
            try:
 
404
                altphase_label = _(getattr(getattr(module, 'do_' + altphase), 'label'))
 
405
            except AttributeError:
 
406
                altphase_label = altphase
 
407
            self.error_resolution_model.append(
 
408
                    (_('Go to phase "%s"') % altphase_label, altphase))
 
409
        self.error_resolution_model.append(('', ''))
 
410
        self.error_resolution_model.append(
 
411
                (_('Open Terminal'), 'shell'))
 
412
 
 
413
        self.error_combo.set_active_iter(iter)
 
414
        self.error_hbox.set_sensitive(True)
 
415
        self.error_hbox.show_all()
 
416
        self.error_resolution = None
 
417
 
412
418
        while True:
413
 
 
414
 
            #self.message('error during %s for module %s' % (state, module.name))
415
 
 
416
 
            text_view.scroll_to_iter(self.build_text.get_end_iter(), 0.0, True, 0.5, 0.5)
417
 
            dialog.show_all()
418
 
 
419
 
            val = dialog.run()
420
 
 
421
 
            if val != 4:
422
 
                dialog.hide()
423
 
            # If the dialog was destroyed, interpret that as try again.
424
 
            if val in (1, gtk.RESPONSE_NONE, gtk.RESPONSE_DELETE_EVENT):
425
 
                return state
426
 
            elif val == 2:
427
 
                return nextstate
428
 
            elif val == 3:
429
 
                return 'fail'
430
 
            elif val == 4:
431
 
                command = 'cd %s; %s' % (module.get_builddir(self),
432
 
                                         self.terminal_command)
433
 
                os.system(command)
434
 
            else:
435
 
                return altstates[val - 5]
436
 
 
437
 
    def _createWindow(self):
438
 
        glade_filename = get_glade_filename()
439
 
        self.glade = gtk.glade.XML(glade_filename)
440
 
        
441
 
        self.window               = self.glade.get_widget("BuildWindow")
442
 
        self.build_progress       = self.glade.get_widget("BuildProgressBar")
443
 
        self.build_text_view      = self.glade.get_widget("BuildText")
444
 
        self.current_status_label = self.glade.get_widget("CurrentStatusLabel")
445
 
        self.pause_button         = self.glade.get_widget("BuildPauseButton")
446
 
        self.cancel_button        = self.glade.get_widget("BuildCancelButton")
447
 
        #self.expander_button      = self.glade.get_widget("ExpanderButton")
448
 
        #self.expander_arrow       = self.glade.get_widget("ExpanderArrow")
449
 
        
450
 
        self.window.connect('destroy', lambda win: sys.exit())
451
 
        self.cancel_button.connect('clicked', lambda button: sys.exit())
452
 
        #self.expander_button.connect('activate', 
453
 
                                     
454
 
        self.tag_table = gtk.TextTagTable()
455
 
        self.build_text = gtk.TextBuffer(self.tag_table)
456
 
        self.warning_tag = self.build_text.create_tag("warning")
457
 
        self.warning_tag.set_property("foreground", "red")
458
 
        self.build_text_view.set_buffer(self.build_text)
459
 
        self.build_text_view.set_wrap_mode(gtk.WRAP_WORD)
460
 
        self.iter = self.build_text.get_end_iter()
461
 
        self.ins_mark = self.build_text.create_mark ("jhbuild-mark", self.iter, True);
462
 
        
463
 
BUILD_SCRIPT = GtkBuildScript
 
419
            self.error_resolution = None
 
420
            while gtk.events_pending():
 
421
                gtk.main_iteration()
 
422
                if self.quit:
 
423
                    return 'fail'
 
424
            if not self.error_resolution:
 
425
                continue
 
426
            self.set_urgency_hint(False)
 
427
            if self.error_resolution == 'shell':
 
428
                # set back combobox to "Pick an action"
 
429
                self.error_combo.set_active_iter(iter)
 
430
                if os.fork() == 0:
 
431
                    cmd = ['gnome-terminal', '--working-directory', module.get_builddir(self)]
 
432
                    os.execvp('gnome-terminal', cmd)
 
433
                    sys.exit(0)
 
434
                continue
 
435
            if self.error_resolution == '_done':
 
436
                self.error_resolution = None
 
437
            # keep the error hox visible during all of this module duration
 
438
            self.error_hbox.set_sensitive(False)
 
439
            return self.error_resolution
 
440
 
 
441
    def execute(self, command, hint=None, cwd=None, extra_env=None):
 
442
        if not command:
 
443
            raise CommandError(_('No command given'))
 
444
 
 
445
        if isinstance(command, (str, unicode)):
 
446
            short_command = command.split()[0]
 
447
        else:
 
448
            short_command = command[0]
 
449
 
 
450
        if vte is None:
 
451
            textbuffer = self.terminal.get_buffer()
 
452
 
 
453
            if isinstance(command, (str, unicode)):
 
454
                self.terminal.get_buffer().insert_with_tags_by_name(
 
455
                        textbuffer.get_end_iter(),
 
456
                        ' $ ' + command + '\n', 'stdin')
 
457
            else:
 
458
                self.terminal.get_buffer().insert_with_tags_by_name(
 
459
                        textbuffer.get_end_iter(),
 
460
                        ' $ ' + ' '.join(command) + '\n', 'stdin')
 
461
 
 
462
            kws = {
 
463
                'close_fds': True,
 
464
                'shell': isinstance(command, (str,unicode)),
 
465
                'stdin': subprocess.PIPE,
 
466
                'stdout': subprocess.PIPE,
 
467
                'stderr': subprocess.PIPE,
 
468
                }
 
469
 
 
470
            if cwd is not None:
 
471
                kws['cwd'] = cwd
 
472
 
 
473
            if extra_env is not None:
 
474
                kws['env'] = os.environ.copy()
 
475
                kws['env'].update(extra_env)
 
476
 
 
477
            try:
 
478
                p = subprocess.Popen(command, **kws)
 
479
            except OSError, e:
 
480
                raise CommandError(str(e))
 
481
            self.child_pid = p.pid
 
482
 
 
483
            p.stdin.close()
 
484
 
 
485
            def make_non_blocking(fd):
 
486
                fl = fcntl.fcntl(fd, fcntl.F_GETFL)
 
487
                fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
 
488
 
 
489
            make_non_blocking(p.stdout)
 
490
            make_non_blocking(p.stderr)
 
491
 
 
492
            build_paused = False
 
493
            read_set = [p.stdout, p.stderr]
 
494
 
 
495
            while read_set:
 
496
                # Allow the frontend to get a little time
 
497
                while gtk.events_pending():
 
498
                    gtk.main_iteration()
 
499
                    if self.quit:
 
500
                        raise ExitRequestedException()
 
501
 
 
502
                rlist, wlist, xlist = select.select(read_set, [], [], 0)
 
503
 
 
504
                if p.stdout in rlist:
 
505
                    chunk = p.stdout.read()
 
506
                    if chunk == '':
 
507
                        p.stdout.close()
 
508
                        read_set.remove(p.stdout)
 
509
                    textbuffer.insert_with_tags_by_name(
 
510
                            textbuffer.get_end_iter(), chunk, 'stdout')
 
511
 
 
512
                if p.stderr in rlist:
 
513
                    chunk = p.stderr.read()
 
514
                    if chunk == '':
 
515
                        p.stderr.close()
 
516
                        read_set.remove(p.stderr)
 
517
                    textbuffer.insert_with_tags_by_name(
 
518
                            textbuffer.get_end_iter(), chunk, 'stderr')
 
519
 
 
520
                if textbuffer.get_line_count() > 200:
 
521
                    textbuffer.delete(textbuffer.get_start_iter(),
 
522
                            textbuffer.get_iter_at_line_offset(
 
523
                                textbuffer.get_line_count()-200, 0))
 
524
 
 
525
                mark = textbuffer.get_mark('end')
 
526
                if mark:
 
527
                    textbuffer.move_mark(mark, textbuffer.get_end_iter())
 
528
                else:
 
529
                    mark = textbuffer.create_mark('end', textbuffer.get_end_iter(), False)
 
530
 
 
531
                if self.terminal_sclwin.get_vadjustment().upper == \
 
532
                        (self.terminal_sclwin.size_request()[1] + 
 
533
                         self.terminal_sclwin.get_vadjustment().get_value()):
 
534
                    # currently at the bottom of the textview, therefore scroll
 
535
                    # automatically
 
536
                    self.terminal.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
 
537
 
 
538
                # See if we should pause the current command
 
539
                if not build_paused and self.is_build_paused():
 
540
                    os.kill(p.pid, signal.SIGSTOP)
 
541
                    build_paused = True
 
542
                elif build_paused and not self.is_build_paused():
 
543
                    os.kill(p.pid, signal.SIGCONT)
 
544
                    build_paused = False
 
545
 
 
546
                time.sleep(0.05)
 
547
 
 
548
            rc = p.wait()
 
549
            self.child_pid = None
 
550
        else:
 
551
            # use the vte widget
 
552
            if isinstance(command, (str, unicode)):
 
553
                self.terminal.feed(' $ ' + command + '\n\r')
 
554
                command = [os.environ.get('SHELL', '/bin/sh'), '-c', command]
 
555
            else:
 
556
                self.terminal.feed(' $ ' + ' '.join(command) + '\n\r')
 
557
 
 
558
            kws = {}
 
559
            if extra_env is not None:
 
560
                env = os.environ.copy()
 
561
                env.update(extra_env)
 
562
                kws['envv'] = ['%s=%s' % x for x in env.items()]
 
563
 
 
564
            if cwd:
 
565
                kws['directory'] = cwd
 
566
 
 
567
            self.vte_fork_running = True
 
568
            self.vte_child_exit_status = None
 
569
            # In earlier python-vte versions,
 
570
            #  - the environment had to be passed as a sequence of strings
 
571
            #    ("FOO=1", "BAR=2") (GNOME bug 583078)
 
572
            #  - directory keyword could not be set to None (GNOME bug 583129)
 
573
            # The bugs have been fixed, but for compatibility reasons the old
 
574
            # compatibility code is still in place.
 
575
            self.child_pid = self.terminal.fork_command(
 
576
                    command=command[0], argv=command, **kws)
 
577
            while self.vte_fork_running:
 
578
                gtk.main_iteration()
 
579
                if self.quit:
 
580
                    raise ExitRequestedException()
 
581
            self.child_pid = None
 
582
            if os.WIFEXITED(self.vte_child_exit_status):
 
583
                rc = os.WEXITSTATUS(self.vte_child_exit_status)
 
584
            elif os.WIFSIGNALED(self.vte_child_exit_status):
 
585
                raise CommandError(_('%(command)s died with signal %(rc)s') % {
 
586
                        'command': short_command, 'rc': os.WTERMSIG(rc)})
 
587
 
 
588
        if rc:
 
589
            raise CommandError(_('%(command)s returned with an error code (%(rc)s)') % {
 
590
                    'command': short_command, 'rc': rc})
 
591
 
 
592
    def on_vte_child_exit_cb(self, terminal):
 
593
        self.vte_fork_running = False
 
594
        self.vte_child_exit_status = self.terminal.get_child_exit_status()
 
595
 
 
596
 
 
597
class SelectModulesDialog(gtk.Dialog):
 
598
    def __init__(self, parent, default_module=None):
 
599
        gtk.Dialog.__init__(self, '', parent)
 
600
        self.app = parent
 
601
        self.create_model()
 
602
        self.create_ui()
 
603
 
 
604
        if default_module:
 
605
            for module_row in self.modules_model:
 
606
                if self.modules_model.get(module_row.iter, 0)[0] == default_module:
 
607
                    self.treeview.get_selection().select_iter(module_row.iter)
 
608
                    self.treeview.scroll_to_cell(
 
609
                            self.modules_model.get_path(module_row.iter))
 
610
                    break
 
611
        self.connect('response', self.on_response_cb)
 
612
 
 
613
    def create_model(self):
 
614
        self.modules_model = gtk.ListStore(str)
 
615
        modules = [x.name for x in self.app.module_set.get_full_module_list()]
 
616
        for module in sorted(modules, lambda x,y: cmp(x.lower(), y.lower())):
 
617
            self.modules_model.append((module,))
 
618
 
 
619
    def create_frame(self, label, child):
 
620
        frame = gtk.Frame('')
 
621
        frame.set_border_width(3)
 
622
        frame.set_shadow_type(gtk.SHADOW_NONE)
 
623
        frame.get_label_widget().set_markup('<b>%s</b>' % label)
 
624
 
 
625
        alignment = gtk.Alignment()
 
626
        alignment.set_padding(0, 0, 12, 0)
 
627
        frame.add(alignment)
 
628
        alignment.add(child)
 
629
 
 
630
        return frame
 
631
 
 
632
    def create_ui(self):
 
633
        vbox = gtk.VBox()
 
634
        self.vbox.add(vbox)
 
635
 
 
636
        sclwin = gtk.ScrolledWindow()
 
637
        sclwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
 
638
        sclwin.set_size_request(-1, 200)
 
639
        vbox.pack_start(self.create_frame(_('Module'), sclwin))
 
640
 
 
641
        self.treeview = gtk.TreeView(self.modules_model)
 
642
        self.treeview.set_headers_visible(False)
 
643
        sclwin.add(self.treeview)
 
644
        selection = self.treeview.get_selection()
 
645
        selection.connect('changed', self.on_selection_changed_cb)
 
646
 
 
647
        renderer = gtk.CellRendererText()
 
648
        tv_col = gtk.TreeViewColumn('', renderer, text=0)
 
649
        tv_col.set_expand(True)
 
650
        tv_col.set_min_width(200)
 
651
        self.treeview.append_column(tv_col)
 
652
 
 
653
        self.startat_model = gtk.ListStore(str)
 
654
        self.combo_startat = gtk.ComboBox(self.startat_model)
 
655
        cell = gtk.CellRendererText()
 
656
        self.combo_startat.pack_start(cell, True)
 
657
        self.combo_startat.add_attribute(cell, 'text', 0)
 
658
        vbox.pack_start(self.create_frame(_('Start At'), self.combo_startat))
 
659
 
 
660
        self.vbox.show_all()
 
661
 
 
662
        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
 
663
        self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
 
664
 
 
665
    def on_selection_changed_cb(self, selection, *args):
 
666
        iter = selection.get_selected()[1]
 
667
        self.selected_module = self.modules_model.get(iter, 0)[0]
 
668
 
 
669
        old_start_at = None
 
670
        old_start_at_iter = self.combo_startat.get_active_iter()
 
671
        new_active_iter = None
 
672
        if old_start_at_iter:
 
673
            old_start_at = self.startat_model.get(old_start_at_iter, 0)[0]
 
674
 
 
675
        self.startat_model.clear()
 
676
        modulelist = self.app.module_set.get_module_list([self.selected_module],
 
677
                ignore_suggests=self.app.config.ignore_suggests)
 
678
        for module in modulelist:
 
679
            iter = self.startat_model.append((module.name,))
 
680
            if module.name == old_start_at:
 
681
                new_active_iter = iter
 
682
 
 
683
        if new_active_iter:
 
684
            self.combo_startat.set_active_iter(new_active_iter)
 
685
        else:
 
686
            self.combo_startat.set_active_iter(self.startat_model[0].iter)
 
687
 
 
688
    def on_response_cb(self, dlg, response_id, *args):
 
689
        if response_id != gtk.RESPONSE_OK:
 
690
            return
 
691
 
 
692
        old_start_at_iter = self.combo_startat.get_active_iter()
 
693
        self.startat = None
 
694
        if old_start_at_iter:
 
695
            self.startat = self.startat_model.get(old_start_at_iter, 0)[0]
 
696
 
 
697
        return gtk.RESPONSE_OK
 
698
 
 
699
class PreferencesDialog(gtk.Dialog):
 
700
    def __init__(self, parent, default_module=None):
 
701
        gtk.Dialog.__init__(self, _('Preferences'), parent)
 
702
        self.app = parent
 
703
        self.create_ui()
 
704
        self.connect('response', self.on_response_cb)
 
705
        self.connect('delete-event', self.on_response_cb)
 
706
 
 
707
    def create_ui(self):
 
708
        vbox = gtk.VBox(spacing=5)
 
709
        vbox.set_border_width(5)
 
710
        self.vbox.add(vbox)
 
711
 
 
712
        for key, label in (
 
713
                ('nonetwork', _('Disable network access')),
 
714
                ('alwaysautogen', _('Always run autogen.sh')),
 
715
                ('nopoison', _('Don\'t poison modules on failure'))):
 
716
            checkbutton = gtk.CheckButton(label)
 
717
            checkbutton.set_active(getattr(self.app.config, key))
 
718
            checkbutton.connect('toggled', self.on_toggled_key, key)
 
719
            vbox.pack_start(checkbutton, expand=False, fill=False)
 
720
 
 
721
        self.vbox.show_all()
 
722
        self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
 
723
 
 
724
    def on_toggled_key(self, checkbutton, key):
 
725
        setattr(self.app.config, key, checkbutton.get_active())
 
726
 
 
727
    def on_response_cb(self, *args):
 
728
        self.destroy()
 
729
        self.app.preference_dialog = None
 
730
 
 
731
 
 
732
BUILD_SCRIPT = AppWindow