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