Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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