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