Example #1
0
 def __init__(self, palabra_window, properties):
     PalabraDialog.__init__(self, palabra_window, u"Appearance")
     self.palabra_window = palabra_window
     hbox = gtk.HBox()
     hbox.set_spacing(18)
     hbox.pack_start(self.create_content(properties))
     mode = constants.VIEW_MODE_PREVIEW_SOLUTION
     self.preview = GridPreview(mode=mode, cell_size=None)
     self.preview.set_size_request(200, 200)
     hbox.pack_start(self.preview, False, False, 0)
     self.pack(hbox)
     g = Grid(3, 3)
     g.set_block(0, 2, True)
     g.set_void(2, 0, True)
     g.set_char(0, 0, "A")
     g.assign_numbers()
     self.preview.display(g)
     self.on_update()
     self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
     self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_OK)
Example #2
0
    def __init__(self, parent, size=None):
        super(GridEditor, self).__init__(parent, u"Grid editor", horizontal=True)
        self.size = size if size else (15, 15)

        table = gtk.Table(2, 2, False)

        radio = gtk.RadioButton(None, u"Tile from: ")
        radio.connect("toggled", self.on_option_toggle, "tile")
        self.tile_starts = [(p, q) for q in xrange(2) for p in xrange(2)]
        self.tile_combo = gtk.combo_box_new_text()
        self.tile_combo.append_text(u"")
        for x, y in self.tile_starts:
            content = str(''.join(["(", str(x + 1), ",", str(y + 1), ")" ]))
            self.tile_combo.append_text(content)
        self.tile_combo.connect("changed", self.on_tile_changed)
        table.attach(radio, 0, 1, 0, 1)
        table.attach(self.tile_combo, 1, 2, 0, 1)

        radio = gtk.RadioButton(radio, u"Fill with: ")
        radio.connect("toggled", self.on_option_toggle, "fill")
        self.fill_combo = create_combo([u"", u"Block"], f_change=self.on_fill_changed)
        table.attach(radio, 0, 1, 1, 2)
        table.attach(self.fill_combo, 1, 2, 1, 2)

        self.preview = GridPreview()
        self.preview.set_size_request(384, 384)

        alignment = gtk.Alignment()
        alignment.add(table)
        vbox2 = gtk.VBox(False, 6)
        vbox2.pack_start(create_label(u"<b>Options</b>"), False, False, 0)
        vbox2.pack_start(alignment, False, False, 0)
        self.pack(vbox2, False)
        self.pack(self.preview, False)

        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.ok_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.ok_button.set_sensitive(False)
        self._select_option("tile")
        self.display_pattern(None)
Example #3
0
    def __init__(self, palabra_window):
        flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
        buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
            gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
        super(NewWindow, self).__init__("New puzzle", palabra_window, flags, buttons)
        
        self.showing_pattern = False
        
        self.preview = GridPreview()
        self.preview.set_size_request(300, 400)
        
        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(12)
        hbox.set_spacing(18)
        
        options_vbox = gtk.VBox(False, 0)
        hbox.pack_start(options_vbox, True, True, 0)
        hbox.pack_start(self.preview, True, True, 0)
        
        self.vbox.pack_start(hbox, True, True, 0)
        
        self.size_component = SizeComponent(
            title=u"<b>Dimensions</b>"
            , callback=self.load_empty_grid)
        options_vbox.pack_start(self.size_component, False, False, 0)
        
        label = gtk.Label()
        label.set_alignment(0, 0)
        label.set_markup(u"<b>Grids</b>")
        options_vbox.pack_start(label, False, False, 6)
        
        # display_string grid
        self.store = gtk.ListStore(str, gobject.TYPE_PYOBJECT)
        self.tree = gtk.TreeView(self.store)
        self.tree.set_headers_visible(False)
        self.tree.get_selection().connect("changed", self.on_pattern_changed)
        
        cell = gtk.CellRendererText()
        column = gtk.TreeViewColumn("")
        column.pack_start(cell, True)
        column.set_attributes(cell, text=0)
        self.tree.append_column(column)
        
        window = gtk.ScrolledWindow(None, None)
        window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        window.add(self.tree)
        
        self.clear_button = gtk.Button("Clear grid")
        self.clear_button.connect("clicked", self.clear_pattern)
        
        self.files = []
        for f in constants.STANDARD_PATTERN_FILES + preferences.prefs["pattern_files"]:
            self.files.append(get_real_filename(f))
        
        self.patterns = []
        for f, meta, data in palabra_window.patterns:
            if f is not None:
                self.patterns.append((f, meta, [p.grid for p in data]))
        
        file_combo = gtk.combo_box_new_text()
        file_combo.append_text("All files")
        file_combo.set_active(0)
        for path, metadata, data in self.patterns:
            filename = path[path.rfind(os.sep) + 1:]
            caption = metadata["title"] if "title" in metadata else filename
            file_combo.append_text(caption)
        file_combo.connect("changed", self.on_file_changed)
        
        patterns_vbox = gtk.VBox(False, 0)
        
        files_hbox = gtk.HBox(False, 0)
        files_hbox.pack_start(gtk.Label(u"Show grids from: "), False, False, 0)
        align = gtk.Alignment(0, 0.5, 0, 0)
        align.add(file_combo)
        files_hbox.pack_start(align, False, False, 0)
        self.find_button = gtk.Button(u"Find grids")
        self.find_button.connect("clicked", self.on_find_patterns)
        files_hbox.pack_start(self.find_button, False, False, 0)
        
        patterns_vbox.pack_start(files_hbox, False, False, 6)
        
        patterns_vbox.pack_start(window, True, True, 0)
        
        buttons_hbox = gtk.HBox(False, 6)
        generate_button = gtk.Button(u"Construct grid")
        generate_button.connect("clicked", self.construct_pattern)
        buttons_hbox.pack_start(generate_button, False, False, 0)
        align = gtk.Alignment(0, 0, 1, 0)
        align.add(self.clear_button)
        buttons_hbox.pack_start(align, False, False, 0)
        
        patterns_vbox.pack_start(buttons_hbox, False, False, 6)
        
        align = gtk.Alignment(0, 0, 1, 1)
        align.set_padding(0, 0, 12, 0)
        align.add(patterns_vbox)
        options_vbox.pack_start(align, True, True, 0)

        self.clear_button.set_sensitive(False)
        self._load_pattern_list(self.files)
Example #4
0
class NewWindow(gtk.Dialog):
    def __init__(self, palabra_window):
        flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
        buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
            gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
        super(NewWindow, self).__init__("New puzzle", palabra_window, flags, buttons)
        
        self.showing_pattern = False
        
        self.preview = GridPreview()
        self.preview.set_size_request(300, 400)
        
        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(12)
        hbox.set_spacing(18)
        
        options_vbox = gtk.VBox(False, 0)
        hbox.pack_start(options_vbox, True, True, 0)
        hbox.pack_start(self.preview, True, True, 0)
        
        self.vbox.pack_start(hbox, True, True, 0)
        
        self.size_component = SizeComponent(
            title=u"<b>Dimensions</b>"
            , callback=self.load_empty_grid)
        options_vbox.pack_start(self.size_component, False, False, 0)
        
        label = gtk.Label()
        label.set_alignment(0, 0)
        label.set_markup(u"<b>Grids</b>")
        options_vbox.pack_start(label, False, False, 6)
        
        # display_string grid
        self.store = gtk.ListStore(str, gobject.TYPE_PYOBJECT)
        self.tree = gtk.TreeView(self.store)
        self.tree.set_headers_visible(False)
        self.tree.get_selection().connect("changed", self.on_pattern_changed)
        
        cell = gtk.CellRendererText()
        column = gtk.TreeViewColumn("")
        column.pack_start(cell, True)
        column.set_attributes(cell, text=0)
        self.tree.append_column(column)
        
        window = gtk.ScrolledWindow(None, None)
        window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        window.add(self.tree)
        
        self.clear_button = gtk.Button("Clear grid")
        self.clear_button.connect("clicked", self.clear_pattern)
        
        self.files = []
        for f in constants.STANDARD_PATTERN_FILES + preferences.prefs["pattern_files"]:
            self.files.append(get_real_filename(f))
        
        self.patterns = []
        for f, meta, data in palabra_window.patterns:
            if f is not None:
                self.patterns.append((f, meta, [p.grid for p in data]))
        
        file_combo = gtk.combo_box_new_text()
        file_combo.append_text("All files")
        file_combo.set_active(0)
        for path, metadata, data in self.patterns:
            filename = path[path.rfind(os.sep) + 1:]
            caption = metadata["title"] if "title" in metadata else filename
            file_combo.append_text(caption)
        file_combo.connect("changed", self.on_file_changed)
        
        patterns_vbox = gtk.VBox(False, 0)
        
        files_hbox = gtk.HBox(False, 0)
        files_hbox.pack_start(gtk.Label(u"Show grids from: "), False, False, 0)
        align = gtk.Alignment(0, 0.5, 0, 0)
        align.add(file_combo)
        files_hbox.pack_start(align, False, False, 0)
        self.find_button = gtk.Button(u"Find grids")
        self.find_button.connect("clicked", self.on_find_patterns)
        files_hbox.pack_start(self.find_button, False, False, 0)
        
        patterns_vbox.pack_start(files_hbox, False, False, 6)
        
        patterns_vbox.pack_start(window, True, True, 0)
        
        buttons_hbox = gtk.HBox(False, 6)
        generate_button = gtk.Button(u"Construct grid")
        generate_button.connect("clicked", self.construct_pattern)
        buttons_hbox.pack_start(generate_button, False, False, 0)
        align = gtk.Alignment(0, 0, 1, 0)
        align.add(self.clear_button)
        buttons_hbox.pack_start(align, False, False, 0)
        
        patterns_vbox.pack_start(buttons_hbox, False, False, 6)
        
        align = gtk.Alignment(0, 0, 1, 1)
        align.set_padding(0, 0, 12, 0)
        align.add(patterns_vbox)
        options_vbox.pack_start(align, True, True, 0)

        self.clear_button.set_sensitive(False)
        self._load_pattern_list(self.files)
        
    def on_file_changed(self, combo):
        index = combo.get_active()
        files = self.files if index == 0 else self.files[index - 1:index]
        if files:
            self._load_pattern_list(files)    
            
    def _load_pattern_list(self, files):
        data = [d for (f, _, d) in self.patterns if f in files]
        grids = reduce(operator.add, data) if data else []
        stats = [(g.count_words(), g.count_blocks(), g) for g in grids]
        stats.sort()
        self.grids = [grid for (_, _, grid) in stats]
        self.load_empty_grid(*self.size_component.get_size())
        
    def on_pattern_changed(self, selection):
        store, it = selection.get_selected()
        if it is not None:
            self.show_grid(store.get_value(it, 1))
            
    def show_grid(self, grid, showing_pattern=True):
        self.showing_pattern = showing_pattern
        self.grid = grid
        self.preview.display(self.grid)
        self.clear_button.set_sensitive(showing_pattern)
            
    def clear_pattern(self, button=None):
        """Display an empty grid without the currently selected pattern."""
        self.show_grid(Grid(*self.grid.size), False)
        self.tree.get_selection().unselect_all()
        
    def construct_pattern(self, button):
        """Open the pattern editor to construct a pattern."""
        editor = GridEditor(self, size=self.grid.size)
        editor.show_all()
        if editor.run() == gtk.RESPONSE_OK:
            self.show_grid(editor.grid)
            self.tree.get_selection().unselect_all()
        editor.destroy()
        
    def on_find_patterns(self, button):
        d = FindPatternDialog(self)
        d.show_all()
        if d.run() == gtk.RESPONSE_OK:
            buff = d.text.get_buffer()
            text = buff.get_text(*buff.get_bounds())
            words = [w for w in text.split() if w != '']
            if words:
                w, h = self.grid.size
                c = self.generate_criteria(list(set(words)))
                self.clear_pattern()
                self.display_patterns(w, h, criteria=c)
        d.destroy()        
            
    def load_empty_grid(self, width, height):
        """Load an empty grid with the specified dimensions and load patterns."""
        self.grid = Grid(width, height)
        self.preview.display(self.grid)
        self.display_patterns(width, height, criteria=None)
        
    def generate_criteria(self, words):
        """Determine search criteria per word length."""
        counts = {}
        for word in words:
            l = len(word)
            if l in counts:
                counts[l] += 1
            else:
                counts[l] = 1
        return {"counts": counts, "words": words}
        
    def _check_grid(self, grid, criteria):
        """Return a grid or None when the grid meets all the search criteria."""
        if "counts" in criteria:
            counts = grid.determine_word_counts()
            for k, v in criteria["counts"].items():
                if k not in counts or counts[k] < v:
                    return None
        if "words" in criteria:
            return attempt_fill(grid, criteria["words"])
        return grid
        
    def display_patterns(self, width, height, criteria=None):
        gs = []
        for grid in self.grids:
            if grid.size != (width, height):
                continue
            if not criteria:
                gs.append(grid)
                continue
            g = self._check_grid(grid, criteria)
            if g is not None and g.has_chars():
                gs.append(g)
        self.store.clear()
        self.find_button.set_sensitive(len(gs) > 0)
        for g in gs:
            blocks = g.count_blocks()
            words = g.count_words()
            s = ''.join([str(words), " words, ", str(blocks), " blocks"])
            self.store.append([s, g])
                
    def get_configuration(self):
        configuration = {}
        configuration["type"] = "crossword"
        
        if self.grid is not None:
            configuration["grid"] = copy.deepcopy(self.grid)
        return configuration
Example #5
0
class GridEditor(PalabraDialog):
    def __init__(self, parent, size=None):
        super(GridEditor, self).__init__(parent, u"Grid editor", horizontal=True)
        self.size = size if size else (15, 15)

        table = gtk.Table(2, 2, False)

        radio = gtk.RadioButton(None, u"Tile from: ")
        radio.connect("toggled", self.on_option_toggle, "tile")
        self.tile_starts = [(p, q) for q in xrange(2) for p in xrange(2)]
        self.tile_combo = gtk.combo_box_new_text()
        self.tile_combo.append_text(u"")
        for x, y in self.tile_starts:
            content = str(''.join(["(", str(x + 1), ",", str(y + 1), ")" ]))
            self.tile_combo.append_text(content)
        self.tile_combo.connect("changed", self.on_tile_changed)
        table.attach(radio, 0, 1, 0, 1)
        table.attach(self.tile_combo, 1, 2, 0, 1)

        radio = gtk.RadioButton(radio, u"Fill with: ")
        radio.connect("toggled", self.on_option_toggle, "fill")
        self.fill_combo = create_combo([u"", u"Block"], f_change=self.on_fill_changed)
        table.attach(radio, 0, 1, 1, 2)
        table.attach(self.fill_combo, 1, 2, 1, 2)

        self.preview = GridPreview()
        self.preview.set_size_request(384, 384)

        alignment = gtk.Alignment()
        alignment.add(table)
        vbox2 = gtk.VBox(False, 6)
        vbox2.pack_start(create_label(u"<b>Options</b>"), False, False, 0)
        vbox2.pack_start(alignment, False, False, 0)
        self.pack(vbox2, False)
        self.pack(self.preview, False)

        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.ok_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
        self.ok_button.set_sensitive(False)
        self._select_option("tile")
        self.display_pattern(None)

    def on_option_toggle(self, widget, option):
        if widget.get_active() == 1:
            self._select_option(option)

    def _select_option(self, option):
        if option == "tile":
            self.fill_combo.set_active(0)
        elif option == "fill":
            self.tile_combo.set_active(0)
        self.tile_combo.set_sensitive(option == "tile")
        self.fill_combo.set_sensitive(option == "fill")

    def display_pattern(self, pattern=None):
        """
        Display a pattern in the preview. If pattern=None then
        an empty Grid is displayed.
        """
        self.ok_button.set_sensitive(pattern is not None)
        self.grid = Grid(*self.size)
        if pattern:
            apply_pattern(self.grid, pattern)
        self.preview.display(self.grid)

    def on_tile_changed(self, combo):
        """Create and display a tiled pattern in the preview."""
        index = combo.get_active()
        if index == 0:
            self.display_pattern(None)
            return
        width, height = self.grid.size
        pattern = tile_from_cell(width, height, *self.tile_starts[index - 1])
        self.display_pattern(pattern)

    def on_fill_changed(self, combo):
        """Fill the entire grid with the specified content."""
        index = combo.get_active()
        if index == 0:
            self.display_pattern(None)
            return
        content = {1: "block", 2: "void"}[index]
        width, height = self.grid.size
        self.display_pattern(fill_with_content(width, height, content))
Example #6
0
    def __init__(self, palabra_window):
        gtk.Dialog.__init__(self, u"Pattern file manager"
            , palabra_window, gtk.DIALOG_MODAL)
        self.palabra_window = palabra_window
        self.set_size_request(640, 512)

        self.preview = GridPreview()
        self.preview.set_size_request(200, 256)

        self.patterns = {}
        # display_string filename id_of_grid
        self.store = gtk.TreeStore(str, str, str)
        self.reset_pattern_list()

        self.tree = gtk.TreeView(self.store)
        self.tree.set_headers_visible(False)
        self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self.tree.get_selection().connect("changed", self.on_selection_changed)

        cell = gtk.CellRendererText()
        column = gtk.TreeViewColumn()
        column.pack_start(cell, True)
        column.set_attributes(cell, text=0)
        self.tree.append_column(column)

        right_vbox = gtk.VBox(False, 6)

        label = gtk.Label()
        label.set_markup(u"<b>Options for pattern files</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        right_vbox.pack_start(align, False, False, 0)

        add_button = gtk.Button(stock=gtk.STOCK_ADD)
        add_button.connect("clicked", lambda button: self.add_file())
        align = add_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Add pattern file");
        right_vbox.pack_start(add_button, False, False, 0)

        self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
        self.remove_button.connect("clicked", lambda button: self.remove_file())
        self.remove_button.set_sensitive(False)
        align = self.remove_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Remove pattern file(s)");
        right_vbox.pack_start(self.remove_button, False, False, 0)

        label = gtk.Label()
        label.set_markup(u"<b>Options for patterns</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        right_vbox.pack_start(align, False, False, 0)

        self.copy_pattern_button = gtk.Button(u"Copy pattern(s) to file...")
        self.copy_pattern_button.set_sensitive(False)
        self.copy_pattern_button.connect("clicked", self.on_copy_patterns)
        right_vbox.pack_start(self.copy_pattern_button, False, False, 0)
        self.move_pattern_button = gtk.Button(u"Move pattern(s) to file...")
        self.move_pattern_button.set_sensitive(False)
        self.move_pattern_button.connect("clicked", self.on_move_patterns)
        right_vbox.pack_start(self.move_pattern_button, False, False, 0)

        self.add_pattern_button = gtk.Button(stock=gtk.STOCK_ADD);
        try:
            grid = self.palabra_window.puzzle_manager.current_puzzle.grid
        except AttributeError:
            # TODO
            self.add_pattern_button.set_sensitive(False)
        self.add_pattern_button.connect("clicked", self.on_add_pattern)
        align = self.add_pattern_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Add current pattern to file...");
        right_vbox.pack_start(self.add_pattern_button, False, False, 0)

        self.remove_pattern_button = gtk.Button(stock=gtk.STOCK_REMOVE);
        self.remove_pattern_button.set_sensitive(False)
        self.remove_pattern_button.connect("clicked", self.on_remove_patterns)
        align = self.remove_pattern_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Remove pattern(s)");
        right_vbox.pack_start(self.remove_pattern_button, False, False, 0)

        scrolled_window = gtk.ScrolledWindow(None, None)
        scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scrolled_window.add_with_viewport(self.tree)

        vbox1 = gtk.VBox(False, 12)
        label = gtk.Label()
        label.set_markup(u"<b>Pattern files</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        vbox1.pack_start(align, False, False, 0)
        vbox1.pack_start(scrolled_window, True, True, 0)
        vbox1.pack_start(self.preview, False, False, 0)

        self.info = gtk.TextView()
        self.info.set_buffer(gtk.TextBuffer())
        self.info.set_editable(False)
        scrolled_window = gtk.ScrolledWindow(None, None)
        scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scrolled_window.add_with_viewport(self.info)

        vbox2 = gtk.VBox(False, 12)
        vbox2.pack_start(right_vbox, False, False, 0)
        label = gtk.Label()
        label.set_markup(u"<b>Information</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        vbox2.pack_start(align, False, False, 0)
        vbox2.pack_start(scrolled_window, True, True, 0)

        options_hbox = gtk.HBox(True, 12)
        options_hbox.pack_start(vbox1, True, True, 0)
        options_hbox.pack_start(vbox2, True, True, 0)

        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(12)
        hbox.set_spacing(18)
        hbox.pack_start(options_hbox, True, True, 0)
        self.vbox.pack_start(hbox, True, True, 0)

        self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
Example #7
0
class PatternFileEditor(gtk.Dialog):
    def __init__(self, palabra_window):
        gtk.Dialog.__init__(self, u"Pattern file manager"
            , palabra_window, gtk.DIALOG_MODAL)
        self.palabra_window = palabra_window
        self.set_size_request(640, 512)

        self.preview = GridPreview()
        self.preview.set_size_request(200, 256)

        self.patterns = {}
        # display_string filename id_of_grid
        self.store = gtk.TreeStore(str, str, str)
        self.reset_pattern_list()

        self.tree = gtk.TreeView(self.store)
        self.tree.set_headers_visible(False)
        self.tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self.tree.get_selection().connect("changed", self.on_selection_changed)

        cell = gtk.CellRendererText()
        column = gtk.TreeViewColumn()
        column.pack_start(cell, True)
        column.set_attributes(cell, text=0)
        self.tree.append_column(column)

        right_vbox = gtk.VBox(False, 6)

        label = gtk.Label()
        label.set_markup(u"<b>Options for pattern files</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        right_vbox.pack_start(align, False, False, 0)

        add_button = gtk.Button(stock=gtk.STOCK_ADD)
        add_button.connect("clicked", lambda button: self.add_file())
        align = add_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Add pattern file");
        right_vbox.pack_start(add_button, False, False, 0)

        self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
        self.remove_button.connect("clicked", lambda button: self.remove_file())
        self.remove_button.set_sensitive(False)
        align = self.remove_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Remove pattern file(s)");
        right_vbox.pack_start(self.remove_button, False, False, 0)

        label = gtk.Label()
        label.set_markup(u"<b>Options for patterns</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        right_vbox.pack_start(align, False, False, 0)

        self.copy_pattern_button = gtk.Button(u"Copy pattern(s) to file...")
        self.copy_pattern_button.set_sensitive(False)
        self.copy_pattern_button.connect("clicked", self.on_copy_patterns)
        right_vbox.pack_start(self.copy_pattern_button, False, False, 0)
        self.move_pattern_button = gtk.Button(u"Move pattern(s) to file...")
        self.move_pattern_button.set_sensitive(False)
        self.move_pattern_button.connect("clicked", self.on_move_patterns)
        right_vbox.pack_start(self.move_pattern_button, False, False, 0)

        self.add_pattern_button = gtk.Button(stock=gtk.STOCK_ADD);
        try:
            grid = self.palabra_window.puzzle_manager.current_puzzle.grid
        except AttributeError:
            # TODO
            self.add_pattern_button.set_sensitive(False)
        self.add_pattern_button.connect("clicked", self.on_add_pattern)
        align = self.add_pattern_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Add current pattern to file...");
        right_vbox.pack_start(self.add_pattern_button, False, False, 0)

        self.remove_pattern_button = gtk.Button(stock=gtk.STOCK_REMOVE);
        self.remove_pattern_button.set_sensitive(False)
        self.remove_pattern_button.connect("clicked", self.on_remove_patterns)
        align = self.remove_pattern_button.get_children()[0]
        hbox = align.get_children()[0]
        image, label = hbox.get_children()
        label.set_text(u"Remove pattern(s)");
        right_vbox.pack_start(self.remove_pattern_button, False, False, 0)

        scrolled_window = gtk.ScrolledWindow(None, None)
        scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scrolled_window.add_with_viewport(self.tree)

        vbox1 = gtk.VBox(False, 12)
        label = gtk.Label()
        label.set_markup(u"<b>Pattern files</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        vbox1.pack_start(align, False, False, 0)
        vbox1.pack_start(scrolled_window, True, True, 0)
        vbox1.pack_start(self.preview, False, False, 0)

        self.info = gtk.TextView()
        self.info.set_buffer(gtk.TextBuffer())
        self.info.set_editable(False)
        scrolled_window = gtk.ScrolledWindow(None, None)
        scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scrolled_window.add_with_viewport(self.info)

        vbox2 = gtk.VBox(False, 12)
        vbox2.pack_start(right_vbox, False, False, 0)
        label = gtk.Label()
        label.set_markup(u"<b>Information</b>")
        align = gtk.Alignment(0, 0.5)
        align.add(label)
        vbox2.pack_start(align, False, False, 0)
        vbox2.pack_start(scrolled_window, True, True, 0)

        options_hbox = gtk.HBox(True, 12)
        options_hbox.pack_start(vbox1, True, True, 0)
        options_hbox.pack_start(vbox2, True, True, 0)

        hbox = gtk.HBox(False, 0)
        hbox.set_border_width(12)
        hbox.set_spacing(18)
        hbox.pack_start(options_hbox, True, True, 0)
        self.vbox.pack_start(hbox, True, True, 0)

        self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)

    def reset_pattern_list(self):
        self.store.clear()
        for f in preferences.prefs["pattern_files"]:
            try:
                g, meta, data = read_pattern_file(f)
                self.patterns[f] = {"metadata": meta, "data": data}
            except ParserError:
                # TODO
                pass
        for item in self.patterns.items():
            self._append_file(*item)

    def _append_file(self, path, patterns):
        meta = patterns["metadata"]
        data = patterns["data"]
        s = meta["title"] if "title" in meta else path
        parent = self.store.append(None, [s, path, "0"])
        for id, grid in data.items():
            blocks = str(grid.count_blocks())
            words = str(grid.count_words())
            s = "".join([words, " words, ", blocks, " blocks"])
            self.store.append(parent, [s, path, id])

    def add_file(self):
        dialog = gtk.FileChooserDialog(u"Add pattern file"
            , self
            , gtk.FILE_CHOOSER_ACTION_OPEN
            , (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL
            , gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        filter = gtk.FileFilter()
        filter.set_name(u"Palabra pattern files (*.xml)")
        filter.add_pattern("*.xml")
        dialog.add_filter(filter)
        dialog.show_all()
        response = dialog.run()
        path = dialog.get_filename()
        dialog.destroy()
        if response == gtk.RESPONSE_OK:
            for g, pattern in self.patterns.items():
                if g == path:
                    mdialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL
                        , gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, u"This file is already in the list.")
                    mdialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
                    mdialog.set_title("Duplicate file")
                    mdialog.run()
                    mdialog.destroy()
                    break
            else:
                try:
                    g, meta, data = read_pattern_file(path)
                    preferences.prefs["pattern_files"].append(path)
                    self.patterns[path] = {"metadata": meta, "data": data}
                    self._append_file(path, self.patterns[path])
                    self.tree.columns_autosize()
                except ParserError:
                    # TODO
                    pass

    def remove_file(self):
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
        dialog = gtk.Dialog(u"Remove pattern files"
            , self
            , gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL
            , (gtk.STOCK_NO, gtk.RESPONSE_NO
            , gtk.STOCK_YES, gtk.RESPONSE_YES))
        dialog.set_default_response(gtk.RESPONSE_CLOSE)
        dialog.set_title(u"Remove pattern files")

        label = gtk.Label(u"Are you sure you want to remove the selected pattern file(s)?")
        hbox = gtk.HBox(False, 0)
        hbox.pack_start(image, False, False, 0)
        hbox.pack_start(label, True, False, 10)
        dialog.vbox.pack_start(hbox, False, False, 10)
        dialog.set_resizable(False)
        dialog.set_modal(True)
        dialog.show_all()

        response = dialog.run()
        dialog.destroy()
        if response == gtk.RESPONSE_YES:
            while True:
                store, paths = self.tree.get_selection().get_selected_rows()
                if not paths:
                    break
                it = store.get_iter(paths.pop())
                filename = store.get_value(it, 1)
                store.remove(it)
                preferences.prefs["pattern_files"].remove(filename)
                try:
                    del self.patterns[filename]
                    self.tree.columns_autosize()
                except KeyError:
                    pass

    def on_selection_changed(self, selection):
        grid = None
        store, paths = selection.get_selected_rows()
        self.copy_pattern_button.set_sensitive(False)
        self.move_pattern_button.set_sensitive(False)
        self.remove_pattern_button.set_sensitive(False)
        self.remove_button.set_sensitive(False)
        self.info.get_buffer().set_text("")
        self.preview.clear()
        if not paths:
            return

        if all([self.is_file(store, p) for p in paths]):
            self.remove_button.set_sensitive(True)

        if len(paths) == 1:
            if not self.is_file(store, paths[0]):
                it = store.get_iter(paths[0])
                filepath = store.get_value(it, 1)
                id = store.get_value(it, 2)
                grid = self.patterns[filepath]["data"][id]
                self.preview.display(grid)

        only_patterns = not any([self.is_file(store, p) for p in paths])
        self.copy_pattern_button.set_sensitive(only_patterns)
        self.move_pattern_button.set_sensitive(only_patterns)
        self.remove_pattern_button.set_sensitive(only_patterns)

        files = list(set([self.get_file(store, p) for p in paths]))
        self.info.get_buffer().set_text("")
        if len(files) == 1:
            for g, pattern in self.patterns.items():
                if g == files[0]:
                    if grid:
                        stats = grid.determine_status()
                        info = "".join(["Blocks: ", str(stats["block_count"])
                            , " (%.2f" % stats["block_percentage"], "%)\n"
                            , "Letters: ", str(stats["char_count"]), "\n"
                            , "Words: ", str(stats["word_count"]), "\n"
                            , "Voids: ", str(stats["void_count"]), "\n"])
                    else:
                        total = str(len(self.patterns[g]["data"].keys()))
                        info = "".join(["Location: ", g, "\n"
                            , "Number of patterns: ", total, "\n"])
                    self.info.get_buffer().set_text(info)
                    break

    def append_to_file(self, path, patterns):
        """Append all patterns to the specified file."""
        try:
            g, meta, data = read_pattern_file(path)
        except ParserError:
            # TODO
            return
        try:
            max_id = int(max(data.keys())) + 1
        except ValueError: # max() arg is an empty sequence
            max_id = 1
        for f, keys in patterns.items():
            for k in keys:
                data[str(max_id)] = self.patterns[f]["data"][k]
                max_id += 1
        write_pattern_file(g, meta, data)

    @staticmethod
    def remove_from_files(patterns):
        """Remove the patterns from their respective files."""
        for f, keys in patterns.items():
            try:
                g, meta, data = read_pattern_file(f)
                ndata = {}
                for k, v in data.items():
                    if k not in keys:
                        ndata[k] = v
                write_pattern_file(g, meta, ndata)
            except ParserError:
                # TODO
                pass

    def on_copy_patterns(self, button):
        """Copy the currently selected patterns to a specified file."""
        patterns = self._gather_selected_patterns()
        path = self._get_pattern_file()
        if not path:
            return
        self.append_to_file(path, patterns)

    def on_move_patterns(self, button):
        """Move the currently selected patterns to a specified file."""
        patterns = self._gather_selected_patterns()
        path = self._get_pattern_file()
        if not path:
            return
        self.append_to_file(path, patterns)
        self.remove_from_files(patterns)

    def on_add_pattern(self, button):
        """Add the pattern of the current puzzle to a specified file."""
        path = self._get_pattern_file()
        if not path:
            return
        # TODO ugly
        try:
            grid = self.palabra_window.puzzle_manager.current_puzzle.grid
        except AttributeError:
            # TODO
            return
        try:
            g, meta, data = read_pattern_file(path)
        except ParserError:
            # TODO
            return
        max_id = int(max(data.keys())) + 1
        data[str(max_id)] = grid
        write_pattern_file(g, meta, data)

    def on_remove_patterns(self, button):
        """Remove the currently selected patterns from their respective files."""
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
        dialog = gtk.Dialog(u"Remove patterns"
            , self
            , gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL
            , (gtk.STOCK_NO, gtk.RESPONSE_NO
            , gtk.STOCK_YES, gtk.RESPONSE_YES))
        dialog.set_default_response(gtk.RESPONSE_CLOSE)
        dialog.set_title(u"Remove patterns")

        label = gtk.Label(u"Are you sure you want to remove the selected pattern(s)?")
        hbox = gtk.HBox(False, 0)
        hbox.pack_start(image, False, False, 0)
        hbox.pack_start(label, True, False, 10)
        dialog.vbox.pack_start(hbox, False, False, 10)
        dialog.set_resizable(False)
        dialog.set_modal(True)
        dialog.show_all()

        response = dialog.run()
        dialog.destroy()
        if response == gtk.RESPONSE_YES:
            patterns = self._gather_selected_patterns()
            self.remove_from_files(patterns)
            while True:
                store, paths = self.tree.get_selection().get_selected_rows()
                if not paths:
                    break
                it = store.get_iter(paths.pop())
                filename = store.get_value(it, 1)
                store.remove(it)
            # currently disabled, don't automatically remove file without patterns
            if False:
                for row in self.store:
                    if not self.is_file_with_patterns(self.store, row.path):
                        filename = row[1]
                        it = store.get_iter(row.path)
                        self.store.remove(it)
                        preferences.prefs["pattern_files"].remove(filename)
                        try:
                            del self.patterns[filename]
                        except KeyError:
                            pass
            self.tree.columns_autosize()

    def _get_pattern_file(self):
        """Request a filepath from the user."""
        dialog = gtk.FileChooserDialog(u"Select a pattern file"
            , self
            , gtk.FILE_CHOOSER_ACTION_OPEN
            , (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL
            , gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        filter = gtk.FileFilter()
        filter.set_name(u"Palabra pattern files (*.xml)")
        filter.add_pattern("*.xml")
        dialog.add_filter(filter)
        dialog.show_all()

        path = None
        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            path = dialog.get_filename()
        dialog.destroy()
        return path

    def _gather_selected_patterns(self):
        """Gather the currently selected patterns and the files they belong to."""
        patterns = {}
        store, paths = self.tree.get_selection().get_selected_rows()
        for path in paths:
            it = store.get_iter(path)
            parent = store.iter_parent(it)
            id = store.get_value(it, 2)
            try:
                patterns[store.get_value(parent, 1)].append(id)
            except KeyError:
                patterns[store.get_value(parent, 1)] = [id]
        return patterns

    def get_file(self, store, path):
        return store.get_value(store.get_iter(path), 1)

    def is_file(self, store, path):
        return store.iter_parent(store.get_iter(path)) is None

    def is_file_with_patterns(self, store, path):
        return self.is_file(store, path) and store.iter_has_child(store.get_iter(path))
Example #8
0
class AppearanceDialog(PalabraDialog):
    def __init__(self, palabra_window, properties):
        PalabraDialog.__init__(self, palabra_window, u"Appearance")
        self.palabra_window = palabra_window
        hbox = gtk.HBox()
        hbox.set_spacing(18)
        hbox.pack_start(self.create_content(properties))
        mode = constants.VIEW_MODE_PREVIEW_SOLUTION
        self.preview = GridPreview(mode=mode, cell_size=None)
        self.preview.set_size_request(200, 200)
        hbox.pack_start(self.preview, False, False, 0)
        self.pack(hbox)
        g = Grid(3, 3)
        g.set_block(0, 2, True)
        g.set_void(2, 0, True)
        g.set_char(0, 0, "A")
        g.assign_numbers()
        self.preview.display(g)
        self.on_update()
        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_OK)

    def create_content(self, properties):
        main = gtk.VBox()
        main.set_spacing(6)

        table = gtk.Table(10, 3)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        main.pack_start(table)

        def create_label(label):
            align = gtk.Alignment(0, 0.5)
            align.set_padding(0, 0, 12, 0)
            align.add(gtk.Label(label))
            return align

        def create_width_spinner(current):
            adj = gtk.Adjustment(current, 1, constants.MAX_LINE_WIDTH, 1, 0, 0)
            button = gtk.SpinButton(adj, 0.0, 0)
            return button

        def create_row(table, y, label, c1, c2=None):
            table.attach(label, 0, 1, y, y + 1, gtk.FILL, gtk.FILL)
            table.attach(c1, 1, 2, y, y + 1, 0, 0)
            if c2 is not None:
                table.attach(c2, 2, 3, y, y + 1, 0, 0)

        table.attach(create_label(u"Color"), 1, 2, 0, 1, gtk.FILL, gtk.FILL)
        table.attach(create_label(u"Width (px)"), 2, 3, 0, 1, gtk.FILL, gtk.FILL)

        def create_line_controls(title, key_color, key_width):
            label = create_label(title)
            button = create_color_button(properties[key_color], self.on_update)
            spinner = create_width_spinner(properties[key_width])
            return label, button, spinner

        # borders and lines
        widgets = create_line_controls(u"Border:", ("border", "color"), ("border", "width"))
        self.border_color_button = widgets[1]
        self.border_width_spinner = widgets[2]
        create_row(table, 1, *widgets)
        widgets = create_line_controls(u"Line:", ("line", "color"), ("line", "width"))
        self.line_color_button = widgets[1]
        self.line_width_spinner = widgets[2]
        create_row(table, 2, *widgets)

        def cap_line_width_at(bound):
            s = self.line_width_spinner
            adj = s.get_adjustment()
            adj.set_upper(bound)
            if s.get_value_as_int() > bound:
                s.set_value(bound)

        def on_border_width_update(widget):
            cap_line_width_at(widget.get_value_as_int())
            self.on_update()

        self.border_width_spinner.connect("value-changed", on_border_width_update)
        self.line_width_spinner.connect("value_changed", self.on_update)
        cap_line_width_at(properties["border", "width"])

        table.attach(create_label(u"Color"), 1, 2, 3, 4, gtk.FILL, gtk.FILL)
        table.attach(create_label(u"Size (%)"), 2, 3, 3, 4, gtk.FILL, gtk.FILL)

        def create_font_controls(title, key_color, key_size):
            label = create_label(title)
            button = create_color_button(properties[key_color], self.on_update)
            adj = gtk.Adjustment(properties[key_size][0], 10, 100, 1, 0, 0)
            spinner = gtk.SpinButton(adj)
            spinner.connect("value-changed", self.on_update)
            return label, button, spinner

        # letters and numbers
        widgets = create_font_controls(u"Letter:", ("char", "color"), ("char", "size"))
        self.char_color_button = widgets[1]
        self.char_size_spinner = widgets[2]
        create_row(table, 4, *widgets)
        widgets = create_font_controls(u"Number:", ("number", "color"), ("number", "size"))
        self.number_color_button = widgets[1]
        self.number_size_spinner = widgets[2]
        create_row(table, 5, *widgets)

        # cells
        table.attach(create_label(u"Color"), 1, 2, 6, 7, gtk.FILL, gtk.FILL)
        table.attach(create_label(u"Size (px)"), 2, 3, 6, 7, gtk.FILL, gtk.FILL)

        label = create_label(u"Cell:")
        self.cell_color_button = create_color_button(properties["cell", "color"], self.on_update)
        adj = gtk.Adjustment(properties["cell", "size"], 32, 128, 1, 0, 0)
        self.cell_size_spinner = gtk.SpinButton(adj, 0.0, 0)
        self.cell_size_spinner.connect("value-changed", self.on_update)
        create_row(table, 7, label, self.cell_color_button, self.cell_size_spinner)

        # blocks
        table.attach(create_label(u"Color"), 1, 2, 8, 9, gtk.FILL, gtk.FILL)
        table.attach(create_label(u"Margin (%)"), 2, 3, 8, 9, gtk.FILL, gtk.FILL)

        current = properties["block", "margin"]
        label = create_label(u"Block:")
        self.block_color_button = create_color_button(properties["block", "color"], self.on_update)
        adj = gtk.Adjustment(current, 0, 49, 1, 0, 0)
        self.block_margin_spinner = gtk.SpinButton(adj, 0.0, 0)
        self.block_margin_spinner.connect("value-changed", self.on_update)
        create_row(table, 9, label, self.block_color_button, self.block_margin_spinner)
        return main

    def on_update(self, widget=None):
        for k, v in self.gather_appearance().items():
            self.preview.view.properties[k] = v
        self.preview.refresh(force=True)

    def gather_appearance(self):
        a = {}
        a["block", "margin"] = self.block_margin_spinner.get_value_as_int()
        a["border", "width"] = self.border_width_spinner.get_value_as_int()
        a["cell", "size"] = self.cell_size_spinner.get_value_as_int()
        a["line", "width"] = self.line_width_spinner.get_value_as_int()
        a["cell", "color"] = color_tuple(self.cell_color_button)
        a["line", "color"] = color_tuple(self.line_color_button)
        a["border", "color"] = color_tuple(self.border_color_button)
        a["block", "color"] = color_tuple(self.block_color_button)
        a["char", "color"] = color_tuple(self.char_color_button)
        a["number", "color"] = color_tuple(self.number_color_button)
        p = self.char_size_spinner.get_value_as_int()
        key = ("cell", "size")
        a["char", "size"] = (p, _relative_to(key, p / 100.0, d=a))
        p = self.number_size_spinner.get_value_as_int()
        a["number", "size"] = (p, _relative_to(key, p / 100.0, d=a))
        return a
Example #9
0
    def __init__(self, palabra_window, properties):
        super(CellPropertiesDialog, self).__init__(palabra_window, u"Cell properties")
        self.palabra_window = palabra_window
        self.properties = properties
        x, y = properties["cell"]
        c1 = (u"Background color", ("cell", "color"))
        c2 = (u"Block color", ("block", "color"))
        c3 = (u"Letter color", ("char", "color"))
        c4 = (u"Number color", ("number", "color"))
        self.colors = [c1, c2, c3, c4]

        self.grid = Grid(1, 1)
        self.grid.data[0][0].update(properties["grid"].data[y][x])

        table = gtk.Table(3, 3, False)
        table.set_col_spacings(6)
        table.set_row_spacings(6)

        def create_row(table, title, value, x, y):
            table.attach(create_label(title), x, x + 1, y, y + 1, gtk.FILL, gtk.FILL)
            table.attach(create_label(value, align=(0, 0)), x + 1, x + 2, y, y + 1)

        def create_color_row(table, title, b_align, r_align, x, y):
            table.attach(create_label(title), x, x + 1, y, y + 1, gtk.FILL, gtk.FILL)
            table.attach(b_align, x + 1, x + 2, y, y + 1)
            table.attach(r_align, x + 2, x + 3, y, y + 1)

        on_color_set = lambda button, key: self._on_update(key, color_tuple(button))
        for i, (title, key) in enumerate(self.colors):
            attr = "_".join(list(key) + ["button"])
            setattr(self, attr, create_color_button(properties[key]))
            getattr(self, attr).connect("color-set", on_color_set, key)
            attr2 = "_".join(list(key) + ["reset", "button"])
            setattr(self, attr2, gtk.Button(u"Reset"))
            getattr(self, attr2).connect("clicked", self.on_color_reset, key)
            b_align = gtk.Alignment(0, 0.5)
            b_align.add(getattr(self, attr))
            r_align = gtk.Alignment(0, 0.5)
            r_align.add(getattr(self, attr2))
            create_color_row(table, title, b_align, r_align, 0, i)

        table.attach(create_label(u"Other options"), 0, 1, 4, 5, gtk.FILL, gtk.FILL)
        on_circle = lambda b: self._on_update("circle", b.get_active())
        self.circle_button = create_check_button(u"Display circle", active=properties["circle"], f_toggle=on_circle)
        table.attach(self.circle_button, 1, 3, 4, 5)

        main = gtk.VBox()
        main.set_spacing(6)
        main.pack_start(create_label(u"<b>Properties</b>"), False, False, 0)
        main.pack_start(table, False, False, 0)
        content = gtk.HBox()
        content.set_border_width(6)
        content.set_spacing(6)
        content.pack_start(main)

        self.previews = []
        prevs = gtk.VBox()
        p1 = (constants.VIEW_MODE_PREVIEW_CELL, "Puzzle")
        p2 = (constants.VIEW_MODE_PREVIEW_SOLUTION, "Solution")
        for m, h in [p1, p2]:
            p = GridPreview(mode=m, header=h, cell_size=96)
            p.set_size_request(164, 164)
            align = gtk.Alignment()
            align.add(p)
            self.previews.append(p)
            p.display(self.grid)
            for k in DEFAULTS_CELL:
                p.view.properties[k] = properties[k]
            p.refresh()
            prevs.pack_start(align, False, False, 0)
        content.pack_start(prevs, False, False, 0)
        self.pack(content)
        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_OK)