Skip to content
92 changes: 42 additions & 50 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class MouseCursorChanger : public QObject
const auto index = folderList->indexAt(pos);
if (model->classify(index) == FolderStatusModel::RootFolder &&
(FolderStatusDelegate::errorsListRect(folderList->visualRect(index)).contains(pos) ||
FolderStatusDelegate::optionsButtonRect(folderList->visualRect(index),folderList->layoutDirection()).contains(pos))) {
FolderStatusDelegate::moreRectPos(folderList->visualRect(index)).contains(pos))) {
shape = Qt::PointingHandCursor;
}
folderList->setCursor(shape);
Expand Down Expand Up @@ -579,8 +579,9 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
{
Q_UNUSED(pos);

QMenu menu;
auto ac = menu.addAction(tr("Open folder"));
auto menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose);
auto ac = menu->addAction(tr("Open folder"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenCurrentLocalSubFolder);

const auto fileName = _model->data(index, FolderStatusDelegate::FolderPathRole).toString();
Expand All @@ -599,24 +600,21 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
const auto isExternal = info->_isExternal;

if (!isEncrypted && !isParentEncrypted && !isExternal && isTopFolder) {
ac = menu.addAction(tr("Encrypt"));
ac = menu->addAction(tr("Encrypt"));
connect(ac, &QAction::triggered, [this, info] { slotMarkSubfolderEncrypted(info); });
} else {
// Ignore decrypting for now since it only works with an empty folder
// connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderDecrypted(info); });
}
}

ac = menu.addAction(tr("Edit Ignored Files"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentLocalIgnoredFiles);

ac = menu.addAction(tr("Create new folder"));
ac = menu->addAction(tr("Create new folder"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenMakeFolderDialog);
ac->setEnabled(QFile::exists(fileName));

const auto folder = info->_folder;
if (folder && folder->virtualFilesEnabled()) {
auto availabilityMenu = menu.addMenu(tr("Availability"));
auto availabilityMenu = menu->addMenu(tr("Availability"));

// Has '/' suffix convention for paths here but VFS and
// sync engine expects no such suffix
Expand All @@ -639,7 +637,23 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
connect(ac, &QAction::triggered, this, [this, folder, path] { slotSetSubFolderAvailability(folder, path, PinState::OnlineOnly); });
}

menu.exec(QCursor::pos());
const auto highlightColor = palette().highlight().color();
menu->setStyleSheet(QString(R"(
QMenu {
border: 1px solid black;
border-radius: 4px;
padding: 6px;
}
QMenu::item {
padding: 8px;
}
QMenu::item:selected,
QMenu::item:hover {
background-color: %1;
}
)").arg(highlightColor.name(QColor::HexRgb)));

menu->popup(QCursor::pos());
}

void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
Expand Down Expand Up @@ -670,16 +684,13 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
return;
}

const auto menu = new QMenu(treeView);
auto menu = new QMenu(treeView);

menu->setAttribute(Qt::WA_DeleteOnClose);

auto ac = menu->addAction(tr("Open folder"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenCurrentFolder);

ac = menu->addAction(tr("Edit Ignored Files"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentIgnoredFiles);

ac = menu->addAction(tr("Create new folder"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenMakeFolderDialog);
ac->setEnabled(QFile::exists(folder->path()));
Expand Down Expand Up @@ -720,52 +731,33 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
ac->setDisabled(Theme::instance()->enforceVirtualFilesSyncFolder());
}

if (const auto mode = bestAvailableVfsMode();
!Theme::instance()->disableVirtualFilesSyncFolder() &&
Theme::instance()->showVirtualFilesOption() && !folder->virtualFilesEnabled() && Vfs::checkAvailability(folder->path(), mode)) {
if (mode == Vfs::WindowsCfApi || ConfigFile().showExperimentalOptions()) {
ac = menu->addAction(tr("Enable virtual file support %1 …").arg(mode == Vfs::WindowsCfApi ? QString() : tr("(experimental)")));
// TODO: remove when UX decision is made
ac->setEnabled(!Utility::isPathWindowsDrivePartitionRoot(folder->path()));
//
connect(ac, &QAction::triggered, this, &AccountSettings::slotEnableVfsCurrentFolder);
}
}
const auto highlightColor = palette().highlight().color();

menu->setStyleSheet(QString(R"(
QMenu {
border: 1px solid black;
border-radius: 4px;
padding: 6px;
}
QMenu::item {
padding: 8px;
}
QMenu::item:selected,
QMenu::item:hover {
background-color: %1;
}
)").arg(highlightColor.name(QColor::HexRgb)));

menu->popup(treeView->mapToGlobal(pos));
menu->popup(treeView->viewport()->mapToGlobal(pos));
}

void AccountSettings::slotFolderListClicked(const QModelIndex &indx)
{
if (indx.data(FolderStatusDelegate::AddButton).toBool()) {
// "Add Folder Sync Connection"
const auto treeView = _ui->_folderList;
const auto pos = treeView->mapFromGlobal(QCursor::pos());
QStyleOptionViewItem opt;
opt.initFrom(treeView);
const auto btnRect = treeView->visualRect(indx);
const auto btnSize = treeView->itemDelegateForIndex(indx)->sizeHint(opt, indx);
const auto actual = QStyle::visualRect(opt.direction, btnRect, QRect(btnRect.topLeft(), btnSize));
if (!actual.contains(pos)) {
return;
}

if (indx.flags() & Qt::ItemIsEnabled) {
slotAddFolder();
} else {
QToolTip::showText(
QCursor::pos(),
_model->data(indx, Qt::ToolTipRole).toString(),
this);
}
return;
}
if (_model->classify(indx) == FolderStatusModel::RootFolder) {
// tries to find if we clicked on the '...' button.
const auto treeView = _ui->_folderList;
const auto pos = treeView->mapFromGlobal(QCursor::pos());
if (FolderStatusDelegate::optionsButtonRect(treeView->visualRect(indx), layoutDirection()).contains(pos)) {
if (FolderStatusDelegate::moreRectPos(treeView->visualRect(indx)).contains(pos)) {
slotCustomContextMenuRequested(pos);
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/gui/accountsetupcommandlinemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,6 @@ void AccountSetupCommandLineManager::setupAccountFromCommandLine()
_serverUrl.clear();
_remoteDirPath.clear();
_localDirPath.clear();
_isVfsEnabled = true;
_isVfsEnabled = false;
}
}
6 changes: 3 additions & 3 deletions src/gui/folderman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1868,9 +1868,9 @@ QString FolderMan::trayTooltipStatusString(SyncResult::Status syncStatus, bool h

static QString checkPathValidityRecursive(const QString &path)
{
if (path.isEmpty()) {
return FolderMan::tr("Please choose a different location. The selected folder isn't valid.");
}
// if (path.isEmpty()) {
// return FolderMan::tr("Please choose a different location. The selected folder isn't valid.");
// }

#ifdef Q_OS_WIN
Utility::NtfsPermissionLookupRAII ntfs_perm;
Expand Down
143 changes: 131 additions & 12 deletions src/gui/folderstatusdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include <QFileIconProvider>
#include <QPainter>
#include <QPainterPath>
#include <QRect>
#include <QApplication>
#include <QMouseEvent>
#include <QStyleFactory>
Expand Down Expand Up @@ -83,9 +85,28 @@ QSize FolderStatusDelegate::sizeHint(const QStyleOptionViewItem &option,
}
}

// Make sure its at least 76 Pixel high
h = std::max(h, 76);

return {0, h};
}

QRect FolderStatusDelegate::moreRectPos(const QRect &rectIndex)
{
if (rectIndex.isValid())
{
constexpr int buttonWidth = 88;
constexpr int buttonHeight = 32;
constexpr int margin = 16;

const int xMoreButton = rectIndex.right() - buttonWidth - margin;
const int yMoreButton = rectIndex.center().y() - (buttonHeight / 2);

return QRect(xMoreButton, yMoreButton, buttonWidth, buttonHeight);
}
return {};
}

int FolderStatusDelegate::rootFolderHeightWithoutErrors(const QFontMetrics &fm, const QFontMetrics &aliasFm)
{
const int aliasMargin = aliasFm.height() / 2;
Expand All @@ -107,6 +128,56 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
const_cast<QStyleOptionViewItem &>(option).showDecorationSelected = false;
}

const QModelIndex parentIndex = index.parent(); // NMC customization
{
painter->save();

// Verhindere das Zeichnen des "Neuer Ordner"-Buttons
if (index.data(AddButton).toBool()) {
return;
}

const QRect leftRect(0, option.rect.y(), option.rect.x(), option.rect.height());

if (option.state & QStyle::State_MouseOver) {
QColor hoverColor = QApplication::palette().color(QPalette::Mid);
painter->fillRect(option.rect, hoverColor);
painter->fillRect(leftRect, hoverColor);
}

if (option.state & QStyle::State_Selected) {
// Auswahlhintergrundfarbe abrufen
const QColor selectionColor = option.palette.color(QPalette::Highlight);
painter->fillRect(option.rect, selectionColor);
painter->fillRect(leftRect, selectionColor);
}

const QTreeView* treeView = qobject_cast<const QTreeView*>(option.widget);
if (treeView) {
QIcon leftIcon;
QSize iconSize(16, 16);

if (!parentIndex.isValid()) {
// Wir befinden uns im Stammverzeichnis, also Icon vergrößern
iconSize = QSize(24, 24);
}

if (index.isValid() && treeView->isExpanded(index)) {
// Das übergeordnete Element ist erweitert
leftIcon = QIcon(Theme::createColorAwareIcon(QStringLiteral(":/client/theme/NMCIcons/collapse-down.svg")));
} else {
// Das übergeordnete Element ist nicht erweitert
leftIcon = QIcon(Theme::createColorAwareIcon(QStringLiteral(":/client/theme/NMCIcons/collapse-right.svg")));
}

const QPoint iconPos(leftRect.width() - iconSize.width(),
leftRect.y() + leftRect.height() / 2 - iconSize.height() / 2);
painter->drawPixmap(iconPos, leftIcon.pixmap(iconSize));
}

painter->restore();
}

QStyledItemDelegate::paint(painter, option, index);

auto textAlign = Qt::AlignLeft;
Expand Down Expand Up @@ -183,19 +254,28 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
iconRect.setBottom(localPathRect.bottom());
iconRect.setWidth(iconRect.height());

const auto nextToIcon = iconRect.right() + aliasMargin;
const auto nextToIcon = iconRect.right() + std::max(aliasMargin, 16);
aliasRect.setLeft(nextToIcon);
localPathRect.setLeft(nextToIcon);
remotePathRect.setLeft(nextToIcon);

const auto iconSize = iconRect.width();

auto optionsButtonVisualRect = optionsButtonRect(option.rect, option.direction);

statusIcon.paint(
painter,
QStyle::visualRect(option.direction, option.rect, iconRect),
Qt::AlignCenter,
syncEnabled ? QIcon::Normal : QIcon::Disabled
);
// NMC Customization
if (!parentIndex.isValid()) {
QIcon nmcFolderIcon = QIcon(QLatin1String(":/client/theme/NMCIcons/folderLogo.svg"));
const auto nmcFolderPixmap = nmcFolderIcon.pixmap(iconSize, iconSize, QIcon::Normal);
painter->drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect).left(), iconRect.top(), nmcFolderPixmap);

const QSize statusIconSize(24,24);
const auto statusPixmap = statusIcon.pixmap(statusIconSize.width(), statusIconSize.height(), syncEnabled ? QIcon::Normal : QIcon::Disabled);
painter->drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect).right() - statusIconSize.width() * 0.6, iconRect.bottom() - statusIconSize.height() * 0.8, statusPixmap);
} else {
const auto statusPixmap = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled);
painter->drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect).left(), iconRect.top(), statusPixmap);
}

auto palette = option.palette;

Expand Down Expand Up @@ -267,18 +347,23 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
drawTextBox(infoTexts, QColor(0x4d, 0x4d, 0xba));
}

// NMC customization: we need these infos already here to adjust the progress bar
const QRect currentButtonRectPos = moreRectPos(option.rect);
const int nmcWidth = currentButtonRectPos.x() - nextToIcon - 8; // 8 is the margin to "More" button

// Sync File Progress Bar: Show it if syncFile is not empty.
if (showProgess) {
const auto fileNameTextHeight = subFm.boundingRect(tr("File")).height();
constexpr auto barHeight = 7; // same height as quota bar
const auto overallWidth = option.rect.right() - aliasMargin - optionsButtonVisualRect.width() - nextToIcon;
Q_UNUSED(overallWidth);

painter->save();

// Overall Progress Bar.
const auto progressBarRect = QRect(nextToIcon,
remotePathRect.top(),
overallWidth - 2 * margin,
nmcWidth,
barHeight);

QStyleOptionProgressBar progressBarOpt;
Expand Down Expand Up @@ -310,21 +395,55 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
painter->restore();
}

painter->restore();

{
QStyleOptionToolButton btnOpt;
btnOpt.state = option.state;
btnOpt.state &= ~(QStyle::State_Selected | QStyle::State_HasFocus);
btnOpt.state |= QStyle::State_Raised;
btnOpt.arrowType = Qt::NoArrow;
btnOpt.subControls = QStyle::SC_ToolButton;
btnOpt.rect = optionsButtonVisualRect;
//NMC customization
btnOpt.rect = currentButtonRectPos;
//make sure the button is not too far away from the left border
btnOpt.rect.setRight(btnOpt.rect.x() + btnOpt.rect.width() + 4);

// Create QPainterPath with rounded corners
QPainterPath path;
path.addRoundedRect(btnOpt.rect, 4, 4); // 4 ist der Radius für die abgerundeten Ecken

// Draw border line
QPen borderPen(QColor(0, 0, 0)); // Beispiel: Schwarzer Rand
borderPen.setWidth(1);
painter->setPen(borderPen);
painter->drawPath(path);

// Fill the rectangle
painter->fillPath(path, Qt::transparent);

// Draw the icon in rectangle
btnOpt.icon = _iconMore;
const auto buttonSize = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize);
btnOpt.iconSize = QSize(buttonSize, buttonSize);
QApplication::style()->drawComplexControl(QStyle::CC_ToolButton, &btnOpt, painter);

// Set icon position
int iconX = btnOpt.rect.x() + btnOpt.rect.width()/5;
int iconY = btnOpt.rect.y() + (btnOpt.rect.height() - btnOpt.iconSize.height()) / 2;

painter->drawPixmap(iconX, iconY, btnOpt.icon.pixmap(btnOpt.iconSize));

//Add text
const QString buttonText = QCoreApplication::translate("", "MORE");
painter->setFont(btnOpt.font);
painter->setPen(option.palette.color(QPalette::ButtonText));
int textX = iconX + btnOpt.iconSize.width() + 10;
int textY = iconY;
int textWidth = currentButtonRectPos.x() + currentButtonRectPos.width() - textX;
int textHeight = btnOpt.fontMetrics.height();

painter->drawText(QRect(textX, textY, textWidth, textHeight), Qt::AlignLeft | Qt::AlignVCenter, buttonText);
}

painter->restore();
}

bool FolderStatusDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
Expand Down
Loading
Loading