def preview_or_run_operations(self, really_delete, operations=None): """Preview operations or run operations (delete files)""" assert(isinstance(really_delete, bool)) from bleachbit import Worker self.start_time = None if None == operations: operations = {} for operation in self.get_selected_operations(): operations[operation] = self.get_operation_options(operation) assert(isinstance(operations, dict)) if 0 == len(operations): GuiBasic.message_dialog(self.window, _("You must select an operation"), gtk.MESSAGE_WARNING, gtk.BUTTONS_OK) return try: self.set_sensitive(False) self.textbuffer.set_text("") self.progressbar.show() self.worker = Worker.Worker(self, really_delete, operations) except Exception: logger.exception('Error in Worker()') else: self.start_time = time.time() worker = self.worker.run() gobject.idle_add(worker.next)
def create_menubar(self): """Create the menu bar (file, help)""" # Create a UIManager instance uimanager = gtk.UIManager() # Add the accelerator group to the top level window accelgroup = uimanager.get_accel_group() self.window.add_accel_group(accelgroup) # Create an ActionGroup actiongroup = gtk.ActionGroup('UIManagerExample') self.actiongroup = actiongroup # Create actions entries = ( ('ShredFiles', None, _('_Shred Files'), None, None, self.cb_shred_file), ('ShredFolders', None, _('Sh_red Folders'), None, None, self.cb_shred_file), ('WipeFreeSpace', None, _('_Wipe Free Space'), None, None, self.cb_wipe_free_space), ('ShredQuit', None, _('S_hred Settings and Quit'), None, None, self.cb_shred_quit), ('Quit', gtk.STOCK_QUIT, _('_Quit'), None, None, lambda *dummy: gtk.main_quit()), ('File', None, _('_File')), ('Preferences', gtk.STOCK_PREFERENCES, _( "Preferences"), None, None, self.cb_preferences_dialog), ('ShredClipboard', None, _("Shred Paths from Clipboard"), None, None, self.cb_menu_shred_clipboard), ('Edit', None, _("_Edit")), ('HelpContents', gtk.STOCK_HELP, _('Help Contents'), 'F1', None, lambda link: GuiBasic.open_url( bleachbit.help_contents_url, self.window)), ('ReleaseNotes', gtk.STOCK_INFO, _('_Release Notes'), None, None, lambda link: GuiBasic.open_url( bleachbit.release_notes_url, self.window)), ('SystemInformation', None, _('_System Information'), None, None, lambda foo: self.diagnostic_dialog(self.window)), ('About', gtk.STOCK_ABOUT, _( '_About'), None, None, self.about), ('Help', None, _("_Help"))) actiongroup.add_actions(entries) actiongroup.get_action('Quit').set_property('short-label', '_Quit') # Add the actiongroup to the uimanager uimanager.insert_action_group(actiongroup, 0) # Add a UI description uimanager.add_ui_from_string(self.ui) # Create a MenuBar menubar = uimanager.get_widget('/MenuBar') return menubar
def set_cleaner(self, path, model, parent_window, value=None): """Activate or deactive option of cleaner.""" if None == value: # if not value given, toggle current value value = not model[path][1] assert(type(value) is types.BooleanType) assert(type(model) is gtk.TreeStore) cleaner_id = None i = path if type(i) is str: # type is either str or gtk.TreeIter i = model.get_iter(path) parent = model.iter_parent(i) if None != parent: # this is an option (child), not a cleaner (parent) cleaner_id = model[parent][2] option_id = model[path][2] if cleaner_id and value: # when toggling an option, present any warnings warning = backends[cleaner_id].get_warning(option_id) # TRANSLATORS: %(cleaner) may be Firefox, System, etc. # %(option) may be cache, logs, cookies, etc. # %(warning) may be 'This option is really slow' msg = _("Warning regarding %(cleaner)s - %(option)s:\n\n%(warning)s") % \ {'cleaner': model[parent][0], 'option': model[path][0], 'warning': warning} if warning: resp = GuiBasic.message_dialog(parent_window, msg, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK_CANCEL) if gtk.RESPONSE_OK != resp: # user cancelled, so don't toggle option return model[path][1] = value
def about(self, __event): """Create and show the about dialog""" if 'nt' != os.name and (2, 16, 6) != gtk.gtk_version: # workaround for broken GTK+ # (https://bugs.launchpad.net/bleachbit/+bug/797012) gtk.about_dialog_set_url_hook(lambda dialog, link: GuiBasic.open_url(link, self.window, False)) dialog = gtk.AboutDialog() dialog.set_comments(_("Program to clean unnecessary files")) dialog.set_copyright("Copyright (C) 2008-2018 Andrew Ziem") try: with open(bleachbit.license_filename) as f: dialog.set_license(f.read()) except (IOError, TypeError): # In case the license file cannot be read, there will be an # IOError. In case the license file does not exist, the filename # will be none, causing a TypeError. dialog.set_license( _("GNU General Public License version 3 or later.\nSee http://www.gnu.org/licenses/gpl-3.0.txt")) dialog.set_name(APP_NAME) # TRANSLATORS: Maintain the names of translators here. # Launchpad does this automatically for translations # typed in Launchpad. This is a special string shown # in the 'About' box. dialog.set_translator_credits(_("translator-credits")) dialog.set_version(bleachbit.APP_VERSION) dialog.set_website(bleachbit.APP_URL) dialog.set_transient_for(self.window) if appicon_path and os.path.exists(appicon_path): icon = gtk.gdk.pixbuf_new_from_file(appicon_path) dialog.set_logo(icon) dialog.run() dialog.hide()
def cb_shred_file(self, action, param): """Callback for shredding a file""" # get list of files paths = GuiBasic.browse_files(self._window, _("Choose files to shred")) if not paths: return GUI.shred_paths(self._window, paths)
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 cb_shred_file(self, action): """Callback for shredding a file or folder""" # get list of files if 'ShredFiles' == action.get_name(): paths = GuiBasic.browse_files(self.window, _("Choose files to shred")) elif 'ShredFolders' == action.get_name(): paths = GuiBasic.browse_folder(self.window, _("Choose folder to shred"), multiple=True, stock_button=gtk.STOCK_DELETE) else: raise RuntimeError("Unexpected kind in cb_shred_file") if not paths: return self.shred_paths(paths)
def cb_shred_folder(self, action, param): """Callback for shredding a folder""" paths = GuiBasic.browse_folder(self._window, _("Choose folder to shred"), multiple=True, stock_button=_('_Delete')) if not paths: return GUI.shred_paths(self._window, paths)
def run_operations(self, __widget): """Event when the 'delete' toolbar button is clicked.""" # fixme: should present this dialog after finding operations # Disable delete confirmation message. # if the option is selected under preference. if options.get("delete_confirmation"): if not GuiBasic.delete_confirmation_dialog(self.window, True): return self.preview_or_run_operations(True)
def get_autostart_path(): """Return the path of the BleachBit shortcut in the user's startup folder""" try: startupdir = shell.SHGetSpecialFolderPath(None, shellcon.CSIDL_STARTUP) except: # example of failure # https://www.bleachbit.org/forum/error-windows-7-x64-bleachbit-091 logger.exception('exception in get_autostart_path()') msg = 'Error finding user startup folder: %s ' % ( str(sys.exc_info()[1])) from bleachbit import GuiBasic GuiBasic.message_dialog(None, msg) # as a fallback, guess # Windows XP: C:\Documents and Settings\(username)\Start Menu\Programs\Startup # Windows 7: # C:\Users\(username)\AppData\Roaming\Microsoft\Windows\Start # Menu\Programs\Startup startupdir = bleachbit.expandvars('$USERPROFILE\\Start Menu\\Programs\\Startup') if not os.path.exists(startupdir): startupdir = bleachbit.expandvars('$APPDATA\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup') return os.path.join(startupdir, 'bleachbit.lnk')
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]: logger.warning("'%s' already exists in whitelist", pathname) return liststore.append([_('File'), pathname]) pathnames.append(['file', pathname]) options.set_custom_paths(pathnames)
def cb_run_option(self, widget, really_delete, cleaner_id, option_id): """Callback from context menu to delete/preview a single option""" operations = {cleaner_id: [option_id]} # preview if not really_delete: self.preview_or_run_operations(False, operations) return # delete if GuiBasic.delete_confirmation_dialog(self.window, mention_preview=False): self.preview_or_run_operations(True, operations) return
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]: logger.warning("'%s' already exists in whitelist", pathname) return liststore.append([_('Folder'), pathname]) pathnames.append(['folder', pathname]) options.set_custom_paths(pathnames)
def cb_wipe_free_space(self, action): """callback to wipe free space in arbitrary folder""" path = GuiBasic.browse_folder(self.window, _("Choose a folder"), multiple=False, stock_button=gtk.STOCK_OK) if not path: # user cancelled return backends['_gui'] = Cleaner.create_wipe_cleaner(path) # execute operations = {'_gui': ['free_disk_space']} self.preview_or_run_operations(True, operations)
def shred_paths(self, paths): """Shred file or folders If user confirms and files are deleted, returns True. If user aborts, returns False. """ # create a temporary cleaner object backends['_gui'] = Cleaner.create_simple_cleaner(paths) # preview and confirm operations = {'_gui': ['files']} self.preview_or_run_operations(False, operations) if GuiBasic.delete_confirmation_dialog(self.window, mention_preview=False): # delete self.preview_or_run_operations(True, operations) return True # user aborted return False
def _confirm_delete(self, mention_preview, shred_settings=False): if options.get("delete_confirmation"): return GuiBasic.delete_confirmation_dialog( self, mention_preview, shred_settings=shred_settings) return True
def cb_help(self, action, param): """Callback for help""" GuiBasic.open_url(bleachbit.help_contents_url, self._window)