1 /*
2 * Copyright (C) by Roeland Jago Douma <roeland@owncloud.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include "shareusergroupwidget.h"
16 #include "ui_shareusergroupwidget.h"
17 #include "ui_shareuserline.h"
18 #include "account.h"
19 #include "folderman.h"
20 #include "folder.h"
21 #include "accountmanager.h"
22 #include "theme.h"
23 #include "configfile.h"
24 #include "capabilities.h"
25 #include "guiutility.h"
26 #include "thumbnailjob.h"
27 #include "sharee.h"
28 #include "sharemanager.h"
29 #include "guiutility.h"
30
31 #include "QProgressIndicator.h"
32 #include <QBuffer>
33 #include <QFileIconProvider>
34 #include <QClipboard>
35 #include <QFileInfo>
36 #include <QAbstractProxyModel>
37 #include <QCompleter>
38 #include <qscrollarea.h>
39 #include <qlayout.h>
40 #include <QPropertyAnimation>
41 #include <QMenu>
42 #include <QAction>
43 #include <QDesktopServices>
44 #include <QMessageBox>
45 #include <QCryptographicHash>
46 #include <QColor>
47 #include <QPainter>
48
49 namespace OCC {
50
ShareUserGroupWidget(AccountPtr account,const QString & sharePath,const QString & localPath,SharePermissions maxSharingPermissions,const QString & privateLinkUrl,QWidget * parent)51 ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account,
52 const QString &sharePath,
53 const QString &localPath,
54 SharePermissions maxSharingPermissions,
55 const QString &privateLinkUrl,
56 QWidget *parent)
57 : QWidget(parent)
58 , _ui(new Ui::ShareUserGroupWidget)
59 , _account(account)
60 , _sharePath(sharePath)
61 , _localPath(localPath)
62 , _maxSharingPermissions(maxSharingPermissions)
63 , _privateLinkUrl(privateLinkUrl)
64 , _disableCompleterActivated(false)
65 {
66 setAttribute(Qt::WA_DeleteOnClose);
67 setObjectName("SharingDialogUG"); // required as group for saveGeometry call
68
69 _ui->setupUi(this);
70
71 //Is this a file or folder?
72 _isFile = QFileInfo(localPath).isFile();
73
74 _completer = new QCompleter(this);
75 _completerModel = new ShareeModel(_account,
76 _isFile ? QLatin1String("file") : QLatin1String("folder"),
77 _completer);
78 connect(_completerModel, &ShareeModel::shareesReady, this, &ShareUserGroupWidget::slotShareesReady);
79 connect(_completerModel, &ShareeModel::displayErrorMessage, this, &ShareUserGroupWidget::displayError);
80
81 _completer->setModel(_completerModel);
82 _completer->setCaseSensitivity(Qt::CaseInsensitive);
83 _completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
84 _ui->shareeLineEdit->setCompleter(_completer);
85
86 _manager = new ShareManager(_account, this);
87 connect(_manager, &ShareManager::sharesFetched, this, &ShareUserGroupWidget::slotSharesFetched);
88 connect(_manager, &ShareManager::shareCreated, this, &ShareUserGroupWidget::getShares);
89 connect(_manager, &ShareManager::serverError, this, &ShareUserGroupWidget::displayError);
90 connect(_ui->shareeLineEdit, &QLineEdit::returnPressed, this, &ShareUserGroupWidget::slotLineEditReturn);
91 connect(_ui->privateLinkText, &QLabel::linkActivated, this, &ShareUserGroupWidget::slotPrivateLinkShare);
92
93 // By making the next two QueuedConnections we can override
94 // the strings the completer sets on the line edit.
95 connect(_completer, SIGNAL(activated(QModelIndex)), SLOT(slotCompleterActivated(QModelIndex)),
96 Qt::QueuedConnection);
97 connect(_completer, SIGNAL(highlighted(QModelIndex)), SLOT(slotCompleterHighlighted(QModelIndex)),
98 Qt::QueuedConnection);
99
100 // Queued connection so this signal is recieved after textChanged
101 connect(_ui->shareeLineEdit, &QLineEdit::textEdited,
102 this, &ShareUserGroupWidget::slotLineEditTextEdited, Qt::QueuedConnection);
103 connect(&_completionTimer, &QTimer::timeout, this, &ShareUserGroupWidget::searchForSharees);
104 _completionTimer.setSingleShot(true);
105 _completionTimer.setInterval(600);
106
107 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
108 _ui->errorLabel->hide();
109
110 // Setup the sharee search progress indicator
111 _ui->shareeHorizontalLayout->addWidget(&_pi_sharee);
112 }
113
~ShareUserGroupWidget()114 ShareUserGroupWidget::~ShareUserGroupWidget()
115 {
116 delete _ui;
117 }
118
on_shareeLineEdit_textChanged(const QString &)119 void ShareUserGroupWidget::on_shareeLineEdit_textChanged(const QString &)
120 {
121 _completionTimer.stop();
122 }
123
slotLineEditTextEdited(const QString & text)124 void ShareUserGroupWidget::slotLineEditTextEdited(const QString &text)
125 {
126 _disableCompleterActivated = false;
127 // First textChanged is called first and we stopped the timer when the text is changed, programatically or not
128 // Then we restart the timer here if the user touched a key
129 if (!text.isEmpty()) {
130 _completionTimer.start();
131 }
132 }
133
slotLineEditReturn()134 void ShareUserGroupWidget::slotLineEditReturn()
135 {
136 _disableCompleterActivated = false;
137 // did the user type in one of the options?
138 const auto text = _ui->shareeLineEdit->text();
139 for (int i = 0; i < _completerModel->rowCount(); ++i) {
140 const auto sharee = _completerModel->getSharee(i);
141 if (sharee->format() == text
142 || sharee->displayName() == text
143 || sharee->shareWith() == text) {
144 slotCompleterActivated(_completerModel->index(i));
145 // make sure we do not send the same item twice (because return is called when we press
146 // return to activate an item inthe completer)
147 _disableCompleterActivated = true;
148 return;
149 }
150 }
151
152 // nothing found? try to refresh completion
153 _completionTimer.start();
154 }
155
156
searchForSharees()157 void ShareUserGroupWidget::searchForSharees()
158 {
159 _completionTimer.stop();
160 _pi_sharee.startAnimation();
161 ShareeModel::ShareeSet blacklist;
162
163 // Add the current user to _sharees since we can't share with ourself
164 QSharedPointer<Sharee> currentUser(new Sharee(_account->credentials()->user(), "", Sharee::Type::User));
165 blacklist << currentUser;
166
167 foreach (auto sw, _ui->scrollArea->findChildren<ShareUserLine *>()) {
168 blacklist << sw->share()->getShareWith();
169 }
170 _ui->errorLabel->hide();
171 _completerModel->fetch(_ui->shareeLineEdit->text(), blacklist);
172 }
173
getShares()174 void ShareUserGroupWidget::getShares()
175 {
176 _manager->fetchShares(_sharePath);
177 }
178
slotSharesFetched(const QList<QSharedPointer<Share>> & shares)179 void ShareUserGroupWidget::slotSharesFetched(const QList<QSharedPointer<Share>> &shares)
180 {
181 QScrollArea *scrollArea = _ui->scrollArea;
182
183 auto newViewPort = new QWidget(scrollArea);
184 auto layout = new QVBoxLayout(newViewPort);
185 layout->setMargin(0);
186 layout->setSpacing(0);
187
188 QSize minimumSize = newViewPort->sizeHint();
189 int x = 0;
190
191 foreach (const auto &share, shares) {
192 // We don't handle link shares
193 if (share->getShareType() == Share::TypeLink) {
194 continue;
195 }
196
197 ShareUserLine *s = new ShareUserLine(share, _maxSharingPermissions, _isFile, _ui->scrollArea);
198 connect(s, &ShareUserLine::resizeRequested, this, &ShareUserGroupWidget::slotAdjustScrollWidgetSize);
199 connect(s, &ShareUserLine::visualDeletionDone, this, &ShareUserGroupWidget::getShares);
200 s->setBackgroundRole(layout->count() % 2 == 0 ? QPalette::Base : QPalette::AlternateBase);
201 layout->addWidget(s);
202
203 x++;
204 if (x <= 3) {
205 minimumSize = newViewPort->sizeHint();
206 } else {
207 minimumSize.rwidth() = qMax(newViewPort->sizeHint().width(), minimumSize.width());
208 }
209 }
210 if (layout->isEmpty()) {
211 layout->addWidget(new QLabel(tr("The item is not shared with any users or groups")));
212 } else {
213 layout->addStretch(1);
214 }
215
216 minimumSize.rwidth() += layout->spacing();
217 minimumSize.rheight() += layout->spacing();
218 scrollArea->setMinimumSize(minimumSize);
219 scrollArea->setWidget(newViewPort);
220
221 _disableCompleterActivated = false;
222 _ui->shareeLineEdit->setEnabled(true);
223 }
224
slotAdjustScrollWidgetSize()225 void ShareUserGroupWidget::slotAdjustScrollWidgetSize()
226 {
227 QScrollArea *scrollArea = _ui->scrollArea;
228 if (scrollArea->findChildren<ShareUserLine *>().count() <= 3) {
229 auto minimumSize = scrollArea->widget()->sizeHint();
230 auto spacing = scrollArea->widget()->layout()->spacing();
231 minimumSize.rwidth() += spacing;
232 minimumSize.rheight() += spacing;
233 scrollArea->setMinimumSize(minimumSize);
234 }
235 }
236
slotPrivateLinkShare()237 void ShareUserGroupWidget::slotPrivateLinkShare()
238 {
239 auto menu = new QMenu(this);
240 menu->setAttribute(Qt::WA_DeleteOnClose);
241
242 menu->addAction(tr("Open link in browser"),
243 this, SLOT(slotPrivateLinkOpenBrowser()));
244 menu->addAction(tr("Copy link to clipboard"),
245 this, SLOT(slotPrivateLinkCopy()));
246 menu->addAction(tr("Send link by email"),
247 this, SLOT(slotPrivateLinkEmail()));
248
249 menu->exec(QCursor::pos());
250 }
251
slotShareesReady()252 void ShareUserGroupWidget::slotShareesReady()
253 {
254 _pi_sharee.stopAnimation();
255 if (_completerModel->rowCount() == 0) {
256 displayError(0, tr("No results for '%1'").arg(_completerModel->currentSearch()));
257 return;
258 }
259 _completer->complete();
260 }
261
slotCompleterActivated(const QModelIndex & index)262 void ShareUserGroupWidget::slotCompleterActivated(const QModelIndex &index)
263 {
264 if (_disableCompleterActivated)
265 return;
266 // The index is an index from the QCompletion model which is itelf a proxy
267 // model proxying the _completerModel
268 auto sharee = qvariant_cast<QSharedPointer<Sharee>>(index.data(Qt::UserRole));
269 if (sharee.isNull()) {
270 return;
271 }
272
273 /*
274 * Add spinner to the bottom of the widget list
275 */
276 auto viewPort = _ui->scrollArea->widget();
277 auto layout = qobject_cast<QVBoxLayout *>(viewPort->layout());
278 auto indicator = new QProgressIndicator(viewPort);
279 indicator->startAnimation();
280 if (layout->count() == 1) {
281 // No shares yet! Remove the label, add some stretch.
282 delete layout->itemAt(0)->widget();
283 layout->addStretch(1);
284 }
285 layout->insertWidget(layout->count() - 1, indicator);
286
287 /*
288 * Don't send the reshare permissions for federated shares for servers <9.1
289 * https://github.com/owncloud/core/issues/22122#issuecomment-185637344
290 * https://github.com/owncloud/client/issues/4996
291 */
292 const SharePermissions defaultPermissions = static_cast<SharePermissions>(_account->capabilities().defaultPermissions());
293 if (sharee->type() == Sharee::Federated
294 && _account->serverVersionInt() < Account::makeServerVersion(9, 1, 0)) {
295 SharePermissions permissions = SharePermissionRead | SharePermissionUpdate;
296 if (!_isFile) {
297 permissions |= SharePermissionCreate | SharePermissionDelete;
298 }
299 permissions &= defaultPermissions;
300 _manager->createShare(_sharePath, Share::ShareType(sharee->type()),
301 sharee->shareWith(), permissions);
302 } else {
303 _manager->createShare(_sharePath, Share::ShareType(sharee->type()),
304 sharee->shareWith(), _maxSharingPermissions & defaultPermissions);
305 }
306
307 _ui->shareeLineEdit->setEnabled(false);
308 _ui->shareeLineEdit->setText(QString());
309 }
310
slotCompleterHighlighted(const QModelIndex & index)311 void ShareUserGroupWidget::slotCompleterHighlighted(const QModelIndex &index)
312 {
313 // By default the completer would set the text to EditRole,
314 // override that here.
315 _ui->shareeLineEdit->setText(index.data(Qt::DisplayRole).toString());
316 }
317
displayError(int code,const QString & message)318 void ShareUserGroupWidget::displayError(int code, const QString &message)
319 {
320 _pi_sharee.stopAnimation();
321
322 // Also remove the spinner in the widget list, if any
323 foreach (auto pi, _ui->scrollArea->findChildren<QProgressIndicator *>()) {
324 delete pi;
325 }
326
327 qCWarning(lcSharing) << "Sharing error from server" << code << message;
328 _ui->errorLabel->setText(message);
329 _ui->errorLabel->show();
330 _ui->shareeLineEdit->setEnabled(true);
331 }
332
slotPrivateLinkOpenBrowser()333 void ShareUserGroupWidget::slotPrivateLinkOpenBrowser()
334 {
335 Utility::openBrowser(_privateLinkUrl, this);
336 }
337
slotPrivateLinkCopy()338 void ShareUserGroupWidget::slotPrivateLinkCopy()
339 {
340 QApplication::clipboard()->setText(_privateLinkUrl);
341 }
342
slotPrivateLinkEmail()343 void ShareUserGroupWidget::slotPrivateLinkEmail()
344 {
345 Utility::openEmailComposer(
346 tr("I shared something with you"),
347 _privateLinkUrl,
348 this);
349 }
350
ShareUserLine(QSharedPointer<Share> share,SharePermissions maxSharingPermissions,bool isFile,QWidget * parent)351 ShareUserLine::ShareUserLine(QSharedPointer<Share> share,
352 SharePermissions maxSharingPermissions,
353 bool isFile,
354 QWidget *parent)
355 : QWidget(parent)
356 , _ui(new Ui::ShareUserLine)
357 , _share(share)
358 , _isFile(isFile)
359 {
360 _ui->setupUi(this);
361
362 _ui->sharedWith->setText(share->getShareWith()->format());
363
364 // Create detailed permissions menu
365 QMenu *menu = new QMenu(this);
366 _permissionCreate = new QAction(tr("create"), this);
367 _permissionCreate->setCheckable(true);
368 _permissionCreate->setEnabled(maxSharingPermissions & SharePermissionCreate);
369 _permissionUpdate = new QAction(tr("change"), this);
370 _permissionUpdate->setCheckable(true);
371 _permissionUpdate->setEnabled(maxSharingPermissions & SharePermissionUpdate);
372 _permissionDelete = new QAction(tr("delete"), this);
373 _permissionDelete->setCheckable(true);
374 _permissionDelete->setEnabled(maxSharingPermissions & SharePermissionDelete);
375
376 menu->addAction(_permissionUpdate);
377 /*
378 * Files can't have create or delete permissions
379 */
380 if (!_isFile) {
381 menu->addAction(_permissionCreate);
382 menu->addAction(_permissionDelete);
383 }
384 _ui->permissionToolButton->setMenu(menu);
385 _ui->permissionToolButton->setPopupMode(QToolButton::InstantPopup);
386 _ui->permissionToolButton->setIcon(Utility::getCoreIcon(QStringLiteral("more")));
387
388 // If there's only a single entry in the detailed permission menu, hide it
389 if (menu->actions().size() == 1) {
390 _ui->permissionToolButton->hide();
391 }
392
393 // Set the permissions checkboxes
394 displayPermissions();
395
396 _ui->permissionShare->setEnabled(maxSharingPermissions & SharePermissionShare);
397 _ui->permissionsEdit->setEnabled(maxSharingPermissions
398 & (SharePermissionCreate | SharePermissionUpdate | SharePermissionDelete));
399
400 connect(_permissionUpdate, &QAction::triggered, this, &ShareUserLine::slotPermissionsChanged);
401 connect(_permissionCreate, &QAction::triggered, this, &ShareUserLine::slotPermissionsChanged);
402 connect(_permissionDelete, &QAction::triggered, this, &ShareUserLine::slotPermissionsChanged);
403 connect(_ui->permissionShare, &QAbstractButton::clicked, this, &ShareUserLine::slotPermissionsChanged);
404 connect(_ui->permissionsEdit, &QAbstractButton::clicked, this, &ShareUserLine::slotEditPermissionsChanged);
405
406 /*
407 * We don't show permssion share for federated shares with server <9.1
408 * https://github.com/owncloud/core/issues/22122#issuecomment-185637344
409 * https://github.com/owncloud/client/issues/4996
410 */
411 if (share->getShareType() == Share::TypeRemote
412 && share->account()->serverVersionInt() < Account::makeServerVersion(9, 1, 0)) {
413 _ui->permissionShare->setVisible(false);
414 _ui->permissionToolButton->setVisible(false);
415 }
416
417 connect(share.data(), &Share::permissionsSet, this, &ShareUserLine::slotPermissionsSet);
418 connect(share.data(), &Share::shareDeleted, this, &ShareUserLine::slotShareDeleted);
419
420 _ui->deleteShareButton->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"),
421 Utility::getCoreIcon(QStringLiteral("delete"))));
422
423 if (!share->account()->capabilities().shareResharing()) {
424 _ui->permissionShare->hide();
425 }
426
427 loadAvatar();
428 }
429
loadAvatar()430 void ShareUserLine::loadAvatar()
431 {
432 const int avatarSize = 36;
433
434 // Set size of the placeholder
435 _ui->avatar->setMinimumHeight(avatarSize);
436 _ui->avatar->setMinimumWidth(avatarSize);
437 _ui->avatar->setMaximumHeight(avatarSize);
438 _ui->avatar->setMaximumWidth(avatarSize);
439 _ui->avatar->setAlignment(Qt::AlignCenter);
440
441 /* Create the fallback avatar.
442 *
443 * This will be shown until the avatar image data arrives.
444 */
445 const QByteArray hash = QCryptographicHash::hash(_ui->sharedWith->text().toUtf8(), QCryptographicHash::Md5);
446 double hue = static_cast<quint8>(hash[0]) / 255.;
447
448 // See core/js/placeholder.js for details on colors and styling
449 const QColor bg = QColor::fromHslF(hue, 0.7, 0.68);
450 const QString style = QString(R"(* {
451 color: #fff;
452 background-color: %1;
453 border-radius: %2px;
454 text-align: center;
455 line-height: %2px;
456 font-size: %2px;
457 })").arg(bg.name(), QString::number(avatarSize / 2));
458 _ui->avatar->setStyleSheet(style);
459
460 // The avatar label is the first character of the user name.
461 const QString text = _share->getShareWith()->displayName();
462 _ui->avatar->setText(text.at(0).toUpper());
463
464 /* Start the network job to fetch the avatar data.
465 *
466 * Currently only regular users can have avatars.
467 */
468 if (_share->getShareWith()->type() == Sharee::User) {
469 AvatarJob *job = new AvatarJob(_share->account(), _share->getShareWith()->shareWith(), avatarSize, this);
470 connect(job, &AvatarJob::avatarPixmap, this, &ShareUserLine::slotAvatarLoaded);
471 job->start();
472 }
473 }
474
slotAvatarLoaded(const QPixmap & avatar)475 void ShareUserLine::slotAvatarLoaded(const QPixmap &avatar)
476 {
477 if (avatar.isNull())
478 return;
479
480 const QPixmap _avatar = AvatarJob::makeCircularAvatar(avatar);
481 _ui->avatar->setPixmap(_avatar);
482
483 // Remove the stylesheet for the fallback avatar
484 _ui->avatar->setStyleSheet("");
485 }
486
on_deleteShareButton_clicked()487 void ShareUserLine::on_deleteShareButton_clicked()
488 {
489 setEnabled(false);
490 _share->deleteShare();
491 }
492
~ShareUserLine()493 ShareUserLine::~ShareUserLine()
494 {
495 delete _ui;
496 }
497
slotEditPermissionsChanged()498 void ShareUserLine::slotEditPermissionsChanged()
499 {
500 setEnabled(false);
501
502 // Can never manually be set to "partial".
503 // This works because the state cycle for clicking is
504 // unchecked -> partial -> checked -> unchecked.
505 if (_ui->permissionsEdit->checkState() == Qt::PartiallyChecked) {
506 _ui->permissionsEdit->setCheckState(Qt::Checked);
507 }
508
509 Share::Permissions permissions = SharePermissionRead;
510
511 if (_ui->permissionShare->checkState() == Qt::Checked) {
512 permissions |= SharePermissionShare;
513 }
514
515 if (_ui->permissionsEdit->checkState() == Qt::Checked) {
516 if (_permissionUpdate->isEnabled())
517 permissions |= SharePermissionUpdate;
518
519 /*
520 * Files can't have create or delete permisisons
521 */
522 if (!_isFile) {
523 if (_permissionCreate->isEnabled())
524 permissions |= SharePermissionCreate;
525 if (_permissionDelete->isEnabled())
526 permissions |= SharePermissionDelete;
527 }
528 }
529
530 _share->setPermissions(permissions);
531 }
532
slotPermissionsChanged()533 void ShareUserLine::slotPermissionsChanged()
534 {
535 setEnabled(false);
536
537 Share::Permissions permissions = SharePermissionRead;
538
539 if (_permissionUpdate->isChecked()) {
540 permissions |= SharePermissionUpdate;
541 }
542
543 if (_permissionCreate->isChecked()) {
544 permissions |= SharePermissionCreate;
545 }
546
547 if (_permissionDelete->isChecked()) {
548 permissions |= SharePermissionDelete;
549 }
550
551 if (_ui->permissionShare->checkState() == Qt::Checked) {
552 permissions |= SharePermissionShare;
553 }
554
555 _share->setPermissions(permissions);
556 }
557
slotDeleteAnimationFinished()558 void ShareUserLine::slotDeleteAnimationFinished()
559 {
560 emit resizeRequested();
561 emit visualDeletionDone();
562 deleteLater();
563
564 // There is a painting bug where a small line of this widget isn't
565 // properly cleared. This explicit repaint() call makes sure any trace of
566 // the share widget is removed once it's destroyed. #4189
567 connect(this, SIGNAL(destroyed(QObject *)), parentWidget(), SLOT(repaint()));
568 }
569
slotShareDeleted()570 void ShareUserLine::slotShareDeleted()
571 {
572 QPropertyAnimation *animation = new QPropertyAnimation(this, "maximumHeight", this);
573
574 animation->setDuration(500);
575 animation->setStartValue(height());
576 animation->setEndValue(0);
577
578 connect(animation, &QAbstractAnimation::finished, this, &ShareUserLine::slotDeleteAnimationFinished);
579 connect(animation, &QVariantAnimation::valueChanged, this, &ShareUserLine::resizeRequested);
580
581 animation->start();
582 }
583
slotPermissionsSet()584 void ShareUserLine::slotPermissionsSet()
585 {
586 displayPermissions();
587 setEnabled(true);
588 }
589
share() const590 QSharedPointer<Share> ShareUserLine::share() const
591 {
592 return _share;
593 }
594
displayPermissions()595 void ShareUserLine::displayPermissions()
596 {
597 const SharePermissions perm = _share->getPermissions();
598
599 _permissionUpdate->setChecked(perm & SharePermissionUpdate);
600 _permissionCreate->setChecked(!_isFile && perm & SharePermissionCreate);
601 _permissionDelete->setChecked(!_isFile && perm & SharePermissionDelete);
602
603 if (perm & SharePermissionUpdate
604 && (_isFile
605 || (perm & SharePermissionCreate
606 && perm & SharePermissionDelete))) {
607 _ui->permissionsEdit->setCheckState(Qt::Checked);
608 } else if (perm & (SharePermissionUpdate | SharePermissionCreate | SharePermissionDelete)) {
609 _ui->permissionsEdit->setCheckState(Qt::PartiallyChecked);
610 } else {
611 _ui->permissionsEdit->setCheckState(Qt::Unchecked);
612 }
613
614 _ui->permissionShare->setChecked(perm & SharePermissionShare);
615 }
616 }
617