1/***************************************************************************
2 * Copyright (C) 2006 by Aaron J. Seigo (<aseigo@kde.org>) *
3 * Copyright (C) 2009 by Peter Penz (<peter.penz@kde.org>) *
4 * *
5 * This library is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU Lesser General Public *
7 * License as published by the Free Software Foundation; either *
8 * version 2 of the License, or (at your option) any later version. *
9 * *
10 * This library is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * Lesser General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Lesser General Public *
16 * License along with this library; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21#include "kurlnavigatorprotocolcombo_p.h"
22
23#include <QtGui/QAction>
24#include <QtGui/QMenu>
25#include <QtGui/QPainter>
26#include <QtGui/QPaintEvent>
27#include <QtGui/QStyleOption>
28
29#include <klocale.h>
30#include <kprotocolinfo.h>
31#include <kprotocolmanager.h>
32#include <kurlnavigator.h>
33
34namespace
35{
36 const int ArrowSize = 10;
37}
38
39namespace KDEPrivate
40{
41
42KUrlNavigatorProtocolCombo::KUrlNavigatorProtocolCombo(const QString& protocol, QWidget* parent) :
43 KUrlNavigatorButtonBase(parent),
44 m_menu(0),
45 m_protocols(),
46 m_categories()
47{
48 m_menu = new QMenu(this);
49 connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(setProtocol(QAction*)));
50 setText(protocol);
51 setMenu(m_menu);
52}
53
54void KUrlNavigatorProtocolCombo::setCustomProtocols(const QStringList& protocols)
55{
56 m_protocols = protocols;
57 m_menu->clear();
58
59 foreach (const QString& protocol, protocols) {
60 QAction* action = m_menu->addAction(protocol);
61 action->setData(protocol);
62 }
63}
64
65QSize KUrlNavigatorProtocolCombo::sizeHint() const
66{
67 const QSize size = KUrlNavigatorButtonBase::sizeHint();
68
69 QFontMetrics fontMetrics(font());
70 int width = fontMetrics.width(KGlobal::locale()->removeAcceleratorMarker(text()));
71 width += (3 * BorderWidth) + ArrowSize;
72
73 return QSize(width, size.height());
74}
75
76void KUrlNavigatorProtocolCombo::setProtocol(const QString& protocol)
77{
78 setText(protocol);
79}
80
81QString KUrlNavigatorProtocolCombo::currentProtocol() const
82{
83 return text();
84}
85
86void KUrlNavigatorProtocolCombo::showEvent(QShowEvent* event)
87{
88 KUrlNavigatorButtonBase::showEvent(event);
89 if (!event->spontaneous() && m_protocols.isEmpty()) {
90 m_protocols = KProtocolInfo::protocols();
91 qSort(m_protocols);
92
93 QStringList::iterator it = m_protocols.begin();
94 while (it != m_protocols.end()) {
95 const KUrl url(*it + "://");
96 if (!KProtocolManager::supportsListing(url)) {
97 it = m_protocols.erase(it);
98 } else {
99 ++it;
100 }
101 }
102
103 updateMenu();
104 }
105}
106
107void KUrlNavigatorProtocolCombo::paintEvent(QPaintEvent* event)
108{
109 Q_UNUSED(event);
110
111 QPainter painter(this);
112 const int buttonWidth = width();
113 const int buttonHeight = height();
114
115 drawHoverBackground(&painter);
116
117 const QColor fgColor = foregroundColor();
118 painter.setPen(fgColor);
119
120 // draw arrow
121 const int arrowX = buttonWidth - ArrowSize - BorderWidth;
122 const int arrowY = (buttonHeight - ArrowSize) / 2;
123
124 QStyleOption option;
125 option.rect = QRect(arrowX, arrowY, ArrowSize, ArrowSize);
126 option.palette = palette();
127 option.palette.setColor(QPalette::Text, fgColor);
128 option.palette.setColor(QPalette::WindowText, fgColor);
129 option.palette.setColor(QPalette::ButtonText, fgColor);
130 style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &option, &painter, this );
131
132 // draw text
133 const int textWidth = arrowX - (2 * BorderWidth);
134 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
135 if (!style()->styleHint(QStyle::SH_UnderlineShortcut, &option, this)) {
136 alignment |= Qt::TextHideMnemonic;
137 }
138 style()->drawItemText(&painter, QRect(BorderWidth, 0, textWidth, buttonHeight),
139 alignment, option.palette, isEnabled(), text());
140}
141
142void KUrlNavigatorProtocolCombo::setProtocol(QAction* action)
143{
144 const QString protocol = action->data().toString();
145 setText(protocol);
146 emit activated(protocol);
147}
148
149void KUrlNavigatorProtocolCombo::updateMenu()
150{
151 initializeCategories();
152 qSort(m_protocols);
153
154 // move all protocols into the corresponding category of 'items'
155 QList<QString> items[CategoryCount];
156 foreach (const QString& protocol, m_protocols) {
157 if (m_categories.contains(protocol)) {
158 const ProtocolCategory category = m_categories.value(protocol);
159 items[category].append(protocol);
160 } else {
161 items[OtherCategory].append(protocol);
162 }
163 }
164
165 // Create the menu that includes all entries from 'items'. The categories
166 // CoreCategory and PlacesCategory are placed at the top level, the remaining
167 // categories are placed in sub menus.
168 QMenu* menu = m_menu;
169 for (int category = 0; category < CategoryCount; ++category) {
170 if (items[category].count() > 0) {
171 switch (category) {
172 case DevicesCategory:
173 menu = m_menu->addMenu(i18nc("@item:inmenu", "Devices"));
174 break;
175
176 case SubversionCategory:
177 menu = m_menu->addMenu(i18nc("@item:inmenu", "Subversion"));
178 break;
179
180 case OtherCategory:
181 menu = m_menu->addMenu(i18nc("@item:inmenu", "Other"));
182 break;
183
184 case CoreCategory:
185 case PlacesCategory:
186 default:
187 break;
188 }
189
190 foreach (const QString& protocol, items[category]) {
191 QAction* action = menu->addAction(protocol);
192 action->setData(protocol);
193 }
194
195 if (menu == m_menu) {
196 menu->addSeparator();
197 }
198 }
199 }
200}
201
202void KUrlNavigatorProtocolCombo::initializeCategories()
203{
204 if (m_categories.isEmpty()) {
205 m_categories.insert("file", CoreCategory);
206 m_categories.insert("ftp", CoreCategory);
207 m_categories.insert("fish", CoreCategory);
208 m_categories.insert("nfs", CoreCategory);
209 m_categories.insert("sftp", CoreCategory);
210 m_categories.insert("smb", CoreCategory);
211 m_categories.insert("webdav", CoreCategory);
212
213 m_categories.insert("desktop", PlacesCategory);
214 m_categories.insert("fonts", PlacesCategory);
215 m_categories.insert("programs", PlacesCategory);
216 m_categories.insert("settings", PlacesCategory);
217 m_categories.insert("trash", PlacesCategory);
218
219 m_categories.insert("floppy", DevicesCategory);
220 m_categories.insert("camera", DevicesCategory);
221 m_categories.insert("remote", DevicesCategory);
222
223 m_categories.insert("svn", SubversionCategory);
224 m_categories.insert("svn+file", SubversionCategory);
225 m_categories.insert("svn+http", SubversionCategory);
226 m_categories.insert("svn+https", SubversionCategory);
227 m_categories.insert("svn+ssh", SubversionCategory);
228 }
229}
230
231} // namespace KDEPrivate
232
233#include "kurlnavigatorprotocolcombo_p.moc"
234