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"));
394 m_defaultCB =
new QCheckBox(
i18n(
"Default for new files in this folder"),
this);
395 m_defaultCB->setObjectName(QStringLiteral(
"defaultCB"));
404 m_buttonGroup->addButton(ownerType);
405 m_buttonIds.insert(ownerType, KACLListView::User);
407 owningGroupType->
setObjectName(QStringLiteral(
"owningGroupType"));
409 m_buttonGroup->addButton(owningGroupType);
410 m_buttonIds.insert(owningGroupType, KACLListView::Group);
414 m_buttonGroup->addButton(othersType);
415 m_buttonIds.insert(othersType, KACLListView::Others);
419 m_buttonGroup->addButton(maskType);
420 m_buttonIds.insert(maskType, KACLListView::Mask);
422 namedUserType->
setObjectName(QStringLiteral(
"namesUserType"));
424 m_buttonGroup->addButton(namedUserType);
425 m_buttonIds.insert(namedUserType, KACLListView::NamedUser);
427 namedGroupType->
setObjectName(QStringLiteral(
"namedGroupType"));
429 m_buttonGroup->addButton(namedGroupType);
430 m_buttonIds.insert(namedGroupType, KACLListView::NamedGroup);
442 m_widgetStack->addWidget(usersBox);
446 m_usersCombo->setEditable(
false);
447 m_usersCombo->setObjectName(QStringLiteral(
"users"));
456 m_widgetStack->addWidget(groupsBox);
459 m_groupsCombo =
new QComboBox(groupsBox);
460 m_groupsCombo->setEditable(
false);
461 m_groupsCombo->setObjectName(QStringLiteral(
"groups"));
462 groupsLabel->
setBuddy(m_groupsCombo);
468 m_buttonIds.key(m_item->type)->setChecked(
true);
470 m_defaultCB->setChecked(m_item->isDefault);
472 slotUpdateAllowedTypes();
473 slotSelectionChanged(m_buttonIds.key(m_item->type));
474 slotUpdateAllowedUsersAndGroups();
475 if (m_item->type == KACLListView::NamedUser) {
476 m_usersCombo->setItemText(m_usersCombo->currentIndex(), m_item->qualifier);
477 }
else if (m_item->type == KACLListView::NamedGroup) {
478 m_groupsCombo->setItemText(m_groupsCombo->currentIndex(), m_item->qualifier);
482 m_buttonIds.key(KACLListView::NamedUser)->setChecked(
true);
483 slotUpdateAllowedTypes();
484 slotSelectionChanged(m_buttonIds.key(KACLListView::NamedUser));
485 slotUpdateAllowedUsersAndGroups();
497void EditACLEntryDialog::slotUpdateAllowedTypes()
499 int allowedTypes = m_allowedTypes;
500 if (m_defaultCB && m_defaultCB->isChecked()) {
501 allowedTypes = m_allowedDefaultTypes;
503 for (
int i = 1; i < KACLListView::AllTypes; i = i * 2) {
504 if (allowedTypes & i) {
505 m_buttonIds.key(i)->show();
507 m_buttonIds.key(i)->hide();
512void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups()
514 const QString oldUser = m_usersCombo->currentText();
515 const QString oldGroup = m_groupsCombo->currentText();
516 m_usersCombo->
clear();
517 m_groupsCombo->clear();
518 if (m_defaultCB && m_defaultCB->isChecked()) {
519 m_usersCombo->addItems(m_defaultUsers);
520 if (m_defaultUsers.contains(oldUser)) {
521 m_usersCombo->setItemText(m_usersCombo->currentIndex(), oldUser);
523 m_groupsCombo->addItems(m_defaultGroups);
524 if (m_defaultGroups.contains(oldGroup)) {
525 m_groupsCombo->setItemText(m_groupsCombo->currentIndex(), oldGroup);
528 m_usersCombo->addItems(m_users);
529 if (m_users.contains(oldUser)) {
530 m_usersCombo->setItemText(m_usersCombo->currentIndex(), oldUser);
532 m_groupsCombo->addItems(m_groups);
533 if (m_groups.contains(oldGroup)) {
534 m_groupsCombo->setItemText(m_groupsCombo->currentIndex(), oldGroup);
538void EditACLEntryDialog::slotOk()
540 KACLListView::EntryType
type =
static_cast<KACLListView::EntryType
>(m_buttonIds[m_buttonGroup->checkedButton()]);
542 qCWarning(KIO_WIDGETS) <<
"Type 2: " <<
type;
545 if (type == KACLListView::NamedUser) {
546 qualifier = m_usersCombo->currentText();
548 if (type == KACLListView::NamedGroup) {
549 qualifier = m_groupsCombo->currentText();
553 m_item =
new KACLListViewItem(m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE,
false, qualifier);
556 m_item->qualifier = qualifier;
559 m_item->isDefault = m_defaultCB->isChecked();
568 switch (m_buttonIds[button]) {
569 case KACLListView::User:
570 case KACLListView::Group:
571 case KACLListView::Others:
572 case KACLListView::Mask:
573 m_widgetStack->setEnabled(
false);
575 case KACLListView::NamedUser:
576 m_widgetStack->setEnabled(
true);
577 m_widgetStack->setCurrentIndex(0 );
579 case KACLListView::NamedGroup:
580 m_widgetStack->setEnabled(
true);
581 m_widgetStack->setCurrentIndex(1 );
588KACLListView::KACLListView(
QWidget *parent)
591 , m_allowDefaults(false)
598 i18nc(
"read permission",
"r"),
599 i18nc(
"write permission",
"w"),
600 i18nc(
"execute permission",
"x"),
603 setHeaderLabels(headers);
605 setSortingEnabled(
false);
608 setRootIsDecorated(
false);
612 connect(
this, &KACLListView::itemDoubleClicked,
this, &KACLListView::slotItemDoubleClicked);
615KACLListView::~KACLListView()
619QSize KACLListView::sizeHint()
const
621 const int width = header()->length() + verticalScrollBar()->
width();
622 const int height = 7 * rowHeight(model()->index(0, 0,
QModelIndex()));
623 return {width, height};
626QStringList KACLListView::allowedUsers(
bool defaults, KACLListViewItem *allowedItem)
628 if (m_allUsers.isEmpty()) {
629 struct passwd *user =
nullptr;
631 while ((user = getpwent()) !=
nullptr) {
641 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
643 if (item->type != NamedUser || item->isDefault != defaults) {
646 if (allowedItem && item == allowedItem && allowedItem->isDefault == defaults) {
654QStringList KACLListView::allowedGroups(
bool defaults, KACLListViewItem *allowedItem)
656 if (m_allGroups.isEmpty()) {
657 struct group *gr =
nullptr;
659 while ((gr = getgrent()) !=
nullptr) {
669 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
671 if (item->type != NamedGroup || item->isDefault != defaults) {
674 if (allowedItem && item == allowedItem && allowedItem->isDefault == defaults) {
677 allowedGroups.
removeAll(item->qualifier);
679 return allowedGroups;
682void KACLListView::fillItemsFromACL(
const KACL &pACL,
bool defaults)
686 while (KACLListViewItem *item =
static_cast<KACLListViewItem *
>(*it)) {
688 if (item->isDefault == defaults) {
699 bool hasMask =
false;
702 new KACLListViewItem(
this, Mask, mask, defaults);
708 while (itu != userList.
end()) {
709 new KACLListViewItem(
this, NamedUser, (*itu).second, defaults, (*itu).first);
716 while (itg != groupList.
end()) {
717 new KACLListViewItem(
this, NamedGroup, (*itg).second, defaults, (*itg).first);
722void KACLListView::setACL(
const KACL &acl)
729 fillItemsFromACL(m_ACL);
732 calculateEffectiveRights();
735void KACLListView::setDefaultACL(
const KACL &acl)
741 fillItemsFromACL(m_defaultACL,
true);
742 calculateEffectiveRights();
745KACL KACLListView::itemsToACL(
bool defaults)
const
748 bool atLeastOneEntry =
false;
754 const KACLListViewItem *item =
static_cast<KACLListViewItem *
>(qlvi);
755 if (item->isDefault != defaults) {
758 atLeastOneEntry =
true;
759 switch (item->type) {
761 newACL.setOwnerPermissions(item->value);
764 newACL.setOwningGroupPermissions(item->value);
767 newACL.setOthersPermissions(item->value);
770 newACL.setMaskPermissions(item->value);
773 users.
append(qMakePair(item->text(1), item->value));
776 groups.
append(qMakePair(item->text(1), item->value));
782 if (atLeastOneEntry) {
783 newACL.setAllUserPermissions(users);
784 newACL.setAllGroupPermissions(groups);
785 if (newACL.isValid()) {
792KACL KACLListView::getACL()
794 return itemsToACL(
false);
797KACL KACLListView::getDefaultACL()
799 return itemsToACL(
true);
802void KACLListView::contentsMousePressEvent(
QMouseEvent * )
848 while (KACLListViewItem *item =
static_cast<KACLListViewItem *
>(*it)) {
850 if (!item->isSelected()) {
855 item->togglePerm(ACL_READ);
858 item->togglePerm(ACL_WRITE);
861 item->togglePerm(ACL_EXECUTE);
891void KACLListView::slotItemDoubleClicked(
QTreeWidgetItem *item,
int column)
898 if (column >= 2 && column <= 4) {
902 KACLListViewItem *aclListItem =
static_cast<KACLListViewItem *
>(item);
903 if (!aclListItem->isAllowedToChangeType()) {
907 setCurrentItem(item);
911void KACLListView::calculateEffectiveRights()
914 KACLListViewItem *pItem;
915 while ((pItem =
dynamic_cast<KACLListViewItem *
>(*it)) !=
nullptr) {
917 pItem->calcEffectiveRights();
921unsigned short KACLListView::maskPermissions()
const
926void KACLListView::setMaskPermissions(
unsigned short maskPerms)
929 calculateEffectiveRights();
932acl_perm_t KACLListView::maskPartialPermissions()
const
938void KACLListView::setMaskPartialPermissions(acl_perm_t )
941 calculateEffectiveRights();
944bool KACLListView::hasDefaultEntries()
const
948 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
950 if (item->isDefault) {
957const KACLListViewItem *KACLListView::findDefaultItemByType(EntryType type)
const
959 return findItemByType(type,
true);
962const KACLListViewItem *KACLListView::findItemByType(EntryType type,
bool defaults)
const
966 const KACLListViewItem *item =
static_cast<const KACLListViewItem *
>(*it);
968 if (item->isDefault == defaults && item->type == type) {
975unsigned short KACLListView::calculateMaskValue(
bool defaults)
const
979 return itemsToACL(defaults).maskPermissions(dummy);
982void KACLListView::slotAddEntry()
984 int allowedTypes = NamedUser | NamedGroup;
986 allowedTypes |= Mask;
988 int allowedDefaultTypes = NamedUser | NamedGroup;
989 if (!findDefaultItemByType(Mask)) {
990 allowedDefaultTypes |= Mask;
992 if (!hasDefaultEntries()) {
993 allowedDefaultTypes |= User | Group;
995 EditACLEntryDialog dlg(
this,
998 allowedGroups(
false),
1000 allowedGroups(
true),
1002 allowedDefaultTypes,
1005 KACLListViewItem *item = dlg.item();
1009 if (item->type == Mask && !item->isDefault) {
1011 m_mask = item->value;
1013 if (item->isDefault && !hasDefaultEntries()) {
1015 if (item->type != User) {
1016 unsigned short v = findDefaultItemByType(User)->value;
1017 new KACLListViewItem(
this, User, v,
true);
1019 if (item->type != Group) {
1020 unsigned short v = findDefaultItemByType(Group)->value;
1021 new KACLListViewItem(
this, Group, v,
true);
1023 if (item->type != Others) {
1024 unsigned short v = findDefaultItemByType(Others)->value;
1025 new KACLListViewItem(
this, Others, v,
true);
1028 const KACLListViewItem *defaultMaskItem = findDefaultItemByType(Mask);
1029 if (item->isDefault && !defaultMaskItem) {
1030 unsigned short v = calculateMaskValue(
true);
1031 new KACLListViewItem(
this, Mask, v,
true);
1033 if (!item->isDefault && !m_hasMask && (item->type == Group || item->type == NamedUser || item->type == NamedGroup)) {
1035 unsigned short v = calculateMaskValue(
false);
1036 new KACLListViewItem(
this, Mask, v,
false);
1040 calculateEffectiveRights();
1042 setCurrentItem(item);
1045 if (topLevelItemCount() == 1) {
1046 Q_EMIT currentItemChanged(item, item);
1050void KACLListView::slotEditEntry()
1056 KACLListViewItem *item =
static_cast<KACLListViewItem *
>(current);
1057 int allowedTypes = item->type | NamedUser | NamedGroup;
1058 bool itemWasMask = item->type == Mask;
1059 if (!m_hasMask || itemWasMask) {
1060 allowedTypes |= Mask;
1062 int allowedDefaultTypes = item->type | NamedUser | NamedGroup;
1063 if (!findDefaultItemByType(Mask)) {
1064 allowedDefaultTypes |= Mask;
1066 if (!hasDefaultEntries()) {
1067 allowedDefaultTypes |= User | Group;
1070 EditACLEntryDialog dlg(
this,
1072 allowedUsers(
false, item),
1073 allowedGroups(
false, item),
1074 allowedUsers(
true, item),
1075 allowedGroups(
true, item),
1077 allowedDefaultTypes,
1080 if (itemWasMask && item->type != Mask) {
1084 if (!itemWasMask && item->type == Mask) {
1085 m_mask = item->value;
1088 calculateEffectiveRights();
1092void KACLListView::slotRemoveEntry()
1096 KACLListViewItem *item =
static_cast<KACLListViewItem *
>(*it);
1101 if (item->type == Mask) {
1102 bool itemWasDefault = item->isDefault;
1103 if (!itemWasDefault && maskCanBeDeleted()) {
1107 }
else if (itemWasDefault && defaultMaskCanBeDeleted()) {
1113 if (!itemWasDefault) {
1114 calculateEffectiveRights();
1118 if (!item->isDefault && (item->type == User || item->type == Group || item->type == Others)) {
1128bool KACLListView::maskCanBeDeleted()
const
1130 return !findItemByType(NamedUser) && !findItemByType(NamedGroup);
1133bool KACLListView::defaultMaskCanBeDeleted()
const
1135 return !findDefaultItemByType(NamedUser) && !findDefaultItemByType(NamedGroup);
1138#include "moc_kacleditwidget.cpp"
1139#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)