• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • kfile
kacleditwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
3 * 2005 - 2007 Till Adam <adam@kde.org> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Library General Public License as *
7 * published by the Free Software Foundation; either version 2 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21#include "kacleditwidget.h"
22#include "kacleditwidget_p.h"
23
24#include <config-acl.h>
25#ifdef HAVE_POSIX_ACL
26
27#include <qpainter.h>
28#include <qpushbutton.h>
29#include <QButtonGroup>
30#include <QGroupBox>
31#include <qradiobutton.h>
32#include <qcombobox.h>
33#include <qlabel.h>
34#include <qcheckbox.h>
35#include <qlayout.h>
36#include <QStackedWidget>
37#include <QMouseEvent>
38#include <QHeaderView>
39
40#include <klocale.h>
41#include <kfileitem.h>
42#include <kdebug.h>
43#include <kdialog.h>
44#include <kvbox.h>
45#include <khbox.h>
46
47#ifdef HAVE_ACL_LIBACL_H
48# include <acl/libacl.h>
49#endif
50extern "C" {
51#include <pwd.h>
52#include <grp.h>
53}
54#include <assert.h>
55
56static struct {
57 const char* label;
58 const char* pixmapName;
59 QPixmap* pixmap;
60} s_itemAttributes[] = {
61 { I18N_NOOP( "Owner" ), "user-grey", 0 },
62 { I18N_NOOP( "Owning Group" ), "group-grey", 0 },
63 { I18N_NOOP( "Others" ), "others-grey", 0 },
64 { I18N_NOOP( "Mask" ), "mask", 0 },
65 { I18N_NOOP( "Named User" ), "user", 0 },
66 { I18N_NOOP( "Named Group" ), "group", 0 },
67};
68
69class KACLEditWidget::KACLEditWidgetPrivate
70{
71public:
72 KACLEditWidgetPrivate()
73 {
74 }
75
76 // slots
77 void _k_slotUpdateButtons();
78
79 KACLListView *m_listView;
80 QPushButton *m_AddBtn;
81 QPushButton *m_EditBtn;
82 QPushButton *m_DelBtn;
83};
84
85KACLEditWidget::KACLEditWidget( QWidget *parent )
86 : QWidget(parent), d(new KACLEditWidgetPrivate)
87{
88 QHBoxLayout *hbox = new QHBoxLayout( this );
89 hbox->setMargin( 0 );
90 d->m_listView = new KACLListView(this);
91 hbox->addWidget(d->m_listView);
92 connect(d->m_listView->selectionModel(),
93 SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
94 this,
95 SLOT(_k_slotUpdateButtons()));
96 QVBoxLayout *vbox = new QVBoxLayout();
97 hbox->addLayout( vbox );
98 d->m_AddBtn = new QPushButton(i18n("Add Entry..."), this);
99 vbox->addWidget(d->m_AddBtn);
100 d->m_AddBtn->setObjectName(QLatin1String("add_entry_button"));
101 connect(d->m_AddBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotAddEntry()));
102 d->m_EditBtn = new QPushButton(i18n("Edit Entry..."), this);
103 vbox->addWidget(d->m_EditBtn);
104 d->m_EditBtn->setObjectName(QLatin1String("edit_entry_button"));
105 connect(d->m_EditBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotEditEntry()));
106 d->m_DelBtn = new QPushButton(i18n("Delete Entry"), this);
107 vbox->addWidget(d->m_DelBtn);
108 d->m_DelBtn->setObjectName(QLatin1String("delete_entry_button"));
109 connect(d->m_DelBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotRemoveEntry()));
110 vbox->addItem( new QSpacerItem( 10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding ) );
111 d->_k_slotUpdateButtons();
112}
113
114KACLEditWidget::~KACLEditWidget()
115{
116 delete d;
117}
118
119void KACLEditWidget::KACLEditWidgetPrivate::_k_slotUpdateButtons()
120{
121 bool atLeastOneIsNotDeletable = false;
122 bool atLeastOneIsNotAllowedToChangeType = false;
123 int selectedCount = 0;
124 QList<QTreeWidgetItem*> selected = m_listView->selectedItems();
125 QListIterator<QTreeWidgetItem*> it( selected );
126 while ( it.hasNext() ) {
127 KACLListViewItem *item = static_cast<KACLListViewItem*>( it.next() );
128 ++selectedCount;
129 if ( !item->isDeletable() )
130 atLeastOneIsNotDeletable = true;
131 if ( !item->isAllowedToChangeType() )
132 atLeastOneIsNotAllowedToChangeType = true;
133 }
134 m_EditBtn->setEnabled( selectedCount && !atLeastOneIsNotAllowedToChangeType );
135 m_DelBtn->setEnabled( selectedCount && !atLeastOneIsNotDeletable );
136}
137
138KACL KACLEditWidget::getACL() const
139{
140 return d->m_listView->getACL();
141}
142
143KACL KACLEditWidget::getDefaultACL() const
144{
145 return d->m_listView->getDefaultACL();
146}
147
148void KACLEditWidget::setACL( const KACL &acl )
149{
150 return d->m_listView->setACL(acl);
151}
152
153void KACLEditWidget::setDefaultACL( const KACL &acl )
154{
155 return d->m_listView->setDefaultACL(acl);
156}
157
158void KACLEditWidget::setAllowDefaults( bool value )
159{
160 d->m_listView->setAllowDefaults(value);
161}
162
163KACLListViewItem::KACLListViewItem( QTreeWidget* parent,
164 KACLListView::EntryType _type,
165 unsigned short _value, bool defaults,
166 const QString& _qualifier )
167 : QTreeWidgetItem( parent),
168 type( _type ), value( _value ), isDefault( defaults ),
169 qualifier( _qualifier ), isPartial( false )
170{
171 m_pACLListView = qobject_cast<KACLListView*>( parent );
172 repaint();
173}
174
175
176KACLListViewItem::~ KACLListViewItem()
177{
178
179}
180
181QString KACLListViewItem::key() const
182{
183 QString key;
184 if ( !isDefault )
185 key = 'A';
186 else
187 key = 'B';
188 switch ( type )
189 {
190 case KACLListView::User:
191 key += 'A';
192 break;
193 case KACLListView::Group:
194 key += 'B';
195 break;
196 case KACLListView::Others:
197 key += 'C';
198 break;
199 case KACLListView::Mask:
200 key += 'D';
201 break;
202 case KACLListView::NamedUser:
203 key += 'E' + text( 1 );
204 break;
205 case KACLListView::NamedGroup:
206 key += 'F' + text( 1 );
207 break;
208 default:
209 key += text( 0 );
210 break;
211 }
212 return key;
213}
214
215bool KACLListViewItem::operator< ( const QTreeWidgetItem& other ) const
216{
217 return key() < static_cast<const KACLListViewItem&>(other).key();
218}
219
220#if 0
221void KACLListViewItem::paintCell( QPainter* p, const QColorGroup &cg,
222 int column, int width, int alignment )
223{
224 if ( isDefault ) {
225 setForeground( QColor( 0, 0, 255 ) );
226 }
227 if ( isPartial ) {
228 QFont font = p->font();
229 font.setItalic( true );
230 setForeground( QColor( 100, 100, 100 ) );
231 p->setFont( font );
232 }
233 QTreeWidgetItem::paintCell( p, mycg, column, width, alignment );
234
235 KACLListViewItem *below =0;
236 if ( itemBelow() )
237 below = static_cast<KACLListViewItem*>( itemBelow() );
238 const bool lastUser = type == KACLListView::NamedUser && below && below->type == KACLListView::NamedGroup;
239 const bool lastNonDefault = !isDefault && below && below->isDefault;
240 if ( type == KACLListView::Mask || lastUser || lastNonDefault )
241 {
242 p->setPen( QPen( Qt::gray, 0, Qt::DotLine ) );
243 if ( type == KACLListView::Mask )
244 p->drawLine( 0, 0, width - 1, 0 );
245 p->drawLine( 0, height() - 1, width - 1, height() - 1 );
246 }
247}
248#endif
249
250
251void KACLListViewItem::updatePermPixmaps()
252{
253 unsigned int partialPerms = value;
254
255 if ( value & ACL_READ )
256 setIcon( 2, m_pACLListView->getYesPixmap() );
257 else if ( partialPerms & ACL_READ )
258 setIcon( 2, m_pACLListView->getYesPartialPixmap() );
259 else
260 setIcon( 2, QIcon() );
261
262 if ( value & ACL_WRITE )
263 setIcon( 3, m_pACLListView->getYesPixmap() );
264 else if ( partialPerms & ACL_WRITE )
265 setIcon( 3, m_pACLListView->getYesPartialPixmap() );
266 else
267 setIcon( 3, QIcon() );
268
269 if ( value & ACL_EXECUTE )
270 setIcon( 4, m_pACLListView->getYesPixmap() );
271 else if ( partialPerms & ACL_EXECUTE )
272 setIcon( 4, m_pACLListView->getYesPartialPixmap() );
273 else
274 setIcon( 4, QIcon() );
275}
276
277void KACLListViewItem::repaint()
278{
279 int idx = 0;
280 switch ( type )
281 {
282 case KACLListView::User:
283 idx = KACLListView::OWNER_IDX;
284 break;
285 case KACLListView::Group:
286 idx = KACLListView::GROUP_IDX;
287 break;
288 case KACLListView::Others:
289 idx = KACLListView::OTHERS_IDX;
290 break;
291 case KACLListView::Mask:
292 idx = KACLListView::MASK_IDX;
293 break;
294 case KACLListView::NamedUser:
295 idx = KACLListView::NAMED_USER_IDX;
296 break;
297 case KACLListView::NamedGroup:
298 idx = KACLListView::NAMED_GROUP_IDX;
299 break;
300 default:
301 idx = KACLListView::OWNER_IDX;
302 break;
303 }
304 setText( 0, i18n(s_itemAttributes[idx].label) );
305 setIcon( 0, *s_itemAttributes[idx].pixmap );
306 if ( isDefault )
307 setText( 0, text( 0 ) + i18n( " (Default)" ) );
308 setText( 1, qualifier );
309 // Set the pixmaps for which of the perms are set
310 updatePermPixmaps();
311}
312
313void KACLListViewItem::calcEffectiveRights()
314{
315 QString strEffective = QString( "---" );
316
317 // Do we need to worry about the mask entry? It applies to named users,
318 // owning group, and named groups
319 if ( m_pACLListView->hasMaskEntry()
320 && ( type == KACLListView::NamedUser
321 || type == KACLListView::Group
322 || type == KACLListView::NamedGroup )
323 && !isDefault )
324 {
325
326 strEffective[0] = ( m_pACLListView->maskPermissions() & value & ACL_READ ) ? 'r' : '-';
327 strEffective[1] = ( m_pACLListView->maskPermissions() & value & ACL_WRITE ) ? 'w' : '-';
328 strEffective[2] = ( m_pACLListView->maskPermissions() & value & ACL_EXECUTE ) ? 'x' : '-';
329/*
330 // What about any partial perms?
331 if ( maskPerms & partialPerms & ACL_READ || // Partial perms on entry
332 maskPartialPerms & perms & ACL_READ || // Partial perms on mask
333 maskPartialPerms & partialPerms & ACL_READ ) // Partial perms on mask and entry
334 strEffective[0] = 'R';
335 if ( maskPerms & partialPerms & ACL_WRITE || // Partial perms on entry
336 maskPartialPerms & perms & ACL_WRITE || // Partial perms on mask
337 maskPartialPerms & partialPerms & ACL_WRITE ) // Partial perms on mask and entry
338 strEffective[1] = 'W';
339 if ( maskPerms & partialPerms & ACL_EXECUTE || // Partial perms on entry
340 maskPartialPerms & perms & ACL_EXECUTE || // Partial perms on mask
341 maskPartialPerms & partialPerms & ACL_EXECUTE ) // Partial perms on mask and entry
342 strEffective[2] = 'X';
343*/
344 }
345 else
346 {
347 // No, the effective value are just the value in this entry
348 strEffective[0] = ( value & ACL_READ ) ? 'r' : '-';
349 strEffective[1] = ( value & ACL_WRITE ) ? 'w' : '-';
350 strEffective[2] = ( value & ACL_EXECUTE ) ? 'x' : '-';
351
352 /*
353 // What about any partial perms?
354 if ( partialPerms & ACL_READ )
355 strEffective[0] = 'R';
356 if ( partialPerms & ACL_WRITE )
357 strEffective[1] = 'W';
358 if ( partialPerms & ACL_EXECUTE )
359 strEffective[2] = 'X';
360 */
361 }
362 setText( 5, strEffective );
363}
364
365bool KACLListViewItem::isDeletable() const
366{
367 bool isMaskAndDeletable = false;
368 if (type == KACLListView::Mask ) {
369 if ( !isDefault && m_pACLListView->maskCanBeDeleted() )
370 isMaskAndDeletable = true;
371 else if ( isDefault && m_pACLListView->defaultMaskCanBeDeleted() )
372 isMaskAndDeletable = true;
373 }
374 return type != KACLListView::User &&
375 type != KACLListView::Group &&
376 type != KACLListView::Others &&
377 ( type != KACLListView::Mask || isMaskAndDeletable );
378}
379
380bool KACLListViewItem::isAllowedToChangeType() const
381{
382 return type != KACLListView::User &&
383 type != KACLListView::Group &&
384 type != KACLListView::Others &&
385 type != KACLListView::Mask;
386}
387
388void KACLListViewItem::togglePerm( acl_perm_t perm )
389{
390 value ^= perm; // Toggle the perm
391 if ( type == KACLListView::Mask && !isDefault ) {
392 m_pACLListView->setMaskPermissions( value );
393 }
394 calcEffectiveRights();
395 updatePermPixmaps();
396/*
397 // If the perm is in the partial perms then remove it. i.e. Once
398 // a user changes a partial perm it then applies to all selected files.
399 if ( m_pEntry->m_partialPerms & perm )
400 m_pEntry->m_partialPerms ^= perm;
401
402 m_pEntry->setPartialEntry( false );
403 // Make sure that all entries have their effective rights calculated if
404 // we are changing the ACL_MASK entry.
405 if ( type == Mask )
406 {
407 m_pACLListView->setMaskPartialPermissions( m_pEntry->m_partialPerms );
408 m_pACLListView->setMaskPermissions( value );
409 m_pACLListView->calculateEffectiveRights();
410 }
411*/
412}
413
414
415
416EditACLEntryDialog::EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item,
417 const QStringList &users,
418 const QStringList &groups,
419 const QStringList &defaultUsers,
420 const QStringList &defaultGroups,
421 int allowedTypes, int allowedDefaultTypes,
422 bool allowDefaults )
423 : KDialog( listView ),
424 m_listView( listView ), m_item( item ), m_users( users ), m_groups( groups ),
425 m_defaultUsers( defaultUsers ), m_defaultGroups( defaultGroups ),
426 m_allowedTypes( allowedTypes ), m_allowedDefaultTypes( allowedDefaultTypes ),
427 m_defaultCB( 0 )
428{
429 setObjectName( "edit_entry_dialog" );
430 setModal( true );
431 setCaption( i18n( "Edit ACL Entry" ) );
432 setButtons( KDialog::Ok | KDialog::Cancel );
433 setDefaultButton( KDialog::Ok );
434
435 QWidget *page = new QWidget( this );
436 setMainWidget( page );
437 QVBoxLayout *mainLayout = new QVBoxLayout( page );
438 mainLayout->setMargin( 0 );
439 QGroupBox *gb = new QGroupBox( i18n("Entry Type"), page );
440 QVBoxLayout *gbLayout = new QVBoxLayout( gb );
441
442 m_buttonGroup = new QButtonGroup( page );
443
444 if ( allowDefaults ) {
445 m_defaultCB = new QCheckBox( i18n("Default for new files in this folder"), page );
446 m_defaultCB->setObjectName( QLatin1String( "defaultCB" ) );
447 mainLayout->addWidget( m_defaultCB );
448 connect( m_defaultCB, SIGNAL(toggled(bool)),
449 this, SLOT(slotUpdateAllowedUsersAndGroups()) );
450 connect( m_defaultCB, SIGNAL(toggled(bool)),
451 this, SLOT(slotUpdateAllowedTypes()) );
452 }
453
454 QRadioButton *ownerType = new QRadioButton( i18n("Owner"), gb );
455 ownerType->setObjectName( QLatin1String( "ownerType" ) );
456 gbLayout->addWidget( ownerType );
457 m_buttonGroup->addButton( ownerType );
458 m_buttonIds.insert( ownerType, KACLListView::User );
459 QRadioButton *owningGroupType = new QRadioButton( i18n("Owning Group"), gb );
460 owningGroupType->setObjectName( QLatin1String( "owningGroupType" ) );
461 gbLayout->addWidget( owningGroupType );
462 m_buttonGroup->addButton( owningGroupType );
463 m_buttonIds.insert( owningGroupType, KACLListView::Group );
464 QRadioButton *othersType = new QRadioButton( i18n("Others"), gb );
465 othersType->setObjectName( QLatin1String( "othersType" ) );
466 gbLayout->addWidget( othersType );
467 m_buttonGroup->addButton( othersType );
468 m_buttonIds.insert( othersType, KACLListView::Others );
469 QRadioButton *maskType = new QRadioButton( i18n("Mask"), gb );
470 maskType->setObjectName( QLatin1String( "maskType" ) );
471 gbLayout->addWidget( maskType );
472 m_buttonGroup->addButton( maskType );
473 m_buttonIds.insert( maskType, KACLListView::Mask );
474 QRadioButton *namedUserType = new QRadioButton( i18n("Named user"), gb );
475 namedUserType->setObjectName( QLatin1String( "namesUserType" ) );
476 gbLayout->addWidget( namedUserType );
477 m_buttonGroup->addButton( namedUserType );
478 m_buttonIds.insert( namedUserType, KACLListView::NamedUser );
479 QRadioButton *namedGroupType = new QRadioButton( i18n("Named group"), gb );
480 namedGroupType->setObjectName( QLatin1String( "namedGroupType" ) );
481 gbLayout->addWidget( namedGroupType );
482 m_buttonGroup->addButton( namedGroupType );
483 m_buttonIds.insert( namedGroupType, KACLListView::NamedGroup );
484
485 mainLayout->addWidget( gb );
486
487 connect( m_buttonGroup, SIGNAL(buttonClicked(QAbstractButton*)),
488 this, SLOT(slotSelectionChanged(QAbstractButton*)) );
489
490 m_widgetStack = new QStackedWidget( page );
491 mainLayout->addWidget( m_widgetStack );
492
493 KHBox *usersBox = new KHBox( m_widgetStack );
494 m_widgetStack->addWidget( usersBox );
495
496 KHBox *groupsBox = new KHBox( m_widgetStack );
497 m_widgetStack->addWidget( groupsBox );
498
499 QLabel *usersLabel = new QLabel( i18n( "User: " ), usersBox );
500 m_usersCombo = new KComboBox( usersBox );
501 m_usersCombo->setEditable( false );
502 m_usersCombo->setObjectName( QLatin1String( "users" ) );
503 usersLabel->setBuddy( m_usersCombo );
504
505 QLabel *groupsLabel = new QLabel( i18n( "Group: " ), groupsBox );
506 m_groupsCombo = new KComboBox( groupsBox );
507 m_groupsCombo->setEditable( false );
508 m_groupsCombo->setObjectName( QLatin1String( "groups" ) );
509 groupsLabel->setBuddy( m_groupsCombo );
510
511 if ( m_item ) {
512 m_buttonIds.key( m_item->type )->setChecked( true );
513 if ( m_defaultCB )
514 m_defaultCB->setChecked( m_item->isDefault );
515 slotUpdateAllowedTypes();
516 slotSelectionChanged( m_buttonIds.key( m_item->type ) );
517 slotUpdateAllowedUsersAndGroups();
518 if ( m_item->type == KACLListView::NamedUser ) {
519 m_usersCombo->setItemText( m_usersCombo->currentIndex(), m_item->qualifier );
520 } else if ( m_item->type == KACLListView::NamedGroup ) {
521 m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), m_item->qualifier );
522 }
523 } else {
524 // new entry, preselect "named user", arguably the most common one
525 m_buttonIds.key( KACLListView::NamedUser )->setChecked( true );
526 slotUpdateAllowedTypes();
527 slotSelectionChanged( m_buttonIds.key( KACLListView::NamedUser ) );
528 slotUpdateAllowedUsersAndGroups();
529 }
530 incrementInitialSize( QSize( 100, 0 ) );
531 connect(this,SIGNAL(okClicked()), this, SLOT(slotOk()));
532}
533
534void EditACLEntryDialog::slotUpdateAllowedTypes()
535{
536 int allowedTypes = m_allowedTypes;
537 if ( m_defaultCB && m_defaultCB->isChecked() ) {
538 allowedTypes = m_allowedDefaultTypes;
539 }
540 for ( int i=1; i < KACLListView::AllTypes; i=i*2 ) {
541 if ( allowedTypes & i )
542 m_buttonIds.key( i )->show();
543 else
544 m_buttonIds.key( i )->hide();
545 }
546}
547
548void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups()
549{
550 const QString oldUser = m_usersCombo->currentText();
551 const QString oldGroup = m_groupsCombo->currentText();
552 m_usersCombo->clear();
553 m_groupsCombo->clear();
554 if ( m_defaultCB && m_defaultCB->isChecked() ) {
555 m_usersCombo->addItems( m_defaultUsers );
556 if ( m_defaultUsers.contains( oldUser ) )
557 m_usersCombo->setItemText( m_usersCombo->currentIndex(), oldUser );
558 m_groupsCombo->addItems( m_defaultGroups );
559 if ( m_defaultGroups.contains( oldGroup ) )
560 m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), oldGroup );
561 } else {
562 m_usersCombo->addItems( m_users );
563 if ( m_users.contains( oldUser ) )
564 m_usersCombo->setItemText( m_usersCombo->currentIndex(), oldUser );
565 m_groupsCombo->addItems( m_groups );
566 if ( m_groups.contains( oldGroup ) )
567 m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), oldGroup );
568 }
569}
570void EditACLEntryDialog::slotOk()
571{
572 KACLListView::EntryType type = static_cast<KACLListView::EntryType>( m_buttonIds[m_buttonGroup->checkedButton()] );
573
574 kWarning() << "Type 2: " << type;
575
576 QString qualifier;
577 if ( type == KACLListView::NamedUser )
578 qualifier = m_usersCombo->currentText();
579 if ( type == KACLListView::NamedGroup )
580 qualifier = m_groupsCombo->currentText();
581
582 if ( !m_item ) {
583 m_item = new KACLListViewItem( m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE, false, qualifier );
584 } else {
585 m_item->type = type;
586 m_item->qualifier = qualifier;
587 }
588 if ( m_defaultCB )
589 m_item->isDefault = m_defaultCB->isChecked();
590 m_item->repaint();
591
592 KDialog::accept();
593}
594
595void EditACLEntryDialog::slotSelectionChanged( QAbstractButton *button )
596{
597 switch ( m_buttonIds[ button ] ) {
598 case KACLListView::User:
599 case KACLListView::Group:
600 case KACLListView::Others:
601 case KACLListView::Mask:
602 m_widgetStack->setEnabled( false );
603 break;
604 case KACLListView::NamedUser:
605 m_widgetStack->setEnabled( true );
606 m_widgetStack->setCurrentIndex( 0 /* User */ );
607 break;
608 case KACLListView::NamedGroup:
609 m_widgetStack->setEnabled( true );
610 m_widgetStack->setCurrentIndex( 1 /* Group */ );
611 break;
612 default:
613 break;
614 }
615}
616
617
618KACLListView::KACLListView( QWidget* parent )
619 : QTreeWidget( parent ),
620 m_hasMask( false ), m_allowDefaults( false )
621{
622 // Add the columns
623 setColumnCount( 6 );
624 QStringList headers;
625 headers << i18n( "Type" );
626 headers << i18n( "Name" );
627 headers << i18nc( "read permission", "r" );
628 headers << i18nc( "write permission", "w" );
629 headers << i18nc( "execute permission", "x" );
630 headers << i18n( "Effective" );
631 setHeaderLabels( headers );
632
633 setSortingEnabled( false );
634 setSelectionMode( QAbstractItemView::ExtendedSelection );
635 header()->setResizeMode( QHeaderView::ResizeToContents );
636 setRootIsDecorated( false );
637
638 // Load the avatars
639 for ( int i=0; i < LAST_IDX; ++i ) {
640 s_itemAttributes[i].pixmap = new QPixmap( QString::fromLatin1(":/images/%1").arg(s_itemAttributes[i].pixmapName) );
641 }
642 m_yesPixmap = new QPixmap( ":/images/yes.png" );
643 m_yesPartialPixmap = new QPixmap( ":/images/yespartial.png" );
644
645
646 // fill the lists of all legal users and groups
647 struct passwd *user = 0;
648 setpwent();
649 while ( ( user = getpwent() ) != 0 ) {
650 m_allUsers << QString::fromLatin1( user->pw_name );
651 }
652 endpwent();
653
654 struct group *gr = 0;
655 setgrent();
656 while ( ( gr = getgrent() ) != 0 ) {
657 m_allGroups << QString::fromLatin1( gr->gr_name );
658 }
659 endgrent();
660 m_allUsers.sort();
661 m_allGroups.sort();
662
663 connect( this, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
664 this, SLOT(slotItemClicked(QTreeWidgetItem*,int)) );
665}
666
667
668KACLListView::~KACLListView()
669{
670 for ( int i=0; i < LAST_IDX; ++i ) {
671 delete s_itemAttributes[i].pixmap;
672 }
673 delete m_yesPixmap;
674 delete m_yesPartialPixmap;
675}
676
677QStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *allowedItem )
678{
679 QStringList allowedUsers = m_allUsers;
680 QTreeWidgetItemIterator it( this );
681 while ( *it ) {
682 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
683 ++it;
684 if ( item->type != NamedUser || item->isDefault != defaults ) continue;
685 if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
686 allowedUsers.removeAll( item->qualifier );
687 }
688 return allowedUsers;
689}
690
691QStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *allowedItem )
692{
693 QStringList allowedGroups = m_allGroups;
694 QTreeWidgetItemIterator it( this );
695 while ( *it ) {
696 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
697 ++it;
698 if ( item->type != NamedGroup || item->isDefault != defaults ) continue;
699 if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
700 allowedGroups.removeAll( item->qualifier );
701 }
702 return allowedGroups;
703}
704
705void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults )
706{
707 // clear out old entries of that ilk
708 QTreeWidgetItemIterator it( this );
709 while ( KACLListViewItem *item = static_cast<KACLListViewItem*>( *it ) ) {
710 ++it;
711 if ( item->isDefault == defaults )
712 delete item;
713 }
714 KACLListViewItem *item =
715 new KACLListViewItem( this, User, pACL.ownerPermissions(), defaults );
716
717 item = new KACLListViewItem( this, Group, pACL.owningGroupPermissions(), defaults );
718
719 item = new KACLListViewItem( this, Others, pACL.othersPermissions(), defaults );
720
721 bool hasMask = false;
722 unsigned short mask = pACL.maskPermissions( hasMask );
723 if ( hasMask ) {
724 item = new KACLListViewItem( this, Mask, mask, defaults );
725 }
726
727 // read all named user entries
728 const ACLUserPermissionsList &userList = pACL.allUserPermissions();
729 ACLUserPermissionsConstIterator itu = userList.begin();
730 while ( itu != userList.end() ) {
731 new KACLListViewItem( this, NamedUser, (*itu).second, defaults, (*itu).first );
732 ++itu;
733 }
734
735 // and now all named groups
736 const ACLUserPermissionsList &groupList = pACL.allGroupPermissions();
737 ACLUserPermissionsConstIterator itg = groupList.begin();
738 while ( itg != groupList.end() ) {
739 new KACLListViewItem( this, NamedGroup, (*itg).second, defaults, (*itg).first );
740 ++itg;
741 }
742}
743
744void KACLListView::setACL( const KACL &acl )
745{
746 if ( !acl.isValid() ) return;
747 // Remove any entries left over from displaying a previous ACL
748 m_ACL = acl;
749 fillItemsFromACL( m_ACL );
750
751 m_mask = acl.maskPermissions( m_hasMask );
752 calculateEffectiveRights();
753}
754
755void KACLListView::setDefaultACL( const KACL &acl )
756{
757 if ( !acl.isValid() ) return;
758 m_defaultACL = acl;
759 fillItemsFromACL( m_defaultACL, true );
760 calculateEffectiveRights();
761}
762
763KACL KACLListView::itemsToACL( bool defaults ) const
764{
765 KACL newACL( 0 );
766 bool atLeastOneEntry = false;
767 ACLUserPermissionsList users;
768 ACLGroupPermissionsList groups;
769 QTreeWidgetItemIterator it( const_cast<KACLListView*>( this ) );
770 while ( QTreeWidgetItem* qlvi = *it ) {
771 ++it;
772 const KACLListViewItem* item = static_cast<KACLListViewItem*>( qlvi );
773 if ( item->isDefault != defaults ) continue;
774 atLeastOneEntry = true;
775 switch ( item->type ) {
776 case User:
777 newACL.setOwnerPermissions( item->value );
778 break;
779 case Group:
780 newACL.setOwningGroupPermissions( item->value );
781 break;
782 case Others:
783 newACL.setOthersPermissions( item->value );
784 break;
785 case Mask:
786 newACL.setMaskPermissions( item->value );
787 break;
788 case NamedUser:
789 users.append( qMakePair( item->text( 1 ), item->value ) );
790 break;
791 case NamedGroup:
792 groups.append( qMakePair( item->text( 1 ), item->value ) );
793 break;
794 default:
795 break;
796 }
797 }
798 if ( atLeastOneEntry ) {
799 newACL.setAllUserPermissions( users );
800 newACL.setAllGroupPermissions( groups );
801 if ( newACL.isValid() )
802 return newACL;
803 }
804 return KACL();
805}
806
807KACL KACLListView::getACL()
808{
809 return itemsToACL( false );
810}
811
812
813KACL KACLListView::getDefaultACL()
814{
815 return itemsToACL( true );
816}
817
818void KACLListView::contentsMousePressEvent( QMouseEvent * /*e*/ )
819{
820 /*
821 QTreeWidgetItem *clickedItem = itemAt( e->pos() );
822 if ( !clickedItem ) return;
823 // if the click is on an as yet unselected item, select it first
824 if ( !clickedItem->isSelected() )
825 QAbstractItemView::contentsMousePressEvent( e );
826
827 if ( !currentItem() ) return;
828 int column = header()->sectionAt( e->x() );
829 acl_perm_t perm;
830 switch ( column )
831 {
832 case 2:
833 perm = ACL_READ;
834 break;
835 case 3:
836 perm = ACL_WRITE;
837 break;
838 case 4:
839 perm = ACL_EXECUTE;
840 break;
841 default:
842 return QTreeWidget::contentsMousePressEvent( e );
843 }
844 KACLListViewItem* referenceItem = static_cast<KACLListViewItem*>( clickedItem );
845 unsigned short referenceHadItSet = referenceItem->value & perm;
846 QTreeWidgetItemIterator it( this );
847 while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( *it ) ) {
848 ++it;
849 if ( !item->isSelected() ) continue;
850 // toggle those with the same value as the clicked item, leave the others
851 if ( referenceHadItSet == ( item->value & perm ) )
852 item->togglePerm( perm );
853 }
854 */
855}
856
857void KACLListView::slotItemClicked( QTreeWidgetItem* pItem, int col )
858{
859 if ( !pItem ) return;
860
861 QTreeWidgetItemIterator it( this );
862 while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( *it ) ) {
863 ++it;
864 if ( !item->isSelected() ) continue;
865 switch ( col )
866 {
867 case 2:
868 item->togglePerm( ACL_READ );
869 break;
870 case 3:
871 item->togglePerm( ACL_WRITE );
872 break;
873 case 4:
874 item->togglePerm( ACL_EXECUTE );
875 break;
876
877 default:
878 ; // Do nothing
879 }
880 }
881 /*
882 // Has the user changed one of the required entries in a default ACL?
883 if ( m_pACL->aclType() == ACL_TYPE_DEFAULT &&
884 ( col == 2 || col == 3 || col == 4 ) &&
885 ( pACLItem->entryType() == ACL_USER_OBJ ||
886 pACLItem->entryType() == ACL_GROUP_OBJ ||
887 pACLItem->entryType() == ACL_OTHER ) )
888 {
889 // Mark the required entries as no longer being partial entries.
890 // That is, they will get applied to all selected directories.
891 KACLListViewItem* pUserObj = findACLEntryByType( this, ACL_USER_OBJ );
892 pUserObj->entry()->setPartialEntry( false );
893
894 KACLListViewItem* pGroupObj = findACLEntryByType( this, ACL_GROUP_OBJ );
895 pGroupObj->entry()->setPartialEntry( false );
896
897 KACLListViewItem* pOther = findACLEntryByType( this, ACL_OTHER );
898 pOther->entry()->setPartialEntry( false );
899
900 update();
901 }
902 */
903}
904
905
906void KACLListView::calculateEffectiveRights()
907{
908 QTreeWidgetItemIterator it( this );
909 KACLListViewItem* pItem;
910 while ( ( pItem = dynamic_cast<KACLListViewItem*>( *it ) ) != 0 )
911 {
912 ++it;
913 pItem->calcEffectiveRights();
914 }
915}
916
917
918unsigned short KACLListView::maskPermissions() const
919{
920 return m_mask;
921}
922
923
924void KACLListView::setMaskPermissions( unsigned short maskPerms )
925{
926 m_mask = maskPerms;
927 calculateEffectiveRights();
928}
929
930
931acl_perm_t KACLListView::maskPartialPermissions() const
932{
933 // return m_pMaskEntry->m_partialPerms;
934 return 0;
935}
936
937
938void KACLListView::setMaskPartialPermissions( acl_perm_t /*maskPartialPerms*/ )
939{
940 //m_pMaskEntry->m_partialPerms = maskPartialPerms;
941 calculateEffectiveRights();
942}
943
944bool KACLListView::hasDefaultEntries() const
945{
946 QTreeWidgetItemIterator it( const_cast<KACLListView*>( this ) );
947 while ( *it ) {
948 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
949 ++it;
950 if ( item->isDefault ) return true;
951 }
952 return false;
953}
954
955const KACLListViewItem* KACLListView::findDefaultItemByType( EntryType type ) const
956{
957 return findItemByType( type, true );
958}
959
960const KACLListViewItem* KACLListView::findItemByType( EntryType type, bool defaults ) const
961{
962 QTreeWidgetItemIterator it( const_cast<KACLListView*>( this ) );
963 while ( *it ) {
964 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
965 ++it;
966 if ( item->isDefault == defaults && item->type == type ) {
967 return item;
968 }
969 }
970 return 0;
971}
972
973
974unsigned short KACLListView::calculateMaskValue( bool defaults ) const
975{
976 // KACL auto-adds the relevant maks entries, so we can simply query
977 bool dummy;
978 return itemsToACL( defaults ).maskPermissions( dummy );
979}
980
981void KACLListView::slotAddEntry()
982{
983 int allowedTypes = NamedUser | NamedGroup;
984 if ( !m_hasMask )
985 allowedTypes |= Mask;
986 int allowedDefaultTypes = NamedUser | NamedGroup;
987 if ( !findDefaultItemByType( Mask ) )
988 allowedDefaultTypes |= Mask;
989 if ( !hasDefaultEntries() )
990 allowedDefaultTypes |= User | Group;
991 EditACLEntryDialog dlg( this, 0,
992 allowedUsers( false ), allowedGroups( false ),
993 allowedUsers( true ), allowedGroups( true ),
994 allowedTypes, allowedDefaultTypes, m_allowDefaults );
995 dlg.exec();
996 KACLListViewItem *item = dlg.item();
997 if ( !item ) return; // canceled
998 if ( item->type == Mask && !item->isDefault ) {
999 m_hasMask = true;
1000 m_mask = item->value;
1001 }
1002 if ( item->isDefault && !hasDefaultEntries() ) {
1003 // first default entry, fill in what is needed
1004 if ( item->type != User ) {
1005 unsigned short v = findDefaultItemByType( User )->value;
1006 new KACLListViewItem( this, User, v, true );
1007 }
1008 if ( item->type != Group ) {
1009 unsigned short v = findDefaultItemByType( Group )->value;
1010 new KACLListViewItem( this, Group, v, true );
1011 }
1012 if ( item->type != Others ) {
1013 unsigned short v = findDefaultItemByType( Others )->value;
1014 new KACLListViewItem( this, Others, v, true );
1015 }
1016 }
1017 const KACLListViewItem *defaultMaskItem = findDefaultItemByType( Mask );
1018 if ( item->isDefault && !defaultMaskItem ) {
1019 unsigned short v = calculateMaskValue( true );
1020 new KACLListViewItem( this, Mask, v, true );
1021 }
1022 if ( !item->isDefault && !m_hasMask &&
1023 ( item->type == Group
1024 || item->type == NamedUser
1025 || item->type == NamedGroup ) ) {
1026 // auto-add a mask entry
1027 unsigned short v = calculateMaskValue( false );
1028 new KACLListViewItem( this, Mask, v, false );
1029 m_hasMask = true;
1030 m_mask = v;
1031 }
1032 calculateEffectiveRights();
1033 sortItems( sortColumn(), Qt::AscendingOrder );
1034 setCurrentItem( item );
1035 // QTreeWidget doesn't seem to emit, in this case, and we need to update
1036 // the buttons...
1037 if ( topLevelItemCount() == 1 )
1038 emit currentItemChanged( item, item );
1039}
1040
1041void KACLListView::slotEditEntry()
1042{
1043 QTreeWidgetItem * current = currentItem();
1044 if ( !current ) return;
1045 KACLListViewItem *item = static_cast<KACLListViewItem*>( current );
1046 int allowedTypes = item->type | NamedUser | NamedGroup;
1047 bool itemWasMask = item->type == Mask;
1048 if ( !m_hasMask || itemWasMask )
1049 allowedTypes |= Mask;
1050 int allowedDefaultTypes = item->type | NamedUser | NamedGroup;
1051 if ( !findDefaultItemByType( Mask ) )
1052 allowedDefaultTypes |= Mask;
1053 if ( !hasDefaultEntries() )
1054 allowedDefaultTypes |= User | Group;
1055
1056 EditACLEntryDialog dlg( this, item,
1057 allowedUsers( false, item ), allowedGroups( false, item ),
1058 allowedUsers( true, item ), allowedGroups( true, item ),
1059 allowedTypes, allowedDefaultTypes, m_allowDefaults );
1060 dlg.exec();
1061 if ( itemWasMask && item->type != Mask ) {
1062 m_hasMask = false;
1063 m_mask = 0;
1064 }
1065 if ( !itemWasMask && item->type == Mask ) {
1066 m_mask = item->value;
1067 m_hasMask = true;
1068 }
1069 calculateEffectiveRights();
1070 sortItems( sortColumn(), Qt::AscendingOrder );
1071}
1072
1073void KACLListView::slotRemoveEntry()
1074{
1075 QTreeWidgetItemIterator it( this, QTreeWidgetItemIterator::Selected );
1076 while ( *it ) {
1077 KACLListViewItem *item = static_cast<KACLListViewItem*>( *it );
1078 ++it;
1079 /* First check if it's a mask entry and if so, make sure that there is
1080 * either no name user or group entry, which means the mask can be
1081 * removed, or don't remove it, but reset it. That is allowed. */
1082 if ( item->type == Mask ) {
1083 bool itemWasDefault = item->isDefault;
1084 if ( !itemWasDefault && maskCanBeDeleted() ) {
1085 m_hasMask= false;
1086 m_mask = 0;
1087 delete item;
1088 } else if ( itemWasDefault && defaultMaskCanBeDeleted() ) {
1089 delete item;
1090 } else {
1091 item->value = 0;
1092 item->repaint();
1093 }
1094 if ( !itemWasDefault )
1095 calculateEffectiveRights();
1096 } else {
1097 // for the base permissions, disable them, which is what libacl does
1098 if ( !item->isDefault &&
1099 ( item->type == User
1100 || item->type == Group
1101 || item->type == Others ) ) {
1102 item->value = 0;
1103 item->repaint();
1104 } else {
1105 delete item;
1106 }
1107 }
1108 }
1109}
1110
1111bool KACLListView::maskCanBeDeleted() const
1112{
1113 return !findItemByType( NamedUser ) && !findItemByType( NamedGroup );
1114}
1115
1116bool KACLListView::defaultMaskCanBeDeleted() const
1117{
1118 return !findDefaultItemByType( NamedUser ) && !findDefaultItemByType( NamedGroup );
1119}
1120
1121#include "kacleditwidget.moc"
1122#include "kacleditwidget_p.moc"
1123#endif
1124// vim:set ts=8 sw=4:
KACL
The KACL class encapsulates a POSIX Access Control List.
Definition: kacl.h:48
KACL::maskPermissions
unsigned short maskPermissions(bool &exists) const
Return the entry for the permissions mask if there is one and sets exists to true.
Definition: kacl.cpp:281
KACL::setACL
bool setACL(const QString &aclStr)
Sets the whole list from a string.
Definition: kacl.cpp:590
KACL::isValid
bool isValid() const
Returns whether the KACL object represents a valid acl.
Definition: kacl.cpp:120
KACL::allGroupPermissions
ACLGroupPermissionsList allGroupPermissions() const
Returns the list of all group permission entries.
Definition: kacl.cpp:553
KACL::othersPermissions
unsigned short othersPermissions() const
Definition: kacl.cpp:245
KACL::allUserPermissions
ACLUserPermissionsList allUserPermissions() const
Returns the list of all group permission entries.
Definition: kacl.cpp:415
KACL::ownerPermissions
unsigned short ownerPermissions() const
The standard (non-extended) part of an ACL.
Definition: kacl.cpp:207
KACL::owningGroupPermissions
unsigned short owningGroupPermissions() const
Definition: kacl.cpp:226
KComboBox
KDialog
KDialog::Ok
Ok
KDialog::Cancel
Cancel
KHBox
QGroupBox
QLabel
QList
QPushButton
QTreeWidget
QWidget
header
const char header[]
kWarning
#define kWarning
mask
#define mask
ACLUserPermissionsConstIterator
QList< ACLUserPermissions >::const_iterator ACLUserPermissionsConstIterator
Definition: kacl.h:34
kacleditwidget.h
kacleditwidget_p.h
kdebug.h
kdialog.h
kfileitem.h
khbox.h
klocale.h
i18n
QString i18n(const char *text)
I18N_NOOP
#define I18N_NOOP(x)
i18nc
QString i18nc(const char *ctxt, const char *text)
kvbox.h
group
group
defaults
KGuiItem defaults()
label
QString label(StandardShortcut id)
Group
Group
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal