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 | |
21 | namespace |
22 | { |
23 | const int ArrowSize = 10; |
24 | } |
25 | |
26 | namespace KDEPrivate |
27 | { |
28 | KUrlNavigatorSchemeCombo::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 | |
40 | void 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 | |
51 | QSize 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 | |
61 | void KUrlNavigatorSchemeCombo::setScheme(const QString &scheme) |
62 | { |
63 | setText(scheme); |
64 | } |
65 | |
66 | QString KUrlNavigatorSchemeCombo::currentScheme() const |
67 | { |
68 | return text(); |
69 | } |
70 | |
71 | void 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 | |
90 | void 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 | |
124 | void KUrlNavigatorSchemeCombo::(QAction *action) |
125 | { |
126 | const QString scheme = action->data().toString(); |
127 | setText(scheme); |
128 | Q_EMIT activated(scheme); |
129 | } |
130 | |
131 | void KUrlNavigatorSchemeCombo::() |
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 * = 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 | |
184 | void 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 | |