kacleditwidget.cpp

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