#
# Machekku Open FileTransfer-Item Menu
#
# Version: 0.1
# Date: 2005-05-13
#
# http://machekku.uaznia.net/jabber/psi/patches/
#
# filetransdlg.cpp |  148 +++++++++++++++++++++++++++++++++++++++++++++++++------
# filetransdlg.h   |    4 +
# 2 files changed, 135 insertions(+), 17 deletions(-)
#
diff -X exclude -x src.pro -x *.diff -Naru psi_cvs-2005.05.08/psi/src/filetransdlg.cpp psi/psi/src/filetransdlg.cpp
--- psi_cvs-2005.05.08/psi/src/filetransdlg.cpp	Mon Feb 28 15:11:10 2005
+++ psi/psi/src/filetransdlg.cpp	Fri May 13 04:38:04 2005
@@ -28,6 +28,10 @@
 #include"psiiconset.h"
 #include"msgmle.h"

+#ifdef Q_OS_WIN
+#	include <qt_windows.h>
+#endif
+
 #if QT_VERSION >= 0x030200
 typedef Q_UINT64 LARGE_TYPE;
 #else
@@ -129,7 +133,7 @@
 	FileTransfer *ft;
 	S5BConnection *c;
 	Jid peer;
-	QString fileName, saveName;
+	QString fileName, saveName, fullPath;
 	Q_LLONG fileSize, sent, offset, length;
 	QString desc;
 	bool sending;
@@ -185,6 +189,7 @@
 	d->peer = to;
 	QFileInfo fi(fname);
 	d->fileName = fi.fileName();
+	d->fullPath = fi.absFilePath();
 	d->fileSize = fi.size(); // TODO: large file support
 	d->desc = desc;
 	d->shift = calcShift(d->fileSize);
@@ -253,6 +258,17 @@
 	return d->saveName;
 }

+/*!
+	Returns full path of the file being sent
+	or full path where the file is being saved
+	(including ".part" before the transfer is finished)
+*/
+
+QString FileTransferHandler::fullPath() const
+{
+	return d->fullPath;
+}
+
 void FileTransferHandler::accept(const QString &saveName, const QString &fileName, Q_LLONG offset)
 {
 	if(d->sending)
@@ -262,6 +278,7 @@
 	d->offset = offset;
 	d->length = d->fileSize;
 	d->f.setName(saveName);
+	d->fullPath = QFileInfo(d->f).absFilePath();
 	d->ft->accept(offset);
 }

@@ -920,6 +937,7 @@
 	QPixmap icon;
 	bool sending;
 	QString name;
+	QString path;
 	Q_LLONG size;
 	QString peer;
 	QString rate;
@@ -929,15 +947,18 @@
 	int timeRemaining;
 	int id;
 	int dist;
-	bool done;
+	bool done;		// done = file is no longer being transferred: maybe it finished or maybe there was an error
+	bool finished;	// finished = file transfer finished with a success :)
 	QString error;

-	FileTransItem(QListView *parent, const QString &_name, Q_LLONG _size, const QString &_peer, bool _sending)
+	FileTransItem(QListView *parent, const QString &_name, const QString &_path, Q_LLONG _size, const QString &_peer, bool _sending)
 	:QListViewItem(parent)
 	{
 		done = false;
+		finished = false;
 		sending = _sending;
 		name = _name;
+		path = _path;
 		size = _size;
 		peer = _peer;
 		rate = FileTransDlg::tr("N/A");
@@ -1266,6 +1287,7 @@
 	:QListView(parent, name), QToolTip(viewport())
 	{
 		connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)), this, SLOT(qlv_contextMenuRequested(QListViewItem *, const QPoint &, int)));
+		connect(this, SIGNAL(doubleClicked(QListViewItem *, const QPoint &, int)), this, SLOT(qlv_doubleClicked(QListViewItem *, const QPoint &, int)));
 	}

 	void maybeTip(const QPoint &pos)
@@ -1287,6 +1309,7 @@

 signals:
 	void itemCancel(int id);
+	void itemOpen(int id);
 	void itemOpenDest(int id);
 	void itemClear(int id);

@@ -1301,17 +1324,25 @@
 		QPopupMenu p;
 		p.insertItem(tr("&Cancel"), 0);
 		p.insertSeparator();
-		//p.insertItem(tr("&Open Destination Folder"), 1);
+#ifdef Q_OS_WIN	// FIX-ME: Open menu items - need to implement on other systems
+		p.insertItem(tr("&Open"), 3);
+		p.insertItem(tr("Open Containing &Folder"), 1);
+#endif
 		p.insertItem(tr("Cl&ear"), 2);

-		if(i->done) {
+		if ( i->done ) {
 			p.setItemEnabled(0, false);
 		}
 		else {
-			//p.setItemEnabled(1, false);
 			p.setItemEnabled(2, false);
 		}

+		if ( !i->sending && !i->finished || i->path.isEmpty() ) {
+#ifdef Q_OS_WIN	// FIX-ME: Open menu items - need to implement on other systems
+			p.setItemEnabled(3, false);
+#endif
+		}
+
 		int x = p.exec(pos);

 		// TODO: what if item is deleted during exec?
@@ -1324,6 +1355,28 @@
 			itemOpenDest(i->id);
 		else if(x == 2)
 			itemClear(i->id);
+		else if(x == 3)
+			itemOpen(i->id);
+	}
+
+	/*!
+		Internal slot invoked when item \a item is doubleclicked.
+		It opens the file associated with this item
+		(unless it is still being received).
+	*/
+
+	void qlv_doubleClicked(QListViewItem *item, const QPoint &, int)
+	{
+		if( !item )
+			return;
+
+		FileTransItem *i = static_cast<FileTransItem*>(item);
+
+		if( (i->sending || i->finished) && !i->path.isEmpty() ) {
+#ifdef Q_OS_WIN	// FIX-ME: Open menu items - need to implement on other systems
+			itemOpen(i->id);
+#endif
+		}
 	}

 private:
@@ -1462,6 +1515,7 @@
 		if(done) {
 			FileTransItem *fi = findItem(i->id);
 			fi->done = true;
+			fi->finished = true;
 		}

 		parent->setProgress(i->id, i->p, i->h->totalSteps(), i->sent, bps, updateAll);
@@ -1475,6 +1529,7 @@
 			}

 			PsiAccount *pa = i->h->account();
+			const int id = i->id;
 			transferList.removeRef(i);
 
 			if(recv) {
@@ -1488,8 +1543,13 @@
 				if(!dir.rename(fi.fileName(), fname)) {
 					// TODO: display some error about renaming
 				}
+				else {
+		     		FileTransItem *fi = findItem(id);
+		     		fi->path = dir.absFilePath(fname);
+				}
 			}
 
+
 			pa->playSound(option.onevent[eFTComplete]);
 		}
 	}
@@ -1512,6 +1572,7 @@
 	QVBoxLayout *vb = new QVBoxLayout(this, 11, 6);
 	d->lv = new FileTransView(this);
 	connect(d->lv, SIGNAL(itemCancel(int)), SLOT(itemCancel(int)));
+	connect(d->lv, SIGNAL(itemOpen(int)), SLOT(itemOpen(int)));
 	connect(d->lv, SIGNAL(itemOpenDest(int)), SLOT(itemOpenDest(int)));
 	connect(d->lv, SIGNAL(itemClear(int)), SLOT(itemClear(int)));
 	vb->addWidget(d->lv);
@@ -1543,10 +1604,10 @@
 	delete d;
 }
 
-int FileTransDlg::addItem(const QString &filename, Q_LLONG size, const QString &peer, bool sending)
+int FileTransDlg::addItem(const QString &filename, const QString &fullpath, Q_LLONG size, const QString &peer, bool sending)
 {
 	int id = d->findFreeId();
-	FileTransItem *i = new FileTransItem(d->lv, filename, size, peer, sending);
+	FileTransItem *i = new FileTransItem(d->lv, filename, fullpath, size, peer, sending);
 	if(sending)
 		i->icon = IconsetFactory::icon("psi/upload").impix().pixmap();
 	else
@@ -1611,7 +1672,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->fullPath(), h->fileSize(), peer, (h->mode() == FileTransferHandler::Sending));
 	i->p = p;
 	i->sent = sent;
 	d->transferList.append(i);
@@ -1691,16 +1752,71 @@
 	delete fi;
 }
 
+/*!
+	Opens a file which has id \a id on the list of file transfers.
+*/
+
+void FileTransDlg::itemOpen(int id)
+{
+	FileTransItem *fi = d->findItem(id);
+
+	const QString path = fi->path;
+
+	if ( path.isEmpty() )
+		return;
+
+#ifdef Q_OS_WIN	// FIX-ME: Open menu items - need to implement on other systems
+
+	const QString ext = QFileInfo(path).extension(false);
+	const QString dangerousExtensions = ";exe;bat;com;reg;vbs;wsh;";	// TO-DO: any other ideas?
+
+	if ( dangerousExtensions.find(QRegExp(";" + ext + ";")) >= 0
+		&& QMessageBox::question(this, tr("Warning"), QString(tr("Files with '%1' extension may be dangerous.\n"
+				"Are you sure you want to open this file?")).arg(ext),
+				QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes ) {
+
+		return;
+	}
+
+    int x;
+
+	QT_WA( {
+		x = (int)ShellExecute( 0, 0, (TCHAR*)path.ucs2(), 0, 0, SW_SHOWNORMAL );
+	} , {
+		x = (int)ShellExecuteA( 0, 0, path.local8Bit(), 0, 0, SW_SHOWNORMAL );
+	} );
+
+	if ( x == SE_ERR_NOASSOC ) {
+		QMessageBox::critical(this, tr("Error"), QString("There is no application associated with '%1' file type.").arg(ext));
+	}
+
+#endif
+
+}
+
+/*!
+	Opens a directory containing file
+	having id \a id on the list of file transfers.
+*/
+
 void FileTransDlg::itemOpenDest(int id)
 {
-	TransferMapping *i = d->findMapping(id);
+	FileTransItem *fi = d->findItem(id);
 
-	QString path;
-	bool recv = (i->h->mode() == FileTransferHandler::Receiving);
-	if(recv)
-		path = QFileInfo(i->h->saveName()).dirPath();
-	else
-		path = QFileInfo(i->h->fileName()).dirPath();
+	const QString path = QFileInfo(fi->path).dirPath();
+
+   	if ( path.isEmpty() )
+		return;
+
+#ifdef Q_OS_WIN	// FIX-ME: Open menu items - need to implement on other systems
+
+	QT_WA( {
+		ShellExecute( 0, 0, (TCHAR*)path.ucs2(), 0, 0, SW_SHOWNORMAL );
+	} , {
+		ShellExecuteA( 0, 0, path.local8Bit(), 0, 0, SW_SHOWNORMAL );
+	} );
+
+#endif
 
 	//printf("item open dest: [%s]\n", path.latin1());
 }
diff -X exclude -x src.pro -x *.diff -Naru psi_cvs-2005.05.08/psi/src/filetransdlg.h psi/psi/src/filetransdlg.h
--- psi_cvs-2005.05.08/psi/src/filetransdlg.h	Wed Jun 30 13:51:30 2004
+++ psi/psi/src/filetransdlg.h	Fri May 13 02:31:00 2005
@@ -36,6 +36,7 @@
 	int totalSteps() const;
 	bool resumeSupported() const;
 	QString saveName() const;
+	QString fullPath() const;
 
 	void send(const Jid &to, const QString &fname, const QString &desc);
 	void accept(const QString &saveName, const QString &fileName, Q_LLONG offset=0);
@@ -114,7 +115,7 @@
 	FileTransDlg(PsiCon *);
 	~FileTransDlg();
 
-	int addItem(const QString &filename, Q_LLONG size, const QString &peer, bool sending);
+	int addItem(const QString &filename, const QString &fullpath, Q_LLONG size, const QString &peer, bool sending);
 	void setProgress(int id, int step, int total, Q_LLONG sent, int bytesPerSecond, bool updateAll=false);
 	void setError(int id, const QString &reason);
 	void removeItem(int id);
@@ -129,6 +130,7 @@
 	void updateItems();
 
 	void itemCancel(int);
+	void itemOpen(int);
 	void itemOpenDest(int);
 	void itemClear(int);

