KIO
kacleditwidget.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> * 00003 * 2005 - 2007 Till Adam <adam@kde.org> * 00004 * * 00005 * This program is free software; you can redistribute it and/or modify * 00006 * it under the terms of the GNU Library General Public License as * 00007 * published by the Free Software Foundation; either version 2 of the * 00008 * License, or (at your option) any later version. * 00009 * * 00010 * This program is distributed in the hope that it will be useful, * 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00013 * GNU General Public License for more details. * 00014 * * 00015 * You should have received a copy of the GNU General Public License * 00016 * along with this program; if not, write to the * 00017 * Free Software Foundation, Inc., * 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 00019 ***************************************************************************/ 00020 00021 #include "kacleditwidget.h" 00022 #include "kacleditwidget_p.h" 00023 00024 #include <config-acl.h> 00025 #ifdef HAVE_POSIX_ACL 00026 00027 #include <qpainter.h> 00028 #include <qpushbutton.h> 00029 #include <QButtonGroup> 00030 #include <QGroupBox> 00031 #include <qradiobutton.h> 00032 #include <qcombobox.h> 00033 #include <qlabel.h> 00034 #include <qcheckbox.h> 00035 #include <qlayout.h> 00036 #include <QStackedWidget> 00037 #include <QMouseEvent> 00038 #include <QHeaderView> 00039 00040 #include <klocale.h> 00041 #include <kfileitem.h> 00042 #include <kdebug.h> 00043 #include <kdialog.h> 00044 #include <kvbox.h> 00045 #include <khbox.h> 00046 00047 #ifdef HAVE_ACL_LIBACL_H 00048 # include <acl/libacl.h> 00049 #endif 00050 extern "C" { 00051 #include <pwd.h> 00052 #include <grp.h> 00053 } 00054 #include <assert.h> 00055 00056 static struct { 00057 const char* label; 00058 const char* pixmapName; 00059 QPixmap* pixmap; 00060 } s_itemAttributes[] = { 00061 { I18N_NOOP( "Owner" ), "user-grey", 0 }, 00062 { I18N_NOOP( "Owning Group" ), "group-grey", 0 }, 00063 { I18N_NOOP( "Others" ), "others-grey", 0 }, 00064 { I18N_NOOP( "Mask" ), "mask", 0 }, 00065 { I18N_NOOP( "Named User" ), "user", 0 }, 00066 { I18N_NOOP( "Named Group" ), "group", 0 }, 00067 }; 00068 00069 class KACLEditWidget::KACLEditWidgetPrivate 00070 { 00071 public: 00072 KACLEditWidgetPrivate() 00073 { 00074 } 00075 00076 // slots 00077 void _k_slotUpdateButtons(); 00078 00079 KACLListView *m_listView; 00080 QPushButton *m_AddBtn; 00081 QPushButton *m_EditBtn; 00082 QPushButton *m_DelBtn; 00083 }; 00084 00085 KACLEditWidget::KACLEditWidget( QWidget *parent ) 00086 : QWidget(parent), d(new KACLEditWidgetPrivate) 00087 { 00088 QHBoxLayout *hbox = new QHBoxLayout( this ); 00089 hbox->setMargin( 0 ); 00090 d->m_listView = new KACLListView(this); 00091 hbox->addWidget(d->m_listView); 00092 connect(d->m_listView->selectionModel(), 00093 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection& )), 00094 this, 00095 SLOT(_k_slotUpdateButtons())); 00096 QVBoxLayout *vbox = new QVBoxLayout(); 00097 hbox->addLayout( vbox ); 00098 d->m_AddBtn = new QPushButton(i18n("Add Entry..."), this); 00099 vbox->addWidget(d->m_AddBtn); 00100 d->m_AddBtn->setObjectName(QLatin1String("add_entry_button")); 00101 connect(d->m_AddBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotAddEntry())); 00102 d->m_EditBtn = new QPushButton(i18n("Edit Entry..."), this); 00103 vbox->addWidget(d->m_EditBtn); 00104 d->m_EditBtn->setObjectName(QLatin1String("edit_entry_button")); 00105 connect(d->m_EditBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotEditEntry())); 00106 d->m_DelBtn = new QPushButton(i18n("Delete Entry"), this); 00107 vbox->addWidget(d->m_DelBtn); 00108 d->m_DelBtn->setObjectName(QLatin1String("delete_entry_button")); 00109 connect(d->m_DelBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotRemoveEntry())); 00110 vbox->addItem( new QSpacerItem( 10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding ) ); 00111 d->_k_slotUpdateButtons(); 00112 } 00113 00114 KACLEditWidget::~KACLEditWidget() 00115 { 00116 delete d; 00117 } 00118 00119 void KACLEditWidget::KACLEditWidgetPrivate::_k_slotUpdateButtons() 00120 { 00121 bool atLeastOneIsNotDeletable = false; 00122 bool atLeastOneIsNotAllowedToChangeType = false; 00123 int selectedCount = 0; 00124 QList<QTreeWidgetItem*> selected = m_listView->selectedItems(); 00125 QListIterator<QTreeWidgetItem*> it( selected ); 00126 while ( it.hasNext() ) { 00127 KACLListViewItem *item = static_cast<KACLListViewItem*>( it.next() ); 00128 ++selectedCount; 00129 if ( !item->isDeletable() ) 00130 atLeastOneIsNotDeletable = true; 00131 if ( !item->isAllowedToChangeType() ) 00132 atLeastOneIsNotAllowedToChangeType = true; 00133 } 00134 m_EditBtn->setEnabled( selectedCount && !atLeastOneIsNotAllowedToChangeType ); 00135 m_DelBtn->setEnabled( selectedCount && !atLeastOneIsNotDeletable ); 00136 } 00137 00138 KACL KACLEditWidget::getACL() const 00139 { 00140 return d->m_listView->getACL(); 00141 } 00142 00143 KACL KACLEditWidget::getDefaultACL() const 00144 { 00145 return d->m_listView->getDefaultACL(); 00146 } 00147 00148 void KACLEditWidget::setACL( const KACL &acl ) 00149 { 00150 return d->m_listView->setACL(acl); 00151 } 00152 00153 void KACLEditWidget::setDefaultACL( const KACL &acl ) 00154 { 00155 return d->m_listView->setDefaultACL(acl); 00156 } 00157 00158 void KACLEditWidget::setAllowDefaults( bool value ) 00159 { 00160 d->m_listView->setAllowDefaults(value); 00161 } 00162 00163 KACLListViewItem::KACLListViewItem( QTreeWidget* parent, 00164 KACLListView::EntryType _type, 00165 unsigned short _value, bool defaults, 00166 const QString& _qualifier ) 00167 : QTreeWidgetItem( parent), 00168 type( _type ), value( _value ), isDefault( defaults ), 00169 qualifier( _qualifier ), isPartial( false ) 00170 { 00171 m_pACLListView = qobject_cast<KACLListView*>( parent ); 00172 repaint(); 00173 } 00174 00175 00176 KACLListViewItem::~ KACLListViewItem() 00177 { 00178 00179 } 00180 00181 QString KACLListViewItem::key() const 00182 { 00183 QString key; 00184 if ( !isDefault ) 00185 key = 'A'; 00186 else 00187 key = 'B'; 00188 switch ( type ) 00189 { 00190 case KACLListView::User: 00191 key += 'A'; 00192 break; 00193 case KACLListView::Group: 00194 key += 'B'; 00195 break; 00196 case KACLListView::Others: 00197 key += 'C'; 00198 break; 00199 case KACLListView::Mask: 00200 key += 'D'; 00201 break; 00202 case KACLListView::NamedUser: 00203 key += 'E' + text( 1 ); 00204 break; 00205 case KACLListView::NamedGroup: 00206 key += 'F' + text( 1 ); 00207 break; 00208 default: 00209 key += text( 0 ); 00210 break; 00211 } 00212 return key; 00213 } 00214 00215 bool KACLListViewItem::operator< ( const QTreeWidgetItem& other ) const 00216 { 00217 return key() < static_cast<const KACLListViewItem&>(other).key(); 00218 } 00219 00220 #if 0 00221 void KACLListViewItem::paintCell( QPainter* p, const QColorGroup &cg, 00222 int column, int width, int alignment ) 00223 { 00224 if ( isDefault ) { 00225 setForeground( QColor( 0, 0, 255 ) ); 00226 } 00227 if ( isPartial ) { 00228 QFont font = p->font(); 00229 font.setItalic( true ); 00230 setForeground( QColor( 100, 100, 100 ) ); 00231 p->setFont( font ); 00232 } 00233 QTreeWidgetItem::paintCell( p, mycg, column, width, alignment ); 00234 00235 KACLListViewItem *below =0; 00236 if ( itemBelow() ) 00237 below = static_cast<KACLListViewItem*>( itemBelow() ); 00238 const bool lastUser = type == KACLListView::NamedUser && below && below->type == KACLListView::NamedGroup; 00239 const bool lastNonDefault = !isDefault && below && below->isDefault; 00240 if ( type == KACLListView::Mask || lastUser || lastNonDefault ) 00241 { 00242 p->setPen( QPen( Qt::gray, 0, Qt::DotLine ) ); 00243 if ( type == KACLListView::Mask ) 00244 p->drawLine( 0, 0, width - 1, 0 ); 00245 p->drawLine( 0, height() - 1, width - 1, height() - 1 ); 00246 } 00247 } 00248 #endif 00249 00250 00251 void KACLListViewItem::updatePermPixmaps() 00252 { 00253 unsigned int partialPerms = value; 00254 00255 if ( value & ACL_READ ) 00256 setIcon( 2, m_pACLListView->getYesPixmap() ); 00257 else if ( partialPerms & ACL_READ ) 00258 setIcon( 2, m_pACLListView->getYesPartialPixmap() ); 00259 else 00260 setIcon( 2, QIcon() ); 00261 00262 if ( value & ACL_WRITE ) 00263 setIcon( 3, m_pACLListView->getYesPixmap() ); 00264 else if ( partialPerms & ACL_WRITE ) 00265 setIcon( 3, m_pACLListView->getYesPartialPixmap() ); 00266 else 00267 setIcon( 3, QIcon() ); 00268 00269 if ( value & ACL_EXECUTE ) 00270 setIcon( 4, m_pACLListView->getYesPixmap() ); 00271 else if ( partialPerms & ACL_EXECUTE ) 00272 setIcon( 4, m_pACLListView->getYesPartialPixmap() ); 00273 else 00274 setIcon( 4, QIcon() ); 00275 } 00276 00277 void KACLListViewItem::repaint() 00278 { 00279 int idx = 0; 00280 switch ( type ) 00281 { 00282 case KACLListView::User: 00283 idx = KACLListView::OWNER_IDX; 00284 break; 00285 case KACLListView::Group: 00286 idx = KACLListView::GROUP_IDX; 00287 break; 00288 case KACLListView::Others: 00289 idx = KACLListView::OTHERS_IDX; 00290 break; 00291 case KACLListView::Mask: 00292 idx = KACLListView::MASK_IDX; 00293 break; 00294 case KACLListView::NamedUser: 00295 idx = KACLListView::NAMED_USER_IDX; 00296 break; 00297 case KACLListView::NamedGroup: 00298 idx = KACLListView::NAMED_GROUP_IDX; 00299 break; 00300 default: 00301 idx = KACLListView::OWNER_IDX; 00302 break; 00303 } 00304 setText( 0, i18n(s_itemAttributes[idx].label) ); 00305 setIcon( 0, *s_itemAttributes[idx].pixmap ); 00306 if ( isDefault ) 00307 setText( 0, text( 0 ) + i18n( " (Default)" ) ); 00308 setText( 1, qualifier ); 00309 // Set the pixmaps for which of the perms are set 00310 updatePermPixmaps(); 00311 } 00312 00313 void KACLListViewItem::calcEffectiveRights() 00314 { 00315 QString strEffective = QString( "---" ); 00316 00317 // Do we need to worry about the mask entry? It applies to named users, 00318 // owning group, and named groups 00319 if ( m_pACLListView->hasMaskEntry() 00320 && ( type == KACLListView::NamedUser 00321 || type == KACLListView::Group 00322 || type == KACLListView::NamedGroup ) 00323 && !isDefault ) 00324 { 00325 00326 strEffective[0] = ( m_pACLListView->maskPermissions() & value & ACL_READ ) ? 'r' : '-'; 00327 strEffective[1] = ( m_pACLListView->maskPermissions() & value & ACL_WRITE ) ? 'w' : '-'; 00328 strEffective[2] = ( m_pACLListView->maskPermissions() & value & ACL_EXECUTE ) ? 'x' : '-'; 00329 /* 00330 // What about any partial perms? 00331 if ( maskPerms & partialPerms & ACL_READ || // Partial perms on entry 00332 maskPartialPerms & perms & ACL_READ || // Partial perms on mask 00333 maskPartialPerms & partialPerms & ACL_READ ) // Partial perms on mask and entry 00334 strEffective[0] = 'R'; 00335 if ( maskPerms & partialPerms & ACL_WRITE || // Partial perms on entry 00336 maskPartialPerms & perms & ACL_WRITE || // Partial perms on mask 00337 maskPartialPerms & partialPerms & ACL_WRITE ) // Partial perms on mask and entry 00338 strEffective[1] = 'W'; 00339 if ( maskPerms & partialPerms & ACL_EXECUTE || // Partial perms on entry 00340 maskPartialPerms & perms & ACL_EXECUTE || // Partial perms on mask 00341 maskPartialPerms & partialPerms & ACL_EXECUTE ) // Partial perms on mask and entry 00342 strEffective[2] = 'X'; 00343 */ 00344 } 00345 else 00346 { 00347 // No, the effective value are just the value in this entry 00348 strEffective[0] = ( value & ACL_READ ) ? 'r' : '-'; 00349 strEffective[1] = ( value & ACL_WRITE ) ? 'w' : '-'; 00350 strEffective[2] = ( value & ACL_EXECUTE ) ? 'x' : '-'; 00351 00352 /* 00353 // What about any partial perms? 00354 if ( partialPerms & ACL_READ ) 00355 strEffective[0] = 'R'; 00356 if ( partialPerms & ACL_WRITE ) 00357 strEffective[1] = 'W'; 00358 if ( partialPerms & ACL_EXECUTE ) 00359 strEffective[2] = 'X'; 00360 */ 00361 } 00362 setText( 5, strEffective ); 00363 } 00364 00365 bool KACLListViewItem::isDeletable() const 00366 { 00367 bool isMaskAndDeletable = false; 00368 if (type == KACLListView::Mask ) { 00369 if ( !isDefault && m_pACLListView->maskCanBeDeleted() ) 00370 isMaskAndDeletable = true; 00371 else if ( isDefault && m_pACLListView->defaultMaskCanBeDeleted() ) 00372 isMaskAndDeletable = true; 00373 } 00374 return type != KACLListView::User && 00375 type != KACLListView::Group && 00376 type != KACLListView::Others && 00377 ( type != KACLListView::Mask || isMaskAndDeletable ); 00378 } 00379 00380 bool KACLListViewItem::isAllowedToChangeType() const 00381 { 00382 return type != KACLListView::User && 00383 type != KACLListView::Group && 00384 type != KACLListView::Others && 00385 type != KACLListView::Mask; 00386 } 00387 00388 void KACLListViewItem::togglePerm( acl_perm_t perm ) 00389 { 00390 value ^= perm; // Toggle the perm 00391 if ( type == KACLListView::Mask && !isDefault ) { 00392 m_pACLListView->setMaskPermissions( value ); 00393 } 00394 calcEffectiveRights(); 00395 updatePermPixmaps(); 00396 /* 00397 // If the perm is in the partial perms then remove it. i.e. Once 00398 // a user changes a partial perm it then applies to all selected files. 00399 if ( m_pEntry->m_partialPerms & perm ) 00400 m_pEntry->m_partialPerms ^= perm; 00401 00402 m_pEntry->setPartialEntry( false ); 00403 // Make sure that all entries have their effective rights calculated if 00404 // we are changing the ACL_MASK entry. 00405 if ( type == Mask ) 00406 { 00407 m_pACLListView->setMaskPartialPermissions( m_pEntry->m_partialPerms ); 00408 m_pACLListView->setMaskPermissions( value ); 00409 m_pACLListView->calculateEffectiveRights(); 00410 } 00411 */ 00412 } 00413 00414 00415 00416 EditACLEntryDialog::EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item, 00417 const QStringList &users, 00418 const QStringList &groups, 00419 const QStringList &defaultUsers, 00420 const QStringList &defaultGroups, 00421 int allowedTypes, int allowedDefaultTypes, 00422 bool allowDefaults ) 00423 : KDialog( listView ), 00424 m_listView( listView ), m_item( item ), m_users( users ), m_groups( groups ), 00425 m_defaultUsers( defaultUsers ), m_defaultGroups( defaultGroups ), 00426 m_allowedTypes( allowedTypes ), m_allowedDefaultTypes( allowedDefaultTypes ), 00427 m_defaultCB( 0 ) 00428 { 00429 setObjectName( "edit_entry_dialog" ); 00430 setModal( true ); 00431 setCaption( i18n( "Edit ACL Entry" ) ); 00432 setButtons( KDialog::Ok | KDialog::Cancel ); 00433 setDefaultButton( KDialog::Ok ); 00434 00435 QWidget *page = new QWidget( this ); 00436 setMainWidget( page ); 00437 QVBoxLayout *mainLayout = new QVBoxLayout( page ); 00438 mainLayout->setMargin( 0 ); 00439 QGroupBox *gb = new QGroupBox( i18n("Entry Type"), page ); 00440 QVBoxLayout *gbLayout = new QVBoxLayout( gb ); 00441 00442 m_buttonGroup = new QButtonGroup( page ); 00443 00444 if ( allowDefaults ) { 00445 m_defaultCB = new QCheckBox( i18n("Default for new files in this folder"), page ); 00446 m_defaultCB->setObjectName( QLatin1String( "defaultCB" ) ); 00447 mainLayout->addWidget( m_defaultCB ); 00448 connect( m_defaultCB, SIGNAL( toggled( bool ) ), 00449 this, SLOT( slotUpdateAllowedUsersAndGroups() ) ); 00450 connect( m_defaultCB, SIGNAL( toggled( bool ) ), 00451 this, SLOT( slotUpdateAllowedTypes() ) ); 00452 } 00453 00454 QRadioButton *ownerType = new QRadioButton( i18n("Owner"), gb ); 00455 ownerType->setObjectName( QLatin1String( "ownerType" ) ); 00456 gbLayout->addWidget( ownerType ); 00457 m_buttonGroup->addButton( ownerType ); 00458 m_buttonIds.insert( ownerType, KACLListView::User ); 00459 QRadioButton *owningGroupType = new QRadioButton( i18n("Owning Group"), gb ); 00460 owningGroupType->setObjectName( QLatin1String( "owningGroupType" ) ); 00461 gbLayout->addWidget( owningGroupType ); 00462 m_buttonGroup->addButton( owningGroupType ); 00463 m_buttonIds.insert( owningGroupType, KACLListView::Group ); 00464 QRadioButton *othersType = new QRadioButton( i18n("Others"), gb ); 00465 othersType->setObjectName( QLatin1String( "othersType" ) ); 00466 gbLayout->addWidget( othersType ); 00467 m_buttonGroup->addButton( othersType ); 00468 m_buttonIds.insert( othersType, KACLListView::Others ); 00469 QRadioButton *maskType = new QRadioButton( i18n("Mask"), gb ); 00470 maskType->setObjectName( QLatin1String( "maskType" ) ); 00471 gbLayout->addWidget( maskType ); 00472 m_buttonGroup->addButton( maskType ); 00473 m_buttonIds.insert( maskType, KACLListView::Mask ); 00474 QRadioButton *namedUserType = new QRadioButton( i18n("Named user"), gb ); 00475 namedUserType->setObjectName( QLatin1String( "namesUserType" ) ); 00476 gbLayout->addWidget( namedUserType ); 00477 m_buttonGroup->addButton( namedUserType ); 00478 m_buttonIds.insert( namedUserType, KACLListView::NamedUser ); 00479 QRadioButton *namedGroupType = new QRadioButton( i18n("Named group"), gb ); 00480 namedGroupType->setObjectName( QLatin1String( "namedGroupType" ) ); 00481 gbLayout->addWidget( namedGroupType ); 00482 m_buttonGroup->addButton( namedGroupType ); 00483 m_buttonIds.insert( namedGroupType, KACLListView::NamedGroup ); 00484 00485 mainLayout->addWidget( gb ); 00486 00487 connect( m_buttonGroup, SIGNAL( buttonClicked( QAbstractButton* ) ), 00488 this, SLOT( slotSelectionChanged( QAbstractButton * ) ) ); 00489 00490 m_widgetStack = new QStackedWidget( page ); 00491 mainLayout->addWidget( m_widgetStack ); 00492 00493 KHBox *usersBox = new KHBox( m_widgetStack ); 00494 m_widgetStack->addWidget( usersBox ); 00495 00496 KHBox *groupsBox = new KHBox( m_widgetStack ); 00497 m_widgetStack->addWidget( groupsBox ); 00498 00499 QLabel *usersLabel = new QLabel( i18n( "User: " ), usersBox ); 00500 m_usersCombo = new KComboBox( usersBox ); 00501 m_usersCombo->setEditable( false ); 00502 m_usersCombo->setObjectName( QLatin1String( "users" ) ); 00503 usersLabel->setBuddy( m_usersCombo ); 00504 00505 QLabel *groupsLabel = new QLabel( i18n( "Group: " ), groupsBox ); 00506 m_groupsCombo = new KComboBox( groupsBox ); 00507 m_groupsCombo->setEditable( false ); 00508 m_groupsCombo->setObjectName( QLatin1String( "groups" ) ); 00509 groupsLabel->setBuddy( m_groupsCombo ); 00510 00511 if ( m_item ) { 00512 m_buttonIds.key( m_item->type )->setChecked( true ); 00513 if ( m_defaultCB ) 00514 m_defaultCB->setChecked( m_item->isDefault ); 00515 slotUpdateAllowedTypes(); 00516 slotSelectionChanged( m_buttonIds.key( m_item->type ) ); 00517 slotUpdateAllowedUsersAndGroups(); 00518 if ( m_item->type == KACLListView::NamedUser ) { 00519 m_usersCombo->setItemText( m_usersCombo->currentIndex(), m_item->qualifier ); 00520 } else if ( m_item->type == KACLListView::NamedGroup ) { 00521 m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), m_item->qualifier ); 00522 } 00523 } else { 00524 // new entry, preselect "named user", arguably the most common one 00525 m_buttonIds.key( KACLListView::NamedUser )->setChecked( true ); 00526 slotUpdateAllowedTypes(); 00527 slotSelectionChanged( m_buttonIds.key( KACLListView::NamedUser ) ); 00528 slotUpdateAllowedUsersAndGroups(); 00529 } 00530 incrementInitialSize( QSize( 100, 0 ) ); 00531 connect(this,SIGNAL(okClicked()), this, SLOT(slotOk())); 00532 } 00533 00534 void EditACLEntryDialog::slotUpdateAllowedTypes() 00535 { 00536 int allowedTypes = m_allowedTypes; 00537 if ( m_defaultCB && m_defaultCB->isChecked() ) { 00538 allowedTypes = m_allowedDefaultTypes; 00539 } 00540 for ( int i=1; i < KACLListView::AllTypes; i=i*2 ) { 00541 if ( allowedTypes & i ) 00542 m_buttonIds.key( i )->show(); 00543 else 00544 m_buttonIds.key( i )->hide(); 00545 } 00546 } 00547 00548 void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups() 00549 { 00550 const QString oldUser = m_usersCombo->currentText(); 00551 const QString oldGroup = m_groupsCombo->currentText(); 00552 m_usersCombo->clear(); 00553 m_groupsCombo->clear(); 00554 if ( m_defaultCB && m_defaultCB->isChecked() ) { 00555 m_usersCombo->addItems( m_defaultUsers ); 00556 if ( m_defaultUsers.contains( oldUser ) ) 00557 m_usersCombo->setItemText( m_usersCombo->currentIndex(), oldUser ); 00558 m_groupsCombo->addItems( m_defaultGroups ); 00559 if ( m_defaultGroups.contains( oldGroup ) ) 00560 m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), oldGroup ); 00561 } else { 00562 m_usersCombo->addItems( m_users ); 00563 if ( m_users.contains( oldUser ) ) 00564 m_usersCombo->setItemText( m_usersCombo->currentIndex(), oldUser ); 00565 m_groupsCombo->addItems( m_groups ); 00566 if ( m_groups.contains( oldGroup ) ) 00567 m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), oldGroup ); 00568 } 00569 } 00570 void EditACLEntryDialog::slotOk() 00571 { 00572 KACLListView::EntryType type = static_cast<KACLListView::EntryType>( m_buttonIds[m_buttonGroup->checkedButton()] ); 00573 00574 kWarning() << "Type 2: " << type; 00575 00576 QString qualifier; 00577 if ( type == KACLListView::NamedUser ) 00578 qualifier = m_usersCombo->currentText(); 00579 if ( type == KACLListView::NamedGroup ) 00580 qualifier = m_groupsCombo->currentText(); 00581 00582 if ( !m_item ) { 00583 m_item = new KACLListViewItem( m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE, false, qualifier ); 00584 } else { 00585 m_item->type = type; 00586 m_item->qualifier = qualifier; 00587 } 00588 if ( m_defaultCB ) 00589 m_item->isDefault = m_defaultCB->isChecked(); 00590 m_item->repaint(); 00591 00592 KDialog::accept(); 00593 } 00594 00595 void EditACLEntryDialog::slotSelectionChanged( QAbstractButton *button ) 00596 { 00597 switch ( m_buttonIds[ button ] ) { 00598 case KACLListView::User: 00599 case KACLListView::Group: 00600 case KACLListView::Others: 00601 case KACLListView::Mask: 00602 m_widgetStack->setEnabled( false ); 00603 break; 00604 case KACLListView::NamedUser: 00605 m_widgetStack->setEnabled( true ); 00606 m_widgetStack->setCurrentIndex( 0 /* User */ ); 00607 break; 00608 case KACLListView::NamedGroup: 00609 m_widgetStack->setEnabled( true ); 00610 m_widgetStack->setCurrentIndex( 1 /* Group */ ); 00611 break; 00612 default: 00613 break; 00614 } 00615 } 00616 00617 00618 KACLListView::KACLListView( QWidget* parent ) 00619 : QTreeWidget( parent ), 00620 m_hasMask( false ), m_allowDefaults( false ) 00621 { 00622 // Add the columns 00623 setColumnCount( 6 ); 00624 QStringList headers; 00625 headers << i18n( "Type" ); 00626 headers << i18n( "Name" ); 00627 headers << i18nc( "read permission", "r" ); 00628 headers << i18nc( "write permission", "w" ); 00629 headers << i18nc( "execute permission", "x" ); 00630 headers << i18n( "Effective" ); 00631 setHeaderLabels( headers ); 00632 00633 setSortingEnabled( false ); 00634 setSelectionMode( QAbstractItemView::ExtendedSelection ); 00635 header()->setResizeMode( QHeaderView::ResizeToContents ); 00636 setRootIsDecorated( false ); 00637 00638 // Load the avatars 00639 for ( int i=0; i < LAST_IDX; ++i ) { 00640 s_itemAttributes[i].pixmap = new QPixmap( QString::fromLatin1(":/images/%1").arg(s_itemAttributes[i].pixmapName) ); 00641 } 00642 m_yesPixmap = new QPixmap( ":/images/yes.png" ); 00643 m_yesPartialPixmap = new QPixmap( ":/images/yespartial.png" ); 00644 00645 00646 // fill the lists of all legal users and groups 00647 struct passwd *user = 0; 00648 setpwent(); 00649 while ( ( user = getpwent() ) != 0 ) { 00650 m_allUsers << QString::fromLatin1( user->pw_name ); 00651 } 00652 endpwent(); 00653 00654 struct group *gr = 0; 00655 setgrent(); 00656 while ( ( gr = getgrent() ) != 0 ) { 00657 m_allGroups << QString::fromLatin1( gr->gr_name ); 00658 } 00659 endgrent(); 00660 m_allUsers.sort(); 00661 m_allGroups.sort(); 00662 00663 connect( this, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), 00664 this, SLOT( slotItemClicked( QTreeWidgetItem*, int ) ) ); 00665 } 00666 00667 00668 KACLListView::~KACLListView() 00669 { 00670 for ( int i=0; i < LAST_IDX; ++i ) { 00671 delete s_itemAttributes[i].pixmap; 00672 } 00673 delete m_yesPixmap; 00674 delete m_yesPartialPixmap; 00675 } 00676 00677 QStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *allowedItem ) 00678 { 00679 QStringList allowedUsers = m_allUsers; 00680 QTreeWidgetItemIterator it( this ); 00681 while ( *it ) { 00682 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it ); 00683 ++it; 00684 if ( item->type != NamedUser || item->isDefault != defaults ) continue; 00685 if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue; 00686 allowedUsers.removeAll( item->qualifier ); 00687 } 00688 return allowedUsers; 00689 } 00690 00691 QStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *allowedItem ) 00692 { 00693 QStringList allowedGroups = m_allGroups; 00694 QTreeWidgetItemIterator it( this ); 00695 while ( *it ) { 00696 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it ); 00697 ++it; 00698 if ( item->type != NamedGroup || item->isDefault != defaults ) continue; 00699 if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue; 00700 allowedGroups.removeAll( item->qualifier ); 00701 } 00702 return allowedGroups; 00703 } 00704 00705 void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults ) 00706 { 00707 // clear out old entries of that ilk 00708 QTreeWidgetItemIterator it( this ); 00709 while ( KACLListViewItem *item = static_cast<KACLListViewItem*>( *it ) ) { 00710 ++it; 00711 if ( item->isDefault == defaults ) 00712 delete item; 00713 } 00714 KACLListViewItem *item = 00715 new KACLListViewItem( this, User, pACL.ownerPermissions(), defaults ); 00716 00717 item = new KACLListViewItem( this, Group, pACL.owningGroupPermissions(), defaults ); 00718 00719 item = new KACLListViewItem( this, Others, pACL.othersPermissions(), defaults ); 00720 00721 bool hasMask = false; 00722 unsigned short mask = pACL.maskPermissions( hasMask ); 00723 if ( hasMask ) { 00724 item = new KACLListViewItem( this, Mask, mask, defaults ); 00725 } 00726 00727 // read all named user entries 00728 const ACLUserPermissionsList &userList = pACL.allUserPermissions(); 00729 ACLUserPermissionsConstIterator itu = userList.begin(); 00730 while ( itu != userList.end() ) { 00731 new KACLListViewItem( this, NamedUser, (*itu).second, defaults, (*itu).first ); 00732 ++itu; 00733 } 00734 00735 // and now all named groups 00736 const ACLUserPermissionsList &groupList = pACL.allGroupPermissions(); 00737 ACLUserPermissionsConstIterator itg = groupList.begin(); 00738 while ( itg != groupList.end() ) { 00739 new KACLListViewItem( this, NamedGroup, (*itg).second, defaults, (*itg).first ); 00740 ++itg; 00741 } 00742 } 00743 00744 void KACLListView::setACL( const KACL &acl ) 00745 { 00746 if ( !acl.isValid() ) return; 00747 // Remove any entries left over from displaying a previous ACL 00748 m_ACL = acl; 00749 fillItemsFromACL( m_ACL ); 00750 00751 m_mask = acl.maskPermissions( m_hasMask ); 00752 calculateEffectiveRights(); 00753 } 00754 00755 void KACLListView::setDefaultACL( const KACL &acl ) 00756 { 00757 if ( !acl.isValid() ) return; 00758 m_defaultACL = acl; 00759 fillItemsFromACL( m_defaultACL, true ); 00760 calculateEffectiveRights(); 00761 } 00762 00763 KACL KACLListView::itemsToACL( bool defaults ) const 00764 { 00765 KACL newACL( 0 ); 00766 bool atLeastOneEntry = false; 00767 ACLUserPermissionsList users; 00768 ACLGroupPermissionsList groups; 00769 QTreeWidgetItemIterator it( const_cast<KACLListView*>( this ) ); 00770 while ( QTreeWidgetItem* qlvi = *it ) { 00771 ++it; 00772 const KACLListViewItem* item = static_cast<KACLListViewItem*>( qlvi ); 00773 if ( item->isDefault != defaults ) continue; 00774 atLeastOneEntry = true; 00775 switch ( item->type ) { 00776 case User: 00777 newACL.setOwnerPermissions( item->value ); 00778 break; 00779 case Group: 00780 newACL.setOwningGroupPermissions( item->value ); 00781 break; 00782 case Others: 00783 newACL.setOthersPermissions( item->value ); 00784 break; 00785 case Mask: 00786 newACL.setMaskPermissions( item->value ); 00787 break; 00788 case NamedUser: 00789 users.append( qMakePair( item->text( 1 ), item->value ) ); 00790 break; 00791 case NamedGroup: 00792 groups.append( qMakePair( item->text( 1 ), item->value ) ); 00793 break; 00794 default: 00795 break; 00796 } 00797 } 00798 if ( atLeastOneEntry ) { 00799 newACL.setAllUserPermissions( users ); 00800 newACL.setAllGroupPermissions( groups ); 00801 if ( newACL.isValid() ) 00802 return newACL; 00803 } 00804 return KACL(); 00805 } 00806 00807 KACL KACLListView::getACL() 00808 { 00809 return itemsToACL( false ); 00810 } 00811 00812 00813 KACL KACLListView::getDefaultACL() 00814 { 00815 return itemsToACL( true ); 00816 } 00817 00818 void KACLListView::contentsMousePressEvent( QMouseEvent * e ) 00819 { 00820 /* 00821 QTreeWidgetItem *clickedItem = itemAt( e->pos() ); 00822 if ( !clickedItem ) return; 00823 // if the click is on an as yet unselected item, select it first 00824 if ( !clickedItem->isSelected() ) 00825 QAbstractItemView::contentsMousePressEvent( e ); 00826 00827 if ( !currentItem() ) return; 00828 int column = header()->sectionAt( e->x() ); 00829 acl_perm_t perm; 00830 switch ( column ) 00831 { 00832 case 2: 00833 perm = ACL_READ; 00834 break; 00835 case 3: 00836 perm = ACL_WRITE; 00837 break; 00838 case 4: 00839 perm = ACL_EXECUTE; 00840 break; 00841 default: 00842 return QTreeWidget::contentsMousePressEvent( e ); 00843 } 00844 KACLListViewItem* referenceItem = static_cast<KACLListViewItem*>( clickedItem ); 00845 unsigned short referenceHadItSet = referenceItem->value & perm; 00846 QTreeWidgetItemIterator it( this ); 00847 while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( *it ) ) { 00848 ++it; 00849 if ( !item->isSelected() ) continue; 00850 // toggle those with the same value as the clicked item, leave the others 00851 if ( referenceHadItSet == ( item->value & perm ) ) 00852 item->togglePerm( perm ); 00853 } 00854 */ 00855 } 00856 00857 void KACLListView::slotItemClicked( QTreeWidgetItem* pItem, int col ) 00858 { 00859 if ( !pItem ) return; 00860 00861 QTreeWidgetItemIterator it( this ); 00862 while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( *it ) ) { 00863 ++it; 00864 if ( !item->isSelected() ) continue; 00865 switch ( col ) 00866 { 00867 case 2: 00868 item->togglePerm( ACL_READ ); 00869 break; 00870 case 3: 00871 item->togglePerm( ACL_WRITE ); 00872 break; 00873 case 4: 00874 item->togglePerm( ACL_EXECUTE ); 00875 break; 00876 00877 default: 00878 ; // Do nothing 00879 } 00880 } 00881 /* 00882 // Has the user changed one of the required entries in a default ACL? 00883 if ( m_pACL->aclType() == ACL_TYPE_DEFAULT && 00884 ( col == 2 || col == 3 || col == 4 ) && 00885 ( pACLItem->entryType() == ACL_USER_OBJ || 00886 pACLItem->entryType() == ACL_GROUP_OBJ || 00887 pACLItem->entryType() == ACL_OTHER ) ) 00888 { 00889 // Mark the required entries as no longer being partial entries. 00890 // That is, they will get applied to all selected directories. 00891 KACLListViewItem* pUserObj = findACLEntryByType( this, ACL_USER_OBJ ); 00892 pUserObj->entry()->setPartialEntry( false ); 00893 00894 KACLListViewItem* pGroupObj = findACLEntryByType( this, ACL_GROUP_OBJ ); 00895 pGroupObj->entry()->setPartialEntry( false ); 00896 00897 KACLListViewItem* pOther = findACLEntryByType( this, ACL_OTHER ); 00898 pOther->entry()->setPartialEntry( false ); 00899 00900 update(); 00901 } 00902 */ 00903 } 00904 00905 00906 void KACLListView::calculateEffectiveRights() 00907 { 00908 QTreeWidgetItemIterator it( this ); 00909 KACLListViewItem* pItem; 00910 while ( ( pItem = dynamic_cast<KACLListViewItem*>( *it ) ) != 0 ) 00911 { 00912 ++it; 00913 pItem->calcEffectiveRights(); 00914 } 00915 } 00916 00917 00918 unsigned short KACLListView::maskPermissions() const 00919 { 00920 return m_mask; 00921 } 00922 00923 00924 void KACLListView::setMaskPermissions( unsigned short maskPerms ) 00925 { 00926 m_mask = maskPerms; 00927 calculateEffectiveRights(); 00928 } 00929 00930 00931 acl_perm_t KACLListView::maskPartialPermissions() const 00932 { 00933 // return m_pMaskEntry->m_partialPerms; 00934 return 0; 00935 } 00936 00937 00938 void KACLListView::setMaskPartialPermissions( acl_perm_t /*maskPartialPerms*/ ) 00939 { 00940 //m_pMaskEntry->m_partialPerms = maskPartialPerms; 00941 calculateEffectiveRights(); 00942 } 00943 00944 bool KACLListView::hasDefaultEntries() const 00945 { 00946 QTreeWidgetItemIterator it( const_cast<KACLListView*>( this ) ); 00947 while ( *it ) { 00948 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it ); 00949 ++it; 00950 if ( item->isDefault ) return true; 00951 } 00952 return false; 00953 } 00954 00955 const KACLListViewItem* KACLListView::findDefaultItemByType( EntryType type ) const 00956 { 00957 return findItemByType( type, true ); 00958 } 00959 00960 const KACLListViewItem* KACLListView::findItemByType( EntryType type, bool defaults ) const 00961 { 00962 QTreeWidgetItemIterator it( const_cast<KACLListView*>( this ) ); 00963 while ( *it ) { 00964 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it ); 00965 ++it; 00966 if ( item->isDefault == defaults && item->type == type ) { 00967 return item; 00968 } 00969 } 00970 return 0; 00971 } 00972 00973 00974 unsigned short KACLListView::calculateMaskValue( bool defaults ) const 00975 { 00976 // KACL auto-adds the relevant maks entries, so we can simply query 00977 bool dummy; 00978 return itemsToACL( defaults ).maskPermissions( dummy ); 00979 } 00980 00981 void KACLListView::slotAddEntry() 00982 { 00983 int allowedTypes = NamedUser | NamedGroup; 00984 if ( !m_hasMask ) 00985 allowedTypes |= Mask; 00986 int allowedDefaultTypes = NamedUser | NamedGroup; 00987 if ( !findDefaultItemByType( Mask ) ) 00988 allowedDefaultTypes |= Mask; 00989 if ( !hasDefaultEntries() ) 00990 allowedDefaultTypes |= User | Group; 00991 EditACLEntryDialog dlg( this, 0, 00992 allowedUsers( false ), allowedGroups( false ), 00993 allowedUsers( true ), allowedGroups( true ), 00994 allowedTypes, allowedDefaultTypes, m_allowDefaults ); 00995 dlg.exec(); 00996 KACLListViewItem *item = dlg.item(); 00997 if ( !item ) return; // canceled 00998 if ( item->type == Mask && !item->isDefault ) { 00999 m_hasMask = true; 01000 m_mask = item->value; 01001 } 01002 if ( item->isDefault && !hasDefaultEntries() ) { 01003 // first default entry, fill in what is needed 01004 if ( item->type != User ) { 01005 unsigned short v = findDefaultItemByType( User )->value; 01006 new KACLListViewItem( this, User, v, true ); 01007 } 01008 if ( item->type != Group ) { 01009 unsigned short v = findDefaultItemByType( Group )->value; 01010 new KACLListViewItem( this, Group, v, true ); 01011 } 01012 if ( item->type != Others ) { 01013 unsigned short v = findDefaultItemByType( Others )->value; 01014 new KACLListViewItem( this, Others, v, true ); 01015 } 01016 } 01017 const KACLListViewItem *defaultMaskItem = findDefaultItemByType( Mask ); 01018 if ( item->isDefault && !defaultMaskItem ) { 01019 unsigned short v = calculateMaskValue( true ); 01020 new KACLListViewItem( this, Mask, v, true ); 01021 } 01022 if ( !item->isDefault && !m_hasMask && 01023 ( item->type == Group 01024 || item->type == NamedUser 01025 || item->type == NamedGroup ) ) { 01026 // auto-add a mask entry 01027 unsigned short v = calculateMaskValue( false ); 01028 new KACLListViewItem( this, Mask, v, false ); 01029 m_hasMask = true; 01030 m_mask = v; 01031 } 01032 calculateEffectiveRights(); 01033 sortItems( sortColumn(), Qt::AscendingOrder ); 01034 setCurrentItem( item ); 01035 // QTreeWidget doesn't seem to emit, in this case, and we need to update 01036 // the buttons... 01037 if ( topLevelItemCount() == 1 ) 01038 emit currentItemChanged( item, item ); 01039 } 01040 01041 void KACLListView::slotEditEntry() 01042 { 01043 QTreeWidgetItem * current = currentItem(); 01044 if ( !current ) return; 01045 KACLListViewItem *item = static_cast<KACLListViewItem*>( current ); 01046 int allowedTypes = item->type | NamedUser | NamedGroup; 01047 bool itemWasMask = item->type == Mask; 01048 if ( !m_hasMask || itemWasMask ) 01049 allowedTypes |= Mask; 01050 int allowedDefaultTypes = item->type | NamedUser | NamedGroup; 01051 if ( !findDefaultItemByType( Mask ) ) 01052 allowedDefaultTypes |= Mask; 01053 if ( !hasDefaultEntries() ) 01054 allowedDefaultTypes |= User | Group; 01055 01056 EditACLEntryDialog dlg( this, item, 01057 allowedUsers( false, item ), allowedGroups( false, item ), 01058 allowedUsers( true, item ), allowedGroups( true, item ), 01059 allowedTypes, allowedDefaultTypes, m_allowDefaults ); 01060 dlg.exec(); 01061 if ( itemWasMask && item->type != Mask ) { 01062 m_hasMask = false; 01063 m_mask = 0; 01064 } 01065 if ( !itemWasMask && item->type == Mask ) { 01066 m_mask = item->value; 01067 m_hasMask = true; 01068 } 01069 calculateEffectiveRights(); 01070 sortItems( sortColumn(), Qt::AscendingOrder ); 01071 } 01072 01073 void KACLListView::slotRemoveEntry() 01074 { 01075 QTreeWidgetItemIterator it( this, QTreeWidgetItemIterator::Selected ); 01076 while ( *it ) { 01077 KACLListViewItem *item = static_cast<KACLListViewItem*>( *it ); 01078 ++it; 01079 /* First check if it's a mask entry and if so, make sure that there is 01080 * either no name user or group entry, which means the mask can be 01081 * removed, or don't remove it, but reset it. That is allowed. */ 01082 if ( item->type == Mask ) { 01083 bool itemWasDefault = item->isDefault; 01084 if ( !itemWasDefault && maskCanBeDeleted() ) { 01085 m_hasMask= false; 01086 m_mask = 0; 01087 delete item; 01088 } else if ( itemWasDefault && defaultMaskCanBeDeleted() ) { 01089 delete item; 01090 } else { 01091 item->value = 0; 01092 item->repaint(); 01093 } 01094 if ( !itemWasDefault ) 01095 calculateEffectiveRights(); 01096 } else { 01097 // for the base permissions, disable them, which is what libacl does 01098 if ( !item->isDefault && 01099 ( item->type == User 01100 || item->type == Group 01101 || item->type == Others ) ) { 01102 item->value = 0; 01103 item->repaint(); 01104 } else { 01105 delete item; 01106 } 01107 } 01108 } 01109 } 01110 01111 bool KACLListView::maskCanBeDeleted() const 01112 { 01113 return !findItemByType( NamedUser ) && !findItemByType( NamedGroup ); 01114 } 01115 01116 bool KACLListView::defaultMaskCanBeDeleted() const 01117 { 01118 return !findDefaultItemByType( NamedUser ) && !findDefaultItemByType( NamedGroup ); 01119 } 01120 01121 #include "kacleditwidget.moc" 01122 #include "kacleditwidget_p.moc" 01123 #endif 01124 // vim:set ts=8 sw=4:
KDE 4.6 API Reference