Esempio n. 1
0
    def create_toolbar(self):
        """Create the toolbar"""
        toolbar = gtk.Toolbar()

        # create the preview button
        preview_icon = gtk.Image()
        preview_icon.set_from_stock(
            gtk.STOCK_FIND, gtk.ICON_SIZE_LARGE_TOOLBAR)
        # TRANSLATORS: This is the preview button on the main window.  It
        # previews changes.
        preview_button = gtk.ToolButton(
            icon_widget=preview_icon, label=_p('button', "Preview"))
        preview_button.connect(
            "clicked", lambda *dummy: self.preview_or_run_operations(False))
        toolbar.insert(preview_button, -1)
        preview_button.set_tooltip_text(
            _("Preview files in the selected operations (without deleting any files)"))
        preview_button.set_is_important(True)

        # create the delete button
        icon = gtk.Image()
        icon.set_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_LARGE_TOOLBAR)
        # TRANSLATORS: This is the clean button on the main window.
        # It makes permanent changes: usually deleting files, sometimes
        # altering them.
        run_button = gtk.ToolButton(
            icon_widget=icon, label=_p("button", "Clean"))
        run_button.connect("clicked", self.run_operations)
        toolbar.insert(run_button, -1)
        run_button.set_tooltip_text(
            _("Clean files in the selected operations"))
        run_button.set_is_important(True)

        return toolbar
Esempio n. 2
0
    def create_toolbar(self):
        """Create the toolbar"""
        toolbar = gtk.Toolbar()

        # create the preview button
        preview_icon = gtk.Image()
        preview_icon.set_from_stock(
            gtk.STOCK_FIND, gtk.ICON_SIZE_LARGE_TOOLBAR)
        # TRANSLATORS: This is the preview button on the main window.  It
        # previews changes.
        preview_button = gtk.ToolButton(
            icon_widget=preview_icon, label=_p('button', "Preview"))
        preview_button.connect(
            "clicked", lambda *dummy: self.preview_or_run_operations(False))
        toolbar.insert(preview_button, -1)
        preview_button.set_tooltip_text(
            _("Preview files in the selected operations (without deleting any files)"))
        preview_button.set_is_important(True)

        # create the delete button
        icon = gtk.Image()
        icon.set_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_LARGE_TOOLBAR)
        # TRANSLATORS: This is the clean button on the main window.
        # It makes permanent changes: usually deleting files, sometimes
        # altering them.
        run_button = gtk.ToolButton(
            icon_widget=icon, label=_p("button", "Clean"))
        run_button.connect("clicked", self.run_operations)
        toolbar.insert(run_button, -1)
        run_button.set_tooltip_text(
            _("Clean files in the selected operations"))
        run_button.set_is_important(True)
		
		# create the stop 
        icon = gtk.Image()
        icon.set_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_LARGE_TOOLBAR)
        # TRANSLATORS: This is the clean button on the main window.
        # It makes permanent changes: usually deleting files, sometimes
        # altering them.
        run_button = gtk.ToolButton(
            icon_widget=icon, label=_p("button", "Stop!"))
        run_button.connect("clicked", self.run_operations_stop)  
        toolbar.insert(run_button, -1)
        run_button.set_tooltip_text(
            _("STOP the running operations"))
        run_button.set_is_important(True)

        return toolbar
Esempio n. 3
0
    def __locations_page(self, page_type):
        """Return a widget containing a list of files and folders"""

        def add_whitelist_file_cb(button):
            """Callback for adding a file"""
            title = _("Choose a file")
            pathname = GuiBasic.browse_file(self.parent, title)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('File'), pathname])
                pathnames.append(['file', pathname])
                options.set_whitelist_paths(pathnames)

        def add_whitelist_folder_cb(button):
            """Callback for adding a folder"""
            title = _("Choose a folder")
            pathname = GuiBasic.browse_folder(self.parent, title,
                                              multiple=False, stock_button=gtk.STOCK_ADD)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('Folder'), pathname])
                pathnames.append(['folder', pathname])
                options.set_whitelist_paths(pathnames)

        def remove_whitelist_path_cb(button):
            """Callback for removing a path"""
            treeselection = treeview.get_selection()
            (model, _iter) = treeselection.get_selected()
            if None == _iter:
                # nothing selected
                return
            pathname = model[_iter][1]
            liststore.remove(_iter)
            for this_pathname in pathnames:
                if this_pathname[1] == pathname:
                    pathnames.remove(this_pathname)
                    options.set_whitelist_paths(pathnames)

        def add_custom_file_cb(button):
            """Callback for adding a file"""
            title = _("Choose a file")
            pathname = GuiBasic.browse_file(self.parent, title)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('File'), pathname])
                pathnames.append(['file', pathname])
                options.set_custom_paths(pathnames)

        def add_custom_folder_cb(button):
            """Callback for adding a folder"""
            title = _("Choose a folder")
            pathname = GuiBasic.browse_folder(self.parent, title,
                                              multiple=False, stock_button=gtk.STOCK_ADD)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('Folder'), pathname])
                pathnames.append(['folder', pathname])
                options.set_custom_paths(pathnames)

        def remove_custom_path_cb(button):
            """Callback for removing a path"""
            treeselection = treeview.get_selection()
            (model, _iter) = treeselection.get_selected()
            if None == _iter:
                # nothing selected
                return
            pathname = model[_iter][1]
            liststore.remove(_iter)
            for this_pathname in pathnames:
                if this_pathname[1] == pathname:
                    pathnames.remove(this_pathname)
                    options.set_custom_paths(pathnames)

        vbox = gtk.VBox()

        # load data
        if LOCATIONS_WHITELIST == page_type:
            pathnames = options.get_whitelist_paths()
        elif LOCATIONS_CUSTOM == page_type:
            pathnames = options.get_custom_paths()
        liststore = gtk.ListStore(str, str)
        for paths in pathnames:
            type_code = paths[0]
            type_str = None
            if type_code == 'file':
                type_str = _('File')
            elif type_code == 'folder':
                type_str = _('Folder')
            else:
                raise RuntimeError("Invalid type code: '%s'" % type_code)
            path = paths[1]
            liststore.append([type_str, path])

        if LOCATIONS_WHITELIST == page_type:
            # TRANSLATORS: "Paths" is used generically to refer to both files
            # and folders
            notice = gtk.Label(
                _("Theses paths will not be deleted or modified."))
        elif LOCATIONS_CUSTOM == page_type:
            notice = gtk.Label(
                _("These locations can be selected for deletion."))
        vbox.pack_start(notice)

        # create treeview
        treeview = gtk.TreeView(liststore)

        # create column views
        self.renderer0 = gtk.CellRendererText()
        self.column0 = gtk.TreeViewColumn(_("Type"), self.renderer0, text=0)
        treeview.append_column(self.column0)

        self.renderer1 = gtk.CellRendererText()
        # TRANSLATORS: In the tree view "Path" is used generically to refer to a
        # file, a folder, or a pattern describing either
        self.column1 = gtk.TreeViewColumn(_("Path"), self.renderer1, text=1)
        treeview.append_column(self.column1)
        treeview.set_search_column(1)

        # finish tree view
        swindow = gtk.ScrolledWindow()
        swindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        swindow.set_size_request(300, 200)
        swindow.add(treeview)
        vbox.pack_start(swindow, False)

        # buttons that modify the list
        button_add_file = gtk.Button(_p('button', 'Add file'))
        if LOCATIONS_WHITELIST == page_type:
            button_add_file.connect("clicked", add_whitelist_file_cb)
        elif LOCATIONS_CUSTOM == page_type:
            button_add_file.connect("clicked", add_custom_file_cb)

        button_add_folder = gtk.Button(_p('button', 'Add folder'))
        if LOCATIONS_WHITELIST == page_type:
            button_add_folder.connect("clicked", add_whitelist_folder_cb)
        elif LOCATIONS_CUSTOM == page_type:
            button_add_folder.connect("clicked", add_custom_folder_cb)

        button_remove = gtk.Button(_p('button', 'Remove'))
        if LOCATIONS_WHITELIST == page_type:
            button_remove.connect("clicked", remove_whitelist_path_cb)
        elif LOCATIONS_CUSTOM == page_type:
            button_remove.connect("clicked", remove_custom_path_cb)

        button_box = gtk.HButtonBox()
        button_box.set_layout(gtk.BUTTONBOX_START)
        button_box.pack_start(button_add_file)
        button_box.pack_start(button_add_folder)
        button_box.pack_start(button_remove)
        vbox.pack_start(button_box, False)

        # return page
        return vbox
Esempio n. 4
0
    def __drives_page(self):
        """Return widget containing the drives page"""

        def add_drive_cb(button):
            """Callback for adding a drive"""
            title = _("Choose a folder")
            pathname = GuiBasic.browse_folder(self.parent, title,
                                              multiple=False, stock_button=gtk.STOCK_ADD)
            if pathname:
                liststore.append([pathname])
                pathnames.append(pathname)
                options.set_list('shred_drives', pathnames)

        def remove_drive_cb(button):
            """Callback for removing a drive"""
            treeselection = treeview.get_selection()
            (model, _iter) = treeselection.get_selected()
            if None == _iter:
                # nothing selected
                return
            pathname = model[_iter][0]
            liststore.remove(_iter)
            pathnames.remove(pathname)
            options.set_list('shred_drives', pathnames)

        vbox = gtk.VBox()

        # TRANSLATORS: 'free' means 'unallocated'
        notice = gtk.Label(
            _("Choose a writable folder for each drive for which to overwrite free space."))
        notice.set_line_wrap(True)
        vbox.pack_start(notice, False)

        liststore = gtk.ListStore(str)

        pathnames = options.get_list('shred_drives')
        if pathnames:
            pathnames = sorted(pathnames)
        if not pathnames:
            pathnames = []
        for pathname in pathnames:
            liststore.append([pathname])
        treeview = gtk.TreeView(model=liststore)
        crt = gtk.CellRendererText()
        tvc = gtk.TreeViewColumn(None, crt, text=0)
        treeview.append_column(tvc)

        vbox.pack_start(treeview)

        # TRANSLATORS: In the preferences dialog, this button adds a path to
        # the list of paths
        button_add = gtk.Button(_p('button', 'Add'))
        button_add.connect("clicked", add_drive_cb)
        # TRANSLATORS: In the preferences dialog, this button removes a path
        # from the list of paths
        button_remove = gtk.Button(_p('button', 'Remove'))
        button_remove.connect("clicked", remove_drive_cb)

        button_box = gtk.HButtonBox()
        button_box.set_layout(gtk.BUTTONBOX_START)
        button_box.pack_start(button_add)
        button_box.pack_start(button_remove)
        vbox.pack_start(button_box, False)

        return vbox
def cleaner_change_dialog(changes, parent):
    """Present a dialog regarding the change of cleaner definitions"""
    def toggled(cell, path, model):
        """Callback for clicking the checkbox"""
        __iter = model.get_iter_from_string(path)
        value = not model.get_value(__iter, 0)
        model.set(__iter, 0, value)

    import pygtk
    pygtk.require('2.0')
    import gtk

    dialog = gtk.Dialog(title=_("Security warning"),
                        parent=parent,
                        flags=gtk.DIALOG_MODAL
                        | gtk.DIALOG_DESTROY_WITH_PARENT)
    dialog.set_default_size(600, 500)

    # create warning
    warnbox = gtk.HBox()
    image = gtk.Image()
    image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
    warnbox.pack_start(image, False)
    # TRANSLATORS: Cleaner definitions are XML data files that define
    # which files will be cleaned.
    label = gtk.Label(
        _("These cleaner definitions are new or have changed. Malicious definitions can damage your system. If you do not trust these changes, delete the files or quit."
          ))
    label.set_line_wrap(True)
    warnbox.pack_start(label, True)
    dialog.vbox.pack_start(warnbox, False)

    # create tree view
    liststore = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING)
    treeview = gtk.TreeView(model=liststore)

    renderer0 = gtk.CellRendererToggle()
    renderer0.set_property('activatable', True)
    renderer0.connect('toggled', toggled, liststore)
    # TRANSLATORS: This is the column label (header) in the tree view for the
    # security dialog
    treeview.append_column(
        gtk.TreeViewColumn(_p('column_label', 'Delete'), renderer0, active=0))
    renderer1 = gtk.CellRendererText()
    # TRANSLATORS: This is the column label (header) in the tree view for the
    # security dialog
    treeview.append_column(
        gtk.TreeViewColumn(_p('column_label', 'Filename'), renderer1, text=1))

    # populate tree view
    for change in changes:
        liststore.append([False, change[0]])

    # populate dialog with widgets
    scrolled_window = gtk.ScrolledWindow()
    scrolled_window.add_with_viewport(treeview)
    dialog.vbox.pack_start(scrolled_window)

    dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
    dialog.add_button(gtk.STOCK_QUIT, gtk.RESPONSE_CLOSE)

    # run dialog
    dialog.show_all()
    while True:
        if gtk.RESPONSE_ACCEPT != dialog.run():
            sys.exit(0)
        delete = []
        for row in liststore:
            b = row[0]
            path = row[1]
            if b:
                delete.append(path)
        if 0 == len(delete):
            # no files selected to delete
            break
        import GuiBasic
        if not GuiBasic.delete_confirmation_dialog(parent,
                                                   mention_preview=False):
            # confirmation not accepted, so do not delete files
            continue
        for path in delete:
            print "info: deleting unrecognized CleanerML '%s'" % path
            os.remove(path)
        break
    dialog.destroy()
def cleaner_change_dialog(changes, parent):
    """Present a dialog regarding the change of cleaner definitions"""

    def toggled(cell, path, model):
        """Callback for clicking the checkbox"""
        __iter = model.get_iter_from_string(path)
        value = not model.get_value(__iter, 0)
        model.set(__iter, 0, value)

    import pygtk
    pygtk.require('2.0')
    import gtk

    dialog = gtk.Dialog(title=_("Security warning"),
                        parent=parent,
                        flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
    dialog.set_default_size(600, 500)

    # create warning
    warnbox = gtk.HBox()
    image = gtk.Image()
    image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
    warnbox.pack_start(image, False)
    # TRANSLATORS: Cleaner definitions are XML data files that define
    # which files will be cleaned.
    label = gtk.Label(
        _("These cleaner definitions are new or have changed. Malicious definitions can damage your system. If you do not trust these changes, delete the files or quit."))
    label.set_line_wrap(True)
    warnbox.pack_start(label, True)
    dialog.vbox.pack_start(warnbox, False)

    # create tree view
    liststore = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING)
    treeview = gtk.TreeView(model=liststore)

    renderer0 = gtk.CellRendererToggle()
    renderer0.set_property('activatable', True)
    renderer0.connect('toggled', toggled, liststore)
    # TRANSLATORS: This is the column label (header) in the tree view for the
    # security dialog
    treeview.append_column(
        gtk.TreeViewColumn(_p('column_label', 'Delete'), renderer0, active=0))
    renderer1 = gtk.CellRendererText()
    # TRANSLATORS: This is the column label (header) in the tree view for the
    # security dialog
    treeview.append_column(
        gtk.TreeViewColumn(_p('column_label', 'Filename'), renderer1, text=1))

    # populate tree view
    for change in changes:
        liststore.append([False, change[0]])

    # populate dialog with widgets
    scrolled_window = gtk.ScrolledWindow()
    scrolled_window.add_with_viewport(treeview)
    dialog.vbox.pack_start(scrolled_window)

    dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
    dialog.add_button(gtk.STOCK_QUIT, gtk.RESPONSE_CLOSE)

    # run dialog
    dialog.show_all()
    while True:
        if gtk.RESPONSE_ACCEPT != dialog.run():
            sys.exit(0)
        delete = []
        for row in liststore:
            b = row[0]
            path = row[1]
            if b:
                delete.append(path)
        if 0 == len(delete):
            # no files selected to delete
            break
        import GuiBasic
        if not GuiBasic.delete_confirmation_dialog(parent, mention_preview=False):
            # confirmation not accepted, so do not delete files
            continue
        for path in delete:
            print "info: deleting unrecognized CleanerML '%s'" % path
            os.remove(path)
        break
    dialog.destroy()
Esempio n. 7
0
    def __locations_page(self, page_type):
        """Return a widget containing a list of files and folders"""
        def add_whitelist_file_cb(button):
            """Callback for adding a file"""
            title = _("Choose a file")
            pathname = GuiBasic.browse_file(self.parent, title)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('File'), pathname])
                pathnames.append(['file', pathname])
                options.set_whitelist_paths(pathnames)

        def add_whitelist_folder_cb(button):
            """Callback for adding a folder"""
            title = _("Choose a folder")
            pathname = GuiBasic.browse_folder(self.parent,
                                              title,
                                              multiple=False,
                                              stock_button=gtk.STOCK_ADD)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('Folder'), pathname])
                pathnames.append(['folder', pathname])
                options.set_whitelist_paths(pathnames)

        def remove_whitelist_path_cb(button):
            """Callback for removing a path"""
            treeselection = treeview.get_selection()
            (model, _iter) = treeselection.get_selected()
            if None == _iter:
                # nothing selected
                return
            pathname = model[_iter][1]
            liststore.remove(_iter)
            for this_pathname in pathnames:
                if this_pathname[1] == pathname:
                    pathnames.remove(this_pathname)
                    options.set_whitelist_paths(pathnames)

        def add_custom_file_cb(button):
            """Callback for adding a file"""
            title = _("Choose a file")
            pathname = GuiBasic.browse_file(self.parent, title)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('File'), pathname])
                pathnames.append(['file', pathname])
                options.set_custom_paths(pathnames)

        def add_custom_folder_cb(button):
            """Callback for adding a folder"""
            title = _("Choose a folder")
            pathname = GuiBasic.browse_folder(self.parent,
                                              title,
                                              multiple=False,
                                              stock_button=gtk.STOCK_ADD)
            if pathname:
                for this_pathname in pathnames:
                    if pathname == this_pathname[1]:
                        print "warning: '%s' already exists in whitelist" % pathname
                        return
                liststore.append([_('Folder'), pathname])
                pathnames.append(['folder', pathname])
                options.set_custom_paths(pathnames)

        def remove_custom_path_cb(button):
            """Callback for removing a path"""
            treeselection = treeview.get_selection()
            (model, _iter) = treeselection.get_selected()
            if None == _iter:
                # nothing selected
                return
            pathname = model[_iter][1]
            liststore.remove(_iter)
            for this_pathname in pathnames:
                if this_pathname[1] == pathname:
                    pathnames.remove(this_pathname)
                    options.set_custom_paths(pathnames)

        vbox = gtk.VBox()

        # load data
        if LOCATIONS_WHITELIST == page_type:
            pathnames = options.get_whitelist_paths()
        elif LOCATIONS_CUSTOM == page_type:
            pathnames = options.get_custom_paths()
        liststore = gtk.ListStore(str, str)
        for paths in pathnames:
            type_code = paths[0]
            type_str = None
            if type_code == 'file':
                type_str = _('File')
            elif type_code == 'folder':
                type_str = _('Folder')
            else:
                raise RuntimeError("Invalid type code: '%s'" % type_code)
            path = paths[1]
            liststore.append([type_str, path])

        if LOCATIONS_WHITELIST == page_type:
            # TRANSLATORS: "Paths" is used generically to refer to both files
            # and folders
            notice = gtk.Label(
                _("Theses paths will not be deleted or modified."))
        elif LOCATIONS_CUSTOM == page_type:
            notice = gtk.Label(
                _("These locations can be selected for deletion."))
        vbox.pack_start(notice, False)

        # create treeview
        treeview = gtk.TreeView(liststore)

        # create column views
        self.renderer0 = gtk.CellRendererText()
        self.column0 = gtk.TreeViewColumn(_("Type"), self.renderer0, text=0)
        treeview.append_column(self.column0)

        self.renderer1 = gtk.CellRendererText()
        # TRANSLATORS: In the tree view "Path" is used generically to refer to a
        # file, a folder, or a pattern describing either
        self.column1 = gtk.TreeViewColumn(_("Path"), self.renderer1, text=1)
        treeview.append_column(self.column1)
        treeview.set_search_column(1)

        # finish tree view
        swindow = gtk.ScrolledWindow()
        swindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        swindow.set_size_request(300, 200)
        swindow.add(treeview)
        vbox.pack_start(swindow)

        # buttons that modify the list
        button_add_file = gtk.Button(_p('button', 'Add file'))
        if LOCATIONS_WHITELIST == page_type:
            button_add_file.connect("clicked", add_whitelist_file_cb)
        elif LOCATIONS_CUSTOM == page_type:
            button_add_file.connect("clicked", add_custom_file_cb)

        button_add_folder = gtk.Button(_p('button', 'Add folder'))
        if LOCATIONS_WHITELIST == page_type:
            button_add_folder.connect("clicked", add_whitelist_folder_cb)
        elif LOCATIONS_CUSTOM == page_type:
            button_add_folder.connect("clicked", add_custom_folder_cb)

        button_remove = gtk.Button(_p('button', 'Remove'))
        if LOCATIONS_WHITELIST == page_type:
            button_remove.connect("clicked", remove_whitelist_path_cb)
        elif LOCATIONS_CUSTOM == page_type:
            button_remove.connect("clicked", remove_custom_path_cb)

        button_box = gtk.HButtonBox()
        button_box.set_layout(gtk.BUTTONBOX_START)
        button_box.pack_start(button_add_file)
        button_box.pack_start(button_add_folder)
        button_box.pack_start(button_remove)
        vbox.pack_start(button_box, False)

        # return page
        return vbox
Esempio n. 8
0
    def __drives_page(self):
        """Return widget containing the drives page"""
        def add_drive_cb(button):
            """Callback for adding a drive"""
            title = _("Choose a folder")
            pathname = GuiBasic.browse_folder(self.parent,
                                              title,
                                              multiple=False,
                                              stock_button=gtk.STOCK_ADD)
            if pathname:
                liststore.append([pathname])
                pathnames.append(pathname)
                options.set_list('shred_drives', pathnames)

        def remove_drive_cb(button):
            """Callback for removing a drive"""
            treeselection = treeview.get_selection()
            (model, _iter) = treeselection.get_selected()
            if None == _iter:
                # nothing selected
                return
            pathname = model[_iter][0]
            liststore.remove(_iter)
            pathnames.remove(pathname)
            options.set_list('shred_drives', pathnames)

        vbox = gtk.VBox()

        # TRANSLATORS: 'free' means 'unallocated'
        notice = gtk.Label(
            _("Choose a writable folder for each drive for which to overwrite free space."
              ))
        notice.set_line_wrap(True)
        vbox.pack_start(notice, False)

        liststore = gtk.ListStore(str)

        pathnames = options.get_list('shred_drives')
        if pathnames:
            pathnames = sorted(pathnames)
        if not pathnames:
            pathnames = []
        for pathname in pathnames:
            liststore.append([pathname])
        treeview = gtk.TreeView(model=liststore)
        crt = gtk.CellRendererText()
        tvc = gtk.TreeViewColumn(None, crt, text=0)
        treeview.append_column(tvc)

        vbox.pack_start(treeview)

        # TRANSLATORS: In the preferences dialog, this button adds a path to
        # the list of paths
        button_add = gtk.Button(_p('button', 'Add'))
        button_add.connect("clicked", add_drive_cb)
        # TRANSLATORS: In the preferences dialog, this button removes a path
        # from the list of paths
        button_remove = gtk.Button(_p('button', 'Remove'))
        button_remove.connect("clicked", remove_drive_cb)

        button_box = gtk.HButtonBox()
        button_box.set_layout(gtk.BUTTONBOX_START)
        button_box.pack_start(button_add)
        button_box.pack_start(button_remove)
        vbox.pack_start(button_box, False)

        return vbox