File indexing completed on 2023-09-24 04:08:56
0001 /* 0002 SPDX-FileCopyrightText: 2006 Aaron J. Seigo <aseigo@kde.org> 0003 SPDX-FileCopyrightText: 2009 Peter Penz <peter.penz@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kurlnavigatorprotocolcombo_p.h" 0009 0010 #include <QAction> 0011 #include <QMenu> 0012 #include <QPaintEvent> 0013 #include <QPainter> 0014 #include <QStyleOption> 0015 0016 #include <KLocalizedString> 0017 #include <kprotocolinfo.h> 0018 #include <kprotocolmanager.h> 0019 #include <kurlnavigator.h> 0020 0021 namespace 0022 { 0023 const int ArrowSize = 10; 0024 } 0025 0026 namespace KDEPrivate 0027 { 0028 KUrlNavigatorProtocolCombo::KUrlNavigatorProtocolCombo(const QString &protocol, KUrlNavigator *parent) 0029 : KUrlNavigatorButtonBase(parent) 0030 , m_menu(nullptr) 0031 , m_protocols() 0032 , m_categories() 0033 { 0034 m_menu = new QMenu(this); 0035 connect(m_menu, &QMenu::triggered, this, &KUrlNavigatorProtocolCombo::setProtocolFromMenu); 0036 setText(protocol); 0037 setMenu(m_menu); 0038 } 0039 0040 void KUrlNavigatorProtocolCombo::setCustomProtocols(const QStringList &protocols) 0041 { 0042 m_protocols = protocols; 0043 m_menu->clear(); 0044 0045 for (const QString &protocol : protocols) { 0046 QAction *action = m_menu->addAction(protocol); 0047 action->setData(protocol); 0048 } 0049 } 0050 0051 QSize KUrlNavigatorProtocolCombo::sizeHint() const 0052 { 0053 const QSize size = KUrlNavigatorButtonBase::sizeHint(); 0054 0055 int width = fontMetrics().boundingRect(KLocalizedString::removeAcceleratorMarker(text())).width(); 0056 width += (3 * BorderWidth) + ArrowSize; 0057 0058 return QSize(width, size.height()); 0059 } 0060 0061 void KUrlNavigatorProtocolCombo::setProtocol(const QString &protocol) 0062 { 0063 setText(protocol); 0064 } 0065 0066 QString KUrlNavigatorProtocolCombo::currentProtocol() const 0067 { 0068 return text(); 0069 } 0070 0071 void KUrlNavigatorProtocolCombo::showEvent(QShowEvent *event) 0072 { 0073 KUrlNavigatorButtonBase::showEvent(event); 0074 if (!event->spontaneous() && m_protocols.isEmpty()) { 0075 m_protocols = KProtocolInfo::protocols(); 0076 0077 auto it = std::remove_if(m_protocols.begin(), m_protocols.end(), [](const QString &s) { 0078 QUrl url; 0079 url.setScheme(s); 0080 return !KProtocolManager::supportsListing(url); 0081 }); 0082 m_protocols.erase(it, m_protocols.end()); 0083 0084 std::sort(m_protocols.begin(), m_protocols.end()); 0085 0086 updateMenu(); 0087 } 0088 } 0089 0090 void KUrlNavigatorProtocolCombo::paintEvent(QPaintEvent *event) 0091 { 0092 Q_UNUSED(event); 0093 0094 QPainter painter(this); 0095 const int buttonWidth = width(); 0096 const int buttonHeight = height(); 0097 0098 drawHoverBackground(&painter); 0099 0100 const QColor fgColor = foregroundColor(); 0101 painter.setPen(fgColor); 0102 0103 // draw arrow 0104 const int arrowX = buttonWidth - ArrowSize - BorderWidth; 0105 const int arrowY = (buttonHeight - ArrowSize) / 2; 0106 0107 QStyleOption option; 0108 option.rect = QRect(arrowX, arrowY, ArrowSize, ArrowSize); 0109 option.palette = palette(); 0110 option.palette.setColor(QPalette::Text, fgColor); 0111 option.palette.setColor(QPalette::WindowText, fgColor); 0112 option.palette.setColor(QPalette::ButtonText, fgColor); 0113 style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &option, &painter, this); 0114 0115 // draw text 0116 const int textWidth = arrowX - (2 * BorderWidth); 0117 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic; 0118 if (!style()->styleHint(QStyle::SH_UnderlineShortcut, &option, this)) { 0119 alignment |= Qt::TextHideMnemonic; 0120 } 0121 style()->drawItemText(&painter, QRect(BorderWidth, 0, textWidth, buttonHeight), alignment, option.palette, isEnabled(), text()); 0122 } 0123 0124 void KUrlNavigatorProtocolCombo::setProtocolFromMenu(QAction *action) 0125 { 0126 const QString protocol = action->data().toString(); 0127 setText(protocol); 0128 Q_EMIT activated(protocol); 0129 } 0130 0131 void KUrlNavigatorProtocolCombo::updateMenu() 0132 { 0133 initializeCategories(); 0134 std::sort(m_protocols.begin(), m_protocols.end()); 0135 0136 // move all protocols into the corresponding category of 'items' 0137 QList<QString> items[CategoryCount]; 0138 for (const QString &protocol : std::as_const(m_protocols)) { 0139 if (m_categories.contains(protocol)) { 0140 const ProtocolCategory category = m_categories.value(protocol); 0141 items[category].append(protocol); 0142 } else { 0143 items[OtherCategory].append(protocol); 0144 } 0145 } 0146 0147 // Create the menu that includes all entries from 'items'. The categories 0148 // CoreCategory and PlacesCategory are placed at the top level, the remaining 0149 // categories are placed in sub menus. 0150 QMenu *menu = m_menu; 0151 for (int category = 0; category < CategoryCount; ++category) { 0152 if (!items[category].isEmpty()) { 0153 switch (category) { 0154 case DevicesCategory: 0155 menu = m_menu->addMenu(i18nc("@item:inmenu", "Devices")); 0156 break; 0157 0158 case SubversionCategory: 0159 menu = m_menu->addMenu(i18nc("@item:inmenu", "Subversion")); 0160 break; 0161 0162 case OtherCategory: 0163 menu = m_menu->addMenu(i18nc("@item:inmenu", "Other")); 0164 break; 0165 0166 case CoreCategory: 0167 case PlacesCategory: 0168 default: 0169 break; 0170 } 0171 0172 for (const QString &protocol : std::as_const(items[category])) { 0173 QAction *action = menu->addAction(protocol); 0174 action->setData(protocol); 0175 } 0176 0177 if (menu == m_menu) { 0178 menu->addSeparator(); 0179 } 0180 } 0181 } 0182 } 0183 0184 void KUrlNavigatorProtocolCombo::initializeCategories() 0185 { 0186 if (m_categories.isEmpty()) { 0187 m_categories.insert(QStringLiteral("file"), CoreCategory); 0188 m_categories.insert(QStringLiteral("ftp"), CoreCategory); 0189 m_categories.insert(QStringLiteral("fish"), CoreCategory); 0190 m_categories.insert(QStringLiteral("nfs"), CoreCategory); 0191 m_categories.insert(QStringLiteral("sftp"), CoreCategory); 0192 m_categories.insert(QStringLiteral("smb"), CoreCategory); 0193 m_categories.insert(QStringLiteral("webdav"), CoreCategory); 0194 0195 m_categories.insert(QStringLiteral("desktop"), PlacesCategory); 0196 m_categories.insert(QStringLiteral("fonts"), PlacesCategory); 0197 m_categories.insert(QStringLiteral("programs"), PlacesCategory); 0198 m_categories.insert(QStringLiteral("settings"), PlacesCategory); 0199 m_categories.insert(QStringLiteral("trash"), PlacesCategory); 0200 0201 m_categories.insert(QStringLiteral("floppy"), DevicesCategory); 0202 m_categories.insert(QStringLiteral("camera"), DevicesCategory); 0203 m_categories.insert(QStringLiteral("remote"), DevicesCategory); 0204 0205 m_categories.insert(QStringLiteral("svn"), SubversionCategory); 0206 m_categories.insert(QStringLiteral("svn+file"), SubversionCategory); 0207 m_categories.insert(QStringLiteral("svn+http"), SubversionCategory); 0208 m_categories.insert(QStringLiteral("svn+https"), SubversionCategory); 0209 m_categories.insert(QStringLiteral("svn+ssh"), SubversionCategory); 0210 } 0211 } 0212 0213 } // namespace KDEPrivate 0214 0215 #include "moc_kurlnavigatorprotocolcombo_p.cpp"