📄 gui.py
字号:
#!/usr/bin/env python# vim: ts=4:sw=4:expandtab## BleachBit## Copyright (C) 2009 Andrew Ziem## http://bleachbit.sourceforge.net#### This program is free software: you can redistribute it and/or modify## it under the terms of the GNU General Public License as published by## the Free Software Foundation, either version 3 of the License, or## (at your option) any later version.## ## This program is distributed in the hope that it will be useful,## but WITHOUT ANY WARRANTY; without even the implied warranty of## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the## GNU General Public License for more details.## ## You should have received a copy of the GNU General Public License## along with this program. If not, see <http://www.gnu.org/licenses/>.from gettext import gettext as _import pygtkpygtk.require('2.0')import gtkimport gobjectimport osimport sysimport threadingimport FileUtilitiesimport CleanerBackendimport Updatefrom CleanerBackend import backendsfrom Options import optionsfrom globals import APP_NAME, APP_VERSION, appicon_path, \ license_filename, online_update_notification_enableddef open_url(url): """Open an HTTP URL""" print "debug: on_url('%s')" % (url,) try: import gnomevfs gnomevfs.url_show(url) return except: import webbrowser webbrowser.open(url)def threaded(func): """Decoration to create a threaded function""" def wrapper(*args): thread = threading.Thread(target = func, args=args) thread.start() return wrapperclass PreferencesDialog: """Present the preferences dialog and save changes""" def __init__(self, parent): self.dialog = gtk.Dialog(title = _("Preferences"), \ parent = parent, \ flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) self.dialog.set_default_size(500, 300) self.tooltips = gtk.Tooltips() self.tooltips.enable() notebook = gtk.Notebook() notebook.append_page(self.__general_page(), gtk.Label(_("General"))) notebook.append_page(self.__languages_page(), gtk.Label(_("Languages"))) self.dialog.vbox.pack_start(notebook, False) self.dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) def __general_page(self): """Return a widget containing the general page""" def toggle_callback(cell, path): """Callback function to toggle option b""" options.toggle(path) vbox = gtk.VBox() if online_update_notification_enabled: cb_updates = gtk.CheckButton(_("Check periodically for software updates via the Internet")) cb_updates.set_active(options.get('check_online_updates')) cb_updates.connect('toggled', toggle_callback, 'check_online_updates') self.tooltips.set_tip(cb_updates, _("If an update is found, you will be given the option to view information about it. Then, you may manually download and install the update.")) vbox.pack_start(cb_updates, False) cb_shred = gtk.CheckButton(_("Overwrite files to hide contents (ineffective in some situations)")) cb_shred.set_active(options.get('shred')) cb_shred.connect('toggled', toggle_callback, 'shred') self.tooltips.set_tip(cb_shred, _("Overwriting is ineffective on some file systems and with certain BleachBit operations. Overwriting is significantly slower.")) vbox.pack_start(cb_shred, False) return vbox def __languages_page(self): """Return widget containing the languages page""" def preserve_toggled_cb(cell, path, liststore): """Callback for toggling the 'preserve' column""" __iter = liststore.get_iter_from_string(path) value = not liststore.get_value(__iter, 0) liststore.set(__iter, 0, value) langid = liststore[path][1] options.set_language(langid, value) vbox = gtk.VBox() notice = gtk.Label(_("All languages will be deleted except those checked.")) vbox.pack_start(notice) # populate data import Unix liststore = gtk.ListStore('gboolean', str, str) for lang in Unix.locales.iterate_languages(): preserve = options.get_language(lang) native = Unix.locales.native_name(lang) liststore.append( [ preserve, lang, native ] ) # create treeview treeview = gtk.TreeView(liststore) # create column views self.renderer0 = gtk.CellRendererToggle() self.renderer0.set_property('activatable', True) self.renderer0.connect('toggled', preserve_toggled_cb, liststore) self.column0 = gtk.TreeViewColumn(_("Preserve"), self.renderer0, active=0) treeview.append_column(self.column0) self.renderer1 = gtk.CellRendererText() self.column1 = gtk.TreeViewColumn(_("Code"), self.renderer1, text=1) treeview.append_column(self.column1) self.renderer2 = gtk.CellRendererText() self.column2 = gtk.TreeViewColumn(_("Name"), self.renderer2, text=2) treeview.append_column(self.column2) treeview.set_search_column(2) # finish swindow = gtk.ScrolledWindow() swindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) swindow.set_size_request(500, 300) swindow.add(treeview) vbox.pack_start(swindow, False) return vbox def run(self): """Run the dialog""" self.dialog.show_all() self.dialog.run() self.dialog.destroy()def delete_confirmation_dialog(parent): """Return boolean whether OK to delete files.""" dialog = gtk.Dialog(title = _("Delete confirmation"), parent = parent, flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) dialog.set_default_size(300, -1) hbox = gtk.HBox(homogeneous=False, spacing=10) icon = gtk.Image() icon.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG) hbox.pack_start(icon, False) question = gtk.Label(_("Are you sure you want to delete files according to the selected operations? The actual files that will be deleted may have changed since you ran the preview. Files cannot be undeleted.")) question.set_line_wrap(True) hbox.pack_start(question, False) dialog.vbox.pack_start(hbox, False) dialog.vbox.set_spacing(10) dialog.add_button(gtk.STOCK_CANCEL, False) dialog.add_button(gtk.STOCK_DELETE, True) dialog.set_default_response(gtk.RESPONSE_CANCEL) dialog.show_all() ret = dialog.run() dialog.destroy() return retclass TreeInfoModel: """Model holds information to be displayed in the tree view""" def __init__(self): self.tree_store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT) for key in sorted(backends): c_name = backends[key].get_name() c_id = backends[key].get_id() c_value = options.get_tree(c_id, None) parent = self.tree_store.append(None, (c_name, c_value, c_id)) for (o_id, o_name, o_value) in backends[key].get_options(): o_value = options.get_tree(c_id, o_id) self.tree_store.append(parent, (o_name, o_value, o_id)) if None == self.tree_store: raise Exception("cannot create tree store") self.tree_store.connect("row-changed", self.on_row_changed) return def on_row_changed(self, __treemodel, path, __iter): """Event handler for when a row changes""" parent = self.tree_store[path[0]][2] child = None if 2 == len(path): child = self.tree_store[path][2] value = self.tree_store[path][1] print "debug: on_row_changed('%s', '%s', '%s', '%s')" % (path, parent, child, value) options.set_tree(parent, child, value) def get_model(self): """Return the tree store""" return self.tree_storeclass TreeDisplayModel: """Displays the info model in a view""" def make_view(self, model): """Create and return a TreeView object""" self.view = gtk.TreeView(model) # first column self.renderer0 = gtk.CellRendererText() self.column0 = gtk.TreeViewColumn(_("Name"), self.renderer0, text=0) self.view.append_column(self.column0) self.view.set_search_column(0) # second column self.renderer1 = gtk.CellRendererToggle() self.renderer1.set_property('activatable', True) self.renderer1.connect('toggled', self.col1_toggled_cb, model) self.column1 = gtk.TreeViewColumn(_("Active"), self.renderer1) self.column1.add_attribute(self.renderer1, "active", 1) self.view.append_column(self.column1) # finish self.view.expand_all() return self.view def col1_toggled_cb(self, cell, path, model): """When toggles the checkbox""" model[path][1] = not model[path][1] i = model.get_iter(path) # if toggled on, enable the parent parent = model.iter_parent(i) if None != parent and model[path][1]: model[parent][1] = True # if all siblings toggled off, disable the parent if parent and not model[path][1]: sibling = model.iter_nth_child(parent, 0) any_true = False while sibling: print "debug: col1_toggled_cb: %s = %s" % (model[sibling][0], model[sibling][1]) if model[sibling][1]: any_true = True sibling = model.iter_next(sibling) if not any_true: model[parent][1] = False # if toggled and has children, do the same for each child child = model.iter_children(i) while child: model[child][1] = model[path][1] child = model.iter_next(child) returnclass GUI: """The main application GUI""" ui = \ '''<ui> <menubar name="MenuBar"> <menu action="File"> <menuitem action="Quit"/> </menu> <menu action="Edit"> <menuitem action="Preferences"/> </menu> <menu action="Help"> <menuitem action="About"/> </menu> </menubar> </ui>''' def append_text(self, text, tag = None, __iter = None): if not __iter: __iter = self.textbuffer.get_end_iter() if tag: self.textbuffer.insert_with_tags_by_name(__iter, text, tag) else: self.textbuffer.insert(__iter, text) def on_selection_changed(self, selection): """When the tree view selection changed""" model = self.view.get_model() selected_rows = selection.get_selected_rows() if 0 == len(selected_rows[1]): # happens when searching in the tree view return paths = selected_rows[1][0] row = paths[0] #print "debug: on_selection_changed: paths = '%s', row='%s', model[paths][0] = '%s'" % (paths,row, model[paths][0]) name = model[row][0] cleaner_id = model[row][2] self.progressbar.hide() description = backends[cleaner_id].get_description() #print "debug: on_selection_changed: row='%s', name='%s', desc='%s'," % ( row, name ,description) self.textbuffer.set_text("") self.append_text(name + "\n", 'operation') self.append_text(description + "\n\n\n") for (label, description) in backends[cleaner_id].get_option_descriptions(): self.append_text(label + ': ', 'option_label') self.append_text(description + "\n\n") def get_selected_operations(self): """Return a list of the IDs of the selected operations in the tree view""" ret = [] model = self.tree_store.get_model() __iter = model.get_iter_root() while __iter: #print "debug: get_selected_operations: iter id = '%s', value='%s'" % (model[iter][2], model[iter][1]) if True == model[__iter][1]: ret.append(model[__iter][2]) __iter = model.iter_next(__iter) return ret def get_operation_options(self, operation): """For the given operation ID, return a list of the selected option IDs.""" ret = [] model = self.tree_store.get_model() __iter = model.get_iter_root() while __iter: #print "debug: get_operation_options: iter id = '%s', value='%s'" % (model[iter][2], model[iter][1])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -