~yuriy-kozlov/guidance/userconfig-kde4

« back to all changes in this revision

Viewing changes to userconfig.py

  • Committer: Yuriy Kozlov
  • Date: 2008-07-27 20:20:36 UTC
  • Revision ID: yuriy.kozlov@gmail.com-20080727202036-g6lmrlgyd9uwte5n
Initial import.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# -*- coding: UTF-8 -*-
 
3
###########################################################################
 
4
# userconfig.py - description                                             #
 
5
# ------------------------------                                          #
 
6
# begin     : Wed Apr 30 2003                                             #
 
7
# copyright : (C) 2003-2006 by Simon Edwards                              #
 
8
# email     : simon@simonzone.com                                         #
 
9
#                                                                         #
 
10
###########################################################################
 
11
#                                                                         #
 
12
#   This program is free software; you can redistribute it and/or modify  #
 
13
#   it under the terms of the GNU General Public License as published by  #
 
14
#   the Free Software Foundation; either version 2 of the License, or     #
 
15
#   (at your option) any later version.                                   #
 
16
#                                                                         #
 
17
###########################################################################
 
18
 
 
19
from qt import *
 
20
from kdeui import *
 
21
from kdecore import *
 
22
from kfile import *
 
23
import sys
 
24
import os.path
 
25
import shutil
 
26
import unixauthdb
 
27
import locale
 
28
 
 
29
programname = "userconfig"
 
30
version = "0.8.0"
 
31
# Are we running as a separate standalone application or in KControl?
 
32
standalone = __name__=='__main__'
 
33
 
 
34
# Running as the root user or not?
 
35
isroot = os.getuid()==0
 
36
#isroot = True
 
37
 
 
38
###########################################################################
 
39
def SptimeToQDate(sptime):
 
40
    t = QDateTime()
 
41
    t.setTime_t(0)
 
42
    return t.addDays(sptime).date()
 
43
 
 
44
###########################################################################
 
45
def QDateToSptime(qdate):
 
46
    x = QDateTime()
 
47
    x.setTime_t(0)
 
48
    return x.daysTo(QDateTime(qdate))
 
49
 
 
50
###########################################################################
 
51
# Try translating this code to C++. I dare ya!
 
52
if standalone:
 
53
    programbase = KDialogBase
 
54
else:
 
55
    programbase = KCModule
 
56
 
 
57
class UserConfigApp(programbase):
 
58
    def __init__(self,parent=None,name=None):
 
59
        global standalone,isroot
 
60
        KGlobal.locale().insertCatalogue("guidance")
 
61
 
 
62
        if standalone:
 
63
            KDialogBase.__init__(self,KJanusWidget.Tabbed,i18n("User Accounts and Groups"),
 
64
                KDialogBase.User1|KDialogBase.Close, KDialogBase.Close)
 
65
            self.setButtonText(KDialogBase.User1,i18n("About"))
 
66
        else:
 
67
            KCModule.__init__(self,parent,name)
 
68
            self.setButtons(0)
 
69
            self.aboutdata = MakeAboutData()
 
70
 
 
71
            toplayout = QVBoxLayout( self, 0, KDialog.spacingHint() )
 
72
            tabcontrol = QTabWidget(self)
 
73
            toplayout.addWidget(tabcontrol)
 
74
            toplayout.setStretchFactor(tabcontrol,1)
 
75
 
 
76
        # Create a configuration object.
 
77
        self.config = KConfig("userconfigrc")
 
78
 
 
79
        KGlobal.iconLoader().addAppDir("guidance")
 
80
 
 
81
        self.usersToListItems = None
 
82
        self.selecteduserid = None
 
83
        self.selectedgroupid = None
 
84
        self.showsystemaccounts = False
 
85
        self.showsystemgroups = False
 
86
 
 
87
        self.updatingGUI = True
 
88
 
 
89
 
 
90
        self.aboutus = KAboutApplication(self)
 
91
 
 
92
        # --- User Tab ---
 
93
        if standalone:
 
94
            usershbox = self.addHBoxPage("Users")
 
95
            vbox = QVBox(usershbox)
 
96
        else:
 
97
            vbox = QVBox(tabcontrol)
 
98
            vbox.setMargin(KDialog.marginHint())
 
99
 
 
100
        vbox.setSpacing(KDialog.spacingHint())
 
101
 
 
102
        hb = QHBox(vbox)
 
103
        hb.setSpacing(KDialog.spacingHint())
 
104
        vbox.setStretchFactor(hb,0)
 
105
 
 
106
        label = QLabel(hb)
 
107
        label.setPixmap(UserIcon("hi32-user"))
 
108
        hb.setStretchFactor(label,0)
 
109
 
 
110
        label = QLabel(i18n("User Accounts:"),hb)
 
111
        hb.setStretchFactor(label,1)
 
112
 
 
113
        self.userlist = KListView(vbox)
 
114
        self.userlist.addColumn(i18n("Login Name"))
 
115
        self.userlist.addColumn(i18n("Real Name"))
 
116
        self.userlist.addColumn(i18n("UID"))
 
117
        self.userlist.setAllColumnsShowFocus(True)
 
118
        self.userlist.setSelectionMode(QListView.Single)
 
119
 
 
120
        self.connect(self.userlist, SIGNAL("selectionChanged(QListViewItem *)"), self.slotListClicked)
 
121
        if isroot:
 
122
            self.connect(self.userlist, SIGNAL("doubleClicked(QListViewItem *)"), self.slotModifyClicked)
 
123
        self.connect(self.userlist, SIGNAL("contextMenu(KListView*,QListViewItem*,const QPoint&)"), self.slotUserContext)
 
124
 
 
125
        self.showspecialcheckbox = QCheckBox(i18n("Show system accounts"),vbox)
 
126
        vbox.setStretchFactor(self.showspecialcheckbox,0)
 
127
        self.connect(self.showspecialcheckbox,SIGNAL("toggled(bool)"), self.slotShowSystemToggled)
 
128
 
 
129
        hbox = QHBox(vbox)
 
130
        hbox.setSpacing(KDialog.spacingHint())
 
131
 
 
132
        vbox.setStretchFactor(hbox,0)
 
133
 
 
134
        self.modifybutton = KPushButton(i18n("Modify..."),hbox)
 
135
        hbox.setStretchFactor(self.modifybutton,1)
 
136
        self.connect(self.modifybutton,SIGNAL("clicked()"),self.slotModifyClicked)
 
137
 
 
138
        self.newbutton = KPushButton(i18n("New..."),hbox)
 
139
        hbox.setStretchFactor(self.newbutton,1)
 
140
        self.connect(self.newbutton,SIGNAL("clicked()"),self.slotNewClicked)
 
141
 
 
142
        self.deletebutton = KPushButton(i18n("Delete..."),hbox)
 
143
        hbox.setStretchFactor(self.deletebutton,1)
 
144
        self.connect(self.deletebutton,SIGNAL("clicked()"),self.slotDeleteClicked)
 
145
 
 
146
        detailsbox = QVGroupBox(i18n("Details"),vbox)
 
147
        userinfovbox = QWidget(detailsbox)
 
148
 
 
149
        infogrid = QGridLayout(userinfovbox,3,4)
 
150
        infogrid.setSpacing(KDialog.spacingHint())
 
151
 
 
152
        label = QLabel(i18n("Login Name:"),userinfovbox)
 
153
        infogrid.addWidget(label,0,0)
 
154
        self.loginnamelabel = KLineEdit("",userinfovbox)
 
155
        self.loginnamelabel.setReadOnly(True)
 
156
        infogrid.addWidget(self.loginnamelabel,0,1)
 
157
 
 
158
        label = QLabel(i18n("Real Name:"),userinfovbox)
 
159
        infogrid.addWidget(label,0,2)
 
160
        self.realnamelabel = KLineEdit("",userinfovbox)
 
161
        self.realnamelabel.setReadOnly(True)
 
162
        infogrid.addWidget(self.realnamelabel,0,3)
 
163
 
 
164
        label = QLabel(i18n("UID:"),userinfovbox)
 
165
        infogrid.addWidget(label,1,0)
 
166
        self.uidlabel = KLineEdit("",userinfovbox)
 
167
        self.uidlabel.setReadOnly(True)
 
168
        infogrid.addWidget(self.uidlabel,1,1)
 
169
 
 
170
        label = QLabel(i18n("Status:"),userinfovbox)
 
171
        infogrid.addWidget(label,1,2)
 
172
        self.statuslabel = KLineEdit("",userinfovbox)
 
173
        self.statuslabel.setReadOnly(True)
 
174
        infogrid.addWidget(self.statuslabel,1,3)
 
175
 
 
176
        label = QLabel(i18n("Primary Group:"),userinfovbox)
 
177
        infogrid.addWidget(label,2,0)
 
178
        self.primarygrouplabel = KLineEdit("",userinfovbox)
 
179
        self.primarygrouplabel.setReadOnly(True)
 
180
        infogrid.addWidget(self.primarygrouplabel,2,1)
 
181
 
 
182
        label = QLabel(i18n("Secondary Groups:"),userinfovbox)
 
183
        infogrid.addWidget(label,2,2)
 
184
        self.secondarygrouplabel = KLineEdit("",userinfovbox)
 
185
        self.secondarygrouplabel.setReadOnly(True)
 
186
        infogrid.addWidget(self.secondarygrouplabel,2,3)
 
187
 
 
188
        if not standalone:
 
189
            tabcontrol.addTab(vbox,i18n("Users"))
 
190
 
 
191
        #--- Groups Tab ---
 
192
        if standalone:
 
193
            groupsvbox = self.addVBoxPage(i18n("Groups"))
 
194
            hb = QHBox(groupsvbox)
 
195
        else:
 
196
            groupsvbox = QVBox(tabcontrol)
 
197
            groupsvbox.setMargin(KDialog.marginHint())
 
198
            hb = QHBox(groupsvbox)
 
199
 
 
200
        topframe = QFrame(groupsvbox)
 
201
        groupsvbox.setSpacing(KDialog.spacingHint())
 
202
        hb.setSpacing(KDialog.spacingHint())
 
203
        groupsvbox.setStretchFactor(hb,0)
 
204
 
 
205
        label = QLabel(hb)
 
206
        label.setPixmap(UserIcon("hi32-group"))
 
207
        hb.setStretchFactor(label,0)
 
208
 
 
209
        label = QLabel(i18n("Groups:"),hb)
 
210
        hb.setStretchFactor(label,1)
 
211
 
 
212
        groupsplitter = QSplitter(Qt.Vertical,groupsvbox)
 
213
 
 
214
        self.grouplist = KListView(groupsplitter)
 
215
        self.grouplist.addColumn(i18n("Group Name"))
 
216
        self.grouplist.addColumn(i18n("GID"))
 
217
        self.grouplist.setAllColumnsShowFocus(True)
 
218
        self.connect(self.grouplist, SIGNAL("selectionChanged(QListViewItem *)"), self.slotGroupListClicked)
 
219
 
 
220
        if isroot:
 
221
            self.connect(self.grouplist, SIGNAL("doubleClicked(QListViewItem *)"), self.slotModifyGroupClicked)
 
222
        self.connect(self.grouplist, SIGNAL("contextMenu(KListView*,QListViewItem*,const QPoint&)"), 
 
223
                self.slotGroupContext)
 
224
 
 
225
        groupbottomvbox = QVBox(groupsplitter)
 
226
        groupbottomvbox.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
 
227
 
 
228
        self.showspecialgroupscheckbox = QCheckBox(i18n("Show system groups"),groupbottomvbox)
 
229
        vbox.setStretchFactor(self.showspecialgroupscheckbox,0)
 
230
        self.connect(self.showspecialgroupscheckbox,SIGNAL("toggled(bool)"), self.slotShowSystemGroupsToggled)
 
231
 
 
232
        hbox = QHBox(groupbottomvbox)
 
233
        hbox.setSpacing(KDialog.spacingHint())
 
234
 
 
235
        groupsvbox.setStretchFactor(hbox,0)
 
236
 
 
237
        self.modifygroupbutton = KPushButton(i18n("Modify..."),hbox)
 
238
        hbox.setStretchFactor(self.modifygroupbutton,1)
 
239
        self.connect(self.modifygroupbutton,SIGNAL("clicked()"),self.slotModifyGroupClicked)
 
240
 
 
241
        self.newgroupbutton = KPushButton(i18n("New..."),hbox)
 
242
        hbox.setStretchFactor(self.newgroupbutton,1)
 
243
        self.connect(self.newgroupbutton,SIGNAL("clicked()"),self.slotNewGroupClicked)
 
244
 
 
245
        self.deletegroupbutton = KPushButton(i18n("Delete..."),hbox)
 
246
        hbox.setStretchFactor(self.deletegroupbutton,1)
 
247
        self.connect(self.deletegroupbutton,SIGNAL("clicked()"),self.slotDeleteGroupClicked)
 
248
 
 
249
        if not isroot:
 
250
            disablebuttons = (  self.modifybutton, self.modifygroupbutton, self.deletebutton, self.deletegroupbutton,
 
251
                                self.newbutton, self.newgroupbutton)
 
252
            for widget in disablebuttons:
 
253
                widget.setDisabled(True)
 
254
 
 
255
        label = QLabel(i18n("Group Members:"),groupbottomvbox)
 
256
        groupsvbox.setStretchFactor(label,0)
 
257
 
 
258
        self.groupmemberlist = KListView(groupbottomvbox)
 
259
        self.groupmemberlist.addColumn(i18n("Login Name"))
 
260
        self.groupmemberlist.addColumn(i18n("Real Name"))
 
261
        self.groupmemberlist.addColumn(i18n("UID"))
 
262
        self.groupmemberlist.setAllColumnsShowFocus(True)
 
263
 
 
264
        if not standalone:
 
265
            tabcontrol.addTab(groupsvbox,i18n("Groups"))
 
266
 
 
267
        self.admincontext = unixauthdb.getContext(isroot)
 
268
 
 
269
        self.updatingGUI = True
 
270
 
 
271
        self.showspecialcheckbox.setChecked(self.showsystemaccounts)
 
272
        self.showspecialgroupscheckbox.setChecked(self.showsystemgroups)
 
273
 
 
274
        self.__updateUserList()
 
275
        self.__updateGroupList()
 
276
        self.updatingGUI = False
 
277
 
 
278
        self.usereditdialog = UserEditDialog(None,self.admincontext)
 
279
        self.userdeletedialog = UserDeleteDialog(None,self.admincontext)
 
280
        self.groupeditdialog = GroupEditDialog(None,self.admincontext)
 
281
 
 
282
    #######################################################################
 
283
    def exec_loop(self):
 
284
        global programbase
 
285
        self.__loadOptions()
 
286
        self.updatingGUI = True
 
287
        self.__updateUserList()
 
288
        self.__updateGroupList()
 
289
        self.updatingGUI = False
 
290
        programbase.exec_loop(self)
 
291
        self.__saveOptions()
 
292
 
 
293
    #######################################################################
 
294
    def slotUser1(self):
 
295
        self.aboutus.show()
 
296
 
 
297
    #######################################################################
 
298
    def slotUserContext(self,l,v,p):
 
299
        cmenu = KPopupMenu(self,"MyActions")
 
300
        cmenu.insertItem(i18n("Modify..."), self.slotModifyClicked, 0, 0)
 
301
        cmenu.insertItem(i18n("Delete..."), self.slotDeleteClicked, 0, 1)
 
302
        if not isroot:
 
303
            cmenu.setItemEnabled(0,False)
 
304
            cmenu.setItemEnabled(1,False)
 
305
 
 
306
        cmenu.exec_loop(p)
 
307
 
 
308
    #######################################################################
 
309
    def slotGroupContext(self,l,v,p):
 
310
        cmenu = KPopupMenu(self,"MyActions")
 
311
        cmenu.insertItem(i18n("Modify..."), self.slotModifyGroupClicked, 0, 0)
 
312
        cmenu.insertItem(i18n("Delete..."), self.slotDeleteGroupClicked, 0, 1)
 
313
        if not isroot:
 
314
            cmenu.setItemEnabled(0,False)
 
315
            cmenu.setItemEnabled(1,False)
 
316
        cmenu.exec_loop(p)
 
317
 
 
318
    #######################################################################        
 
319
    def sizeHint(self):
 
320
        global programbase
 
321
        size_hint = programbase.sizeHint(self)
 
322
        # Just make the dialog a little shorter by default.
 
323
        size_hint.setHeight(size_hint.height()-200) 
 
324
        return size_hint
 
325
 
 
326
    #######################################################################
 
327
    def slotCloseButton(self):
 
328
        self.close()
 
329
 
 
330
    #######################################################################
 
331
    def slotListClicked(self,item):
 
332
        if self.updatingGUI==False:
 
333
            for userid in self.useridsToListItems:
 
334
                if self.useridsToListItems[userid]==item:
 
335
                    self.updatingGUI = True
 
336
                    self.__selectUser(userid)
 
337
                    self.updatingGUI = False
 
338
                    return
 
339
 
 
340
    #######################################################################
 
341
    def slotShowSystemToggled(self,on):
 
342
        self.showsystemaccounts = on
 
343
        if self.updatingGUI==False:
 
344
            self.updatingGUI = True
 
345
            self.__updateUserList()
 
346
            self.updatingGUI = False
 
347
 
 
348
    #######################################################################
 
349
    def slotModifyClicked(self):
 
350
        self.usereditdialog.showEditUser(self.selecteduserid)
 
351
        self.updatingGUI = True
 
352
        self.__updateUser(self.selecteduserid)
 
353
        self.__selectUser(self.selecteduserid)
 
354
        self.updatingGUI = False
 
355
 
 
356
    #######################################################################
 
357
    def slotNewClicked(self):
 
358
        newuid = self.usereditdialog.showNewUser()
 
359
        if newuid!=None:
 
360
            self.updatingGUI = True
 
361
            self.__updateUserList()
 
362
            self.__selectUser(newuid)
 
363
            self.updatingGUI = False
 
364
 
 
365
    #######################################################################
 
366
    def slotDeleteClicked(self):
 
367
        if self.userdeletedialog.deleteUser(self.selecteduserid):
 
368
            self.updatingGUI = True
 
369
            self.selecteduserid = None
 
370
            self.__updateUserList()
 
371
            self.updatingGUI = False
 
372
 
 
373
    #######################################################################
 
374
    def slotGroupListClicked(self,item):
 
375
        if self.updatingGUI==False:
 
376
            for groupid in self.groupidsToListItems:
 
377
                if groupid and self.groupidsToListItems[groupid]==item:
 
378
                    self.updatingGUI = True
 
379
                    self.__selectGroup(groupid)
 
380
                    self.updatingGUI = False
 
381
                    return
 
382
 
 
383
    #######################################################################
 
384
    def slotShowSystemGroupsToggled(self,on):
 
385
        self.showsystemgroups = on
 
386
        if self.updatingGUI==False:
 
387
            self.updatingGUI = True
 
388
            self.__updateGroupList()
 
389
            self.updatingGUI = False
 
390
 
 
391
    #######################################################################
 
392
    def slotModifyGroupClicked(self):
 
393
        if self.selectedgroupid!=None:
 
394
            if self.groupeditdialog.showEditGroup(self.selectedgroupid):
 
395
                self.__selectGroup(self.selectedgroupid)
 
396
                self.updatingGUI = True
 
397
                self.__updateUser(self.selecteduserid)
 
398
                self.__selectUser(self.selecteduserid)
 
399
                self.updatingGUI = False
 
400
 
 
401
    #######################################################################
 
402
    def slotNewGroupClicked(self):
 
403
        newgroupid = self.groupeditdialog.showNewGroup()
 
404
        if newgroupid!=None:
 
405
            self.updatingGUI = True
 
406
            self.__updateGroupList()
 
407
            self.__updateGroupList()
 
408
            self.__selectGroup(newgroupid)
 
409
            self.__updateUser(self.selecteduserid)
 
410
            self.__selectUser(self.selecteduserid)
 
411
            self.updatingGUI = False
 
412
 
 
413
    #######################################################################
 
414
    def slotDeleteGroupClicked(self):
 
415
        if self.selectedgroupid!=None:
 
416
            groupobj = self.admincontext.lookupGID(self.selectedgroupid)
 
417
            groupname = groupobj.getGroupname()
 
418
            gid = groupobj.getGID()
 
419
            nummembers = len(groupobj.getUsers())
 
420
 
 
421
            message = i18n("Are you sure you want to delete group '%1' (%2)?\nIt currently has %3 members.").arg(groupname).arg(gid).arg(nummembers)
 
422
            if KMessageBox.warningYesNo(self,message,i18n("Delete Group?"))==KMessageBox.Yes:
 
423
                self.admincontext.removeGroup(groupobj)
 
424
                self.admincontext.save()
 
425
                self.updatingGUI = True
 
426
                self.__updateGroupList()
 
427
                self.__updateUser(self.selecteduserid)
 
428
                self.__selectUser(self.selecteduserid)
 
429
                self.updatingGUI = False
 
430
 
 
431
    #######################################################################
 
432
    def __updateUserList(self):
 
433
        self.userlist.clear()
 
434
        self.useridsToListItems = {}
 
435
        firstselecteduserid = None
 
436
 
 
437
        users = self.admincontext.getUsers()
 
438
 
 
439
        for userobj in users:
 
440
            uid = userobj.getUID()
 
441
            if self.showsystemaccounts or not userobj.isSystemUser():
 
442
                lvi = KListViewItem(self.userlist,userobj.getUsername(),userobj.getRealName(),unicode(uid))
 
443
                if userobj.isLocked():
 
444
                    lvi.setPixmap(0,UserIcon("hi16-encrypted"))
 
445
                self.useridsToListItems[uid] = lvi
 
446
                if self.selecteduserid==uid:
 
447
                    firstselecteduserid = uid
 
448
                elif firstselecteduserid==None:
 
449
                    firstselecteduserid = uid
 
450
        self.selecteduserid = firstselecteduserid
 
451
        self.__selectUser(self.selecteduserid)
 
452
        self.userlist.ensureItemVisible(self.userlist.currentItem())
 
453
 
 
454
    #######################################################################
 
455
    def __updateUser(self,userid):
 
456
        lvi = self.useridsToListItems[userid]
 
457
        userobj = self.admincontext.lookupUID(userid)
 
458
        lvi.setText(0,userobj.getUsername())
 
459
        lvi.setText(1,userobj.getRealName())
 
460
        lvi.setText(2,unicode(userobj.getUID()))
 
461
        if userobj.isLocked():
 
462
            lvi.setPixmap(0,UserIcon("hi16-encrypted"))
 
463
        else:
 
464
            lvi.setPixmap(0,QPixmap())
 
465
 
 
466
    #######################################################################
 
467
    def __selectUser(self,userid):
 
468
        self.selecteduserid = userid
 
469
        # Only go on if there are actual users.
 
470
        if len(self.useridsToListItems)>0:
 
471
            lvi = self.useridsToListItems[userid]
 
472
            self.userlist.setSelected(lvi,True)
 
473
            self.userlist.setCurrentItem(lvi)
 
474
 
 
475
            userobj = self.admincontext.lookupUID(userid)
 
476
 
 
477
            username = userobj.getUsername()
 
478
            self.loginnamelabel.setText(username)
 
479
            self.realnamelabel.setText(userobj.getRealName())
 
480
            self.uidlabel.setText(unicode(userid))
 
481
            if userobj.isLocked():
 
482
                self.statuslabel.setText(i18n("Disabled"))
 
483
            else:
 
484
                self.statuslabel.setText(i18n("Enabled"))
 
485
 
 
486
            # Primary Group
 
487
            primarygroupobj = userobj.getPrimaryGroup()
 
488
            primarygroupname = primarygroupobj.getGroupname()
 
489
            self.primarygrouplabel.setText(primarygroupname)
 
490
 
 
491
            # Secondary Groups
 
492
            secondarygroups = [g.getGroupname() for g in userobj.getGroups() if g is not userobj.getPrimaryGroup()]
 
493
            self.secondarygrouplabel.setText(unicode(i18n(", ")).join(secondarygroups))
 
494
 
 
495
            if isroot:
 
496
                self.deletebutton.setDisabled(userobj.getUID()==0)
 
497
 
 
498
    #######################################################################
 
499
    def __updateGroupList(self):
 
500
        self.grouplist.clear()
 
501
        self.groupidsToListItems = {}
 
502
        firstselectedgroupid = None
 
503
 
 
504
        groups = self.admincontext.getGroups()
 
505
        for groupobj in groups:
 
506
            gid = groupobj.getGID()
 
507
            if self.showsystemgroups or not groupobj.isSystemGroup():
 
508
                lvi = QListViewItem(self.grouplist,groupobj.getGroupname(),unicode(gid))
 
509
                self.groupidsToListItems[gid] = lvi
 
510
                if self.selectedgroupid==gid:
 
511
                    firstselectedgroupid = gid
 
512
                elif firstselectedgroupid==None:
 
513
                    firstselectedgroupid = gid
 
514
        self.selectedgroupid = firstselectedgroupid
 
515
        self.__selectGroup(self.selectedgroupid)
 
516
        self.grouplist.ensureItemVisible(self.grouplist.currentItem())
 
517
 
 
518
    #######################################################################
 
519
    def __selectGroup(self,groupid):
 
520
        if groupid:
 
521
            self.selectedgroupid = groupid
 
522
            lvi = self.groupidsToListItems[groupid]
 
523
            self.grouplist.setSelected(lvi,True)
 
524
            self.grouplist.setCurrentItem(lvi)
 
525
 
 
526
            groupobj = self.admincontext.lookupGID(groupid)
 
527
            members = groupobj.getUsers()
 
528
            self.groupmemberlist.clear()
 
529
            for userobj in members:
 
530
                if userobj!=None:
 
531
                    lvi = QListViewItem(self.groupmemberlist,userobj.getUsername(),userobj.getRealName(),unicode(userobj.getUID()))
 
532
            if isroot:
 
533
                self.deletegroupbutton.setDisabled(groupobj.getGID()==0)
 
534
 
 
535
    #######################################################################
 
536
    def __loadOptions(self):
 
537
        self.config.setGroup("General")
 
538
        size = self.config.readSizeEntry("Geometry")
 
539
        if size.isEmpty()==False:
 
540
            self.resize(size)
 
541
        self.config.setGroup("Options")
 
542
        self.showsystemaccounts = self.config.readBoolEntry("ShowSystemAccounts")
 
543
        self.showspecialcheckbox.setChecked(self.showsystemaccounts)
 
544
        self.showsystemgroups = self.config.readBoolEntry("ShowSystemGroups")
 
545
        self.showspecialgroupscheckbox.setChecked(self.showsystemgroups)
 
546
 
 
547
    #######################################################################
 
548
    def __saveOptions(self):
 
549
        global isroot
 
550
        if isroot:
 
551
            return
 
552
        self.config.setGroup("General")
 
553
        self.config.writeEntry("Geometry", self.size())
 
554
        self.config.setGroup("Options")
 
555
        self.config.writeEntry("ShowSystemAccounts",self.showsystemaccounts)
 
556
        self.config.writeEntry("ShowSystemGroups",self.showsystemgroups)
 
557
        self.config.sync()
 
558
 
 
559
    #######################################################################
 
560
    # KControl virtual void methods
 
561
    def load(self):
 
562
        pass
 
563
    def save(self):
 
564
        pass
 
565
    def defaults(self):
 
566
        pass        
 
567
    def sysdefaults(self):
 
568
        pass
 
569
 
 
570
    def aboutData(self):
 
571
        # Return the KAboutData object which we created during initialisation.
 
572
        return self.aboutdata
 
573
    def buttons(self):
 
574
        # Only supply a Help button. Other choices are Default and Apply.
 
575
        return KCModule.Help
 
576
 
 
577
###########################################################################
 
578
 
 
579
# Rudd-O convenience class to map groups to privilege names
 
580
class PrivilegeNames(dict):
 
581
        """Convenience dict-derived class: map known secondary groups to privilege names, provide default mapping for groups that do not have a description.  This could be replaced by a simple dict() but I simply preferred the class declaration.
 
582
        
 
583
        FIXME This should ideally be included in a more general module so it can be reused."""
 
584
 
 
585
        def __init__(self):
 
586
                dict.__init__(self, {
 
587
                        "plugdev":i18n("Access external storage devices automatically"),
 
588
                        "adm":i18n("Administer the system"),
 
589
                        "ltsp":i18n("Allow use of FUSE filesystems like LTSP thin client block devices"),
 
590
                        "dialout":i18n("Connect to the Internet using a modem"),
 
591
                        "syslog":i18n("Monitor system logs"),
 
592
                        "fax":i18n("Send and receive faxes"),
 
593
                        "cdrom":i18n("Use CD-ROM and DVD drives"),
 
594
                        "floppy":i18n("Use floppy drives"),
 
595
                        "modem":i18n("Use modems"),
 
596
                        "scanner":i18n("Use scanners"),
 
597
                })
 
598
 
 
599
        def __getitem__(self,name):
 
600
                # This is cruft but I couldn't bring myself to kill it bua!
 
601
                if name in self: return dict.__getitem__(self,name)
 
602
                return i18n("Be a member of the %s group")%name
 
603
 
 
604
class UserEditDialog(KDialogBase):
 
605
    def __init__(self,parent,admincontext):
 
606
        KDialogBase.__init__(self,KJanusWidget.Tabbed,i18n("User Account"),KDialogBase.Ok|KDialogBase.Cancel,
 
607
            KDialogBase.Cancel,parent)
 
608
 
 
609
        self.admincontext = admincontext
 
610
        self.updatingGUI = True
 
611
 
 
612
        detailsvbox = self.addHBoxPage(i18n("Details"))
 
613
        detailspace = QWidget(detailsvbox)
 
614
 
 
615
        infogrid = QGridLayout(detailspace,9,2)
 
616
        infogrid.setSpacing(self.spacingHint())
 
617
        infogrid.setColStretch(0,0)
 
618
        infogrid.setColStretch(1,1)
 
619
 
 
620
        self.enabledradiogroup = QButtonGroup()
 
621
        self.enabledradiogroup.setRadioButtonExclusive(True)
 
622
        hb = QHBox(detailspace)
 
623
        hb.setSpacing(self.spacingHint())
 
624
        label = QLabel(hb)
 
625
        label.setPixmap(UserIcon("hi32-identity"))
 
626
        hb.setStretchFactor(label,0)
 
627
        label = QLabel(i18n("Status:"),hb)
 
628
        hb.setStretchFactor(label,1)
 
629
        infogrid.addMultiCellWidget(hb,0,1,0,0)
 
630
 
 
631
        self.enabledradio = QRadioButton(i18n("Enabled"),detailspace)
 
632
        infogrid.addWidget(self.enabledradio,0,1)
 
633
 
 
634
        hbox = QHBox(detailspace)
 
635
        hbox.setSpacing(self.spacingHint())
 
636
        self.disabledradio = QRadioButton(i18n("Disabled"),hbox)
 
637
        hbox.setStretchFactor(self.disabledradio,0)
 
638
        label = QLabel(hbox)
 
639
        label.setPixmap(UserIcon("hi16-encrypted"))
 
640
        hbox.setStretchFactor(label,1)        
 
641
        infogrid.addWidget(hbox,1,1)
 
642
 
 
643
        self.enabledradiogroup.insert(self.enabledradio,0)
 
644
        self.enabledradiogroup.insert(self.disabledradio,1)
 
645
 
 
646
        label = QLabel(i18n("Login Name:"),detailspace)
 
647
        infogrid.addWidget(label,2,0)
 
648
        self.loginnameedit = KLineEdit("",detailspace)
 
649
        self.loginnameedit.setValidator(LoginNameValidator(self.loginnameedit))
 
650
 
 
651
        infogrid.addWidget(self.loginnameedit,2,1)
 
652
        self.connect(self.loginnameedit, SIGNAL("textChanged(const QString &)"), self.slotLoginChanged)
 
653
 
 
654
        label = QLabel(i18n("Real Name:"),detailspace)
 
655
        infogrid.addWidget(label,3,0)
 
656
        self.realnameedit = KLineEdit("",detailspace)
 
657
        self.realnameedit.setValidator(RealUserNameValidator(self.realnameedit))
 
658
 
 
659
        infogrid.addWidget(self.realnameedit,3,1)
 
660
 
 
661
        label = QLabel(i18n("User ID:"),detailspace)
 
662
        infogrid.addWidget(label,4,0)
 
663
        self.uidedit = KLineEdit("",detailspace)
 
664
        self.uidedit.setValidator(QIntValidator(0,65535,detailspace))
 
665
        infogrid.addWidget(self.uidedit,4,1)
 
666
 
 
667
        label = QLabel(i18n("Primary Group:"),detailspace)
 
668
        infogrid.addWidget(label,5,0)
 
669
        self.primarygroupedit = KComboBox(False,detailspace)
 
670
        infogrid.addWidget(self.primarygroupedit,5,1)
 
671
 
 
672
        label = QLabel(i18n("Home Directory:"),detailspace)
 
673
        infogrid.addWidget(label,7,0)
 
674
 
 
675
        hbox = QHBox(detailspace)
 
676
        hbox.setSpacing(self.spacingHint())
 
677
        self.homediredit = KLineEdit("",hbox)
 
678
        hbox.setStretchFactor(self.homediredit,1)
 
679
        self.connect(self.homediredit, SIGNAL("textChanged(const QString &)"), self.slotHomeDirChanged)
 
680
        self.homedirbutton = KPushButton(i18n("Browse..."),hbox)
 
681
        hbox.setStretchFactor(self.homedirbutton,0)
 
682
        self.connect(self.homedirbutton,SIGNAL("clicked()"),self.slotBrowseHomeDirClicked)
 
683
        infogrid.addWidget(hbox,7,1)
 
684
 
 
685
        label = QLabel(i18n("Shell:"),detailspace)
 
686
        infogrid.addWidget(label,8,0)
 
687
 
 
688
        self.shelledit = KComboBox(True,detailspace)
 
689
        for shell in self.admincontext.getUserShells():
 
690
            self.shelledit.insertItem(shell)
 
691
        infogrid.addWidget(self.shelledit,8,1)
 
692
 
 
693
        # Rudd-O rules.  Not so much, but enough to rule.
 
694
        # yeah it's not my finest hour, but it works like a charm over here.  Please feel free to clean up dead code that I commented
 
695
        # I extend my deepest thanks to the people that have worked hard to construct this tool in the first place.  I have no idea who the authors and contributors are, but it would make sense to have all the contributors listed on top of the file.
 
696
        # Privileges and groups tab
 
697
        groupsvbox = self.addHBoxPage(i18n("Privileges and groups"))
 
698
 
 
699
        # Rudd-O now here we create the widget that will hold the group listing, and fill it with the groups.
 
700
        self.privilegeslistview = QListView(groupsvbox)
 
701
        self.privilegeslistview.addColumn(i18n("Privilege"),-1)
 
702
        self.groupslistview = QListView(groupsvbox)
 
703
        self.groupslistview.addColumn(i18n("Secondary group"),-1)
 
704
        groupsvbox.setStretchFactor(self.privilegeslistview,3)
 
705
        groupsvbox.setStretchFactor(self.groupslistview,2)
 
706
        
 
707
        # Password and Security Tab.
 
708
        passwordvbox = self.addVBoxPage(i18n("Password && Security"))
 
709
 
 
710
        passwordspace = QWidget(passwordvbox)
 
711
        passwordgrid = QGridLayout(passwordspace,8,3)
 
712
        passwordgrid.setSpacing(self.spacingHint())
 
713
        passwordgrid.setColStretch(0,0)
 
714
        passwordgrid.setColStretch(1,0)
 
715
        passwordgrid.setColStretch(2,1)
 
716
        passwordvbox.setStretchFactor(passwordspace,0)
 
717
 
 
718
        hb = QHBox(passwordspace)
 
719
        hb.setSpacing(self.spacingHint())
 
720
        label = QLabel(hb)
 
721
        label.setPixmap(UserIcon("hi32-password"))
 
722
        hb.setStretchFactor(label,0)
 
723
        label = QLabel(i18n("Password:"),hb)
 
724
        hb.setStretchFactor(label,1)
 
725
        passwordgrid.addWidget(hb,0,0)
 
726
 
 
727
        self.passwordedit = KPasswordEdit(passwordspace)
 
728
        passwordgrid.addWidget(self.passwordedit,0,1)
 
729
 
 
730
        # Last Change
 
731
        label = QLabel(i18n("Last changed:"),passwordspace)
 
732
        passwordgrid.addWidget(label,1,0)
 
733
        self.lastchangelabel = KLineEdit("",passwordspace)
 
734
        self.lastchangelabel.setReadOnly(True)
 
735
        passwordgrid.addWidget(self.lastchangelabel,1,1)
 
736
 
 
737
        self.validradiogroup = QButtonGroup()
 
738
        self.validradiogroup.setRadioButtonExclusive(True)
 
739
 
 
740
        # Valid until.
 
741
        label = QLabel(i18n("Valid until:"),passwordspace)
 
742
        passwordgrid.addWidget(label,2,0)
 
743
        self.validalwaysradio = QRadioButton(i18n("Always"),passwordspace)
 
744
        passwordgrid.addWidget(self.validalwaysradio,2,1)
 
745
 
 
746
        hbox = QHBox(passwordspace)
 
747
        hbox.setSpacing(self.spacingHint())
 
748
        self.expireradio = QRadioButton(hbox)
 
749
        hbox.setStretchFactor(self.expireradio,0)
 
750
 
 
751
        self.expiredate = KDateWidget(hbox)
 
752
        hbox.setStretchFactor(self.expiredate,1)
 
753
        passwordgrid.addWidget(hbox,3,1)
 
754
 
 
755
        self.validradiogroup.insert(self.validalwaysradio,0)
 
756
        self.validradiogroup.insert(self.expireradio,1)
 
757
        self.connect(self.validradiogroup,SIGNAL("clicked(int)"),self.slotValidUntilClicked)
 
758
 
 
759
        # Password Aging & Expiration.
 
760
        passwordaginggroup = QVGroupBox(i18n("Password Aging"),passwordvbox)
 
761
        passwordaginggroup.setInsideSpacing(self.spacingHint())
 
762
        passwordvbox.setStretchFactor(passwordaginggroup,0)
 
763
 
 
764
        passwordagingwidget = QWidget(passwordaginggroup)
 
765
 
 
766
        passwordaginggrid = QGridLayout(passwordagingwidget,4,3)
 
767
        passwordaginggrid.setSpacing(self.spacingHint())
 
768
 
 
769
        # [*] Require new password after: [_____5 days]
 
770
        self.forcepasswordchangecheckbox = QCheckBox(passwordagingwidget)
 
771
        self.connect(self.forcepasswordchangecheckbox,SIGNAL("toggled(bool)"),self.slotForcePasswordChangeToggled)
 
772
        passwordaginggrid.addWidget(self.forcepasswordchangecheckbox,0,0)
 
773
        label = QLabel(i18n("Require new password after:"),passwordagingwidget)
 
774
        passwordaginggrid.addWidget(label,0,1) 
 
775
        self.maximumpasswordedit = QSpinBox(passwordagingwidget)
 
776
        self.maximumpasswordedit.setSuffix(i18n(" days"))
 
777
        self.maximumpasswordedit.setMinValue(1)
 
778
        self.maximumpasswordedit.setMaxValue(365*5)
 
779
        passwordaginggrid.addWidget(self.maximumpasswordedit,0,2)
 
780
 
 
781
        label = QLabel(i18n("Warn before password expires:"),passwordagingwidget)
 
782
        passwordaginggrid.addWidget(label,1,1)
 
783
        self.warningedit = QSpinBox(passwordagingwidget)
 
784
        self.warningedit.setPrefix(i18n("After "))
 
785
        self.warningedit.setSuffix(i18n(" days"))
 
786
        self.warningedit.setMinValue(0)
 
787
        self.warningedit.setMaxValue(365*5)
 
788
        self.warningedit.setSpecialValueText(i18n("Never"))
 
789
        passwordaginggrid.addWidget(self.warningedit,1,2)
 
790
 
 
791
        label = QLabel(i18n("Disable account after password expires:"),passwordagingwidget)
 
792
        passwordaginggrid.addWidget(label,2,1)
 
793
        self.disableexpireedit = QSpinBox(passwordagingwidget)
 
794
        self.disableexpireedit.setPrefix(i18n("After "))
 
795
        self.disableexpireedit.setSuffix(i18n(" days"))
 
796
        self.disableexpireedit.setMinValue(0)
 
797
        self.disableexpireedit.setMaxValue(365*5)
 
798
        self.disableexpireedit.setSpecialValueText(i18n("Never"))
 
799
        passwordaginggrid.addWidget(self.disableexpireedit,2,2)
 
800
 
 
801
        self.enforcepasswordminagecheckbox = QCheckBox(passwordagingwidget)
 
802
        self.connect(self.enforcepasswordminagecheckbox,SIGNAL("toggled(bool)"),self.slotEnforePasswordAgeToggled)
 
803
        passwordaginggrid.addWidget(self.enforcepasswordminagecheckbox,3,0)
 
804
 
 
805
        label = QLabel(i18n("Enforce minimum password age:"),passwordagingwidget)
 
806
        passwordaginggrid.addWidget(label,3,1)
 
807
        self.minimumpasswordedit = QSpinBox(passwordagingwidget)
 
808
        self.minimumpasswordedit.setSuffix(i18n(" days"))
 
809
        passwordaginggrid.addWidget(self.minimumpasswordedit,3,2)
 
810
 
 
811
        spacer = QWidget(passwordvbox)
 
812
        passwordvbox.setStretchFactor(spacer,1)
 
813
 
 
814
        self.homedirdialog = KDirSelectDialog("/",True,self,"Select Home Directory",True)
 
815
        self.createhomedirectorydialog = OverwriteHomeDirectoryDialog(None)
 
816
        self.updatingGUI = False
 
817
 
 
818
    def _repopulateGroupsPrivileges(self,excludegroups=None):
 
819
        # needs listviews to be constructed.  Expects a list of PwdGroups to be excluded
 
820
        
 
821
        # rehash everything
 
822
        self.privilegeslistview.clear()
 
823
        self.groupslistview.clear()
 
824
        self.secondarygroupcheckboxes = {}
 
825
        pn = PrivilegeNames()
 
826
        
 
827
        if excludegroups: excludegroups = [ g.getGroupname() for g in excludegroups ]
 
828
        else: excludegroups = []
 
829
        for group in [g.getGroupname() for g in self.admincontext.getGroups()]:
 
830
                if group in excludegroups: continue
 
831
                if group in pn:
 
832
                        name = i18n(unicode(pn[group]).encode(locale.getpreferredencoding()))
 
833
                        wid = self.privilegeslistview
 
834
                else:
 
835
                        name = unicode(group).encode(locale.getpreferredencoding())
 
836
                        wid = self.groupslistview
 
837
                self.secondarygroupcheckboxes[group] = QCheckListItem(wid,name,QCheckListItem.CheckBox)
 
838
 
 
839
    ########################################################################
 
840
    def showEditUser(self,userid):
 
841
        self.updatingGUI = True
 
842
        self.newusermode = False
 
843
        self.userobj = self.admincontext.lookupUID(userid)
 
844
        self.userid = userid
 
845
        self.passwordedit.erase()
 
846
        self.selectedgroups = [g.getGroupname() for g in self.userobj.getGroups()
 
847
            if g is not self.userobj.getPrimaryGroup()]
 
848
        
 
849
        # Rudd-O: now here we tick the appropriate group listing checkbox, and hide the currently active primary group of the user.  We are repopulating because if the user to edit changes, we need to hide the user's secondary group.  FIXME we should repopulate the groups privileges list when the primary group is changed in the other tab -- that is, on the change slot of the primary group drop down.
 
850
        self._repopulateGroupsPrivileges(excludegroups=[self.userobj.getPrimaryGroup()])
 
851
        for group,checkbox in self.secondarygroupcheckboxes.items():
 
852
                if group in self.selectedgroups: checkbox.setState(QCheckListItem.On)
 
853
                else: checkbox.setState(QCheckListItem.Off)
 
854
        
 
855
        self.originalgroups = self.selectedgroups[:]
 
856
        self.selectedgroups.sort()
 
857
        self.__syncGUI()
 
858
        self.uidedit.setReadOnly(True)
 
859
        self.updatingGUI = False
 
860
        self.homedirectoryislinked = False
 
861
        if self.exec_loop()==QDialog.Accepted:
 
862
            self.__updateObjectFromGUI(self.userobj)
 
863
            # Set the password.
 
864
            if self.passwordedit.password()!="":
 
865
                self.userobj.setPassword(self.passwordedit.password())
 
866
            # Update the groups for this user object. Rudd-O here's when you go in, stud.
 
867
            # we collect the selected groups
 
868
            self.selectedgroups = [ group for group,checkbox in self.secondarygroupcheckboxes.items() if checkbox.isOn() ]
 
869
 
 
870
            for g in self.userobj.getGroups(): # this seems wasteful to remove the user from all groups then re-add, why not a cross check?
 
871
                self.userobj.removeFromGroup(g)
 
872
            for gn in self.selectedgroups:
 
873
                self.userobj.addToGroup(self.admincontext.lookupGroupname(gn))
 
874
 
 
875
            primarygroupname = unicode(self.primarygroupedit.currentText())
 
876
            self.userobj.setPrimaryGroup(self.admincontext.lookupGroupname(primarygroupname))
 
877
 
 
878
            # Enable/Disable the account            
 
879
            self.userobj.setLocked(self.enabledradiogroup.id(self.enabledradiogroup.selected())!=0)
 
880
            self.admincontext.save()
 
881
 
 
882
    ########################################################################
 
883
    def showNewUser(self):
 
884
        self.updatingGUI = True
 
885
        self.newusermode = True
 
886
        self.userobj = self.admincontext.newUser(True)
 
887
 
 
888
        self.newgroup = self.admincontext.newGroup(True)
 
889
        self.newgroup.setGroupname(self.__fudgeNewGroupName(self.userobj.getUsername()))
 
890
        self.userobj.setPrimaryGroup(self.newgroup)
 
891
 
 
892
        self.selectedgroups = [ u'dialout',u'cdrom',u'floppy',u'audio',u'video',
 
893
                                u'plugdev',u'lpadmin',u'scanner']
 
894
        homedir = self.__fudgeNewHomeDirectory(self.userobj.getUsername())
 
895
        
 
896
        # Rudd-O FIXME: now here we tick the proper groups that should be allowed.  Now it selects what userconfig selected before.  FIXME consider adding a drop down that will select the appropriate profile Limited User, Advanced User or Administrator (and see if there is a config file where these profiles can be read).    We are repopulating because if the user to edit changes, we need to hide the user's secondary group.  FIXME we should repopulate the groups privileges list when the primary group is changed in the other tab -- that is, on the change slot of the primary group drop down.
 
897
        self._repopulateGroupsPrivileges()
 
898
        for group,checkbox in self.secondarygroupcheckboxes.items():
 
899
                if group in self.selectedgroups: checkbox.setState(QCheckListItem.On)
 
900
                else: checkbox.setState(QCheckListItem.Off)
 
901
        
 
902
        self.userobj.setHomeDirectory(homedir)
 
903
        self.homediredit.setText(homedir)
 
904
 
 
905
        shells = self.admincontext.getUserShells()
 
906
        dshell = self.admincontext.dshell
 
907
        if dshell and (dshell in shells):
 
908
            self.userobj.setLoginShell(dshell)
 
909
        elif '/bin/bash' in shells:
 
910
            self.userobj.setLoginShell('/bin/bash')
 
911
        elif '/bin/sh' in shells:
 
912
            self.userobj.setLoginShell('/bin/sh')        
 
913
        elif len(shells)!=0:
 
914
            self.userobj.setLoginShell(shells[0])            
 
915
 
 
916
        self.__syncGUI()
 
917
 
 
918
        self.uidedit.setReadOnly(False)
 
919
        self.updatingGUI = False
 
920
        self.homedirectoryislinked = True
 
921
        self.passwordedit.erase()
 
922
        if self.exec_loop()==QDialog.Accepted:
 
923
            self.__updateObjectFromGUI(self.userobj)
 
924
 
 
925
            makehomedir = True
 
926
            deleteoldhomedir = False
 
927
 
 
928
            if os.path.exists(self.userobj.getHomeDirectory()):
 
929
                rc = self.createhomedirectorydialog.do(self.userobj)
 
930
                if rc==OverwriteHomeDirectoryDialog.CANCEL:
 
931
                    return None
 
932
                if rc==OverwriteHomeDirectoryDialog.OK_KEEP:
 
933
                    makehomedir = False
 
934
                else:
 
935
                    deleteoldhomedir = True
 
936
 
 
937
            self.admincontext.addUser(self.userobj)
 
938
 
 
939
            if self.admincontext.lookupGroupname(self.primarygroupname) is None:
 
940
                # Create a new group
 
941
                newgroup = self.admincontext.newGroup(True)
 
942
                newgroup.setGroupname(self.primarygroupname)
 
943
                self.admincontext.addGroup(newgroup)
 
944
                self.userobj.setPrimaryGroup(newgroup)
 
945
 
 
946
            # Update the groups for this user object. Rudd-O here's when you go in, stud.
 
947
            # we collect the selected groups
 
948
            self.selectedgroups = [ group for group,checkbox in self.secondarygroupcheckboxes.items() if checkbox.isOn() ]
 
949
            for gn in self.selectedgroups:
 
950
                self.userobj.addToGroup(self.admincontext.lookupGroupname(gn))
 
951
 
 
952
            # Set the password.
 
953
            if self.passwordedit.password()!="":
 
954
                self.userobj.setPassword(self.passwordedit.password())
 
955
 
 
956
            # Enable/Disable the account            
 
957
            self.userobj.setLocked(self.enabledradiogroup.id(self.enabledradiogroup.selected())!=0)
 
958
            self.admincontext.save()
 
959
 
 
960
            if deleteoldhomedir:
 
961
                if os.path.exists(self.userobj.getHomeDirectory()):
 
962
                    shutil.rmtree(self.userobj.getHomeDirectory())
 
963
            if makehomedir:
 
964
                self.admincontext.createHomeDirectory(self.userobj)
 
965
 
 
966
            return self.userobj.getUID()
 
967
        else:
 
968
            return None
 
969
 
 
970
    ########################################################################
 
971
    def slotOk(self):
 
972
        ok = True
 
973
        # Sanity check all values.
 
974
        if self.newusermode:
 
975
            newusername = unicode(self.realnameedit.text())
 
976
            if self.admincontext.lookupUsername(newusername)!=None:
 
977
                KMessageBox.sorry(self,i18n("Sorry, you must choose a different user name.\n'%1' is already being used.").arg(newusername))
 
978
                ok = False
 
979
            else:
 
980
                newuid = int(unicode(self.uidedit.text()))
 
981
                originaluid = self.userobj.getUID()
 
982
                if self.admincontext.lookupUID(newuid)!=None:
 
983
                    rc = KMessageBox.questionYesNo(self,i18n("User ID in use"),
 
984
                        i18n("Sorry, the UID %1 is already in use. Should %2 be used instead?").arg(newuid).arg(originaluid))
 
985
                    if rc==KMessageBox.Yes:
 
986
                        self.uidedit.setValue(unicode(originaluid))
 
987
                    else:
 
988
                        ok = False
 
989
                else:
 
990
                    self.userobj.setUID(newuid)
 
991
        if ok:
 
992
            self.passwordedit.clear()
 
993
            KDialogBase.slotOk(self)
 
994
 
 
995
    ########################################################################
 
996
    def slotLoginChanged(self,text):
 
997
        newtext = unicode(text)
 
998
        if not self.updatingGUI:
 
999
            if self.newusermode:
 
1000
                self.newprimarygroupname = self.__fudgeNewGroupName(newtext)
 
1001
                self.updatingGUI = True
 
1002
                self.primarygroupedit.changeItem(self.newprimarygroupname,0)
 
1003
                if self.homedirectoryislinked:
 
1004
                    homedir = self.__fudgeNewHomeDirectory(newtext)
 
1005
                    self.homediredit.setText(homedir)
 
1006
                self.updatingGUI = False
 
1007
 
 
1008
    ########################################################################
 
1009
    def slotHomeDirChanged(self,text):
 
1010
        if self.updatingGUI==False:
 
1011
            self.homedirectoryislinked = False
 
1012
 
 
1013
    ########################################################################
 
1014
    def __syncGUI(self):
 
1015
        if self.userobj.isLocked():
 
1016
            self.enabledradiogroup.setButton(1)
 
1017
        else:
 
1018
            self.enabledradiogroup.setButton(0)
 
1019
 
 
1020
        self.loginnameedit.setText(self.userobj.getUsername())
 
1021
        self.realnameedit.setText(self.userobj.getRealName())
 
1022
        self.uidedit.setText(unicode(self.userobj.getUID()))
 
1023
        self.homediredit.setText(self.userobj.getHomeDirectory())
 
1024
        self.shelledit.setCurrentText(self.userobj.getLoginShell())
 
1025
 
 
1026
        # Primary Group
 
1027
        self.primarygroupedit.clear()
 
1028
        allgroups = [g.getGroupname() for g in self.admincontext.getGroups()]
 
1029
        allgroups.sort()
 
1030
        self.availablegroups = allgroups[:]
 
1031
 
 
1032
        try:
 
1033
            self.availablegroups.remove(self.userobj.getPrimaryGroup().getGroupname())
 
1034
        except ValueError:
 
1035
            pass
 
1036
 
 
1037
        if self.newusermode:
 
1038
            # New user mode
 
1039
            self.newprimarygroupname = self.__fudgeNewGroupName(unicode(self.userobj.getUsername()))
 
1040
            primarygroupname = self.newprimarygroupname
 
1041
            self.primarygroupedit.insertItem(self.newprimarygroupname)
 
1042
        else:
 
1043
            # Existing user mode
 
1044
            primarygroupname = self.userobj.getPrimaryGroup().getGroupname()
 
1045
        for group in allgroups:
 
1046
            self.primarygroupedit.insertItem(group)
 
1047
        self.primarygroupedit.setCurrentText(primarygroupname)
 
1048
 
 
1049
        # If ShadowExpire is turn off then we change the radio box.
 
1050
        if self.userobj.getExpirationDate() is None:
 
1051
            self.validradiogroup.setButton(0)
 
1052
            self.expiredate.setDisabled(True)
 
1053
            self.expiredate.setDate(SptimeToQDate(99999L))
 
1054
        else:
 
1055
            self.validradiogroup.setButton(1)
 
1056
            self.expiredate.setDisabled(False)
 
1057
            self.expiredate.setDate(SptimeToQDate(self.userobj.getExpirationDate()))
 
1058
 
 
1059
        if self.userobj.getMaximumPasswordAge() is None:
 
1060
            # Password aging is turn off
 
1061
            self.forcepasswordchangecheckbox.setChecked(False)
 
1062
            d = True
 
1063
        else:
 
1064
            # Password aging is turn on
 
1065
            self.forcepasswordchangecheckbox.setChecked(True)
 
1066
            d = False
 
1067
        self.warningedit.setDisabled(d)
 
1068
        self.maximumpasswordedit.setDisabled(d)
 
1069
        self.disableexpireedit.setDisabled(d)
 
1070
 
 
1071
        if self.userobj.getPasswordExpireWarning() is None:
 
1072
            self.warningedit.setValue(0)
 
1073
        else:
 
1074
            self.warningedit.setValue(self.userobj.getPasswordExpireWarning())
 
1075
 
 
1076
        if self.userobj.getMaximumPasswordAge() is None:
 
1077
            self.maximumpasswordedit.setValue(30)
 
1078
        else:
 
1079
            self.maximumpasswordedit.setValue(self.userobj.getMaximumPasswordAge())
 
1080
 
 
1081
        if self.userobj.getPasswordDisableAfterExpire() is None:
 
1082
            self.disableexpireedit.setValue(0)
 
1083
        else:
 
1084
            self.disableexpireedit.setValue(self.userobj.getPasswordDisableAfterExpire())
 
1085
 
 
1086
        minage = self.userobj.getMinimumPasswordAgeBeforeChange()
 
1087
        self.enforcepasswordminagecheckbox.setChecked(minage>0)
 
1088
        self.minimumpasswordedit.setDisabled(minage<=0)
 
1089
        if minage<=0:
 
1090
            minage = 1
 
1091
        self.minimumpasswordedit.setValue(minage)
 
1092
 
 
1093
        if self.userobj.getLastPasswordChange() in (None,0):
 
1094
            self.lastchangelabel.setText('-');
 
1095
        else:
 
1096
            self.lastchangelabel.setText(KGlobal.locale().formatDate(SptimeToQDate(int(self.userobj.getLastPasswordChange()))))
 
1097
 
 
1098
    ########################################################################
 
1099
    def __updateObjectFromGUI(self,userobj):
 
1100
        username = unicode(self.loginnameedit.text())
 
1101
        userobj.setUsername(username)
 
1102
        userobj.setRealName(unicode(self.realnameedit.text()))
 
1103
 
 
1104
        userobj.setHomeDirectory(unicode(self.homediredit.text()))
 
1105
        userobj.setLoginShell(unicode(self.shelledit.currentText()))
 
1106
        self.primarygroupname = unicode(self.primarygroupedit.currentText())
 
1107
        groupobj =  self.admincontext.lookupGroupname(self.primarygroupname)
 
1108
        if groupobj is not None:
 
1109
            userobj.setPrimaryGroup(groupobj)
 
1110
 
 
1111
        # Password expiration.
 
1112
        if self.validradiogroup.id(self.validradiogroup.selected())==0:
 
1113
            # Password is always valid.
 
1114
            userobj.setExpirationDate(None)
 
1115
        else:
 
1116
            # Password will expire at...
 
1117
            userobj.setExpirationDate(QDateToSptime(self.expiredate.date()))
 
1118
 
 
1119
        if self.forcepasswordchangecheckbox.isChecked():
 
1120
            userobj.setMaximumPasswordAge(self.maximumpasswordedit.value())
 
1121
        else:
 
1122
            userobj.setMaximumPasswordAge(None)
 
1123
 
 
1124
        if self.disableexpireedit.value()==0:
 
1125
            userobj.setPasswordDisableAfterExpire(None)
 
1126
        else:
 
1127
            userobj.setPasswordDisableAfterExpire(self.disableexpireedit.value())
 
1128
 
 
1129
        if self.enforcepasswordminagecheckbox.isChecked():
 
1130
            userobj.setMinimumPasswordAgeBeforeChange(self.minimumpasswordedit.value())
 
1131
        else:
 
1132
            userobj.setMinimumPasswordAgeBeforeChange(0)
 
1133
 
 
1134
        userobj.setPasswordExpireWarning(self.warningedit.value())
 
1135
 
 
1136
    ########################################################################
 
1137
    def slotBrowseHomeDirClicked(self):
 
1138
        fileurl = KURL()
 
1139
        fileurl.setPath(self.homediredit.text())
 
1140
        self.homedirdialog.setCurrentURL(fileurl)
 
1141
        if self.homedirdialog.exec_loop()==QDialog.Accepted:
 
1142
            self.homediredit.setText(self.homedirdialog.url().path())
 
1143
            self.homedirectoryislinked = False
 
1144
 
 
1145
    ########################################################################
 
1146
    def slotValidUntilClicked(self,id):
 
1147
        if id==0:
 
1148
            self.expiredate.setDisabled(True)
 
1149
        else:
 
1150
            self.expiredate.setDisabled(False)
 
1151
 
 
1152
    ########################################################################
 
1153
    def slotForcePasswordChangeToggled(self,on):
 
1154
        on = not on
 
1155
        self.warningedit.setDisabled(on)
 
1156
        self.maximumpasswordedit.setDisabled(on)
 
1157
        self.disableexpireedit.setDisabled(on)
 
1158
 
 
1159
    ########################################################################
 
1160
    def slotEnforePasswordAgeToggled(self,on):
 
1161
        self.minimumpasswordedit.setDisabled(not on)
 
1162
 
 
1163
    #######################################################################
 
1164
    def __fudgeNewGroupName(self,basename):
 
1165
        if self.admincontext.lookupGroupname(basename) is None:
 
1166
            return basename
 
1167
        x = 1
 
1168
        while self.admincontext.lookupGroupname(basename + u'_' + unicode(x)) is not None:
 
1169
            x += 1
 
1170
        return basename + u'_' + unicode(x)
 
1171
 
 
1172
    #######################################################################
 
1173
    def __fudgeNewHomeDirectory(self,origbasename):
 
1174
        basename = origbasename.replace("/","")
 
1175
        if basename=="":
 
1176
            basename = u"user"
 
1177
 
 
1178
        dhome = self.admincontext.dhome
 
1179
        if not os.path.isdir(dhome):
 
1180
            raise OSError, dhome+" does not exist, is it correctly set in "+ \
 
1181
                    self.admincontext.adduserconf+" ?"
 
1182
        else:
 
1183
            # Make sure there's a trailing /
 
1184
            if dhome[-1] is not '/':
 
1185
                dhome = dhome+'/'
 
1186
 
 
1187
        if os.path.exists(dhome+basename)==False:
 
1188
            return dhome+basename
 
1189
        else:
 
1190
            x = 1
 
1191
            while os.path.exists(dhome+basename + u'_' + unicode(x)):
 
1192
                x += 1
 
1193
            return dhome+basename
 
1194
 
 
1195
 
 
1196
###########################################################################
 
1197
class LoginNameValidator(QValidator):
 
1198
    def __init__(self,parent):
 
1199
        QValidator.__init__(self,parent)
 
1200
 
 
1201
    #######################################################################
 
1202
    def validate(self,inputstr,pos):
 
1203
        instr = unicode(inputstr)
 
1204
        if len(instr)==0:
 
1205
            return (QValidator.Intermediate,pos)
 
1206
        for c in instr:
 
1207
            if ord(c)<0x20 or ord(c)>0x7f or c.isspace() or c==":" or c=="," or c==".":
 
1208
                return (QValidator.Invalid,pos)
 
1209
 
 
1210
        # Try to encode this string in the system encoding.
 
1211
        try:
 
1212
            instr.encode(locale.getpreferredencoding())
 
1213
        except UnicodeEncodeError:
 
1214
            # won't encode -> reject it.
 
1215
            return (QValidator.Invalid,pos)
 
1216
 
 
1217
        return (QValidator.Acceptable,pos)
 
1218
 
 
1219
    #######################################################################
 
1220
    def fixup(self,inputstr):
 
1221
        instr = unicode(inputstr)
 
1222
        newstr = ""
 
1223
        for c in instr:
 
1224
            if (ord(c)<0x20 or ord(c)>0x7f or c.isspace() or c==":" or c=="," or c==".")==False:
 
1225
                newstr += c
 
1226
 
 
1227
        if newstr=="":
 
1228
            return "user"
 
1229
        else:
 
1230
            return newstr
 
1231
 
 
1232
###########################################################################
 
1233
class RealUserNameValidator(QValidator):
 
1234
    def __init__(self,parent):
 
1235
        QValidator.__init__(self,parent)
 
1236
 
 
1237
    #######################################################################
 
1238
    def validate(self,inputstr,pos):
 
1239
        instr = unicode(inputstr)
 
1240
        for c in instr:
 
1241
            if c==":":
 
1242
                return (QValidator.Invalid,pos)
 
1243
 
 
1244
        # Try to encode this string in the system encoding.
 
1245
        try:
 
1246
            instr.encode(locale.getpreferredencoding())
 
1247
        except UnicodeEncodeError:
 
1248
            # won't encode -> reject it.
 
1249
            return (QValidator.Invalid,pos)
 
1250
 
 
1251
        return (QValidator.Acceptable,pos)
 
1252
 
 
1253
    #######################################################################
 
1254
    def fixup(self,inputstr):
 
1255
        return unicode(inputstr).replace(":","")
 
1256
 
 
1257
###########################################################################
 
1258
class ListPickerDialog(KDialogBase):
 
1259
    def __init__(self,parent,caption,leftlabel,rightlabel):
 
1260
        KDialogBase.__init__(self,parent,None,True,caption,KDialogBase.Ok|KDialogBase.Cancel, KDialogBase.Cancel)
 
1261
 
 
1262
        self.tophbox = QHBox(self)
 
1263
        self.setMainWidget(self.tophbox)
 
1264
        self.tophbox.setSpacing(self.spacingHint())
 
1265
        # Available Groups
 
1266
        vbox = QVBox(self.tophbox)
 
1267
        self.tophbox.setStretchFactor(vbox,1)
 
1268
        label = QLabel(leftlabel,vbox)
 
1269
        vbox.setStretchFactor(label,0)
 
1270
        self.availablelist = KListBox(vbox)
 
1271
        vbox.setStretchFactor(self.availablelist,1)
 
1272
 
 
1273
        # ->, <- Buttons
 
1274
        vbox = QVBox(self.tophbox)
 
1275
        self.tophbox.setStretchFactor(vbox,0)
 
1276
        spacer = QWidget(vbox);
 
1277
        vbox.setStretchFactor(spacer,1)
 
1278
        self.addbutton = KPushButton(i18n("Add ->"),vbox)
 
1279
        self.connect(self.addbutton,SIGNAL("clicked()"),self.slotAddClicked)
 
1280
        vbox.setStretchFactor(self.addbutton,0)
 
1281
        self.removebutton = KPushButton(i18n("<- Remove"),vbox)
 
1282
        self.connect(self.removebutton,SIGNAL("clicked()"),self.slotRemoveClicked)
 
1283
        vbox.setStretchFactor(self.removebutton,0)
 
1284
        spacer = QWidget(vbox);
 
1285
        vbox.setStretchFactor(spacer,1)
 
1286
 
 
1287
        # Selected Groups
 
1288
        vbox = QVBox(self.tophbox)
 
1289
        self.tophbox.setStretchFactor(vbox,1)
 
1290
        label = QLabel(rightlabel,vbox)
 
1291
        vbox.setStretchFactor(label,0)
 
1292
        self.selectedlist = KListBox(vbox)
 
1293
        vbox.setStretchFactor(self.selectedlist,1)
 
1294
 
 
1295
    #######################################################################
 
1296
    def do(self,grouplist,selectedlist):
 
1297
        self.selectedlist.clear()
 
1298
        for item in selectedlist:
 
1299
            self.selectedlist.insertItem(item)
 
1300
        self.selectedlist.sort()
 
1301
 
 
1302
        self.availablelist.clear()
 
1303
        for item in grouplist:
 
1304
            if item not in selectedlist:
 
1305
                self.availablelist.insertItem(item)
 
1306
        self.availablelist.sort()
 
1307
 
 
1308
        self._selectFirstAvailable()
 
1309
        self.addbutton.setDisabled(self.availablelist.selectedItem()==None)
 
1310
 
 
1311
        self._selectFirstSelected()
 
1312
        self.removebutton.setDisabled(self.selectedlist.selectedItem()==None)
 
1313
 
 
1314
        if self.exec_loop()==QDialog.Accepted:
 
1315
            newlist = []
 
1316
            for i in range(self.selectedlist.count()):
 
1317
                newlist.append(unicode(self.selectedlist.item(i).text()))
 
1318
            return newlist
 
1319
        else:
 
1320
            return selectedlist
 
1321
 
 
1322
    #######################################################################
 
1323
    def slotAddClicked(self):
 
1324
        item = self.availablelist.selectedItem()
 
1325
        if item!=None:
 
1326
            self.selectedlist.insertItem(item.text())
 
1327
            self.availablelist.removeItem(self.availablelist.index(item))
 
1328
            self._selectFirstAvailable()
 
1329
            self._selectFirstSelected()
 
1330
            self.addbutton.setDisabled(self.availablelist.selectedItem()==None)
 
1331
            self.removebutton.setDisabled(self.selectedlist.selectedItem()==None)
 
1332
 
 
1333
    #######################################################################
 
1334
    def slotRemoveClicked(self):
 
1335
        item = self.selectedlist.selectedItem()
 
1336
        if item!=None:
 
1337
            self.availablelist.insertItem(item.text())
 
1338
            self.selectedlist.removeItem(self.selectedlist.index(item))
 
1339
            self._selectFirstAvailable()
 
1340
            self._selectFirstSelected()
 
1341
            self.addbutton.setDisabled(self.availablelist.selectedItem()==None)
 
1342
            self.removebutton.setDisabled(self.selectedlist.selectedItem()==None)
 
1343
 
 
1344
    #######################################################################
 
1345
    def _selectFirstAvailable(self):
 
1346
        if self.availablelist.count()!=0:
 
1347
            if self.availablelist.selectedItem()==None:
 
1348
                self.availablelist.setSelected(0,True)
 
1349
 
 
1350
    #######################################################################
 
1351
    def _selectFirstSelected(self):
 
1352
        if self.selectedlist.count()!=0:
 
1353
            if self.selectedlist.selectedItem()==None:
 
1354
                self.selectedlist.setSelected(0,True)
 
1355
 
 
1356
###########################################################################
 
1357
class UserDeleteDialog(KDialog):
 
1358
    def __init__(self,parent,admincontext):
 
1359
        KDialog.__init__(self,parent,"Delete user dialog",True,Qt.WType_Dialog)
 
1360
        self.setCaption(i18n("Delete User Account"))
 
1361
        self.admincontext = admincontext
 
1362
        self.updatingGUI = True
 
1363
 
 
1364
        toplayout = QVBoxLayout(self)
 
1365
        toplayout.setSpacing(self.spacingHint())
 
1366
        toplayout.setMargin(self.marginHint())
 
1367
 
 
1368
        contentbox = QHBox(self)
 
1369
        contentbox.setSpacing(self.spacingHint())
 
1370
        toplayout.addWidget(contentbox)
 
1371
        toplayout.setStretchFactor(contentbox,1)
 
1372
 
 
1373
        label = QLabel(contentbox)
 
1374
        label.setPixmap(KGlobal.iconLoader().loadIcon("messagebox_warning", KIcon.NoGroup, KIcon.SizeMedium,
 
1375
            KIcon.DefaultState, None, True))
 
1376
        contentbox.setStretchFactor(label,0)
 
1377
 
 
1378
        textbox = QVBox(contentbox)
 
1379
 
 
1380
        textbox.setSpacing(self.spacingHint())
 
1381
        textbox.setMargin(self.marginHint())
 
1382
 
 
1383
        self.usernamelabel = QLabel("",textbox)
 
1384
        textbox.setStretchFactor(self.usernamelabel,0)
 
1385
 
 
1386
        # Remove directory checkbox.
 
1387
        self.deletedirectorycheckbox = QCheckBox(i18n("Delete home directory ()"),textbox)
 
1388
        textbox.setStretchFactor(self.deletedirectorycheckbox,0)
 
1389
 
 
1390
        # Delete the User's private group.
 
1391
        self.deletegroupcheckbox = QCheckBox(i18n("Delete group ()"),textbox)
 
1392
        textbox.setStretchFactor(self.deletegroupcheckbox ,0)
 
1393
 
 
1394
        # Buttons
 
1395
        buttonbox = QHBox(self)
 
1396
        toplayout.addWidget(buttonbox)
 
1397
 
 
1398
        buttonbox.setSpacing(self.spacingHint())
 
1399
        toplayout.setStretchFactor(buttonbox,0)
 
1400
 
 
1401
        spacer = QWidget(buttonbox)
 
1402
        buttonbox.setStretchFactor(spacer,1)
 
1403
 
 
1404
        okbutton = QPushButton(i18n("OK"),buttonbox)
 
1405
        buttonbox.setStretchFactor(okbutton,0)
 
1406
        self.connect(okbutton,SIGNAL("clicked()"),self.slotOkClicked)
 
1407
 
 
1408
        cancelbutton = QPushButton(i18n("Cancel"),buttonbox)
 
1409
        cancelbutton.setDefault(True)
 
1410
        buttonbox.setStretchFactor(cancelbutton,0)
 
1411
        self.connect(cancelbutton,SIGNAL("clicked()"),self.slotCancelClicked)
 
1412
 
 
1413
    def deleteUser(self,userid):
 
1414
        # Setup the 
 
1415
        userobj = self.admincontext.lookupUID(userid)
 
1416
        self.usernamelabel.setText(i18n("Are you sure want to delete user account '%1' (%2)?").arg(userobj.getUsername()).arg(userobj.getUID()) )
 
1417
        self.deletedirectorycheckbox.setChecked(False)
 
1418
        self.deletedirectorycheckbox.setText(i18n("Delete home directory (%1)").arg(userobj.getHomeDirectory()))
 
1419
        primarygroupobj = userobj.getPrimaryGroup()
 
1420
        primarygroupname = primarygroupobj.getGroupname()
 
1421
        self.deletegroupcheckbox.setText(i18n("Delete group '%1' (%2)").arg(primarygroupname).arg(primarygroupobj.getGID()))
 
1422
        self.deletegroupcheckbox.setChecked(len(primarygroupobj.getUsers())==1)
 
1423
        if self.exec_loop()==QDialog.Accepted:
 
1424
            self.admincontext.removeUser(userobj)
 
1425
            if self.deletedirectorycheckbox.isChecked():
 
1426
                self.admincontext.removeHomeDirectory(userobj)
 
1427
                # FIXME
 
1428
                #self.admincontext.removeMail(userobj)
 
1429
            if self.deletegroupcheckbox.isChecked():
 
1430
                self.admincontext.removeGroup(primarygroupobj)
 
1431
            self.admincontext.save()
 
1432
            return True
 
1433
        else:
 
1434
            return False
 
1435
 
 
1436
    def slotOkClicked(self):
 
1437
        self.accept()
 
1438
 
 
1439
    def slotCancelClicked(self):
 
1440
        self.reject()
 
1441
 
 
1442
###########################################################################
 
1443
class OverwriteHomeDirectoryDialog(KDialog):
 
1444
    CANCEL = 0
 
1445
    OK_KEEP = 1
 
1446
    OK_REPLACE = 2
 
1447
 
 
1448
    def __init__(self,parent):
 
1449
        KDialog.__init__(self,parent,"Create home directory",True,Qt.WType_Dialog)
 
1450
        self.setCaption(i18n("Create home directory"))
 
1451
        self.updatingGUI = True
 
1452
 
 
1453
        toplayout = QVBoxLayout(self)
 
1454
        toplayout.setSpacing(self.spacingHint())
 
1455
        toplayout.setMargin(self.marginHint())
 
1456
 
 
1457
        contentbox = QHBox(self)
 
1458
        contentbox.setSpacing(self.spacingHint())
 
1459
        toplayout.addWidget(contentbox)
 
1460
        toplayout.setStretchFactor(contentbox,1)
 
1461
 
 
1462
        label = QLabel(contentbox)
 
1463
        label.setPixmap(KGlobal.iconLoader().loadIcon("messagebox_warning", KIcon.NoGroup, KIcon.SizeMedium,
 
1464
            KIcon.DefaultState, None, True))
 
1465
        contentbox.setStretchFactor(label,0)
 
1466
 
 
1467
        textbox = QVBox(contentbox)
 
1468
 
 
1469
        textbox.setSpacing(self.spacingHint())
 
1470
        textbox.setMargin(self.marginHint())
 
1471
 
 
1472
        # "%dir was selected as the home directory for %user. This directory already exists. Shall I:."
 
1473
        self.toplabel = QLabel("",textbox)
 
1474
        textbox.setStretchFactor(self.toplabel,0)
 
1475
 
 
1476
        self.radiogroup = QButtonGroup()
 
1477
        self.radiogroup.setRadioButtonExclusive(True)
 
1478
 
 
1479
        # Use Existing home directory radio button.
 
1480
        self.usehomedirectoryradio = QRadioButton(i18n("Use the existing directory without changing it."),textbox)
 
1481
        textbox.setStretchFactor(self.usehomedirectoryradio,0)
 
1482
 
 
1483
        # Replace home directory radio button
 
1484
        self.replacehomedirectoryradio = QRadioButton(i18n("Delete the directory and replace it with a new home directory."),textbox)
 
1485
        textbox.setStretchFactor(self.replacehomedirectoryradio ,0)
 
1486
 
 
1487
        self.radiogroup.insert(self.usehomedirectoryradio,0)
 
1488
        self.radiogroup.insert(self.replacehomedirectoryradio,1)
 
1489
 
 
1490
        # Buttons
 
1491
        buttonbox = QHBox(self)
 
1492
        toplayout.addWidget(buttonbox)
 
1493
 
 
1494
        buttonbox.setSpacing(self.spacingHint())
 
1495
        toplayout.setStretchFactor(buttonbox,0)
 
1496
 
 
1497
        spacer = QWidget(buttonbox)
 
1498
        buttonbox.setStretchFactor(spacer,1)
 
1499
 
 
1500
        okbutton = QPushButton(i18n("OK"),buttonbox)
 
1501
        buttonbox.setStretchFactor(okbutton,0)
 
1502
        self.connect(okbutton,SIGNAL("clicked()"),self.slotOkClicked)
 
1503
 
 
1504
        cancelbutton = QPushButton(i18n("Cancel"),buttonbox)
 
1505
        cancelbutton.setDefault(True)
 
1506
        buttonbox.setStretchFactor(cancelbutton,0)
 
1507
        self.connect(cancelbutton,SIGNAL("clicked()"),self.slotCancelClicked)
 
1508
 
 
1509
    def do(self,userobj):
 
1510
        # Setup the 
 
1511
        self.toplabel.setText(i18n("The directory '%1' was entered as the home directory for new user '%2'.\n This directory already exists.") \
 
1512
            .arg(userobj.getHomeDirectory()).arg(userobj.getUsername()) )
 
1513
        self.radiogroup.setButton(0)
 
1514
 
 
1515
        if self.exec_loop()==QDialog.Accepted:
 
1516
            if self.radiogroup.selectedId()==0:
 
1517
                return OverwriteHomeDirectoryDialog.OK_KEEP
 
1518
            else:
 
1519
                return OverwriteHomeDirectoryDialog.OK_REPLACE
 
1520
        else:
 
1521
            return OverwriteHomeDirectoryDialog.CANCEL
 
1522
 
 
1523
    def slotOkClicked(self):
 
1524
        self.accept()
 
1525
 
 
1526
    def slotCancelClicked(self):
 
1527
        self.reject()
 
1528
 
 
1529
###########################################################################
 
1530
class GroupEditDialog(KDialogBase):
 
1531
    def __init__(self,parent,admincontext):
 
1532
        KDialogBase.__init__(self,parent,None,True,i18n("Edit Group"),KDialogBase.Ok|KDialogBase.Cancel,
 
1533
            KDialogBase.Cancel)
 
1534
 
 
1535
        self.admincontext = admincontext
 
1536
 
 
1537
        topvbox = QVBox(self)
 
1538
        topvbox.setSpacing(self.spacingHint())
 
1539
        self.setMainWidget(topvbox)
 
1540
 
 
1541
        detailspace = QWidget(topvbox)
 
1542
 
 
1543
        # Info about the group.
 
1544
        editgrid = QGridLayout(detailspace,2,2)
 
1545
        editgrid.setSpacing(self.spacingHint())
 
1546
 
 
1547
        label = QLabel(i18n("Group Name:"),detailspace)
 
1548
        editgrid.addWidget(label,0,0)
 
1549
        self.groupnamelabel = KLineEdit("",detailspace)
 
1550
        self.groupnamelabel.setReadOnly(True)
 
1551
        editgrid.addWidget(self.groupnamelabel,0,1)
 
1552
 
 
1553
        label = QLabel(i18n("Group ID:"),detailspace)
 
1554
        editgrid.addWidget(label,1,0)
 
1555
        self.groupidlabel = KLineEdit("",detailspace)
 
1556
        self.groupidlabel.setReadOnly(True)
 
1557
        editgrid.addWidget(self.groupidlabel,1,1)
 
1558
 
 
1559
        # Available Groups
 
1560
        tophbox = QHBox(topvbox)
 
1561
        tophbox.setSpacing(self.spacingHint())
 
1562
 
 
1563
        hbox = tophbox
 
1564
 
 
1565
        vbox = QVBox(hbox)
 
1566
        vbox.setSpacing(self.spacingHint())
 
1567
        hbox.setStretchFactor(vbox,1)
 
1568
        label = QLabel(i18n("Available Accounts"),vbox)
 
1569
        vbox.setStretchFactor(label,0)
 
1570
        self.availablelist = KListBox(vbox)
 
1571
        vbox.setStretchFactor(self.availablelist,1)
 
1572
 
 
1573
        # ->, <- Buttons
 
1574
        vbox = QVBox(hbox)
 
1575
        vbox.setSpacing(self.spacingHint())
 
1576
        hbox.setStretchFactor(vbox,0)
 
1577
        spacer = QWidget(vbox);
 
1578
        vbox.setStretchFactor(spacer,1)
 
1579
        self.addbutton = KPushButton(i18n("Add ->"),vbox)
 
1580
        self.connect(self.addbutton,SIGNAL("clicked()"),self.slotAddClicked)
 
1581
        vbox.setStretchFactor(self.addbutton,0)
 
1582
        self.removebutton = KPushButton(i18n("<- Remove"),vbox)
 
1583
        self.connect(self.removebutton,SIGNAL("clicked()"),self.slotRemoveClicked)
 
1584
        vbox.setStretchFactor(self.removebutton,0)
 
1585
        spacer = QWidget(vbox);
 
1586
        vbox.setStretchFactor(spacer,1)
 
1587
 
 
1588
        # Selected Groups
 
1589
        vbox = QVBox(hbox)
 
1590
        vbox.setSpacing(self.spacingHint())
 
1591
        hbox.setStretchFactor(vbox,1)
 
1592
        label = QLabel(i18n("Selected Accounts"),vbox)
 
1593
        vbox.setStretchFactor(label,0)
 
1594
        self.selectedlist = KListBox(vbox)
 
1595
        vbox.setStretchFactor(self.selectedlist,1)
 
1596
 
 
1597
    #######################################################################
 
1598
    def showEditGroup(self,groupid):
 
1599
        self.groupid = groupid
 
1600
        self.newgroupmode = False
 
1601
 
 
1602
        groupobj = self.admincontext.lookupGID(groupid)
 
1603
 
 
1604
        self.groupnamelabel.setText(groupobj.getGroupname())
 
1605
        self.groupidlabel.setText(unicode(groupid))
 
1606
 
 
1607
        availablemembers = [u.getUsername() for u in self.admincontext.getUsers()]
 
1608
        originalmembers = [u.getUsername() for u in groupobj.getUsers()]
 
1609
 
 
1610
        self.__updateLists(availablemembers,originalmembers)
 
1611
 
 
1612
        if self.exec_loop()==QDialog.Accepted:
 
1613
            newmembers = []
 
1614
            for i in range(self.selectedlist.count()):
 
1615
                newmembers.append(unicode(self.selectedlist.item(i).text()))
 
1616
 
 
1617
            # Remove from the group object any unselected users.
 
1618
            for member in originalmembers:
 
1619
                if u not in newmembers:
 
1620
                    self.admincontext.lookupUsername(member).removeFromGroup(groupobj)
 
1621
            # Put the additional members in the group
 
1622
            for member in newmembers:
 
1623
                self.admincontext.lookupUsername(member).addToGroup(groupobj)
 
1624
            self.admincontext.save()
 
1625
            return True
 
1626
        else:
 
1627
            return False
 
1628
 
 
1629
    #######################################################################
 
1630
    def showNewGroup(self):
 
1631
        self.updatingGUI = True
 
1632
        self.newgroupmode = True
 
1633
 
 
1634
        groupname = self.__fudgeNewGroupName(i18n("<Base string for creating new group names>","new_group"))
 
1635
 
 
1636
        self.groupobj = self.admincontext.newGroup(True)
 
1637
        self.groupobj.setGroupname(groupname)
 
1638
 
 
1639
        groupname = self.groupobj.getGroupname()
 
1640
        self.groupnamelabel.setText(groupname)
 
1641
        self.groupnamelabel.setReadOnly(False)
 
1642
        self.groupidlabel.setText(unicode(self.groupobj.getGID()))
 
1643
        self.groupidlabel.setReadOnly(False)
 
1644
 
 
1645
        availablemembers = [u.getUsername() for u in self.admincontext.getUsers()]
 
1646
 
 
1647
        self.__updateLists(availablemembers,[])
 
1648
 
 
1649
        if self.exec_loop()==QDialog.Accepted:
 
1650
            self.groupobj.setGroupname(unicode(self.groupnamelabel.text()))
 
1651
            newgroupid = int(unicode(self.groupidlabel.text()))
 
1652
            self.groupobj.setGID(newgroupid)
 
1653
 
 
1654
            newmembers = []
 
1655
            for i in range(self.selectedlist.count()):
 
1656
                newmembers.append(unicode(self.selectedlist.item(i).text()))
 
1657
 
 
1658
            self.admincontext.addGroup(self.groupobj)
 
1659
 
 
1660
            # Put the additional members in the group
 
1661
            for member in newmembers:
 
1662
                self.admincontext.lookupUsername(member).addToGroup(self.groupobj)
 
1663
            self.admincontext.save()
 
1664
 
 
1665
            return newgroupid
 
1666
        else:
 
1667
            return None
 
1668
 
 
1669
    #######################################################################
 
1670
    def slotAddClicked(self):
 
1671
        item = self.availablelist.selectedItem()
 
1672
        if item!=None:
 
1673
            self.selectedlist.insertItem(item.text())
 
1674
            self.availablelist.removeItem(self.availablelist.index(item))
 
1675
            self._selectFirstAvailable()
 
1676
            self._selectFirstSelected()
 
1677
            self.addbutton.setDisabled(self.availablelist.selectedItem()==None)
 
1678
            self.removebutton.setDisabled(self.selectedlist.selectedItem()==None)
 
1679
 
 
1680
    #######################################################################
 
1681
    def slotRemoveClicked(self):
 
1682
        item = self.selectedlist.selectedItem()
 
1683
        if item!=None:
 
1684
            self.availablelist.insertItem(item.text())
 
1685
            self.selectedlist.removeItem(self.selectedlist.index(item))
 
1686
            self._selectFirstAvailable()
 
1687
            self._selectFirstSelected()
 
1688
            self.addbutton.setDisabled(self.availablelist.selectedItem()==None)
 
1689
            self.removebutton.setDisabled(self.selectedlist.selectedItem()==None)
 
1690
 
 
1691
    #######################################################################
 
1692
    def __updateLists(self,grouplist,selectedlist):
 
1693
        self.selectedlist.clear()
 
1694
        for item in selectedlist:
 
1695
            self.selectedlist.insertItem(item)
 
1696
        self.selectedlist.sort()
 
1697
 
 
1698
        self.availablelist.clear()
 
1699
        for item in grouplist:
 
1700
            if item not in selectedlist:
 
1701
                self.availablelist.insertItem(item)
 
1702
        self.availablelist.sort()
 
1703
 
 
1704
        self._selectFirstAvailable()
 
1705
        self.addbutton.setDisabled(self.availablelist.selectedItem()==None)
 
1706
 
 
1707
        self._selectFirstSelected()
 
1708
        self.removebutton.setDisabled(self.selectedlist.selectedItem()==None)
 
1709
 
 
1710
    #######################################################################
 
1711
    def _selectFirstAvailable(self):
 
1712
        if self.availablelist.count()!=0:
 
1713
            if self.availablelist.selectedItem()==None:
 
1714
                self.availablelist.setSelected(0,True)
 
1715
 
 
1716
    #######################################################################
 
1717
    def _selectFirstSelected(self):
 
1718
        if self.selectedlist.count()!=0:
 
1719
            if self.selectedlist.selectedItem()==None:
 
1720
                self.selectedlist.setSelected(0,True)
 
1721
 
 
1722
    #######################################################################
 
1723
    def __fudgeNewGroupName(self,basename):
 
1724
        availablegroups = [g.getGroupname() for g in self.admincontext.getGroups()]
 
1725
        if basename not in availablegroups:
 
1726
            return basename
 
1727
        x = 1
 
1728
        while basename + u'_' + unicode(x) in availablegroups:
 
1729
            x += 1
 
1730
        return basename + u'_' + unicode(x)
 
1731
 
 
1732
############################################################################
 
1733
# Factory function for KControl
 
1734
def create_userconfig(parent,name):
 
1735
    return UserConfigApp(parent, name)
 
1736
 
 
1737
##########################################################################
 
1738
def MakeAboutData():
 
1739
    aboutdata = KAboutData("guidance", programname, version,
 
1740
        unicode(i18n("User and Group Configuration Tool")).encode(locale.getpreferredencoding()),
 
1741
        KAboutData.License_GPL, "Copyright (C) 2003-2007 Simon Edwards")
 
1742
    aboutdata.addAuthor("Simon Edwards", "Developer", "simon@simonzone.com", "http://www.simonzone.com/software/")
 
1743
    aboutdata.addAuthor("Sebastian Kügler", "Developer", "sebas@kde.org", "http://vizZzion.org")
 
1744
    return aboutdata
 
1745
 
 
1746
if standalone:
 
1747
    aboutdata = MakeAboutData()
 
1748
 
 
1749
    KCmdLineArgs.init(sys.argv,aboutdata)
 
1750
 
 
1751
    kapp = KApplication()
 
1752
    userconfigapp = UserConfigApp()
 
1753
    userconfigapp.exec_loop()