1/* This file is part of the KDE project
2
3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). <qt-info@nokia.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#include <KDE/KStandardDirs>
22#include <KDE/KGlobal>
23#include <KDE/KComponentData>
24#include <KDE/KGlobalSettings>
25#include <KDE/KStyle>
26#include <KDE/KConfigGroup>
27#include <KDE/KIcon>
28#include <KDE/KFileDialog>
29#include <KDE/KColorDialog>
30#include <QtCore/QHash>
31#include <QtCore/QTimer>
32#include <QtGui/QFileDialog>
33#include <QtGui/QColorDialog>
34#include <QtGui/QApplication>
35#include <QtGui/QToolButton>
36#include <QtGui/QToolBar>
37#include <QtGui/QMainWindow>
38#include "qguiplatformplugin_p.h"
39
40#include <kdebug.h>
41
42/*
43 * Map a Qt filter string into a KDE one.
44 * (from kfiledialog.cpp)
45*/
46static QString qt2KdeFilter(const QString &f)
47{
48 QString filter;
49 QTextStream str(&filter, QIODevice::WriteOnly);
50 const QStringList list(f.split(";;").replaceInStrings("/", "\\/"));
51 QStringList::const_iterator it(list.begin()),
52 end(list.end());
53 bool first=true;
54
55 for(; it!=end; ++it)
56 {
57 int ob=(*it).lastIndexOf('('),
58 cb=(*it).lastIndexOf(')');
59
60 if(-1!=cb && ob<cb)
61 {
62 if(first)
63 first=false;
64 else
65 str << '\n';
66 str << (*it).mid(ob+1, (cb-ob)-1) << '|' << (*it).mid(0, ob);
67 }
68 }
69 return filter;
70}
71
72/*
73 * Map a KDE filter string into a Qt one.
74 * (from kfiledialog.cpp)
75 */
76static void kde2QtFilter(const QString &orig, const QString &kde, QString *sel)
77{
78 if(sel)
79 {
80 const QStringList list(orig.split(";;"));
81 QStringList::const_iterator it(list.begin()),
82 end(list.end());
83 int pos;
84
85 for(; it!=end; ++it)
86 if(-1!=(pos=(*it).indexOf(kde)) && pos>0 &&
87 ('('==(*it)[pos-1] || ' '==(*it)[pos-1]) &&
88 (*it).length()>=kde.length()+pos &&
89 (')'==(*it)[pos+kde.length()] || ' '==(*it)[pos+kde.length()]))
90 {
91 *sel=*it;
92 return;
93 }
94 }
95}
96
97
98class KFileDialogBridge : public KFileDialog
99{
100public:
101 KFileDialogBridge (const KUrl &startDir, const QString &filter, QFileDialog *original_)
102 : KFileDialog (startDir, filter, original_), original(original_)
103 {
104 connect(this, SIGNAL(fileSelected(QString)), original, SIGNAL(currentChanged(QString)));
105 }
106
107 virtual void accept()
108 {
109 kDebug();
110 KFileDialog::accept();
111 QMetaObject::invokeMethod(original, "accept"); //workaround protected
112 }
113
114 virtual void reject()
115 {
116 kDebug();
117 KFileDialog::reject();
118 QMetaObject::invokeMethod(original, "reject"); //workaround protected
119 }
120
121 QFileDialog *original;
122};
123
124class KColorDialogBridge : public KColorDialog
125{
126public:
127 KColorDialogBridge(QColorDialog* original_ = 0L) : KColorDialog(original_, true) , original(original_)
128 {
129 connect(this, SIGNAL(colorSelected(QColor)), original, SIGNAL(currentColorChanged(QColor)));
130 }
131
132 QColorDialog *original;
133
134 virtual void accept()
135 {
136 KColorDialog::accept();
137 original->setCurrentColor(color());
138 QMetaObject::invokeMethod(original, "accept"); //workaround protected
139 }
140
141 virtual void reject()
142 {
143 KColorDialog::reject();
144 QMetaObject::invokeMethod(original, "reject"); //workaround protected
145 }
146};
147
148Q_DECLARE_METATYPE(KFileDialogBridge *)
149Q_DECLARE_METATYPE(KColorDialogBridge *)
150
151class KQGuiPlatformPlugin : public QGuiPlatformPlugin
152{
153 Q_OBJECT
154public:
155 KQGuiPlatformPlugin()
156 {
157 QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
158 }
159
160 virtual QStringList keys() const { return QStringList() << QLatin1String("kde"); }
161 virtual QString styleName()
162 {
163 const QString defaultStyle = KStyle::defaultStyle();
164 const KConfigGroup pConfig(KGlobal::config(), "General");
165 return pConfig.readEntry("widgetStyle", defaultStyle);
166 }
167 virtual QPalette palette()
168 {
169 return KGlobalSettings::createApplicationPalette();
170 }
171 virtual QString systemIconThemeName()
172 {
173 return KIconTheme::current();
174 }
175 virtual QStringList iconThemeSearchPaths()
176 {
177 return KGlobal::dirs()->resourceDirs("icon");
178 }
179 virtual QIcon fileSystemIcon(const QFileInfo &file)
180 {
181 return KIcon(KMimeType::findByPath(file.filePath(), 0, true)->iconName());
182 }
183 virtual int platformHint(PlatformHint hint)
184 {
185 switch(hint)
186 {
187 case PH_ToolButtonStyle: {
188 KConfigGroup group(KGlobal::config(), "Toolbar style");
189 QString style = group.readEntry("ToolButtonStyle", "TextUnderIcon").toLower();
190 if (style == "textbesideicon" || style == "icontextright")
191 return Qt::ToolButtonTextBesideIcon;
192 else if (style == "textundericon" || style == "icontextbottom")
193 return Qt::ToolButtonTextUnderIcon;
194 else if (style == "textonly")
195 return Qt::ToolButtonTextOnly;
196 else
197 return Qt::ToolButtonIconOnly;
198 }
199 case PH_ToolBarIconSize:
200 return KIconLoader::global()->currentSize(KIconLoader::MainToolbar);
201 case PH_ItemView_ActivateItemOnSingleClick:
202 return KGlobalSettings::singleClick();
203 default:
204 break;
205 }
206 return QGuiPlatformPlugin::platformHint(hint);
207 }
208
209public: // File Dialog integration
210#define K_FD(QFD) KFileDialogBridge *kdefd = qvariant_cast<KFileDialogBridge *>(QFD->property("_k_bridge"))
211 virtual void fileDialogDelete(QFileDialog *qfd)
212 {
213 K_FD(qfd);
214 delete kdefd;
215 }
216 virtual bool fileDialogSetVisible(QFileDialog *qfd, bool visible)
217 {
218 K_FD(qfd);
219 if (!kdefd && visible) {
220 if(qfd->options() & QFileDialog::DontUseNativeDialog)
221 return false;
222
223 kdefd = new KFileDialogBridge(KUrl::fromPath(qfd->directory().canonicalPath()),
224 qt2KdeFilter(qfd->nameFilters().join(";;")), qfd);
225
226 qfd->setProperty("_k_bridge", QVariant::fromValue(kdefd));
227 }
228
229 if (visible) {
230 switch (qfd->fileMode()) {
231 case QFileDialog::AnyFile:
232 kdefd->setMode(KFile::LocalOnly | KFile::File);
233 break;
234 case QFileDialog::ExistingFile:
235 kdefd->setMode(KFile::LocalOnly | KFile::File | KFile::ExistingOnly);
236 break;
237 case QFileDialog::ExistingFiles:
238 kdefd->setMode(KFile::LocalOnly | KFile::Files | KFile::ExistingOnly);
239 break;
240 case QFileDialog::Directory:
241 case QFileDialog::DirectoryOnly:
242 kdefd->setMode(KFile::LocalOnly | KFile::Directory);
243 break;
244 }
245
246
247 kdefd->setOperationMode((qfd->acceptMode() == QFileDialog::AcceptSave) ? KFileDialog::Saving : KFileDialog::Opening);
248 kdefd->setCaption(qfd->windowTitle());
249 kdefd->setConfirmOverwrite(qfd->confirmOverwrite());
250 kdefd->setSelection(qfd->selectedFiles().value(0));
251 }
252 kdefd->setVisible(visible);
253 return true;
254 }
255 virtual QDialog::DialogCode fileDialogResultCode(QFileDialog *qfd)
256 {
257 K_FD(qfd);
258 Q_ASSERT(kdefd);
259 return QDialog::DialogCode(kdefd->result());
260 }
261 virtual void fileDialogSetDirectory(QFileDialog *qfd, const QString &directory)
262 {
263 K_FD(qfd);
264 kdefd->setUrl(KUrl::fromPath(directory));
265 }
266 virtual QString fileDialogDirectory(const QFileDialog *qfd) const
267 {
268 K_FD(qfd);
269 Q_ASSERT(kdefd);
270 return kdefd->baseUrl().pathOrUrl();
271 }
272 virtual void fileDialogSelectFile(QFileDialog *qfd, const QString &filename)
273 {
274 K_FD(qfd);
275 Q_ASSERT(kdefd);
276 kdefd->setSelection(filename);
277 }
278 virtual QStringList fileDialogSelectedFiles(const QFileDialog *qfd) const
279 {
280 K_FD(qfd);
281 Q_ASSERT(kdefd);
282 return kdefd->selectedFiles();
283 }
284 /*virtual void fileDialogSetFilter(QFileDialog *qfd)
285 {
286 K_FD(qfd);
287 }*/
288 virtual void fileDialogSetNameFilters(QFileDialog *qfd, const QStringList &filters)
289 {
290 K_FD(qfd);
291 Q_ASSERT(kdefd);
292 kdefd->setFilter(qt2KdeFilter(filters.join(";;")));
293 }
294 /*virtual void fileDialogSelectNameFilter(QFileDialog *qfd, const QString &filter)
295 {
296 K_FD(qfd);
297 }*/
298 virtual QString fileDialogSelectedNameFilter(const QFileDialog *qfd) const
299 {
300 K_FD(qfd);
301 Q_ASSERT(kdefd);
302 QString ret;
303 kde2QtFilter(qfd->nameFilters().join(";;"), kdefd->currentFilter(), &ret);
304 return ret;
305 }
306public: // ColorDialog
307#define K_CD(QCD) KColorDialogBridge *kdecd = qvariant_cast<KColorDialogBridge *>(QCD->property("_k_bridge"))
308 virtual void colorDialogDelete(QColorDialog *qcd)
309 {
310 K_CD(qcd);
311 delete kdecd;
312
313 }
314 virtual bool colorDialogSetVisible(QColorDialog *qcd, bool visible)
315 {
316 K_CD(qcd);
317 if (!kdecd) {
318 kdecd = new KColorDialogBridge(qcd);
319 kdecd->setColor(qcd->currentColor());
320 if (qcd->options() & QColorDialog::NoButtons) {
321 kdecd->setButtons(KDialog::None);
322 }
323 kdecd->setModal(qcd->isModal());
324 qcd->setProperty("_k_bridge", QVariant::fromValue(kdecd));
325 }
326 if (visible) {
327 kdecd->setCaption(qcd->windowTitle());
328 kdecd->setAlphaChannelEnabled(qcd->options() & QColorDialog::ShowAlphaChannel);
329 }
330 kdecd->setVisible(visible);
331 return true;
332 }
333 virtual void colorDialogSetCurrentColor(QColorDialog *qcd, const QColor &color)
334 {
335 K_CD(qcd);
336 if (kdecd) {
337 kdecd->setColor(color);
338 }
339 }
340
341private slots:
342 void init()
343 {
344 connect(KIconLoader::global(), SIGNAL(iconLoaderSettingsChanged()), this, SLOT(updateToolbarIcons()));
345 connect(KGlobalSettings::self(), SIGNAL(toolbarAppearanceChanged(int)), this, SLOT(updateToolbarStyle()));
346 connect(KGlobalSettings::self(), SIGNAL(kdisplayStyleChanged()), this, SLOT(updateWidgetStyle()));
347 }
348
349 void updateToolbarStyle()
350 {
351 //from gtksymbol.cpp
352 QWidgetList widgets = QApplication::allWidgets();
353 for (int i = 0; i < widgets.size(); ++i) {
354 QWidget *widget = widgets.at(i);
355 if (qobject_cast<QToolButton*>(widget)) {
356 QEvent event(QEvent::StyleChange);
357 QApplication::sendEvent(widget, &event);
358 }
359 }
360 }
361
362 void updateToolbarIcons()
363 {
364 QWidgetList widgets = QApplication::allWidgets();
365 for (int i = 0; i < widgets.size(); ++i) {
366 QWidget *widget = widgets.at(i);
367 if (qobject_cast<QToolBar*>(widget) || qobject_cast<QMainWindow*>(widget)) {
368 QEvent event(QEvent::StyleChange);
369 QApplication::sendEvent(widget, &event);
370 }
371 }
372 }
373
374 void updateWidgetStyle()
375 {
376 if (qApp) {
377 if (qApp->style()->objectName() != styleName()) {
378 qApp->setStyle(styleName());
379 }
380 }
381 }
382};
383
384Q_EXPORT_PLUGIN2(KQGuiPlatformPlugin, KQGuiPlatformPlugin)
385
386#include "qguiplatformplugin_kde.moc"
387
388