8#include "kacleditwidget.h"
9#include "kacleditwidget_p.h"
10#include "kio_widgets_debug.h"
14#include <QButtonGroup>
18#include <QDialogButtonBox>
26#include <QRadioButton>
28#include <QStackedWidget>
30#include <KLocalizedString>
34#include <acl/libacl.h>
42class KACLEditWidget::KACLEditWidgetPrivate
45 KACLEditWidgetPrivate()
50 void slotUpdateButtons();
52 KACLListView *m_listView;
58KACLEditWidget::KACLEditWidget(
QWidget *parent)
60 , d(new KACLEditWidgetPrivate)
64 d->m_listView =
new KACLListView(
this);
67 d->slotUpdateButtons();
73 d->m_AddBtn->setObjectName(QStringLiteral(
"add_entry_button"));
77 d->m_EditBtn->setObjectName(QStringLiteral(
"edit_entry_button"));
81 d->m_DelBtn->setObjectName(QStringLiteral(
"delete_entry_button"));
84 d->slotUpdateButtons();
87KACLEditWidget::~KACLEditWidget() =
default;
89void KACLEditWidget::KACLEditWidgetPrivate::slotUpdateButtons()
91 bool atLeastOneIsNotDeletable =
false;
92 bool atLeastOneIsNotAllowedToChangeType =
false;
93 int selectedCount = 0;
96 while (it.hasNext()) {
97 KACLListViewItem *item =
static_cast<KACLListViewItem *
>(it.next());
99 if (!item->isDeletable()) {
100 atLeastOneIsNotDeletable =
true;
102 if (!item->isAllowedToChangeType()) {
103 atLeastOneIsNotAllowedToChangeType =
true;
106 m_EditBtn->setEnabled(selectedCount && !atLeastOneIsNotAllowedToChangeType);
107 m_DelBtn->setEnabled(selectedCount && !atLeastOneIsNotDeletable);
110KACL KACLEditWidget::getACL()
const
112 return d->m_listView->getACL();
115KACL KACLEditWidget::getDefaultACL()
const
117 return d->m_listView->getDefaultACL();
120void KACLEditWidget::setACL(
const KACL &acl)
122 d->m_listView->
setACL(acl);
125void KACLEditWidget::setDefaultACL(
const KACL &acl)
127 d->m_listView->setDefaultACL(acl);
130void KACLEditWidget::setAllowDefaults(
bool value)
132 d->m_listView->setAllowDefaults(value);
135KACLListViewItem::KACLListViewItem(
QTreeWidget *parent, KACLListView::EntryType _type,
unsigned short _value,
bool defaults,
const QString &_qualifier)
140 , qualifier(_qualifier)
143 m_pACLListView = qobject_cast<KACLListView *>(parent);
147KACLListViewItem::~KACLListViewItem()
151QString KACLListViewItem::key()
const
160 case KACLListView::User:
163 case KACLListView::Group:
166 case KACLListView::Others:
169 case KACLListView::Mask:
172 case KACLListView::NamedUser:
175 case KACLListView::NamedGroup:
187 return key() <
static_cast<const KACLListViewItem &
>(other).key();
190void KACLListViewItem::updatePermissionIcons()
192 unsigned int partialPerms = value;
194 if (value & ACL_READ) {
196 }
else if (partialPerms & ACL_READ) {
202 if (value & ACL_WRITE) {
204 }
else if (partialPerms & ACL_WRITE) {
210 if (value & ACL_EXECUTE) {
212 }
else if (partialPerms & ACL_EXECUTE) {
219void KACLListViewItem::repaint()
225 case KACLListView::User:
227 text =
i18nc(
"Unix permissions",
"Owner");
228 icon = QStringLiteral(
"user-gray");
230 case KACLListView::Group:
231 text =
i18nc(
"UNIX permissions",
"Owning Group");
232 icon = QStringLiteral(
"group-gray");
234 case KACLListView::Others:
235 text =
i18nc(
"UNIX permissions",
"Others");
236 icon = QStringLiteral(
"user-others-gray");
238 case KACLListView::Mask:
239 text =
i18nc(
"UNIX permissions",
"Mask");
240 icon = QStringLiteral(
"view-filter");
242 case KACLListView::NamedUser:
243 text =
i18nc(
"UNIX permissions",
"Named User");
244 icon = QStringLiteral(
"user");
246 case KACLListView::NamedGroup:
247 text =
i18nc(
"UNIX permissions",
"Others");
248 icon = QStringLiteral(
"user-others");
254 setText(0,
i18n(
"Owner (Default)"));
256 setText(1, qualifier);
258 updatePermissionIcons();
261void KACLListViewItem::calcEffectiveRights()
263 QString strEffective = QStringLiteral(
"---");
267 if (m_pACLListView->hasMaskEntry()
268 && (type == KACLListView::NamedUser || type == KACLListView::Group || type == KACLListView::NamedGroup)
270 strEffective[0] =
QLatin1Char((m_pACLListView->maskPermissions() & value & ACL_READ) ?
'r' :
'-');
271 strEffective[1] =
QLatin1Char((m_pACLListView->maskPermissions() & value & ACL_WRITE) ?
'w' :
'-');
272 strEffective[2] =
QLatin1Char((m_pACLListView->maskPermissions() & value & ACL_EXECUTE) ?
'x' :
'-');
290 strEffective[0] =
QLatin1Char((value & ACL_READ) ?
'r' :
'-');
291 strEffective[1] =
QLatin1Char((value & ACL_WRITE) ?
'w' :
'-');
292 strEffective[2] =
QLatin1Char((value & ACL_EXECUTE) ?
'x' :
'-');
304 setText(5, strEffective);
307bool KACLListViewItem::isDeletable()
const
309 bool isMaskAndDeletable =
false;
310 if (type == KACLListView::Mask) {
311 if (!isDefault && m_pACLListView->maskCanBeDeleted()) {
312 isMaskAndDeletable =
true;
313 }
else if (isDefault && m_pACLListView->defaultMaskCanBeDeleted()) {
314 isMaskAndDeletable =
true;
319 return type != KACLListView::User
320 &&
type != KACLListView::Group
321 &&
type != KACLListView::Others
322 && (
type != KACLListView::Mask || isMaskAndDeletable);
326bool KACLListViewItem::isAllowedToChangeType()
const
329 return type != KACLListView::User
330 &&
type != KACLListView::Group
331 &&
type != KACLListView::Others
332 &&
type != KACLListView::Mask;
336void KACLListViewItem::togglePerm(acl_perm_t perm)
339 if (type == KACLListView::Mask && !isDefault) {
340 m_pACLListView->setMaskPermissions(value);
342 calcEffectiveRights();
343 updatePermissionIcons();
362EditACLEntryDialog::EditACLEntryDialog(KACLListView *listView,
363 KACLListViewItem *item,
369 int allowedDefaultTypes,
372 , m_listView(listView)
376 , m_defaultUsers(defaultUsers)
377 , m_defaultGroups(defaultGroups)
378 , m_allowedTypes(allowedTypes)
379 , m_allowedDefaultTypes(allowedDefaultTypes)
380 , m_defaultCB(nullptr)
382 setObjectName(QStringLiteral(
"edit_entry_dialog"));
384 setWindowTitle(
i18n(
"Edit ACL Entry"));
393 m_defaultCB =
new QCheckBox(
i18n(
"Default for new files in this folder"),
this);
394 m_defaultCB->setObjectName(QStringLiteral(
"defaultCB"));
403 m_buttonGroup->addButton(ownerType);
404 m_buttonIds.insert(ownerType, KACLListView::User);
406 owningGroupType->
setObjectName(QStringLiteral(
"owningGroupType"));
408 m_buttonGroup->addButton(owningGroupType);
409 m_buttonIds.insert(owningGroupType, KACLListView::Group);
413 m_buttonGroup->addButton(othersType);
414 m_buttonIds.insert(othersType, KACLListView::Others);
418 m_buttonGroup->addButton(maskType);
419 m_buttonIds.insert(maskType, KACLListView::Mask);
421 namedUserType->
setObjectName(QStringLiteral(
"namesUserType"));
423 m_buttonGroup->addButton(namedUserType);
424 m_buttonIds.insert(namedUserType, KACLListView::NamedUser);
426 namedGroupType->
setObjectName(QStringLiteral(
"namedGroupType"));
428 m_buttonGroup->addButton(namedGroupType);
429 m_buttonIds.insert(namedGroupType, KACLListView::NamedGroup);
441 m_widgetStack->addWidget(usersBox);
445 m_usersCombo->setEditable(
false);
446 m_usersCombo->setObjectName(QStringLiteral(
"users"));
455 m_widgetStack->addWidget(groupsBox);
458 m_groupsCombo =
new QComboBox(groupsBox);
459 m_groupsCombo->setEditable(
false);
460 m_groupsCombo->setObjectName(QStringLiteral(
"groups"));
461 groupsLabel->
setBuddy(m_groupsCombo);
467 m_buttonIds.key(m_item->type)->setChecked(
true);
469 m_defaultCB->setChecked(m_item->isDefault);
471 slotUpdateAllowedTypes();
472 slotSelectionChanged(m_buttonIds.key(m_item->type));
473 slotUpdateAllowedUsersAndGroups();
474 if (m_item->type == KACLListView::NamedUser) {
475 m_usersCombo->setItemText(m_usersCombo->currentIndex(), m_item->qualifier);
476 }
else if (m_item->type == KACLListView::NamedGroup) {
477 m_groupsCombo->setItemText(m_groupsCombo->currentIndex(), m_item->qualifier);
481 m_buttonIds.key(KACLListView::NamedUser)->setChecked(
true);
482 slotUpdateAllowedTypes();
483 slotSelectionChanged(m_buttonIds.key(KACLListView::NamedUser));
484 slotUpdateAllowedUsersAndGroups();
496void EditACLEntryDialog::slotUpdateAllowedTypes()
498 int allowedTypes = m_allowedTypes;
499 if (m_defaultCB && m_defaultCB->isChecked()) {
500 allowedTypes = m_allowedDefaultTypes;
502 for (
int i = 1; i < KACLListView::AllTypes; i = i * 2) {
503 if (allowedTypes & i) {
504 m_buttonIds.key(i)->show();
506 m_buttonIds.key(i)->hide();
511void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups()
513 const QString oldUser = m_usersCombo->currentText();
514 const QString oldGroup = m_groupsCombo->currentText();
515 m_usersCombo->
clear();
516 m_groupsCombo->clear();
517 if (m_defaultCB && m_defaultCB->isChecked()) {
518 m_usersCombo->addItems(m_defaultUsers);
519 if (m_defaultUsers.contains(oldUser)) {
520 m_usersCombo->setItemText(m_usersCombo->currentIndex(), oldUser);
522 m_groupsCombo->addItems(m_defaultGroups);
523 if (m_defaultGroups.contains(oldGroup)) {
524 m_groupsCombo->setItemText(m_groupsCombo->currentIndex(), oldGroup);
527 m_usersCombo->addItems(m_users);
528 if (m_users.contains(oldUser)) {
529 m_usersCombo->setItemText(m_usersCombo->currentIndex(), oldUser);
531 m_groupsCombo->addItems(m_groups);
532 if (m_groups.contains(oldGroup)) {
533 m_groupsCombo->setItemText(m_groupsCombo->currentIndex(), oldGroup);
537void EditACLEntryDialog::slotOk()
539 KACLListView::EntryType
type =
static_cast<KACLListView::EntryType
>(m_buttonIds[m_buttonGroup->checkedButton()]);
541 qCWarning(KIO_WIDGETS) <<
"Type 2: " <<
type;
544 if (type == KACLListView::NamedUser) {
545 qualifier = m_usersCombo->currentText();
547 if (type == KACLListView::NamedGroup) {
548 qualifier = m_groupsCombo->currentText();
552 m_item =
new KACLListViewItem(m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE,
false, qualifier);
555 m_item->qualifier = qualifier;
558 m_item->isDefault = m_defaultCB->isChecked();
567 switch (m_buttonIds[button]) {
568 case KACLListView::User:
569 case KACLListView::Group:
570 case KACLListView::Others:
571 case KACLListView::Mask:
572 m_widgetStack->setEnabled(
false);
574 case KACLListView::NamedUser:
575 m_widgetStack->setEnabled(
true);
576 m_widgetStack->setCurrentIndex(0 );
578 case KACLListView::NamedGroup:
579 m_widgetStack->setEnabled(
true);
580 m_widgetStack->setCurrentIndex(1 );
587KACLListView::KACLListView(
QWidget *parent)
590 , m_allowDefaults(false)
597 i18nc(
"read permission",
"r"),
598 i18nc(
"write permission",
"w"),
599 i18nc(
"execute permission",
"x"),
602 setHeaderLabels(headers);
604 setSortingEnabled(
false);
607 setRootIsDecorated(
false);
611 connect(
this, &KACLListView::itemDoubleClicked,
this, &KACLListView::slotItemDoubleClicked);
614KACLListView::~KACLListView()
618QSize KACLListView::sizeHint()
const
620 const int width = header()->length() + verticalScrollBar()->
width();
621 const int height = 7 * rowHeight(model()->index(0, 0,
QModelIndex()));
622 return {width, height};
625QStringList KACLListView::allowedUsers(
bool defaults, KACLListViewItem *allowedItem)
627 if (m_allUsers.isEmpty()) {
628 struct passwd *user =
nullptr;
630 while ((user = getpwent()) !=
nullptr) {
640 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
642 if (item->type != NamedUser || item->isDefault != defaults) {
645 if (allowedItem && item == allowedItem && allowedItem->isDefault == defaults) {
653QStringList KACLListView::allowedGroups(
bool defaults, KACLListViewItem *allowedItem)
655 if (m_allGroups.isEmpty()) {
656 struct group *gr =
nullptr;
658 while ((gr = getgrent()) !=
nullptr) {
668 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
670 if (item->type != NamedGroup || item->isDefault != defaults) {
673 if (allowedItem && item == allowedItem && allowedItem->isDefault == defaults) {
676 allowedGroups.
removeAll(item->qualifier);
678 return allowedGroups;
681void KACLListView::fillItemsFromACL(
const KACL &pACL,
bool defaults)
685 while (KACLListViewItem *item =
static_cast<KACLListViewItem *
>(*it)) {
687 if (item->isDefault == defaults) {
698 bool hasMask =
false;
701 new KACLListViewItem(
this, Mask, mask, defaults);
707 while (itu != userList.
end()) {
708 new KACLListViewItem(
this, NamedUser, (*itu).second, defaults, (*itu).first);
715 while (itg != groupList.
end()) {
716 new KACLListViewItem(
this, NamedGroup, (*itg).second, defaults, (*itg).first);
721void KACLListView::setACL(
const KACL &acl)
728 fillItemsFromACL(m_ACL);
731 calculateEffectiveRights();
734void KACLListView::setDefaultACL(
const KACL &acl)
740 fillItemsFromACL(m_defaultACL,
true);
741 calculateEffectiveRights();
744KACL KACLListView::itemsToACL(
bool defaults)
const
747 bool atLeastOneEntry =
false;
753 const KACLListViewItem *item =
static_cast<KACLListViewItem *
>(qlvi);
754 if (item->isDefault != defaults) {
757 atLeastOneEntry =
true;
758 switch (item->type) {
760 newACL.setOwnerPermissions(item->value);
763 newACL.setOwningGroupPermissions(item->value);
766 newACL.setOthersPermissions(item->value);
769 newACL.setMaskPermissions(item->value);
772 users.
append(qMakePair(item->text(1), item->value));
775 groups.
append(qMakePair(item->text(1), item->value));
781 if (atLeastOneEntry) {
782 newACL.setAllUserPermissions(users);
783 newACL.setAllGroupPermissions(groups);
784 if (newACL.isValid()) {
791KACL KACLListView::getACL()
793 return itemsToACL(
false);
796KACL KACLListView::getDefaultACL()
798 return itemsToACL(
true);
801void KACLListView::contentsMousePressEvent(
QMouseEvent * )
847 while (KACLListViewItem *item =
static_cast<KACLListViewItem *
>(*it)) {
849 if (!item->isSelected()) {
854 item->togglePerm(ACL_READ);
857 item->togglePerm(ACL_WRITE);
860 item->togglePerm(ACL_EXECUTE);
890void KACLListView::slotItemDoubleClicked(
QTreeWidgetItem *item,
int column)
897 if (column >= 2 && column <= 4) {
901 KACLListViewItem *aclListItem =
static_cast<KACLListViewItem *
>(item);
902 if (!aclListItem->isAllowedToChangeType()) {
906 setCurrentItem(item);
910void KACLListView::calculateEffectiveRights()
913 KACLListViewItem *pItem;
914 while ((pItem =
dynamic_cast<KACLListViewItem *
>(*it)) !=
nullptr) {
916 pItem->calcEffectiveRights();
920unsigned short KACLListView::maskPermissions()
const
925void KACLListView::setMaskPermissions(
unsigned short maskPerms)
928 calculateEffectiveRights();
931acl_perm_t KACLListView::maskPartialPermissions()
const
937void KACLListView::setMaskPartialPermissions(acl_perm_t )
940 calculateEffectiveRights();
943bool KACLListView::hasDefaultEntries()
const
947 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
949 if (item->isDefault) {
956const KACLListViewItem *KACLListView::findDefaultItemByType(EntryType type)
const
958 return findItemByType(type,
true);
961const KACLListViewItem *KACLListView::findItemByType(EntryType type,
bool defaults)
const
965 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
967 if (item->isDefault == defaults && item->type == type) {
974unsigned short KACLListView::calculateMaskValue(
bool defaults)
const
978 return itemsToACL(defaults).maskPermissions(dummy);
981void KACLListView::slotAddEntry()
983 int allowedTypes = NamedUser | NamedGroup;
985 allowedTypes |= Mask;
987 int allowedDefaultTypes = NamedUser | NamedGroup;
988 if (!findDefaultItemByType(Mask)) {
989 allowedDefaultTypes |= Mask;
991 if (!hasDefaultEntries()) {
992 allowedDefaultTypes |= User | Group;
994 EditACLEntryDialog dlg(
this,
997 allowedGroups(
false),
1001 allowedDefaultTypes,
1004 KACLListViewItem *item = dlg.item();
1008 if (item->type == Mask && !item->isDefault) {
1010 m_mask = item->value;
1012 if (item->isDefault && !hasDefaultEntries()) {
1014 if (item->type != User) {
1015 unsigned short v = findDefaultItemByType(User)->value;
1016 new KACLListViewItem(
this, User, v,
true);
1018 if (item->type != Group) {
1019 unsigned short v = findDefaultItemByType(Group)->value;
1020 new KACLListViewItem(
this, Group, v,
true);
1022 if (item->type != Others) {
1023 unsigned short v = findDefaultItemByType(Others)->value;
1024 new KACLListViewItem(
this, Others, v,
true);
1027 const KACLListViewItem *defaultMaskItem = findDefaultItemByType(Mask);
1028 if (item->isDefault && !defaultMaskItem) {
1029 unsigned short v = calculateMaskValue(
true);
1030 new KACLListViewItem(
this, Mask, v,
true);
1032 if (!item->isDefault && !m_hasMask && (item->type == Group || item->type == NamedUser || item->type == NamedGroup)) {
1034 unsigned short v = calculateMaskValue(
false);
1035 new KACLListViewItem(
this, Mask, v,
false);
1039 calculateEffectiveRights();
1041 setCurrentItem(item);
1044 if (topLevelItemCount() == 1) {
1045 Q_EMIT currentItemChanged(item, item);
1049void KACLListView::slotEditEntry()
1055 KACLListViewItem *item =
static_cast<KACLListViewItem *
>(current);
1056 int allowedTypes = item->type | NamedUser | NamedGroup;
1057 bool itemWasMask = item->type == Mask;
1058 if (!m_hasMask || itemWasMask) {
1059 allowedTypes |= Mask;
1061 int allowedDefaultTypes = item->type | NamedUser | NamedGroup;
1062 if (!findDefaultItemByType(Mask)) {
1063 allowedDefaultTypes |= Mask;
1065 if (!hasDefaultEntries()) {
1066 allowedDefaultTypes |= User | Group;
1069 EditACLEntryDialog dlg(
this,
1071 allowedUsers(
false, item),
1072 allowedGroups(
false, item),
1073 allowedUsers(
true, item),
1074 allowedGroups(
true, item),
1076 allowedDefaultTypes,
1079 if (itemWasMask && item->type != Mask) {
1083 if (!itemWasMask && item->type == Mask) {
1084 m_mask = item->value;
1087 calculateEffectiveRights();
1091void KACLListView::slotRemoveEntry()
1095 KACLListViewItem *item =
static_cast<KACLListViewItem *
>(*it);
1100 if (item->type == Mask) {
1101 bool itemWasDefault = item->isDefault;
1102 if (!itemWasDefault && maskCanBeDeleted()) {
1106 }
else if (itemWasDefault && defaultMaskCanBeDeleted()) {
1112 if (!itemWasDefault) {
1113 calculateEffectiveRights();
1117 if (!item->isDefault && (item->type == User || item->type == Group || item->type == Others)) {
1127bool KACLListView::maskCanBeDeleted()
const
1129 return !findItemByType(NamedUser) && !findItemByType(NamedGroup);
1132bool KACLListView::defaultMaskCanBeDeleted()
const
1134 return !findDefaultItemByType(NamedUser) && !findDefaultItemByType(NamedGroup);
1137#include "moc_kacleditwidget.cpp"
1138#include "moc_kacleditwidget_p.cpp"
The KACL class encapsulates a POSIX Access Control List.
unsigned short maskPermissions(bool &exists) const
Return the entry for the permissions mask if there is one and sets exists to true.
bool setACL(const QString &aclStr)
Sets the whole list from a string.
bool isValid() const
Returns whether the KACL object represents a valid acl.
ACLGroupPermissionsList allGroupPermissions() const
Returns the list of all group permission entries.
unsigned short othersPermissions() const
ACLUserPermissionsList allUserPermissions() const
Returns the list of all group permission entries.
unsigned short ownerPermissions() const
The standard (non-extended) part of an ACL.
unsigned short owningGroupPermissions() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
virtual void addItem(QLayoutItem *item) override
void addLayout(QLayout *layout, int stretch)
QIcon fromTheme(const QString &name)
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
void setBuddy(QWidget *buddy)
void setContentsMargins(const QMargins &margins)
void append(QList< T > &&value)
qsizetype removeAll(const AT &t)
void setObjectName(QAnyStringView name)
QString fromLatin1(QByteArrayView str)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)