source: trunk/src/gui/itemviews/qfileiconprovider.cpp@ 607

Last change on this file since 607 was 607, checked in by Dmitry A. Kuminov, 15 years ago

gui: Select the correct icon for the drive letter in standard file dialogs depending on the drive type (floppy, hard disk etc) [patch by rudi].

File size: 15.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qfileiconprovider.h"
43
44#ifndef QT_NO_FILEICONPROVIDER
45#include <qstyle.h>
46#include <qapplication.h>
47#include <qdir.h>
48#include <qpixmapcache.h>
49#if defined(Q_WS_WIN)
50# define _WIN32_IE 0x0500
51# include <qt_windows.h>
52# include <commctrl.h>
53# include <objbase.h>
54#elif defined(Q_WS_PM)
55# include <qt_os2.h>
56#elif defined(Q_WS_MAC)
57# include <private/qt_cocoa_helpers_mac_p.h>
58#endif
59
60#include <private/qfunctions_p.h>
61#include <private/qguiplatformplugin_p.h>
62
63#if defined(Q_WS_X11) && !defined(Q_NO_STYLE_GTK)
64# include <private/qgtkstyle_p.h>
65# include <private/qt_x11_p.h>
66#endif
67
68#ifndef SHGFI_ADDOVERLAYS
69# define SHGFI_ADDOVERLAYS 0x000000020
70#endif
71
72QT_BEGIN_NAMESPACE
73
74/*!
75 \class QFileIconProvider
76
77 \brief The QFileIconProvider class provides file icons for the QDirModel class.
78*/
79
80/*!
81 \enum QFileIconProvider::IconType
82 \value Computer
83 \value Desktop
84 \value Trashcan
85 \value Network
86 \value Drive
87 \value Folder
88 \value File
89*/
90
91class QFileIconProviderPrivate
92{
93 Q_DECLARE_PUBLIC(QFileIconProvider)
94
95public:
96 QFileIconProviderPrivate();
97 QIcon getIcon(QStyle::StandardPixmap name) const;
98#ifdef Q_WS_WIN
99 QIcon getWinIcon(const QFileInfo &fi) const;
100#elif defined(Q_WS_MAC)
101 QIcon getMacIcon(const QFileInfo &fi) const;
102#endif
103 QFileIconProvider *q_ptr;
104 QString homePath;
105
106private:
107 QIcon file;
108 QIcon fileLink;
109 QIcon directory;
110 QIcon directoryLink;
111 QIcon harddisk;
112 QIcon floppy;
113 QIcon cdrom;
114 QIcon ram;
115 QIcon network;
116 QIcon computer;
117 QIcon desktop;
118 QIcon trashcan;
119 QIcon generic;
120 QIcon home;
121};
122
123QFileIconProviderPrivate::QFileIconProviderPrivate()
124{
125 QStyle *style = QApplication::style();
126 file = style->standardIcon(QStyle::SP_FileIcon);
127 directory = style->standardIcon(QStyle::SP_DirIcon);
128 fileLink = style->standardIcon(QStyle::SP_FileLinkIcon);
129 directoryLink = style->standardIcon(QStyle::SP_DirLinkIcon);
130 harddisk = style->standardIcon(QStyle::SP_DriveHDIcon);
131 floppy = style->standardIcon(QStyle::SP_DriveFDIcon);
132 cdrom = style->standardIcon(QStyle::SP_DriveCDIcon);
133 network = style->standardIcon(QStyle::SP_DriveNetIcon);
134 computer = style->standardIcon(QStyle::SP_ComputerIcon);
135 desktop = style->standardIcon(QStyle::SP_DesktopIcon);
136 trashcan = style->standardIcon(QStyle::SP_TrashIcon);
137 home = style->standardIcon(QStyle::SP_DirHomeIcon);
138 homePath = QDir::home().absolutePath();
139}
140
141QIcon QFileIconProviderPrivate::getIcon(QStyle::StandardPixmap name) const
142{
143 switch (name) {
144 case QStyle::SP_FileIcon:
145 return file;
146 case QStyle::SP_FileLinkIcon:
147 return fileLink;
148 case QStyle::SP_DirIcon:
149 return directory;
150 case QStyle::SP_DirLinkIcon:
151 return directoryLink;
152 case QStyle::SP_DriveHDIcon:
153 return harddisk;
154 case QStyle::SP_DriveFDIcon:
155 return floppy;
156 case QStyle::SP_DriveCDIcon:
157 return cdrom;
158 case QStyle::SP_DriveNetIcon:
159 return network;
160 case QStyle::SP_ComputerIcon:
161 return computer;
162 case QStyle::SP_DesktopIcon:
163 return desktop;
164 case QStyle::SP_TrashIcon:
165 return trashcan;
166 case QStyle::SP_DirHomeIcon:
167 return home;
168 default:
169 return QIcon();
170 }
171 return QIcon();
172}
173
174/*!
175 Constructs a file icon provider.
176*/
177
178QFileIconProvider::QFileIconProvider()
179 : d_ptr(new QFileIconProviderPrivate)
180{
181}
182
183/*!
184 Destroys the file icon provider.
185
186*/
187
188QFileIconProvider::~QFileIconProvider()
189{
190}
191
192/*!
193 Returns an icon set for the given \a type.
194*/
195
196QIcon QFileIconProvider::icon(IconType type) const
197{
198 Q_D(const QFileIconProvider);
199 switch (type) {
200 case Computer:
201 return d->getIcon(QStyle::SP_ComputerIcon);
202 case Desktop:
203 return d->getIcon(QStyle::SP_DesktopIcon);
204 case Trashcan:
205 return d->getIcon(QStyle::SP_TrashIcon);
206 case Network:
207 return d->getIcon(QStyle::SP_DriveNetIcon);
208 case Drive:
209 return d->getIcon(QStyle::SP_DriveHDIcon);
210 case Folder:
211 return d->getIcon(QStyle::SP_DirIcon);
212 case File:
213 return d->getIcon(QStyle::SP_FileIcon);
214 default:
215 break;
216 };
217 return QIcon();
218}
219
220#ifdef Q_WS_WIN
221QIcon QFileIconProviderPrivate::getWinIcon(const QFileInfo &fileInfo) const
222{
223 QIcon retIcon;
224 const QString fileExtension = QLatin1Char('.') + fileInfo.suffix().toUpper();
225
226 QString key;
227 if (fileInfo.isFile() && !fileInfo.isExecutable() && !fileInfo.isSymLink())
228 key = QLatin1String("qt_") + fileExtension;
229
230 QPixmap pixmap;
231 if (!key.isEmpty()) {
232 QPixmapCache::find(key, pixmap);
233 }
234
235 if (!pixmap.isNull()) {
236 retIcon.addPixmap(pixmap);
237 if (QPixmapCache::find(key + QLatin1Char('l'), pixmap))
238 retIcon.addPixmap(pixmap);
239 return retIcon;
240 }
241
242 /* We don't use the variable, but by storing it statically, we
243 * ensure CoInitialize is only called once. */
244 static HRESULT comInit = CoInitialize(NULL);
245 Q_UNUSED(comInit);
246
247 SHFILEINFO info;
248 unsigned long val = 0;
249
250 //Get the small icon
251#ifndef Q_OS_WINCE
252 val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
253 sizeof(SHFILEINFO), SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS);
254#else
255 val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
256 sizeof(SHFILEINFO), SHGFI_SMALLICON|SHGFI_SYSICONINDEX);
257#endif
258 if (val) {
259 if (fileInfo.isDir() && !fileInfo.isRoot()) {
260 //using the unique icon index provided by windows save us from duplicate keys
261 key = QString::fromLatin1("qt_dir_%1").arg(info.iIcon);
262 QPixmapCache::find(key, pixmap);
263 if (!pixmap.isNull()) {
264 retIcon.addPixmap(pixmap);
265 if (QPixmapCache::find(key + QLatin1Char('l'), pixmap))
266 retIcon.addPixmap(pixmap);
267 DestroyIcon(info.hIcon);
268 return retIcon;
269 }
270 }
271 if (pixmap.isNull()) {
272#ifndef Q_OS_WINCE
273 pixmap = QPixmap::fromWinHICON(info.hIcon);
274#else
275 pixmap = QPixmap::fromWinHICON(ImageList_GetIcon((HIMAGELIST) val, info.iIcon, ILD_NORMAL));
276#endif
277 if (!pixmap.isNull()) {
278 retIcon.addPixmap(pixmap);
279 if (!key.isEmpty())
280 QPixmapCache::insert(key, pixmap);
281 }
282 else {
283 qWarning("QFileIconProviderPrivate::getWinIcon() no small icon found");
284 }
285 }
286 DestroyIcon(info.hIcon);
287 }
288
289 //Get the big icon
290#ifndef Q_OS_WINCE
291 val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
292 sizeof(SHFILEINFO), SHGFI_ICON|SHGFI_LARGEICON|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS);
293#else
294 val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
295 sizeof(SHFILEINFO), SHGFI_LARGEICON|SHGFI_SYSICONINDEX);
296#endif
297 if (val) {
298 if (fileInfo.isDir() && !fileInfo.isRoot()) {
299 //using the unique icon index provided by windows save us from duplicate keys
300 key = QString::fromLatin1("qt_dir_%1").arg(info.iIcon);
301 }
302#ifndef Q_OS_WINCE
303 pixmap = QPixmap::fromWinHICON(info.hIcon);
304#else
305 pixmap = QPixmap::fromWinHICON(ImageList_GetIcon((HIMAGELIST) val, info.iIcon, ILD_NORMAL));
306#endif
307 if (!pixmap.isNull()) {
308 retIcon.addPixmap(pixmap);
309 if (!key.isEmpty())
310 QPixmapCache::insert(key + QLatin1Char('l'), pixmap);
311 }
312 else {
313 qWarning("QFileIconProviderPrivate::getWinIcon() no large icon found");
314 }
315 DestroyIcon(info.hIcon);
316 }
317 return retIcon;
318}
319
320#elif defined(Q_WS_MAC)
321QIcon QFileIconProviderPrivate::getMacIcon(const QFileInfo &fi) const
322{
323 QIcon retIcon;
324 QString fileExtension = fi.suffix().toUpper();
325 fileExtension.prepend(QLatin1String("."));
326
327 const QString keyBase = QLatin1String("qt_") + fileExtension;
328
329 QPixmap pixmap;
330 if (fi.isFile() && !fi.isExecutable() && !fi.isSymLink()) {
331 QPixmapCache::find(keyBase + QLatin1String("16"), pixmap);
332 }
333
334 if (!pixmap.isNull()) {
335 retIcon.addPixmap(pixmap);
336 if (QPixmapCache::find(keyBase + QLatin1String("32"), pixmap)) {
337 retIcon.addPixmap(pixmap);
338 if (QPixmapCache::find(keyBase + QLatin1String("64"), pixmap)) {
339 retIcon.addPixmap(pixmap);
340 if (QPixmapCache::find(keyBase + QLatin1String("128"), pixmap)) {
341 retIcon.addPixmap(pixmap);
342 return retIcon;
343 }
344 }
345 }
346 }
347
348
349 FSRef macRef;
350 OSStatus status = FSPathMakeRef(reinterpret_cast<const UInt8*>(fi.canonicalFilePath().toUtf8().constData()),
351 &macRef, 0);
352 if (status != noErr)
353 return retIcon;
354 FSCatalogInfo info;
355 HFSUniStr255 macName;
356 status = FSGetCatalogInfo(&macRef, kIconServicesCatalogInfoMask, &info, &macName, 0, 0);
357 if (status != noErr)
358 return retIcon;
359 IconRef iconRef;
360 SInt16 iconLabel;
361 status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode,
362 kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag,
363 &iconRef, &iconLabel);
364 if (status != noErr)
365 return retIcon;
366 qt_mac_constructQIconFromIconRef(iconRef, 0, &retIcon);
367 ReleaseIconRef(iconRef);
368
369 pixmap = retIcon.pixmap(16);
370 QPixmapCache::insert(keyBase + QLatin1String("16"), pixmap);
371 pixmap = retIcon.pixmap(32);
372 QPixmapCache::insert(keyBase + QLatin1String("32"), pixmap);
373 pixmap = retIcon.pixmap(64);
374 QPixmapCache::insert(keyBase + QLatin1String("64"), pixmap);
375 pixmap = retIcon.pixmap(128);
376 QPixmapCache::insert(keyBase + QLatin1String("128"), pixmap);
377
378 return retIcon;
379}
380#endif
381
382
383/*!
384 Returns an icon for the file described by \a info.
385*/
386
387QIcon QFileIconProvider::icon(const QFileInfo &info) const
388{
389 Q_D(const QFileIconProvider);
390
391 QIcon platformIcon = qt_guiPlatformPlugin()->fileSystemIcon(info);
392 if (!platformIcon.isNull())
393 return platformIcon;
394
395#if defined(Q_WS_X11) && !defined(QT_NO_STYLE_GTK)
396 if (X11->desktopEnvironment == DE_GNOME) {
397 QIcon gtkIcon = QGtkStylePrivate::getFilesystemIcon(info);
398 if (!gtkIcon.isNull())
399 return gtkIcon;
400 }
401#endif
402
403#ifdef Q_WS_MAC
404 QIcon retIcon = d->getMacIcon(info);
405 if (!retIcon.isNull())
406 return retIcon;
407#elif defined Q_WS_WIN
408 QIcon icon = d->getWinIcon(info);
409 if (!icon.isNull())
410 return icon;
411#endif
412 if (info.isRoot())
413#if defined (Q_WS_WIN) && !defined(Q_WS_WINCE)
414 {
415 UINT type = GetDriveType((wchar_t *)info.absoluteFilePath().utf16());
416
417 switch (type) {
418 case DRIVE_REMOVABLE:
419 return d->getIcon(QStyle::SP_DriveFDIcon);
420 case DRIVE_FIXED:
421 return d->getIcon(QStyle::SP_DriveHDIcon);
422 case DRIVE_REMOTE:
423 return d->getIcon(QStyle::SP_DriveNetIcon);
424 case DRIVE_CDROM:
425 return d->getIcon(QStyle::SP_DriveCDIcon);
426 case DRIVE_RAMDISK:
427 case DRIVE_UNKNOWN:
428 case DRIVE_NO_ROOT_DIR:
429 default:
430 return d->getIcon(QStyle::SP_DriveHDIcon);
431 }
432 }
433#elif defined(Q_WS_PM)
434 {
435 UCHAR ioc_parm[2];
436 BIOSPARAMETERBLOCK bpb;
437 ioc_parm[0] = 0;
438 ioc_parm[1] = info.absoluteFilePath().at(0).cell() - 'A';
439 APIRET arc = DosDevIOCtl((HFILE) - 1, IOCTL_DISK, DSK_GETDEVICEPARAMS,
440 ioc_parm, sizeof(ioc_parm), NULL,
441 &bpb, sizeof(bpb), NULL);
442
443 if (arc == ERROR_NOT_SUPPORTED)
444 return d->getIcon(QStyle::SP_DriveNetIcon);
445
446 if (arc == NO_ERROR && bpb.bDeviceType != DEVTYPE_FIXED) {
447 if (bpb.fsDeviceAttr & 0x10) // floppy format
448 return d->getIcon(QStyle::SP_DriveFDIcon);
449 if (!(bpb.fsDeviceAttr & 0x08)) // partitionable removable
450 return d->getIcon(QStyle::SP_DriveCDIcon);
451 }
452
453 return d->getIcon(QStyle::SP_DriveHDIcon);
454 }
455#else
456 return d->getIcon(QStyle::SP_DriveHDIcon);
457#endif
458 if (info.isFile()) {
459 if (info.isSymLink())
460 return d->getIcon(QStyle::SP_FileLinkIcon);
461 else
462 return d->getIcon(QStyle::SP_FileIcon);
463 }
464 if (info.isDir()) {
465 if (info.isSymLink()) {
466 return d->getIcon(QStyle::SP_DirLinkIcon);
467 } else {
468 if (info.absoluteFilePath() == d->homePath) {
469 return d->getIcon(QStyle::SP_DirHomeIcon);
470 } else {
471 return d->getIcon(QStyle::SP_DirIcon);
472 }
473 }
474 }
475 return QIcon();
476}
477
478/*!
479 Returns the type of the file described by \a info.
480*/
481
482QString QFileIconProvider::type(const QFileInfo &info) const
483{
484 if (info.isRoot())
485 return QApplication::translate("QFileDialog", "Drive");
486 if (info.isFile()) {
487 if (!info.suffix().isEmpty())
488 return info.suffix() + QLatin1Char(' ') + QApplication::translate("QFileDialog", "File");
489 return QApplication::translate("QFileDialog", "File");
490 }
491
492 if (info.isDir())
493#ifdef Q_WS_WIN
494 return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer");
495#else
496 return QApplication::translate("QFileDialog", "Folder", "All other platforms");
497#endif
498 // Windows - "File Folder"
499 // OS X - "Folder"
500 // Konqueror - "Folder"
501 // Nautilus - "folder"
502
503 if (info.isSymLink())
504#ifdef Q_OS_MAC
505 return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder");
506#else
507 return QApplication::translate("QFileDialog", "Shortcut", "All other platforms");
508#endif
509 // OS X - "Alias"
510 // Windows - "Shortcut"
511 // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to
512 // Nautilus - "link to folder" or "link to object file", same as Konqueror
513
514 return QApplication::translate("QFileDialog", "Unknown");
515}
516
517QT_END_NAMESPACE
518
519#endif
Note: See TracBrowser for help on using the repository browser.