3
# Ubuntu Tweak - PyGTK based desktop configure tool
5
# Copyright (C) 2007-2008 TualatriX <tualatrix@gmail.com>
7
# Ubuntu Tweak is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# Ubuntu Tweak is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with Ubuntu Tweak; if not, write to the Free Software Foundation, Inc.,
19
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27
from tweak import TweakModule
28
from common.utils import *
29
from common.misc import filesizeformat
30
from common.policykit import PolkitButton, DbusProxy
31
from common.package import package_worker
32
from common.widgets.dialogs import *
33
from common.widgets.utils import ProcessDialog
34
from backends.packageconfig import PATH
45
def __init__(self, pkg, des):
49
class CleanConfigDialog(ProcessDialog):
50
def __init__(self, parent, pkgs):
53
self.user_action = False
55
super(CleanConfigDialog, self).__init__(parent = parent)
56
self.set_dialog_lable(_('Cleaning Package Config'))
57
self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
59
def process_data(self):
61
if self.user_action == True:
63
self.set_progress_text(_('Cleaning...%s') % pkg)
64
proxy.clean_config(pkg)
75
class CleanCacheDailog(ProcessDialog):
76
def __init__(self, parent, files):
80
self.user_action = False
82
super(CleanCacheDailog, self).__init__(parent=parent)
83
self.set_dialog_lable(_('Cleaning Package Cache'))
84
self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
86
def process_data(self):
87
for file in self.files:
88
if self.user_action == True:
90
self.set_progress_text(_('Cleaning...%s') % os.path.basename(file))
91
result = proxy.delete_file(file)
105
class PackageView(gtk.TreeView):
107
'checked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
108
(gobject.TYPE_BOOLEAN,)),
109
'cleaned': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ())
113
super(PackageView, self).__init__()
115
model = self.__create_model()
116
self.set_model(model)
117
model.set_sort_column_id(COLUMN_NAME, gtk.SORT_ASCENDING)
119
self.__check_list = []
120
self.package_worker = package_worker
124
self.mode = 'package'
125
self.update_package_model()
126
self.selection = self.get_selection()
127
self.set_sensitive(False)
129
def __create_model(self):
130
model = gtk.ListStore(
131
gobject.TYPE_BOOLEAN,
139
def __add_column(self):
140
renderer = gtk.CellRendererToggle()
141
renderer.connect('toggled', self.on_package_toggled)
142
column = gtk.TreeViewColumn(' ', renderer, active = COLUMN_CHECK)
143
column.set_sort_column_id(COLUMN_CHECK)
144
self.append_column(column)
146
self.__column = gtk.TreeViewColumn(_('Package'))
147
self.__column.set_sort_column_id(COLUMN_NAME)
148
self.__column.set_spacing(5)
149
renderer = gtk.CellRendererPixbuf()
150
self.__column.pack_start(renderer, False)
151
self.__column.set_attributes(renderer, pixbuf = COLUMN_ICON)
153
renderer = gtk.CellRendererText()
154
self.__column.pack_start(renderer, True)
155
self.__column.set_attributes(renderer, markup = COLUMN_DISPLAY)
157
self.append_column(self.__column)
160
return self.__check_list
162
def update_package_model(self):
164
model = self.get_model()
166
self.mode = 'package'
168
icon = get_icon_with_name('deb', 24)
169
list = self.package_worker.list_autoremovable()
170
self.total_num = len(list)
171
self.__column.set_title(_('Packages'))
173
while gtk.events_pending():
177
desc = self.package_worker.get_pkgsummary(pkg)
179
iter = model.append()
185
COLUMN_DISPLAY, '<b>%s</b>\n%s' % (pkg, desc)
190
def update_kernel_model(self):
192
model = self.get_model()
196
icon = get_icon_with_name('deb', 24)
197
list = self.package_worker.list_unneeded_kerenl()
198
self.total_num = len(list)
199
self.__column.set_title(_('Packages'))
201
while gtk.events_pending():
205
desc = self.package_worker.get_pkgsummary(pkg)
207
iter = model.append()
213
COLUMN_DISPLAY, '<b>%s</b>\n%s' % (pkg, desc)
217
def update_cache_model(self):
219
model = self.get_model()
223
cache_dir = '/var/cache/apt/archives'
224
icon = get_icon_with_name('deb', 24)
225
list = map(lambda file: '%s/%s' % (cache_dir, file),
226
filter(lambda x:x.endswith('deb'), os.listdir(cache_dir)))
227
self.total_num = len(list)
228
self.__column.set_title(_('Package Cache'))
230
while gtk.events_pending():
234
size = str(os.path.getsize(pkg))
236
iter = model.append()
242
COLUMN_DISPLAY, _('<b>%s</b>\nTake %s of disk space') % (os.path.basename(pkg), filesizeformat(size))
247
def update_config_model(self):
249
model = self.get_model()
252
# command = "dpkg -l |awk '/^rc/ {print $2}'"
253
icon = get_icon_with_name('text', 24)
256
for line in os.popen('dpkg -l'):
258
temp_list = line.split()
259
status, pkg = temp_list[0], temp_list[1]
262
pkg = AbsPkg(pkg, ' '.join(temp_list[3:]))
267
self.total_num = len(list)
268
self.__column.set_title(_('Package Config'))
270
while gtk.events_pending():
274
iter = model.append()
278
COLUMN_NAME, pkg.name,
280
COLUMN_DISPLAY, '<b>%s</b>\n%s' % (pkg.name, pkg.des),
284
def on_package_toggled(self, cell, path):
285
model = self.get_model()
286
iter = model.get_iter(path)
288
check = model.get_value(iter, COLUMN_CHECK)
289
model.set(iter, COLUMN_CHECK, not check)
291
self.__check_list.append(model.get_value(iter, COLUMN_NAME))
293
self.__check_list.remove(model.get_value(iter, COLUMN_NAME))
295
if len(self.__check_list) == self.total_num:
296
self.emit('checked', True)
298
self.emit('checked', False)
300
self.set_column_title()
302
def set_column_title(self):
303
if self.mode == 'package' or self.mode == 'kernel':
304
n = len(self.__check_list)
305
self.__column.set_title(
306
gettext.ngettext('%d package selected to remove' % n,
307
'%d packages selected to remove' % n, n))
308
elif self.mode == 'cache':
309
self.compute_cache_size()
310
self.__column.set_title(_('%s of space will be freed') % filesizeformat(self.size))
312
def compute_cache_size(self):
315
model = self.get_model()
316
model.foreach(self.__cache_foreach)
318
def __cache_foreach(self, model, path, iter):
319
cache = model.get_value(iter, COLUMN_NAME)
321
if cache in self.__check_list:
322
size = model.get_value(iter, COLUMN_DESC)
323
self.size = self.size + int(size)
325
def select_all(self, check = True):
326
self.__check_list = []
328
model = self.get_model()
329
model.foreach(self.__select_foreach, check)
330
self.emit('checked', check)
332
self.set_column_title()
334
def __select_foreach(self, model, path, iter, check):
335
model.set(iter, COLUMN_CHECK, check)
337
self.__check_list.append(model.get_value(iter, COLUMN_NAME))
339
def clean_selected_package(self):
341
state = self.package_worker.perform_action(self.get_toplevel(), [],self.__check_list)
344
self.show_success_dialog()
346
self.show_failed_dialog()
348
package_worker.update_apt_cache(True)
349
if self.mode == 'package':
350
self.update_package_model()
352
self.update_kernel_model()
353
self.__check_list = []
357
def clean_selected_cache(self):
359
model = self.get_model()
361
dialog = CleanCacheDailog(self.get_toplevel(), self.get_list())
362
if dialog.run() == gtk.RESPONSE_REJECT:
364
dialog.user_action = True
365
self.show_usercancel_dialog()
367
if not dialog.user_action:
368
if dialog.error == False:
369
self.show_success_dialog()
371
self.show_failed_dialog()
373
self.update_cache_model()
377
def clean_selected_config(self):
379
model = self.get_model()
381
dialog = CleanConfigDialog(self.get_toplevel(), self.get_list())
382
if dialog.run() == gtk.RESPONSE_REJECT:
384
dialog.user_action = True
385
self.show_usercancel_dialog()
387
self.show_success_dialog()
389
package_worker.update_apt_cache(True)
390
self.update_config_model()
394
def show_usercancel_dialog(self):
395
InfoDialog(_('Canceled by user!')).launch()
397
def show_success_dialog(self):
398
InfoDialog(_('Clean up Successful!')).launch()
400
def show_failed_dialog(self):
401
ErrorDialog(_('Clean up Failed!')).launch()
404
window = self.get_toplevel().window
406
window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
408
def unset_busy(self):
409
window = self.get_toplevel().window
411
window.set_cursor(None)
413
class PackageCleaner(TweakModule):
414
__title__ = _('Package Cleaner')
415
__desc__ = _('Free up disk space by removing unneeded packages and cleaning the package download cache.')
416
__icon__ = 'edit-clear'
417
__category__ = 'application'
420
TweakModule.__init__(self)
424
self.button_list = []
425
self.current_button = 0
427
hbox = gtk.HBox(False, 0)
428
self.add_start(hbox, True, True, 0)
430
sw = gtk.ScrolledWindow()
431
sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
432
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
435
vbox = gtk.VBox(False, 8)
436
hbox.pack_start(vbox, False, False, 5)
439
self.treeview = PackageView()
440
self.treeview.set_rules_hint(True)
441
self.treeview.connect('checked', self.on_item_checked)
442
self.treeview.connect('cleaned', self.on_item_cleaned)
443
sw.add(self.treeview)
446
self.pkg_button = self.create_button(_('Clean Package'),
447
gtk.image_new_from_pixbuf(get_icon_with_name('deb', 24)),
448
self.treeview.update_package_model)
449
vbox.pack_start(self.pkg_button, False, False, 0)
451
self.cache_button = self.create_button(_('Clean Cache'),
452
gtk.image_new_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_BUTTON),
453
self.treeview.update_cache_model)
454
vbox.pack_start(self.cache_button, False, False, 0)
456
self.config_button = self.create_button(_('Clean Config'),
457
gtk.image_new_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_BUTTON),
458
self.treeview.update_config_model)
459
vbox.pack_start(self.config_button, False, False, 0)
461
self.kernel_button = self.create_button(_('Clean Kernel'),
462
gtk.image_new_from_pixbuf(get_icon_with_name('start-here', 24)),
463
self.treeview.update_kernel_model)
464
vbox.pack_start(self.kernel_button, False, False, 0)
467
self.select_button = gtk.CheckButton(_('Select All'))
468
self.select_button.set_sensitive(False)
469
self.__handler_id = self.select_button.connect('toggled', self.on_select_all)
470
self.add_start(self.select_button, False, False, 0)
473
hbox = gtk.HBox(False, 0)
474
self.pack_end(hbox, False ,False, 5)
476
un_lock = PolkitButton()
477
un_lock.connect('changed', self.on_polkit_action)
478
hbox.pack_end(un_lock, False, False, 5)
480
self.clean_button = gtk.Button(stock=gtk.STOCK_CLEAR)
481
set_label_for_stock_button(self.clean_button, _('_Cleanup'))
482
self.clean_button.connect('clicked', self.on_clean_button_clicked)
483
self.clean_button.set_sensitive(False)
484
hbox.pack_end(self.clean_button, False, False, 5)
488
def create_button(self, text, image, function):
489
button = gtk.ToggleButton(text)
490
if len(self.button_list) == 0:
491
button.set_active(True)
492
self.button_list.append(button)
493
button.set_image(image)
494
button.set_data('handler', button.connect('toggled', self.on_button_toggled))
495
button.set_data('function', function)
499
def on_select_all(self, widget):
500
check = widget.get_active()
502
self.treeview.select_all(check)
504
def on_item_checked(self, widget, all):
505
list = widget.get_list()
507
self.clean_button.set_sensitive(True)
509
self.clean_button.set_sensitive(False)
511
self.select_button.handler_block(self.__handler_id)
513
self.select_button.set_active(True)
515
self.select_button.set_active(False)
516
self.select_button.handler_unblock(self.__handler_id)
518
def on_item_cleaned(self, widget):
519
self.select_button.set_active(False)
520
self.clean_button.set_sensitive(False)
522
def on_button_toggled(self, widget):
523
self.select_button.set_active(False)
525
if self.current_button != self.button_list.index(widget):
526
button = self.button_list[self.current_button]
528
handler = button.get_data('handler')
529
button.handler_block(handler)
530
button.set_active(False)
531
button.handler_unblock(handler)
533
widget.set_active(True)
534
self.current_button = self.button_list.index(widget)
536
function = widget.get_data('function')
538
elif self.current_button == self.button_list.index(widget):
539
widget.set_active(True)
541
def on_clean_button_clicked(self, widget):
542
mode = self.treeview.mode
543
if mode == 'package' or mode == 'kernel':
544
self.treeview.clean_selected_package()
545
elif mode == 'cache':
546
self.treeview.clean_selected_cache()
547
elif mode == 'config':
548
self.treeview.clean_selected_config()
550
def on_polkit_action(self, widget, action):
553
self.treeview.set_sensitive(True)
554
self.select_button.set_sensitive(True)
555
proxy = DbusProxy(PATH)
557
AuthenticateFailDialog().launch()