#
# Machekku Show file icons in Transfer Manager on Windows
#
# Version: 0.2
# Date: 2006-12-05
#
# filetransdlg.cpp                               |   52 ++++++++++----
# filetransdlg.h                                 |    4 -
# src.pri                                        |    1
# tools/desktoputil/desktoputil.cpp              |   46 ++++++++++++
# tools/desktoputil/desktoputil.h                |   11 +++
# tools/desktoputil/desktoputil.pri              |    9 ++
# tools/desktoputil/third-party/qt_hicon_win.cpp |   91 +++++++++++++++++++++++++
# tools/desktoputil/third-party/qt_hicon_win.h   |    7 +
# 8 files changed, 207 insertions(+), 14 deletions(-)
#
diff -rN -u old-psi-ft-tmp-2/src/filetransdlg.cpp new-psi-ft-tmp-2/src/filetransdlg.cpp
--- old-psi-ft-tmp-2/src/filetransdlg.cpp	2006-12-05 03:08:46.078125000 +0100
+++ new-psi-ft-tmp-2/src/filetransdlg.cpp	2006-12-05 03:08:50.375000000 +0100
@@ -39,6 +39,7 @@
 #include "psitooltip.h"
 #include "psicontactlist.h"
 #include "accountlabel.h"
+#include "desktoputil.h"
 
 typedef Q_UINT64 LARGE_TYPE;
 
@@ -138,6 +139,7 @@
 	S5BConnection *c;
 	Jid peer;
 	QString fileName, saveName;
+	QString filePath;	// full file path, but without ".part"
 	qlonglong fileSize, sent, offset, length;
 	QString desc;
 	bool sending;
@@ -192,6 +194,7 @@
 
 	d->peer = to;
 	QFileInfo fi(fname);
+	d->filePath = fname;
 	d->fileName = fi.fileName();
 	d->fileSize = fi.size(); // TODO: large file support
 	d->desc = desc;
@@ -233,6 +236,12 @@
 	return d->fileSize;
 }
 
+QPixmap FileTransferHandler::fileIcon() const
+{
+	return DesktopUtil::getFileIcon(d->filePath, !d->sending && d->sent < d->fileSize, true);
+			// use generic icon when still receiving the file
+}
+
 QString FileTransferHandler::description() const
 {
 	return d->desc;
@@ -266,6 +275,8 @@
 	if(d->sending)
 		return;
 	d->fileName = fileName;
+	d->filePath = saveName;
+	d->filePath.chop(5);	// remove ".part"
 	d->saveName = saveName;
 	d->offset = offset;
 	d->length = d->fileSize;
@@ -953,7 +964,7 @@
 class FileTransItem : public Q3ListViewItem
 {
 public:
-	QPixmap icon;
+	QPixmap icon, fileicon;
 	bool sending;
 	QString name;
 	qlonglong size;
@@ -1233,9 +1244,19 @@
 		p->fillRect(0, 0, width, h, br);
 
 		// icon
-		p->drawPixmap(m, m + yoff, icon);
-		int tm = m + icon.width() + 4;
-		tw = tw - (icon.width() + 4);
+		int fullIconWidth;
+		if(!fileicon.isNull()) {
+			fullIconWidth = fileicon.width() + icon.width()/2;
+			p->drawPixmap(m, m + yoff, fileicon);
+			p->drawPixmap(m + fullIconWidth - icon.width(), m + yoff + fileicon.height() - icon.height()/2, icon);
+		}
+		else {
+			fullIconWidth = icon.width();
+			p->drawPixmap(m, m + yoff, icon);
+		}
+
+		int tm = m + fullIconWidth + 4;
+		tw = tw - (fullIconWidth + 4);
 
 		// filename / peer
 		if(isSelected())
@@ -1511,20 +1532,13 @@
 			fi->done = true;
 		}
 
-		parent->setProgress(i->id, i->p, i->h->totalSteps(), i->sent, bps, updateAll);
-
 		if(done) {
 			bool recv = (i->h->mode() == FileTransferHandler::Receiving);
 			QString fname, savename;
 			if(recv) {
 				fname = i->h->fileName();
 				savename = i->h->saveName();
-			}
-
-			PsiAccount *pa = i->h->account();
-			transferList.removeRef(i);
 
-			if(recv) {
 				//printf("fname: [%s], savename: [%s]\n", fname.latin1(), savename.latin1());
 
 				// rename .part to original filename
@@ -1535,10 +1549,19 @@
 				if(!dir.rename(fi.fileName(), fname)) {
 					// TODO: display some error about renaming
 				}
+
+				findItem(i->id)->fileicon = i->h->fileIcon();
 			}
 
+			PsiAccount *pa = i->h->account();
 			pa->playSound(option.onevent[eFTComplete]);
 		}
+
+		parent->setProgress(i->id, i->p, i->h->totalSteps(), i->sent, bps, updateAll);
+
+		if(done) {
+			transferList.removeRef(i);
+		}
 	}
 };
 
@@ -1590,7 +1613,7 @@
 	delete d;
 }
 
-int FileTransDlg::addItem(const QString &filename, qlonglong size, const QString &peer, bool sending)
+int FileTransDlg::addItem(const QString &filename, const QPixmap &fileicon, qlonglong size, const QString &peer, bool sending)
 {
 	int id = d->findFreeId();
 	FileTransItem *i = new FileTransItem(d->lv, filename, size, peer, sending);
@@ -1598,6 +1621,9 @@
 		i->icon = IconsetFactory::icon("psi/upload").impix().pixmap();
 	else
 		i->icon = IconsetFactory::icon("psi/download").impix().pixmap();
+
+	i->fileicon = fileicon;
+
 	i->id = id;
 	d->t.start(1000);
 	return id;
@@ -1658,7 +1684,7 @@
 
 	TransferMapping *i = new TransferMapping;
 	i->h = h;
-	i->id = addItem(h->fileName(), h->fileSize(), peer, (h->mode() == FileTransferHandler::Sending));
+	i->id = addItem(h->fileName(), h->fileIcon(), h->fileSize(), peer, (h->mode() == FileTransferHandler::Sending));
 	i->p = p;
 	i->sent = sent;
 	d->transferList.append(i);
diff -rN -u old-psi-ft-tmp-2/src/filetransdlg.h new-psi-ft-tmp-2/src/filetransdlg.h
--- old-psi-ft-tmp-2/src/filetransdlg.h	2006-12-05 03:08:46.046875000 +0100
+++ new-psi-ft-tmp-2/src/filetransdlg.h	2006-12-05 03:08:50.375000000 +0100
@@ -2,6 +2,7 @@
 #define FILETRANSDLG_H
 
 #include <QKeyEvent>
+#include <QPixmap>
 
 #include "xmpp_jid.h"
 #include "ui_filetrans.h"
@@ -34,6 +35,7 @@
 	int totalSteps() const;
 	bool resumeSupported() const;
 	QString saveName() const;
+	QPixmap fileIcon() const;
 
 	void send(const Jid &to, const QString &fname, const QString &desc);
 	void accept(const QString &saveName, const QString &fileName, qlonglong offset=0);
@@ -113,7 +115,7 @@
 	FileTransDlg(PsiCon *);
 	~FileTransDlg();
 
-	int addItem(const QString &filename, qlonglong size, const QString &peer, bool sending);
+	int addItem(const QString &filename, const QPixmap &fileicon, qlonglong size, const QString &peer, bool sending);
 	void setProgress(int id, int step, int total, qlonglong sent, int bytesPerSecond, bool updateAll=false);
 	void setError(int id, const QString &reason);
 	void removeItem(int id);
diff -rN -u old-psi-ft-tmp-2/src/src.pri new-psi-ft-tmp-2/src/src.pri
--- old-psi-ft-tmp-2/src/src.pri	2006-12-05 03:08:45.875000000 +0100
+++ new-psi-ft-tmp-2/src/src.pri	2006-12-05 03:08:52.046875000 +0100
@@ -13,6 +13,7 @@
 include($$PWD/tools/spellchecker/spellchecker.pri)
 include($$PWD/tools/contactlist/contactlist.pri)
 include($$PWD/tools/grepshortcutkeydlg/grepshortcutkeydlg.pri)
+include($$PWD/tools/desktoputil/desktoputil.pri)
 
 # Growl
 mac {
diff -rN -u old-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.cpp new-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.cpp
--- old-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.cpp	1970-01-01 01:00:00.000000000 +0100
+++ new-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.cpp	2006-12-05 03:08:52.671875000 +0100
@@ -0,0 +1,46 @@
+#include "desktoputil.h"
+
+#include <QFileInfo>
+
+/**
+ * \brief Returns icon of the given file.
+ * \param path, path to the file
+ * \param genericIcon, retrieve the icon basing just on file type
+ * \param largeIcon, retrieve large image
+ *
+ * If the file does not exist, a generic icon is always returned.
+ *
+ * To retrieve icon for a given file extension, simply provide ".extension" as \a path
+ * and set \a genericIcon to true.
+ */
+QPixmap DesktopUtil::getFileIcon(const QString &path, bool genericIcon, bool largeIcon)
+{
+	QPixmap icon;
+
+#ifdef Q_WS_WIN
+
+	SHFILEINFO sfi;
+
+	QFileInfo fi(path);
+	QString iconPath = path;
+
+	UINT flags = SHGFI_ICON;
+	flags |= largeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON;
+
+	if (genericIcon || !fi.exists()) {
+		flags |= SHGFI_USEFILEATTRIBUTES;
+		iconPath = "." + fi.suffix();
+	}
+	else {
+		iconPath.replace('/', '\\');
+	}
+
+	if (SHGetFileInfo(iconPath.utf16(), FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO), flags)) {
+		icon = HIconUtil::convertHIconToPixmap(sfi.hIcon);
+		DestroyIcon(sfi.hIcon);
+	}
+
+#endif
+
+	return icon;
+}
diff -rN -u old-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.h new-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.h
--- old-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.h	1970-01-01 01:00:00.000000000 +0100
+++ new-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.h	2006-12-05 03:08:52.671875000 +0100
@@ -0,0 +1,11 @@
+#include <QPixmap>
+#include <QString>
+
+#ifdef Q_WS_WIN
+#include "third-party/qt_hicon_win.h"
+#endif
+
+namespace DesktopUtil
+{
+	QPixmap getFileIcon(const QString &path, bool genericIcon = false, bool largeIcon = true);
+};
diff -rN -u old-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.pri new-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.pri
--- old-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.pri	1970-01-01 01:00:00.000000000 +0100
+++ new-psi-ft-tmp-2/src/tools/desktoputil/desktoputil.pri	2006-12-05 03:08:52.687500000 +0100
@@ -0,0 +1,9 @@
+HEADERS += $$PWD/desktoputil.h
+SOURCES += $$PWD/desktoputil.cpp
+INCLUDEPATH += $$PWD
+DEPENDPATH  += $$PWD
+
+win32: {
+	HEADERS += $$PWD/third-party/qt_hicon_win.h
+	SOURCES += $$PWD/third-party/qt_hicon_win.cpp
+}
diff -rN -u old-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.cpp new-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.cpp
--- old-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.cpp	1970-01-01 01:00:00.000000000 +0100
+++ new-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.cpp	2006-12-05 03:08:52.718750000 +0100
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file.  Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.trolltech.com/products/qt/opensource.html
+**
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://www.trolltech.com/products/qt/licensing.html or contact the
+** sales department at sales@trolltech.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+/* From Qt 4.1.3, qwindowsstyle.cpp */
+
+#include "qt_hicon_win.h"
+
+QPixmap HIconUtil::convertHIconToPixmap(const HICON icon)
+{
+    bool foundAlpha = false;
+    HDC screenDevice = qt_win_display_dc();
+    HDC hdc = CreateCompatibleDC(screenDevice);
+
+    ICONINFO iconinfo;
+    GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center
+
+    //create image
+    HBITMAP winBitmap = CreateBitmap(iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 1, 32, 0);
+    HGDIOBJ oldhdc = SelectObject(hdc, winBitmap);
+    DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL);
+    QPixmap::HBitmapFormat alphaType = QPixmap::PremultipliedAlpha;
+
+    BITMAP bitmapData;
+    GetObject(iconinfo.hbmColor, sizeof(BITMAP), &bitmapData);
+
+    QPixmap iconpixmap = QPixmap::fromWinHBITMAP(winBitmap, alphaType);
+    QImage img = iconpixmap.toImage();
+
+    if ( bitmapData.bmBitsPixel == 32 ) { //only check 32 bit images for alpha
+        for (int y = 0 ; y < iconpixmap.height() && !foundAlpha ; y++) {
+            QRgb *scanLine= reinterpret_cast<QRgb *>(img.scanLine(y));
+            for (int x = 0; x < img.width() ; x++) {
+                if (qAlpha(scanLine[x]) != 0) {
+                    foundAlpha = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!foundAlpha) {
+        //If no alpha was found, we use the mask to set alpha values
+        HBITMAP winMask = CreateBitmap(iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 1, 32, 0);
+        SelectObject(hdc, winMask);
+        DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_MASK);
+
+        QPixmap maskPixmap = QPixmap::fromWinHBITMAP(winMask, alphaType);
+        QImage mask = maskPixmap.toImage();
+
+        for (int y = 0 ; y< iconpixmap.height() ; y++){
+            QRgb *scanlineImage = reinterpret_cast<QRgb *>(img.scanLine(y));
+            QRgb *scanlineMask = reinterpret_cast<QRgb *>(mask.scanLine(y));
+            for (int x = 0; x < img.width() ; x++){
+                if (qRed(scanlineMask[x]) != 0)
+                    scanlineImage[x] = 0; //mask out this pixel
+                else
+                    scanlineImage[x] |= 0xff000000; // set the alpha channel to 255
+            }
+        }
+        DeleteObject(winMask);
+    }
+
+    //dispose resources created by iconinfo call
+    DeleteObject(iconinfo.hbmMask);
+    DeleteObject(iconinfo.hbmColor);
+
+    SelectObject(hdc, oldhdc); //restore state
+    DeleteDC(hdc);
+    DeleteObject(winBitmap);
+    return QPixmap::fromImage(img);
+}
diff -rN -u old-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.h new-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.h
--- old-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.h	1970-01-01 01:00:00.000000000 +0100
+++ new-psi-ft-tmp-2/src/tools/desktoputil/third-party/qt_hicon_win.h	2006-12-05 03:08:52.734375000 +0100
@@ -0,0 +1,7 @@
+#include <QPixmap>
+#include <windows.h>
+
+namespace HIconUtil
+{
+	QPixmap convertHIconToPixmap(const HICON icon);
+};

