2
# Copyright (C) 2008-2009 Oprea Dan
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License along
15
# with this program; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25
from PyQt4.QtGui import *
26
from PyQt4.QtCore import *
27
from PyKDE4.kdecore import *
28
from PyKDE4.kdeui import *
29
from PyKDE4.kio import *
38
class PopupAutomaticBackupAction( KAction ):
39
def __init__( self, list, id, label ):
40
KAction.__init__( self, label, list )
45
QObject.connect( self, SIGNAL('triggered()'), self.on_selected )
47
def on_selected( self ):
48
item = self.list.currentItem()
50
item.setText( 1, QString.fromUtf8( self.label ) )
51
item.setData( 0, Qt.UserRole, QVariant( self.id ) )
54
class SettingsDialog( KDialog ):
55
def __init__( self, parent ):
56
KDialog.__init__( self, parent )
57
self.config = parent.config
59
self.setWindowIcon( KIcon( 'configure' ) )
60
self.setCaption( QString.fromUtf8( _( 'Settings' ) ) )
62
self.main_widget = KTabWidget( self )
63
self.setMainWidget( self.main_widget )
66
tab_widget = QWidget( self )
67
self.main_widget.addTab( tab_widget, QString.fromUtf8( _( 'General' ) ) )
68
layout = QVBoxLayout( tab_widget )
70
#Where to save snapshots
71
group_box = QGroupBox( self )
72
group_box.setTitle( QString.fromUtf8( _( 'Where to save snapshots' ) ) )
73
layout.addWidget( group_box )
75
hlayout = QHBoxLayout( group_box )
77
self.edit_snapshots_path = KLineEdit( QString.fromUtf8( self.config.get_snapshots_path() ), self )
78
self.edit_snapshots_path.setReadOnly( True )
79
hlayout.addWidget( self.edit_snapshots_path )
81
self.btn_snapshots_path = KPushButton( KIcon( 'folder' ), '', self )
82
hlayout.addWidget( self.btn_snapshots_path )
83
QObject.connect( self.btn_snapshots_path, SIGNAL('clicked()'), self.on_btn_snapshots_path_clicked )
86
group_box = QGroupBox( self )
87
self.global_schedule_group_box = group_box
88
group_box.setTitle( QString.fromUtf8( _( 'Schedule' ) ) )
89
layout.addWidget( group_box )
91
hlayout = QHBoxLayout( group_box )
93
self.combo_automatic_snapshots = KComboBox( self )
94
hlayout.addWidget( self.combo_automatic_snapshots )
95
self.fill_combo( self.combo_automatic_snapshots, self.config.AUTOMATIC_BACKUP_MODES, self.config.get_automatic_backup_mode() )
101
tab_widget = QWidget( self )
102
self.main_widget.addTab( tab_widget, QString.fromUtf8( _( 'Include' ) ) )
103
layout = QVBoxLayout( tab_widget )
105
self.list_include = QTreeWidget( self )
106
self.list_include.setRootIsDecorated( False )
107
#self.list_include.setEditTriggers( QAbstractItemView.NoEditTriggers )
108
self.list_include.setHeaderLabels( [ QString.fromUtf8( _('Include folders') ), QString.fromUtf8( _('Automatic backup') ) ] )
109
self.list_include.header().setResizeMode( 0, QHeaderView.Stretch )
111
self.popup_automatic_backup = KMenu( self )
112
keys = self.config.AUTOMATIC_BACKUP_MODES.keys()
115
self.popup_automatic_backup.addAction( PopupAutomaticBackupAction( self.list_include, key, QString.fromUtf8( self.config.AUTOMATIC_BACKUP_MODES[ key ] ) ) )
117
QObject.connect( self.list_include, SIGNAL('itemActivated(QTreeWidgetItem*,int)'), self.on_list_include_item_activated )
118
layout.addWidget( self.list_include )
120
for include in self.config.get_include_folders():
121
self.add_include( include )
123
buttons_layout = QHBoxLayout()
124
layout.addLayout( buttons_layout )
126
self.btn_include_add = KPushButton( KStandardGuiItem.add(), self )
127
buttons_layout.addWidget( self.btn_include_add )
128
QObject.connect( self.btn_include_add, SIGNAL('clicked()'), self.on_btn_include_add_clicked )
130
self.btn_include_remove = KPushButton( KStandardGuiItem.remove(), self )
131
buttons_layout.addWidget( self.btn_include_remove )
132
QObject.connect( self.btn_include_remove, SIGNAL('clicked()'), self.on_btn_include_remove_clicked )
135
tab_widget = QWidget( self )
136
self.main_widget.addTab( tab_widget, QString.fromUtf8( _( 'Exclude' ) ) )
137
layout = QVBoxLayout( tab_widget )
139
self.list_exclude = KListWidget( self )
140
layout.addWidget( self.list_exclude )
142
for exclude in self.config.get_exclude_patterns():
143
self.add_exclude( exclude )
145
buttons_layout = QHBoxLayout()
146
layout.addLayout( buttons_layout )
148
self.btn_exclude_add = KPushButton( KStandardGuiItem.add(), self )
149
buttons_layout.addWidget( self.btn_exclude_add )
150
QObject.connect( self.btn_exclude_add, SIGNAL('clicked()'), self.on_btn_exclude_add_clicked )
152
self.btn_exclude_file = KPushButton( KStandardGuiItem.add(), self )
153
self.btn_exclude_file.setText( QString.fromUtf8( _( 'Add file' ) ) )
154
buttons_layout.addWidget( self.btn_exclude_file )
155
QObject.connect( self.btn_exclude_file, SIGNAL('clicked()'), self.on_btn_exclude_file_clicked )
157
self.btn_exclude_folder = KPushButton( KStandardGuiItem.add(), self )
158
self.btn_exclude_folder.setText( QString.fromUtf8( _( 'Add folder' ) ) )
159
buttons_layout.addWidget( self.btn_exclude_folder )
160
QObject.connect( self.btn_exclude_folder, SIGNAL('clicked()'), self.on_btn_exclude_folder_clicked )
162
self.btn_exclude_remove = KPushButton( KStandardGuiItem.remove(), self )
163
buttons_layout.addWidget( self.btn_exclude_remove )
164
QObject.connect( self.btn_exclude_remove, SIGNAL('clicked()'), self.on_btn_exclude_remove_clicked )
167
tab_widget = QWidget( self )
168
self.main_widget.addTab( tab_widget, QString.fromUtf8( _( 'Auto-remove' ) ) )
169
layout = QGridLayout( tab_widget )
171
#remove old snapshots
172
enabled, value, unit = self.config.get_remove_old_snapshots()
174
self.cb_remove_older_then = QCheckBox( QString.fromUtf8( _( 'Older than:' ) ), self )
175
layout.addWidget( self.cb_remove_older_then, 0, 0 )
176
self.cb_remove_older_then.setChecked( enabled )
177
QObject.connect( self.cb_remove_older_then, SIGNAL('stateChanged(int)'), self.update_remove_older_than )
179
self.edit_remove_older_then = KIntSpinBox( 1, 1000, 1, value, self )
180
layout.addWidget( self.edit_remove_older_then, 0, 1 )
182
self.combo_remove_older_then = KComboBox( self )
183
layout.addWidget( self.combo_remove_older_then, 0, 2 )
184
self.fill_combo( self.combo_remove_older_then, self.config.REMOVE_OLD_BACKUP_UNITS, unit )
187
enabled, value, unit = self.config.get_min_free_space()
189
self.cb_min_free_space = QCheckBox( QString.fromUtf8( _( 'If free space is less than:' ) ), self )
190
layout.addWidget( self.cb_min_free_space, 1, 0 )
191
self.cb_min_free_space.setChecked( enabled )
192
QObject.connect( self.cb_min_free_space, SIGNAL('stateChanged(int)'), self.update_min_free_space )
194
self.edit_min_free_space = KIntSpinBox( 1, 1000, 1, value, self )
195
layout.addWidget( self.edit_min_free_space, 1, 1 )
197
self.combo_min_free_space = KComboBox( self )
198
layout.addWidget( self.combo_min_free_space, 1, 2 )
199
self.fill_combo( self.combo_min_free_space, self.config.MIN_FREE_SPACE_UNITS, unit )
202
self.cb_smart_remove = QCheckBox( QString.fromUtf8( _( 'Smart remove' ) ), self )
203
layout.addWidget( self.cb_smart_remove, 2, 0 )
204
self.cb_smart_remove.setChecked( self.config.get_smart_remove() )
206
label = QLabel( QString.fromUtf8( _( '- keep all snapshots from today and yesterday\n- keep one snapshot for the last week and one for two weeks ago\n- keep one snapshot per month for all previous months of this year\n- keep one snapshot per year for all previous years' ) ),self )
207
label.setContentsMargins( 25, 0, 0, 0 )
208
layout.addWidget( label, 3, 0 )
210
#don't remove named snapshots
211
self.cb_dont_remove_named_snapshots = QCheckBox( QString.fromUtf8( _( 'Don\'t remove named snapshots' ) ), self )
212
layout.addWidget( self.cb_dont_remove_named_snapshots, 4, 0 )
213
self.cb_dont_remove_named_snapshots.setChecked( self.config.get_dont_remove_named_snapshots() )
216
layout.addWidget( QWidget(), 5, 0 )
217
layout.setRowStretch( 5, 2 )
220
tab_widget = QWidget( self )
221
self.main_widget.addTab( tab_widget, QString.fromUtf8( _( 'Options' ) ) )
222
layout = QVBoxLayout( tab_widget )
224
self.cb_notify_enabled = QCheckBox( QString.fromUtf8( _( 'Enable notifications' ) ), self )
225
layout.addWidget( self.cb_notify_enabled )
226
self.cb_notify_enabled.setChecked( self.config.is_notify_enabled() )
232
tab_widget = QWidget( self )
233
self.main_widget.addTab( tab_widget, QString.fromUtf8( _( 'Expert Options' ) ) )
234
layout = QVBoxLayout( tab_widget )
236
label = QLabel( QString.fromUtf8( _('Change this options only if you really know what you are doing !') ), self )
237
kde4tools.set_font_bold( label )
238
layout.addWidget( label )
240
self.cb_per_diretory_schedule = QCheckBox( QString.fromUtf8( _( 'Enable schedule per included directory (see Include tab; default: disabled)' ) ), self )
241
layout.addWidget( self.cb_per_diretory_schedule )
242
self.cb_per_diretory_schedule.setChecked( self.config.get_per_directory_schedule() )
243
QObject.connect( self.cb_per_diretory_schedule, SIGNAL('clicked()'), self.update_include_columns )
248
self.update_include_columns()
250
self.update_remove_older_than()
251
self.update_min_free_space()
253
def update_include_columns( self ):
254
if self.cb_per_diretory_schedule.isChecked():
255
self.list_include.showColumn( 1 )
256
self.global_schedule_group_box.hide()
258
self.list_include.hideColumn( 1 )
259
self.global_schedule_group_box.show()
261
def on_list_include_item_activated( self, item, column ):
262
if not self.cb_per_diretory_schedule.isChecked():
271
self.popup_automatic_backup.popup( QCursor.pos() )
273
def on_popup_automatic_backup( self ):
276
def update_remove_older_than( self ):
277
enabled = self.cb_remove_older_then.isChecked()
278
self.edit_remove_older_then.setEnabled( enabled )
279
self.combo_remove_older_then.setEnabled( enabled )
281
def update_min_free_space( self ):
282
enabled = self.cb_min_free_space.isChecked()
283
self.edit_min_free_space.setEnabled( enabled )
284
self.combo_min_free_space.setEnabled( enabled )
286
def add_include( self, data ):
287
item = QTreeWidgetItem()
288
item.setText( 0, QString.fromUtf8( data[0] ) )
289
item.setText( 1, QString.fromUtf8( self.config.AUTOMATIC_BACKUP_MODES[ data[1] ] ) )
290
item.setData( 0, Qt.UserRole, QVariant( data[1]) )
291
self.list_include.addTopLevelItem( item )
293
if self.list_include.currentItem() is None:
294
self.list_include.setCurrentItem( item )
298
def add_exclude( self, pattern ):
299
item = QListWidgetItem( KIcon('edit-delete'), pattern, self.list_exclude )
301
if self.list_exclude.currentItem() is None:
302
self.list_exclude.setCurrentItem( item )
306
def fill_combo( self, combo, dict, default_value ):
312
combo.addItem( QIcon(), QString.fromUtf8( dict[ key ] ), QVariant( key ) )
313
if key == default_value:
314
combo.setCurrentIndex( index )
317
def validate( self ):
319
snapshots_path = str( self.edit_snapshots_path.text().toUtf8() )
323
for index in xrange( self.list_include.topLevelItemCount() ):
324
item = self.list_include.topLevelItem( index )
325
include_list.append( [ str( item.text(0).toUtf8() ), item.data( 0, Qt.UserRole ).toInt()[0] ] )
329
for index in xrange( self.list_exclude.count() ):
330
exclude_list.append( str( self.list_exclude.item( index ).text().toUtf8() ) )
333
check_ret_val = self.config.check_take_snapshot_params( snapshots_path, include_list, exclude_list )
334
if not check_ret_val is None:
335
err_id, err_msg = check_ret_val
336
KMessageBox.error( self, QString.fromUtf8( err_msg ) )
339
#check if back folder changed
340
if len( self.config.get_snapshots_path() ) > 0 and self.config.get_snapshots_path() != snapshots_path:
341
if KMessageBox.Yes != KMessageBox.warningYesNo( self, QString.fromUtf8( _('Are you sure you want to change snapshots directory ?') ) ):
344
#ok let's save to config
345
msg = self.config.set_snapshots_path( snapshots_path )
347
KMessageBox.error( self, QString.fromUtf8( msg ) )
350
self.config.set_include_folders( include_list )
351
self.config.set_exclude_patterns( exclude_list )
354
self.config.set_automatic_backup_mode( self.combo_automatic_snapshots.itemData( self.combo_automatic_snapshots.currentIndex() ).toInt()[0] )
357
self.config.set_remove_old_snapshots(
358
self.cb_remove_older_then.isChecked(),
359
self.edit_remove_older_then.value(),
360
self.combo_remove_older_then.itemData( self.combo_remove_older_then.currentIndex() ).toInt()[0] )
361
self.config.set_min_free_space(
362
self.cb_min_free_space.isChecked(),
363
self.edit_min_free_space.value(),
364
self.combo_min_free_space.itemData( self.combo_min_free_space.currentIndex() ).toInt()[0] )
365
self.config.set_dont_remove_named_snapshots( self.cb_dont_remove_named_snapshots.isChecked() )
366
self.config.set_smart_remove( self.cb_smart_remove.isChecked() )
369
self.config.set_notify_enabled( self.cb_notify_enabled.isChecked() )
372
self.config.set_per_directory_schedule( self.cb_per_diretory_schedule.isChecked() )
376
msg = self.config.setup_cron()
378
KMessageBox.error( self, QString.fromUtf8( msg ) )
383
def on_btn_exclude_remove_clicked ( self ):
384
self.list_exclude.takeItem( self.list_exclude.currentRow() )
386
if self.list_exclude.count() > 0:
387
self.list_exclude.setCurrentItem( self.list_exclude.item(0) )
389
def add_exclude_( self, pattern ):
390
if len( pattern ) == 0:
393
for index in xrange( self.list_exclude.count() ):
394
if pattern == self.list_exclude.item( index ).text():
397
self.add_exclude( pattern )
399
def on_btn_exclude_add_clicked( self ):
400
ret_val = KInputDialog.getText( QString.fromUtf8( _( 'Exclude pattern' ) ), '', '', self )
404
self.add_exclude_( str( ret_val[0].toUtf8() ).strip() )
406
def on_btn_exclude_file_clicked( self ):
407
path = str( KFileDialog.getOpenFileName( KUrl(), '', self, QString.fromUtf8( _( 'Exclude file' ) ) ).toUtf8() )
408
self.add_exclude_( path )
410
def on_btn_exclude_folder_clicked( self ):
411
path = str( KFileDialog.getExistingDirectory( KUrl(), self, QString.fromUtf8( _( 'Exclude folder' ) ) ).toUtf8() )
412
self.add_exclude_( path )
414
def on_btn_include_remove_clicked ( self ):
415
item = self.list_include.currentItem()
419
index = self.list_include.indexOfTopLevelItem( item )
423
self.list_include.takeTopLevelItem( index )
425
if self.list_include.topLevelItemCount() > 0:
426
self.list_include.setCurrentItem( self.list_include.topLevelItem(0) )
428
def on_btn_include_add_clicked( self ):
429
path = ( KFileDialog.getExistingDirectory( KUrl(), self, QString.fromUtf8( _( 'Include folder' ) ) ).toUtf8() )
430
if len( path ) == 0 :
433
path = self.config.prepare_path( path )
435
for index in xrange( self.list_include.topLevelItemCount() ):
436
if path == str( self.list_include.topLevelItem( index ).text( 0 ).toUtf8() ):
439
self.add_include( [ path, self.config.NONE ] )
441
def on_btn_snapshots_path_clicked( self ):
442
path = str( KFileDialog.getExistingDirectory( KUrl( self.edit_snapshots_path.text() ), self, QString.fromUtf8( _( 'Where to save snapshots' ) ) ).toUtf8() )
444
self.edit_snapshots_path.setText( QString.fromUtf8( self.config.prepare_path( path ) ) )
448
KDialog.accept( self )