1/*
2 SPDX-FileCopyrightText: 2006 Aaron J. Seigo <aseigo@kde.org>
3 SPDX-FileCopyrightText: 2009 Peter Penz <peter.penz@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kurlnavigatorschemecombo_p.h"
9
10#include <QAction>
11#include <QMenu>
12#include <QPaintEvent>
13#include <QPainter>
14#include <QStyleOption>
15
16#include <KLocalizedString>
17#include <kprotocolinfo.h>
18#include <kprotocolmanager.h>
19#include <kurlnavigator.h>
20
21namespace
22{
23const int ArrowSize = 10;
24}
25
26namespace KDEPrivate
27{
28KUrlNavigatorSchemeCombo::KUrlNavigatorSchemeCombo(const QString &scheme, KUrlNavigator *parent)
29 : KUrlNavigatorButtonBase(parent)
30 , m_menu(nullptr)
31 , m_schemes()
32 , m_categories()
33{
34 m_menu = new QMenu(this);
35 connect(sender: m_menu, signal: &QMenu::triggered, context: this, slot: &KUrlNavigatorSchemeCombo::setSchemeFromMenu);
36 setText(scheme);
37 setMenu(m_menu);
38}
39
40void KUrlNavigatorSchemeCombo::setSupportedSchemes(const QStringList &schemes)
41{
42 m_schemes = schemes;
43 m_menu->clear();
44
45 for (const QString &scheme : schemes) {
46 QAction *action = m_menu->addAction(text: scheme);
47 action->setData(scheme);
48 }
49}
50
51QSize KUrlNavigatorSchemeCombo::sizeHint() const
52{
53 const QSize size = KUrlNavigatorButtonBase::sizeHint();
54
55 int width = fontMetrics().boundingRect(text: KLocalizedString::removeAcceleratorMarker(label: text())).width();
56 width += (3 * BorderWidth) + ArrowSize;
57
58 return QSize(width, size.height());
59}
60
61void KUrlNavigatorSchemeCombo::setScheme(const QString &scheme)
62{
63 setText(scheme);
64}
65
66QString KUrlNavigatorSchemeCombo::currentScheme() const
67{
68 return text();
69}
70
71void KUrlNavigatorSchemeCombo::showEvent(QShowEvent *event)
72{
73 KUrlNavigatorButtonBase::showEvent(event);
74 if (!event->spontaneous() && m_schemes.isEmpty()) {
75 m_schemes = KProtocolInfo::protocols();
76
77 auto it = std::remove_if(first: m_schemes.begin(), last: m_schemes.end(), pred: [](const QString &s) {
78 QUrl url;
79 url.setScheme(s);
80 return !KProtocolManager::supportsListing(url);
81 });
82 m_schemes.erase(abegin: it, aend: m_schemes.end());
83
84 std::sort(first: m_schemes.begin(), last: m_schemes.end());
85
86 updateMenu();
87 }
88}
89
90void KUrlNavigatorSchemeCombo::paintEvent(QPaintEvent *event)
91{
92 Q_UNUSED(event);
93
94 QPainter painter(this);
95 const int buttonWidth = width();
96 const int buttonHeight = height();
97
98 drawHoverBackground(painter: &painter);
99
100 const QColor fgColor = foregroundColor();
101 painter.setPen(fgColor);
102
103 // draw arrow
104 const int arrowX = buttonWidth - ArrowSize - BorderWidth;
105 const int arrowY = (buttonHeight - ArrowSize) / 2;
106
107 QStyleOption option;
108 option.rect = QRect(arrowX, arrowY, ArrowSize, ArrowSize);
109 option.palette = palette();
110 option.palette.setColor(acr: QPalette::Text, acolor: fgColor);
111 option.palette.setColor(acr: QPalette::WindowText, acolor: fgColor);
112 option.palette.setColor(acr: QPalette::ButtonText, acolor: fgColor);
113 style()->drawPrimitive(pe: QStyle::PE_IndicatorArrowDown, opt: &option, p: &painter, w: this);
114
115 // draw text
116 const int textWidth = arrowX - (2 * BorderWidth);
117 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
118 if (!style()->styleHint(stylehint: QStyle::SH_UnderlineShortcut, opt: &option, widget: this)) {
119 alignment |= Qt::TextHideMnemonic;
120 }
121 style()->drawItemText(painter: &painter, rect: QRect(BorderWidth, 0, textWidth, buttonHeight), flags: alignment, pal: option.palette, enabled: isEnabled(), text: text());
122}
123
124void KUrlNavigatorSchemeCombo::setSchemeFromMenu(QAction *action)
125{
126 const QString scheme = action->data().toString();
127 setText(scheme);
128 Q_EMIT activated(scheme);
129}
130
131void KUrlNavigatorSchemeCombo::updateMenu()
132{
133 initializeCategories();
134 std::sort(first: m_schemes.begin(), last: m_schemes.end());
135
136 // move all schemes into the corresponding category of 'items'
137 QList<QString> items[CategoryCount];
138 for (const QString &scheme : std::as_const(t&: m_schemes)) {
139 if (m_categories.contains(key: scheme)) {
140 const SchemeCategory category = m_categories.value(key: scheme);
141 items[category].append(t: scheme);
142 } else {
143 items[OtherCategory].append(t: scheme);
144 }
145 }
146
147 // Create the menu that includes all entries from 'items'. The categories
148 // CoreCategory and PlacesCategory are placed at the top level, the remaining
149 // categories are placed in sub menus.
150 QMenu *menu = m_menu;
151 for (int category = 0; category < CategoryCount; ++category) {
152 if (!items[category].isEmpty()) {
153 switch (category) {
154 case DevicesCategory:
155 menu = m_menu->addMenu(i18nc("@item:inmenu", "Devices"));
156 break;
157
158 case SubversionCategory:
159 menu = m_menu->addMenu(i18nc("@item:inmenu", "Subversion"));
160 break;
161
162 case OtherCategory:
163 menu = m_menu->addMenu(i18nc("@item:inmenu", "Other"));
164 break;
165
166 case CoreCategory:
167 case PlacesCategory:
168 default:
169 break;
170 }
171
172 for (const QString &scheme : std::as_const(t&: items[category])) {
173 QAction *action = menu->addAction(text: scheme);
174 action->setData(scheme);
175 }
176
177 if (menu == m_menu) {
178 menu->addSeparator();
179 }
180 }
181 }
182}
183
184void KUrlNavigatorSchemeCombo::initializeCategories()
185{
186 if (m_categories.isEmpty()) {
187 m_categories.insert(QStringLiteral("file"), value: CoreCategory);
188 m_categories.insert(QStringLiteral("ftp"), value: CoreCategory);
189 m_categories.insert(QStringLiteral("fish"), value: CoreCategory);
190 m_categories.insert(QStringLiteral("nfs"), value: CoreCategory);
191 m_categories.insert(QStringLiteral("sftp"), value: CoreCategory);
192 m_categories.insert(QStringLiteral("smb"), value: CoreCategory);
193 m_categories.insert(QStringLiteral("webdav"), value: CoreCategory);
194
195 m_categories.insert(QStringLiteral("desktop"), value: PlacesCategory);
196 m_categories.insert(QStringLiteral("fonts"), value: PlacesCategory);
197 m_categories.insert(QStringLiteral("programs"), value: PlacesCategory);
198 m_categories.insert(QStringLiteral("settings"), value: PlacesCategory);
199 m_categories.insert(QStringLiteral("trash"), value: PlacesCategory);
200
201 m_categories.insert(QStringLiteral("floppy"), value: DevicesCategory);
202 m_categories.insert(QStringLiteral("camera"), value: DevicesCategory);
203 m_categories.insert(QStringLiteral("remote"), value: DevicesCategory);
204
205 m_categories.insert(QStringLiteral("svn"), value: SubversionCategory);
206 m_categories.insert(QStringLiteral("svn+file"), value: SubversionCategory);
207 m_categories.insert(QStringLiteral("svn+http"), value: SubversionCategory);
208 m_categories.insert(QStringLiteral("svn+https"), value: SubversionCategory);
209 m_categories.insert(QStringLiteral("svn+ssh"), value: SubversionCategory);
210 }
211}
212
213} // namespace KDEPrivate
214
215#include "moc_kurlnavigatorschemecombo_p.cpp"
216

source code of kio/src/filewidgets/kurlnavigatorschemecombo.cpp