Skip to content

Commit d685aa5

Browse files
committed
Merge #375 [stable-3.16] nmc/2025/2003-Folderview_Settings_Dialog_Manual
2 parents d320094 + f4109c7 commit d685aa5

8 files changed

+207
-65
lines changed

src/gui/accountsettings.cpp

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ class MouseCursorChanger : public QObject
164164
const auto index = folderList->indexAt(pos);
165165
if (model->classify(index) == FolderStatusModel::RootFolder &&
166166
(FolderStatusDelegate::errorsListRect(folderList->visualRect(index)).contains(pos) ||
167-
FolderStatusDelegate::optionsButtonRect(folderList->visualRect(index),folderList->layoutDirection()).contains(pos))) {
167+
FolderStatusDelegate::moreRectPos(folderList->visualRect(index)).contains(pos))) {
168168
shape = Qt::PointingHandCursor;
169169
}
170170
folderList->setCursor(shape);
@@ -612,9 +612,6 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
612612
}
613613
}
614614

615-
ac = menu.addAction(tr("Edit Ignored Files"));
616-
connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentLocalIgnoredFiles);
617-
618615
ac = menu.addAction(tr("Create new folder"));
619616
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenMakeFolderDialog);
620617
ac->setEnabled(QFile::exists(fileName));
@@ -644,6 +641,18 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
644641
connect(ac, &QAction::triggered, this, [this, folder, path] { slotSetSubFolderAvailability(folder, path, PinState::OnlineOnly); });
645642
}
646643

644+
menu.setStyleSheet(R"(
645+
QMenu {
646+
border: 1px solid black;
647+
border-radius: 4px;
648+
padding: 4px;
649+
}
650+
651+
QMenu::item {
652+
padding: 6px 8px;
653+
}
654+
)");
655+
647656
menu.exec(QCursor::pos());
648657
}
649658

@@ -682,9 +691,6 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
682691
auto ac = menu->addAction(tr("Open folder"));
683692
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenCurrentFolder);
684693

685-
ac = menu->addAction(tr("Edit Ignored Files"));
686-
connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentIgnoredFiles);
687-
688694
ac = menu->addAction(tr("Create new folder"));
689695
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenMakeFolderDialog);
690696
ac->setEnabled(QFile::exists(folder->path()));
@@ -725,52 +731,28 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
725731
ac->setDisabled(Theme::instance()->enforceVirtualFilesSyncFolder());
726732
}
727733

728-
if (const auto mode = bestAvailableVfsMode();
729-
!Theme::instance()->disableVirtualFilesSyncFolder() &&
730-
Theme::instance()->showVirtualFilesOption() && !folder->virtualFilesEnabled() && Vfs::checkAvailability(folder->path(), mode)) {
731-
if (mode == Vfs::WindowsCfApi || ConfigFile().showExperimentalOptions()) {
732-
ac = menu->addAction(tr("Enable virtual file support %1 …").arg(mode == Vfs::WindowsCfApi ? QString() : tr("(experimental)")));
733-
// TODO: remove when UX decision is made
734-
ac->setEnabled(!Utility::isPathWindowsDrivePartitionRoot(folder->path()));
735-
//
736-
connect(ac, &QAction::triggered, this, &AccountSettings::slotEnableVfsCurrentFolder);
734+
menu->setStyleSheet(R"(
735+
QMenu {
736+
border: 1px solid black;
737+
border-radius: 4px;
738+
padding: 4px;
737739
}
738-
}
739-
740+
741+
QMenu::item {
742+
padding: 6px 8px;
743+
}
744+
)");
740745

741746
menu->popup(treeView->mapToGlobal(pos));
742747
}
743748

744749
void AccountSettings::slotFolderListClicked(const QModelIndex &indx)
745750
{
746-
if (indx.data(FolderStatusDelegate::AddButton).toBool()) {
747-
// "Add Folder Sync Connection"
748-
const auto treeView = _ui->_folderList;
749-
const auto pos = treeView->mapFromGlobal(QCursor::pos());
750-
QStyleOptionViewItem opt;
751-
opt.initFrom(treeView);
752-
const auto btnRect = treeView->visualRect(indx);
753-
const auto btnSize = treeView->itemDelegateForIndex(indx)->sizeHint(opt, indx);
754-
const auto actual = QStyle::visualRect(opt.direction, btnRect, QRect(btnRect.topLeft(), btnSize));
755-
if (!actual.contains(pos)) {
756-
return;
757-
}
758-
759-
if (indx.flags() & Qt::ItemIsEnabled) {
760-
slotAddFolder();
761-
} else {
762-
QToolTip::showText(
763-
QCursor::pos(),
764-
_model->data(indx, Qt::ToolTipRole).toString(),
765-
this);
766-
}
767-
return;
768-
}
769751
if (_model->classify(indx) == FolderStatusModel::RootFolder) {
770752
// tries to find if we clicked on the '...' button.
771753
const auto treeView = _ui->_folderList;
772754
const auto pos = treeView->mapFromGlobal(QCursor::pos());
773-
if (FolderStatusDelegate::optionsButtonRect(treeView->visualRect(indx), layoutDirection()).contains(pos)) {
755+
if (FolderStatusDelegate::moreRectPos(treeView->visualRect(indx)).contains(pos)) {
774756
slotCustomContextMenuRequested(pos);
775757
return;
776758
}

src/gui/accountsetupcommandlinemanager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,6 @@ void AccountSetupCommandLineManager::setupAccountFromCommandLine()
114114
_serverUrl.clear();
115115
_remoteDirPath.clear();
116116
_localDirPath.clear();
117-
_isVfsEnabled = true;
117+
_isVfsEnabled = false;
118118
}
119119
}

src/gui/folderstatusdelegate.cpp

Lines changed: 131 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
#include <theme.h>
2323
#include <account.h>
2424

25-
#include <QFileIconProvider>
26-
#include <QPainter>
2725
#include <QApplication>
26+
#include <QFileIconProvider>
2827
#include <QMouseEvent>
28+
#include <QPainter>
29+
#include <QPainterPath>
30+
#include <QRect>
2931
#include <QStyleFactory>
3032

3133
inline static QFont makeAliasFont(const QFont &normalFont)
@@ -93,6 +95,9 @@ QSize FolderStatusDelegate::sizeHint(const QStyleOptionViewItem &option,
9395
}
9496
}
9597

98+
// Make sure its at least 76 Pixel high
99+
h = std::max(h, 76);
100+
96101
return {0, h};
97102
}
98103

@@ -111,12 +116,77 @@ int FolderStatusDelegate::rootFolderHeightWithoutErrors(const QFontMetrics &fm,
111116
return h;
112117
}
113118

119+
QRect FolderStatusDelegate::moreRectPos(const QRect &rectIndex)
120+
{
121+
if (rectIndex.isValid())
122+
{
123+
constexpr int buttonWidth = 88;
124+
constexpr int buttonHeight = 32;
125+
constexpr int margin = 16;
126+
127+
const int xMoreButton = rectIndex.right() - buttonWidth - margin;
128+
const int yMoreButton = rectIndex.center().y() - (buttonHeight / 2);
129+
130+
return QRect(xMoreButton, yMoreButton, buttonWidth, buttonHeight);
131+
}
132+
return {};
133+
}
134+
114135
void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
115136
{
116137
if (index.data(AddButton).toBool()) {
117138
const_cast<QStyleOptionViewItem &>(option).showDecorationSelected = false;
118139
}
119140

141+
const QModelIndex parentIndex = index.parent(); // NMC customization
142+
{
143+
painter->save();
144+
145+
// Verhindere das Zeichnen des "Neuer Ordner"-Buttons
146+
if (index.data(AddButton).toBool()) {
147+
return;
148+
}
149+
150+
const QRect leftRect(0, option.rect.y(), option.rect.x(), option.rect.height());
151+
152+
if (option.state & QStyle::State_MouseOver) {
153+
QColor hoverColor = QApplication::palette().color(QPalette::AlternateBase);
154+
painter->fillRect(option.rect, hoverColor);
155+
painter->fillRect(leftRect, hoverColor);
156+
}
157+
158+
if (option.state & QStyle::State_Selected) {
159+
// Auswahlhintergrundfarbe abrufen
160+
const QColor selectionColor = option.palette.color(QPalette::Highlight);
161+
painter->fillRect(leftRect, selectionColor);
162+
}
163+
164+
const QTreeView* treeView = qobject_cast<const QTreeView*>(option.widget);
165+
if (treeView) {
166+
QIcon leftIcon;
167+
QSize iconSize(16, 16);
168+
169+
if (!parentIndex.isValid()) {
170+
// Wir befinden uns im Stammverzeichnis, also Icon vergrößern
171+
iconSize = QSize(24, 24);
172+
}
173+
174+
if (index.isValid() && treeView->isExpanded(index)) {
175+
// Das übergeordnete Element ist erweitert
176+
leftIcon = QIcon(QStringLiteral(":/client/theme/NMCIcons/collapse-down.svg"));
177+
} else {
178+
// Das übergeordnete Element ist nicht erweitert
179+
leftIcon = QIcon(QStringLiteral(":/client/theme/NMCIcons/collapse-right.svg"));
180+
}
181+
182+
const QPoint iconPos(leftRect.width() - iconSize.width(),
183+
leftRect.y() + leftRect.height() / 2 - iconSize.height() / 2);
184+
painter->drawPixmap(iconPos, leftIcon.pixmap(iconSize));
185+
}
186+
187+
painter->restore();
188+
}
189+
120190
QStyledItemDelegate::paint(painter, option, index);
121191

122192
auto textAlign = Qt::AlignLeft;
@@ -195,7 +265,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
195265
iconRect.setBottom(localPathRect.bottom());
196266
iconRect.setWidth(iconRect.height());
197267

198-
const auto nextToIcon = iconRect.right() + aliasMargin;
268+
const auto nextToIcon = iconRect.right() + std::max(aliasMargin, 16);
199269
aliasRect.setLeft(nextToIcon);
200270
localPathRect.setLeft(nextToIcon);
201271
remotePathRect.setLeft(nextToIcon);
@@ -204,8 +274,19 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
204274

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

207-
const auto statusPixmap = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled);
208-
painter->drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect).left(), iconRect.top(), statusPixmap);
277+
// NMC Customization
278+
if (!parentIndex.isValid()) {
279+
QIcon nmcFolderIcon = QIcon(QLatin1String(":/client/theme/NMCIcons/folderLogo.svg"));
280+
const auto nmcFolderPixmap = nmcFolderIcon.pixmap(iconSize, iconSize, QIcon::Normal);
281+
painter->drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect).left(), iconRect.top(), nmcFolderPixmap);
282+
283+
const QSize statusIconSize(24,24);
284+
const auto statusPixmap = statusIcon.pixmap(statusIconSize.width(), statusIconSize.height(), syncEnabled ? QIcon::Normal : QIcon::Disabled);
285+
painter->drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect).right() - statusIconSize.width() * 0.6, iconRect.bottom() - statusIconSize.height() * 0.8, statusPixmap);
286+
} else {
287+
const auto statusPixmap = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled);
288+
painter->drawPixmap(QStyle::visualRect(option.direction, option.rect, iconRect).left(), iconRect.top(), statusPixmap);
289+
}
209290

210291
// only show the warning icon if the sync is running. Otherwise its
211292
// encoded in the status icon.
@@ -292,18 +373,23 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
292373
drawTextBox(infoTexts, QColor(0x4d, 0x4d, 0xba));
293374
}
294375

376+
// NMC customization: we need these infos already here to adjust the progress bar
377+
const QRect currentButtonRectPos = moreRectPos(option.rect);
378+
const int nmcWidth = currentButtonRectPos.x() - nextToIcon - 8; // 8 is the margin to "More" button
379+
295380
// Sync File Progress Bar: Show it if syncFile is not empty.
296381
if (showProgess) {
297382
const auto fileNameTextHeight = subFm.boundingRect(tr("File")).height();
298383
constexpr auto barHeight = 7; // same height as quota bar
299384
const auto overallWidth = option.rect.right() - aliasMargin - optionsButtonVisualRect.width() - nextToIcon;
385+
Q_UNUSED(overallWidth);
300386

301387
painter->save();
302388

303389
// Overall Progress Bar.
304390
const auto progressBarRect = QRect(nextToIcon,
305391
remotePathRect.top(),
306-
overallWidth - 2 * margin,
392+
nmcWidth,
307393
barHeight);
308394

309395
QStyleOptionProgressBar progressBarOpt;
@@ -335,21 +421,56 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
335421
painter->restore();
336422
}
337423

338-
painter->restore();
339-
340424
{
341425
QStyleOptionToolButton btnOpt;
342426
btnOpt.state = option.state;
343427
btnOpt.state &= ~(QStyle::State_Selected | QStyle::State_HasFocus);
344428
btnOpt.state |= QStyle::State_Raised;
345429
btnOpt.arrowType = Qt::NoArrow;
346430
btnOpt.subControls = QStyle::SC_ToolButton;
347-
btnOpt.rect = optionsButtonVisualRect;
431+
432+
//NMC customization
433+
btnOpt.rect = currentButtonRectPos;
434+
//make sure the button is not too far away from the left border
435+
btnOpt.rect.setRight(btnOpt.rect.x() + btnOpt.rect.width() + 4);
436+
437+
// Create QPainterPath with rounded corners
438+
QPainterPath path;
439+
path.addRoundedRect(btnOpt.rect, 4, 4); // 4 ist der Radius für die abgerundeten Ecken
440+
441+
// Draw border line
442+
QPen borderPen(QColor(0, 0, 0)); // Beispiel: Schwarzer Rand
443+
borderPen.setWidth(1);
444+
painter->setPen(borderPen);
445+
painter->drawPath(path);
446+
447+
// Fill the rectangle
448+
painter->fillPath(path, Qt::transparent);
449+
450+
// Draw the icon in rectangle
348451
btnOpt.icon = _iconMore;
349452
const auto buttonSize = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize);
350453
btnOpt.iconSize = QSize(buttonSize, buttonSize);
351-
QApplication::style()->drawComplexControl(QStyle::CC_ToolButton, &btnOpt, painter);
454+
455+
// Set icon position
456+
int iconX = btnOpt.rect.x() + btnOpt.rect.width()/5;
457+
int iconY = btnOpt.rect.y() + (btnOpt.rect.height() - btnOpt.iconSize.height()) / 2;
458+
459+
painter->drawPixmap(iconX, iconY, btnOpt.icon.pixmap(btnOpt.iconSize));
460+
461+
//Add text
462+
const QString buttonText = QCoreApplication::translate("", "MORE");
463+
painter->setFont(btnOpt.font);
464+
painter->setPen(option.palette.color(QPalette::ButtonText));
465+
int textX = iconX + btnOpt.iconSize.width() + 10;
466+
int textY = iconY;
467+
int textWidth = currentButtonRectPos.x() + currentButtonRectPos.width() - textX;
468+
int textHeight = btnOpt.fontMetrics.height();
469+
470+
painter->drawText(QRect(textX, textY, textWidth, textHeight), Qt::AlignLeft | Qt::AlignVCenter, buttonText);
352471
}
472+
473+
painter->restore();
353474
}
354475

355476
bool FolderStatusDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,

src/gui/folderstatusdelegate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class FolderStatusDelegate : public QStyledItemDelegate
6464
static QRect addButtonRect(QRect within, Qt::LayoutDirection direction);
6565
static QRect errorsListRect(QRect within);
6666
static int rootFolderHeightWithoutErrors(const QFontMetrics &fm, const QFontMetrics &aliasFm);
67+
static QRect moreRectPos(const QRect &rectIndex);
6768

6869
public slots:
6970
void slotStyleChanged();
@@ -75,6 +76,7 @@ public slots:
7576
QPersistentModelIndex _pressedIndex;
7677

7778
QIcon _iconMore;
79+
QStyleOptionViewItem _newOption;
7880
};
7981

8082
} // namespace OCC

src/gui/folderstatusmodel.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,6 @@ FolderStatusModel::FolderStatusModel(QObject *parent)
5050

5151
FolderStatusModel::~FolderStatusModel() = default;
5252

53-
static bool sortByFolderHeader(const FolderStatusModel::SubFolderInfo &lhs, const FolderStatusModel::SubFolderInfo &rhs)
54-
{
55-
return QString::compare(lhs._folder->shortGuiRemotePathOrAppName(),
56-
rhs._folder->shortGuiRemotePathOrAppName(),
57-
Qt::CaseInsensitive)
58-
< 0;
59-
}
60-
6153
void FolderStatusModel::setAccountState(const AccountState *accountState)
6254
{
6355
connect(accountState->account()->e2e(), &OCC::ClientSideEncryption::initializationFinished, this, &FolderStatusModel::e2eInitializationFinished);
@@ -90,9 +82,6 @@ void FolderStatusModel::setAccountState(const AccountState *accountState)
9082
connect(folder, &Folder::newBigFolderDiscovered, this, &FolderStatusModel::slotNewBigFolder, Qt::UniqueConnection);
9183
}
9284

93-
// Sort by header text
94-
std::sort(_folders.begin(), _folders.end(), sortByFolderHeader);
95-
9685
// Set the root _pathIdx after the sorting
9786
for (auto i = 0; i < _folders.size(); ++i) {
9887
_folders[i]._pathIdx << i;

0 commit comments

Comments
 (0)