[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kopete-devel
Subject:    [kopete-devel] [PATCH] Incoming file transfer in chat window
From:       "Roman Jarosz" <roman.jarosz () gmail ! com>
Date:       2008-08-15 21:53:34
Message-ID: op.ufx63kvnrj95b0 () localhost
[Download RAW message or body]

Hi

I've removed the ugly dialog which is shown when we got file transfer
request and moved it into the chat window.

It's based on Adium chat style (FileTransferRequest.html) although to make
it more user friendly I had to add four new keywords %fileSize%,
%saveFileHandlerId%, %saveFileAsHandlerId%, %cancelRequestHandlerId%.
The three id keywords are used to disable buttons after file transfer
is accepted or rejected.

If current style doesn't have FileTransferRequest.html Kopete creates
default one based on current chat style.

Here are screenshots:
http://kedge.wz.cz/kopete/kopeteft1.png
http://kedge.wz.cz/kopete/kopeteft2.png
http://kedge.wz.cz/kopete/kopeteft3.png

Any comments or suggestions?

Regards,
Roman

PS. Currently there is a bug in khtml which paints disabled buttons as active.
I've already reported this bug. Also there was a bug which has sent click events
even if the button was disabled this bug is already fixed since revision 846734.
Oh and also button accelerators don't work yet also reported to khtml guys.

["ftchatrequest.diff" (ftchatrequest.diff)]

Index: kopete/chatwindow/kopetechatwindowstyle.cpp
===================================================================
--- kopete/chatwindow/kopetechatwindowstyle.cpp	(revision 846204)
+++ kopete/chatwindow/kopetechatwindowstyle.cpp	(working copy)
@@ -27,6 +27,7 @@
 
 // KDE includes
 #include <kdebug.h>
+#include <klocale.h>
 #include <kstandarddirs.h>
 
 class ChatWindowStyle::Private
@@ -46,6 +47,7 @@
 	QString statusHtml;
 	QString actionIncomingHtml;
 	QString actionOutgoingHtml;
+	QString fileTransferIncomingHtml;
 	QHash<QString, bool> compactVariants;
 };
 
@@ -153,6 +155,11 @@
 	return d->actionOutgoingHtml;
 }
 
+QString ChatWindowStyle::getFileTransferIncomingHtml() const
+{
+	return d->fileTransferIncomingHtml;
+}
+
 bool ChatWindowStyle::hasActionTemplate() const
 {
 	return ( !d->actionIncomingHtml.isEmpty() && !d->actionOutgoingHtml.isEmpty() );
@@ -199,6 +206,7 @@
 	QString statusFile = d->baseHref + QString("Status.html");
 	QString actionIncomingFile = d->baseHref + QString("Incoming/Action.html");
 	QString actionOutgoingFile = d->baseHref + QString("Outgoing/Action.html");
+	QString fileTransferIncomingFile = d->baseHref + \
QString("Incoming/FileTransferRequest.html");  
 	QFile fileAccess;
 	// First load header file.
@@ -301,6 +309,36 @@
 		kDebug(14000) << "ActionOutgoing HTML: " << d->actionOutgoingHtml;
 		fileAccess.close();
 	}
+	// Load FileTransfer Incoming file
+	if( QFile::exists(fileTransferIncomingFile) )
+	{
+		fileAccess.setFileName(fileTransferIncomingFile);
+		fileAccess.open(QIODevice::ReadOnly);
+		QTextStream headerStream(&fileAccess);
+		headerStream.setCodec(QTextCodec::codecForName("UTF-8"));
+		d->fileTransferIncomingHtml = headerStream.readAll();
+		kDebug(14000) << "fileTransferIncoming HTML: " << d->fileTransferIncomingHtml;
+		fileAccess.close();
+	}
+	else
+	{	// Create default html
+		d->fileTransferIncomingHtml = d->incomingHtml;
+		QString message = QString( "%message%\n"
+		                           "<div>\n"
+		                           " <div style=\"width:37px; float:left;\">\n"
+		                           "  <img src=\"%fileIconPath%\" style=\"width:32px; \
height:32px; vertical-align:middle;\" />\n" +		                           " </div>\n"
+		                           " <div>\n"
+		                           "  <span><b>%fileName%</b> (%fileSize%)</span><br>\n"
+		                           "  <span>\n"
+		                           "   <input id=\"%saveFileAsHandlerId%\" type=\"button\" \
onClick=\"%saveFileAsHandler%\" value=\"%1\">\n" +		                           "   \
<input id=\"%cancelRequestHandlerId%\" type=\"button\" \
onClick=\"%cancelRequestHandler%\" value=\"%2\">\n" +		                           "  \
</span>\n" +		                           " </div>\n"
+		                           "</div>" )
+		                           .arg( i18n( "Download" ), i18n( "Cancel" ) );
+		d->fileTransferIncomingHtml.replace( QLatin1String("%message%"), message );
+	}
 }
 
 void ChatWindowStyle::reload()
Index: kopete/chatwindow/chatmessagepart.cpp
===================================================================
--- kopete/chatwindow/chatmessagepart.cpp	(revision 846204)
+++ kopete/chatwindow/chatmessagepart.cpp	(working copy)
@@ -35,6 +35,7 @@
 #include <QtCore/QTextCodec>
 #include <QtCore/QTextStream>
 #include <QtCore/QTimer>
+#include <QtCore/QBuffer>
 #include <QtGui/QClipboard>
 #include <QtGui/QCursor>
 #include <QtGui/QPixmap>
@@ -50,6 +51,7 @@
 #include <dom/html_base.h>
 #include <dom/html_document.h>
 #include <dom/html_inline.h>
+#include <dom/html_form.h>
 
 
 // KDE includes
@@ -87,6 +89,7 @@
 #include "kopeteappearancesettings.h"
 #include "kopetebehaviorsettings.h"
 #include "kopetechatwindowsettings.h"
+#include "kopetetransfermanager.h"
 
 #include "kopetechatwindowstyle.h"
 #include "kopetechatwindowstylemanager.h"
@@ -201,12 +204,14 @@
 
 	kDebug(14000) << d->currentChatStyle->getStyleName();
 
+	// File transfer js
+	setJScriptEnabled( true );
+	setOnlyLocalReferences( false );
+
 	//Security settings, we don't need this stuff
-	setJScriptEnabled( false ) ;
 	setJavaEnabled( false );
 	setPluginsEnabled( false );
 	setMetaRefreshEnabled( false );
-	setOnlyLocalReferences( true );
 
 	// Write the template to KHTMLPart
 	writeTemplate();
@@ -235,6 +240,9 @@
 	connect( view()->verticalScrollBar(), SIGNAL(sliderMoved(int)),
 	         this, SLOT(slotScrollingTo(int)) );
 
+	connect( Kopete::TransferManager::transferManager(), \
SIGNAL(askIncomingDone(unsigned int)), +	         this, \
SLOT(slotFileTransferIncomingDone(unsigned int)) ); +	
 	//initActions
 	d->copyAction = KStandardAction::copy( this, SLOT(copy()), actionCollection() );
 	d->saveAction = KStandardAction::saveAs( this, SLOT(save()), actionCollection() );
@@ -331,14 +339,41 @@
 		if ( contact )
 			contact->execute();
 	}
-	else
+	else if ( url.protocol() == QLatin1String("kopeteftsave") )
 	{
-		KRun *runner = new KRun( url, 0, false ); // false = non-local files
+		Kopete::TransferManager::transferManager()->saveIncomingTransfer( \
url.host().toInt() ); +	}
+	else if ( url.protocol() == QLatin1String("kopeteftsaveas") )
+	{
+		Kopete::TransferManager::transferManager()->saveIncomingTransfer( \
url.host().toInt() ); +	}
+	else if ( url.protocol() == QLatin1String("kopeteftcancel") )
+	{
+		Kopete::TransferManager::transferManager()->cancelIncomingTransfer( \
url.host().toInt() ); +	}
+	else if ( url.protocol() != QLatin1String("file") )
+	{
+		KRun *runner = new KRun( url, 0, 0, false ); // false = non-local files
 		runner->setRunExecutables( false ); //security
 		//KRun autodeletes itself by default when finished.
 	}
 }
 
+void ChatMessagePart::slotFileTransferIncomingDone( unsigned int fileTransferId )
+{
+	QList<Kopete::Message>::Iterator it = d->allMessages.end();
+	while ( it != d->allMessages.begin() )
+	{
+		--it;
+		if ( (*it).fileTransferId() == fileTransferId )
+		{
+			(*it).setFileTransferDisabled( true );
+			disabledFileTransferButtons( fileTransferId );
+			break;
+		}
+	}
+}
+
 void ChatMessagePart::readOverrides()
 {
 	d->bgOverride = Kopete::AppearanceSettings::self()->chatBgOverride();
@@ -415,7 +450,9 @@
 	// Group only if the user want it.
 	if( KopeteChatWindowSettings::self()->groupConsecutiveMessages() )
 	{
-		isConsecutiveMessage = (message.direction() == d->latestDirection && \
!d->latestContact.isNull() && d->latestContact == message.from() && message.type() == \
d->latestType); +		isConsecutiveMessage = (message.direction() == d->latestDirection \
&& !d->latestContact.isNull() +		                        && d->latestContact == \
message.from() && message.type() == d->latestType +		                        && \
message.type() != Kopete::Message::TypeFileTransfer );  }
 
 	// Don't test it in the switch to don't break consecutive messages.
@@ -442,6 +479,10 @@
 			formattedMessageHtml = d->currentChatStyle->getStatusHtml();
 		}
 	}
+	else if(message.type() == Kopete::Message::TypeFileTransfer)
+	{
+		formattedMessageHtml = d->currentChatStyle->getFileTransferIncomingHtml();
+	}
 	else
 	{
 		switch(message.direction())
@@ -502,6 +543,9 @@
 		chatNode.appendChild(newMessageNode);
 	}
 
+	if ( message.type() == Kopete::Message::TypeFileTransfer && \
message.fileTransferDisabled() ) +		disabledFileTransferButtons( \
message.fileTransferId() ); +
 	// Keep the direction to see on next message
 	// if it's a consecutive message
 	// Keep also the from() contact.
@@ -842,18 +886,18 @@
 
 
 	// Replace sender (contact nick)
-	resultHTML = resultHTML.replace( QLatin1String("%sender%"), nickLink+nick+"</a>" );
+	resultHTML.replace( QLatin1String("%sender%"), nickLink+nick+"</a>" );
 	// Replace time, by default display only time and display seconds(that was true \
means).  if ( Kopete::BehaviorSettings::showDates() )
-		resultHTML = resultHTML.replace( QLatin1String("%time%"), \
KGlobal::locale()->formatDateTime(message.timestamp(), KLocale::ShortDate, true) ); \
+		resultHTML.replace( QLatin1String("%time%"), \
KGlobal::locale()->formatDateTime(message.timestamp(), KLocale::ShortDate, true) );  \
                else
-		resultHTML = resultHTML.replace( QLatin1String("%time%"), \
KGlobal::locale()->formatTime(message.timestamp().time(), true) ); \
+		resultHTML.replace( QLatin1String("%time%"), \
KGlobal::locale()->formatTime(message.timestamp().time(), true) );  // Replace \
                %screenName% (contact ID)
-	resultHTML = resultHTML.replace( QLatin1String("%senderScreenName%"), \
nickLink+Qt::escape(contactId)+"</a>" ); +	resultHTML.replace( \
QLatin1String("%senderScreenName%"), nickLink+Qt::escape(contactId)+"</a>" );  // \
                Replace service name (protocol name)
-	resultHTML = resultHTML.replace( QLatin1String("%service%"), Qt::escape(service) );
+	resultHTML.replace( QLatin1String("%service%"), Qt::escape(service) );
 	// Replace protocolIcon (sender statusIcon)
-	resultHTML = resultHTML.replace( QLatin1String("%senderStatusIcon%"), \
Qt::escape(protocolIcon).replace('"',"&quot;") ); +	resultHTML.replace( \
QLatin1String("%senderStatusIcon%"), Qt::escape(protocolIcon).replace('"',"&quot;") \
);  
 	// Look for %time{X}%
 	QRegExp timeRegExp("%time\\{([^}]*)\\}%");
@@ -861,7 +905,7 @@
 	while( (pos=timeRegExp.indexIn(resultHTML , pos) ) != -1 )
 	{
 		QString timeKeyword = formatTime( timeRegExp.cap(1), message.timestamp() );
-		resultHTML = resultHTML.replace( pos , timeRegExp.cap(0).length() , timeKeyword );
+		resultHTML.replace( pos , timeRegExp.cap(0).length() , timeKeyword );
 	}
 
 	// Look for %textbackgroundcolor{X}%
@@ -878,7 +922,7 @@
 	int textPos=0;
 	while( (textPos=textBackgroundRegExp.indexIn(resultHTML, textPos) ) != -1 )
 	{
-		resultHTML = resultHTML.replace( textPos , textBackgroundRegExp.cap(0).length() , \
bgColor ); +		resultHTML.replace( textPos , textBackgroundRegExp.cap(0).length() , \
bgColor );  }
 
 	// Replace userIconPath
@@ -892,7 +936,7 @@
 			else if(message.direction() == Kopete::Message::Outbound)
 				photoPath = d->currentChatStyle->getStyleBaseHref() + \
QLatin1String("Outgoing/buddy_icon.png");  }
-		resultHTML = resultHTML.replace(QLatin1String("%userIconPath%"), photoPath);
+		resultHTML.replace(QLatin1String("%userIconPath%"), photoPath);
 	}
 
 	// Replace messages.
@@ -907,7 +951,7 @@
 	}
 
 	// Set message direction("rtl"(Right-To-Left) or "ltr"(Left-to-right))
-	resultHTML = resultHTML.replace( QLatin1String("%messageDirection%"), \
message.isRightToLeft() ? "rtl" : "ltr" ); +	resultHTML.replace( \
QLatin1String("%messageDirection%"), message.isRightToLeft() ? "rtl" : "ltr" );  
 	// These colors are used for coloring nicknames. I tried to use
 	// colors both visible on light and dark background.
@@ -943,12 +987,38 @@
 		if ( doLight && lightColorName.isNull() )
 			lightColorName = QColor( colorName ).light( light ).name();
 
-		resultHTML = resultHTML.replace( textPos , senderColorRegExp.cap(0).length(),
+		resultHTML.replace( textPos , senderColorRegExp.cap(0).length(),
 			doLight ? lightColorName : colorName );
 	}
 
+	if ( message.type() == Kopete::Message::TypeFileTransfer )
+	{
+		QString saveLink = QString("document.location.href='kopeteftsave://%1/';").arg( \
message.fileTransferId() ); +		QString saveAsLink = \
QString("document.location.href='kopeteftsaveas://%1/';").arg( \
message.fileTransferId() ); +		QString cancelLink = \
QString("document.location.href='kopeteftcancel://%1/';").arg( \
message.fileTransferId() ); +
+		QString fileIcon;
+		QPixmap preview = ( !message.filePreview().isNull() ) ? message.filePreview() : \
SmallIcon( "unknown", KIconLoader::SizeMedium ); +		QByteArray tempArray;
+		QBuffer tempBuffer( &tempArray );
+		tempBuffer.open( QIODevice::WriteOnly );
+		if( preview.save( &tempBuffer, "PNG" ) )
+			fileIcon = QString( "data:image/png;base64," ) + tempArray.toBase64();
+
+		resultHTML.replace( QLatin1String("%fileName%"), Qt::escape( message.fileName() \
).replace('"',"&quot;") ); +		resultHTML.replace( QLatin1String("%fileSize%"), \
KGlobal::locale()->formatByteSize( message.fileSize() / 8 ).replace('"',"&quot;") ); \
+		resultHTML.replace( QLatin1String("%fileIconPath%"), fileIcon ); \
+		resultHTML.replace( QLatin1String("%saveFileHandler%"), saveLink ); \
+		resultHTML.replace( QLatin1String("%saveFileAsHandler%"), saveAsLink ); \
+		resultHTML.replace( QLatin1String("%cancelRequestHandler%"), cancelLink ); +		
+		resultHTML.replace( QLatin1String("%saveFileHandlerId%"), QString( "ftS%1" ).arg( \
message.fileTransferId() ) ); +		resultHTML.replace( \
QLatin1String("%saveFileAsHandlerId%"), QString( "ftSA%1" ).arg( \
message.fileTransferId() ) ); +		resultHTML.replace( \
QLatin1String("%cancelRequestHandlerId%"), QString( "ftC%1" ).arg( \
message.fileTransferId() ) ); +	}
+
 	// Replace message at the end, maybe someone could put a Adium keyword in his \
                message :P
-	resultHTML = resultHTML.replace( QLatin1String("%message%"), \
formatMessageBody(message) ); +	resultHTML.replace( QLatin1String("%message%"), \
formatMessageBody(message) );  
 	// TODO: %status
 //	resultHTML = addNickLinks( resultHTML );
@@ -975,13 +1045,13 @@
 			destinationName = remoteContact->nickName();
 
 		// Replace %chatName%, create a internal span to update it by DOM when asked.
-		resultHTML = resultHTML.replace( QLatin1String("%chatName%"), QString("<span \
id=\"KopeteHeaderChatNameInternal\">%1</span>").arg( \
formatName(d->manager->displayName(), Qt::RichText) ) ); +		resultHTML.replace( \
QLatin1String("%chatName%"), QString("<span \
id=\"KopeteHeaderChatNameInternal\">%1</span>").arg( \
formatName(d->manager->displayName(), Qt::RichText) ) );  // Replace %sourceName%
-		resultHTML = resultHTML.replace( QLatin1String("%sourceName%"), \
formatName(sourceName, Qt::RichText) ); +		resultHTML.replace( \
QLatin1String("%sourceName%"), formatName(sourceName, Qt::RichText) );  // Replace \
                %destinationName%
-		resultHTML = resultHTML.replace( QLatin1String("%destinationName%"), \
formatName(destinationName, Qt::RichText) ); +		resultHTML.replace( \
QLatin1String("%destinationName%"), formatName(destinationName, Qt::RichText) );  // \
                For %timeOpened%, display the date and time (also the seconds).
-		resultHTML = resultHTML.replace( QLatin1String("%timeOpened%"), \
KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), KLocale::ShortDate, \
true ) ); +		resultHTML.replace( QLatin1String("%timeOpened%"), \
KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), KLocale::ShortDate, \
true ) );  
 		// Look for %timeOpened{X}%
 		QRegExp timeRegExp("%timeOpened\\{([^}]*)\\}%");
@@ -989,7 +1059,7 @@
 		while( (pos=timeRegExp.indexIn(resultHTML, pos) ) != -1 )
 		{
 			QString timeKeyword = formatTime( timeRegExp.cap(1), QDateTime::currentDateTime() \
                );
-			resultHTML = resultHTML.replace( pos , timeRegExp.cap(0).length() , timeKeyword \
); +			resultHTML.replace( pos , timeRegExp.cap(0).length() , timeKeyword );
 		}
 		// Get contact image paths
 		QString photoIncoming = photoForContact( remoteContact );
@@ -1004,8 +1074,8 @@
 			photoOutgoing = d->currentChatStyle->getStyleBaseHref() + \
QLatin1String("Outgoing/buddy_icon.png");  }
 
-		resultHTML = resultHTML.replace( QLatin1String("%incomingIconPath%"), \
                photoIncoming );
-		resultHTML = resultHTML.replace( QLatin1String("%outgoingIconPath%"), \
photoOutgoing ); +		resultHTML.replace( QLatin1String("%incomingIconPath%"), \
photoIncoming ); +		resultHTML.replace( QLatin1String("%outgoingIconPath%"), \
photoOutgoing );  }
 
 	return resultHTML;
@@ -1202,6 +1272,24 @@
 	return photo;
 }
 
+void ChatMessagePart::disabledFileTransferButtons( unsigned int fileTransferId )
+{
+	QString elementId = QString( "ftS%1" ).arg( fileTransferId );
+	DOM::HTMLInputElement element = document().getElementById( elementId );
+	if ( !element.isNull() )
+		element.setDisabled( true );
+	
+	elementId = QString( "ftSA%1" ).arg( fileTransferId );
+	element = document().getElementById( elementId );
+	if ( !element.isNull() )
+		element.setDisabled( true );
+	
+	elementId = QString( "ftC%1" ).arg( fileTransferId );
+	element = document().getElementById( elementId );
+	if ( !element.isNull() )
+		element.setDisabled( true );
+}
+
 #include "chatmessagepart.moc"
 
 // vim: set noet ts=4 sts=4 sw=4:
Index: kopete/chatwindow/kopetechatwindowstyle.h
===================================================================
--- kopete/chatwindow/kopetechatwindowstyle.h	(revision 846204)
+++ kopete/chatwindow/kopetechatwindowstyle.h	(working copy)
@@ -96,6 +96,8 @@
 	QString getActionIncomingHtml() const;
 	QString getActionOutgoingHtml() const;
 
+	QString getFileTransferIncomingHtml() const;
+
 	/**
 	 * Check if the style has the support for Kopete Action template (Kopete extension)
 	 * @return true if the style has Action template.
Index: kopete/chatwindow/chatmessagepart.h
===================================================================
--- kopete/chatwindow/chatmessagepart.h	(revision 846204)
+++ kopete/chatwindow/chatmessagepart.h	(working copy)
@@ -156,6 +156,7 @@
 
 private slots:
 	void slotOpenURLRequest( const KUrl &url, const KParts::OpenUrlArguments &, const \
KParts::BrowserArguments & ); +	void slotFileTransferIncomingDone( unsigned int \
fileTransferId );  void slotScrollView();
 	void slotAppearanceChanged();
 
@@ -264,6 +265,8 @@
 	 */
 	QString photoForContact( const Kopete::Contact *contact ) const;
 
+	void disabledFileTransferButtons( unsigned int fileTransferId );
+
 	class Private;
 	Private *d;
 };
Index: libkopete/kopetemessage.cpp
===================================================================
--- libkopete/kopetemessage.cpp	(revision 846204)
+++ libkopete/kopetemessage.cpp	(working copy)
@@ -49,7 +49,7 @@
 	Private()
 		: direction(Internal), format(Qt::PlainText), type(TypeNormal), \
                importance(Normal), backgroundOverride(false),
 		  foregroundOverride(false), richTextOverride(false), isRightToLeft(false), \
                timeStamp( QDateTime::currentDateTime() ),
-		  body(new QTextDocument), escapedBodyDirty(true)
+		  body(new QTextDocument), escapedBodyDirty(true), fileTransferId(0), \
fileTransferDisabled(false), fileSize(0)  {}
 	Private (const Private &other);
 	~Private();
@@ -78,6 +78,12 @@
 	QTextDocument* body;
 	mutable QString escapedBody;
 	mutable bool escapedBodyDirty;
+
+	uint fileTransferId;
+	bool fileTransferDisabled;
+	QString fileName;
+	unsigned long fileSize;
+	QPixmap filePreview;
 };
 
 Message::Private::Private (const Message::Private &other)
@@ -107,6 +113,12 @@
 	body = other.body->clone();
 	escapedBody = other.escapedBody;
 	escapedBodyDirty = other.escapedBodyDirty;
+
+	fileTransferId = other.fileTransferId;
+	fileTransferDisabled = other.fileTransferDisabled;
+	fileName = other.fileName;
+	fileSize = other.fileSize;
+	filePreview = other.filePreview;
 }
 
 Message::Private::~Private ()
@@ -558,6 +570,56 @@
 	return styleAttribute;
 }
 
+void Message::setFileTransferId( uint id )
+{
+	d->fileTransferId = id;
+}
+
+uint Message::fileTransferId() const
+{
+	return d->fileTransferId;
+}
+
+void Message::setFileTransferDisabled( bool disabled )
+{
+	d->fileTransferDisabled = disabled;
+}
+
+bool Message::fileTransferDisabled() const
+{
+	return d->fileTransferDisabled;
+}
+
+void Message::setFileName( const QString &fileName )
+{
+	d->fileName = fileName;
+}
+
+QString Message::fileName() const
+{
+	return d->fileName;
+}
+
+void Message::setFileSize( unsigned long size )
+{
+	d->fileSize = size;
+}
+
+unsigned long Message::fileSize() const
+{
+	return d->fileSize;
+}
+
+void Message::setFilePreview( const QPixmap &preview )
+{
+	d->filePreview = preview;
+}
+
+QPixmap Message::filePreview() const
+{
+	return d->filePreview;
+}
+
 // prime candidate for removal
 #if 0 
 QString Message::decodeString( const QByteArray &message, const QTextCodec \
                *providedCodec, bool *success )
Index: libkopete/kopetetransfermanager.h
===================================================================
--- libkopete/kopetetransfermanager.h	(revision 846204)
+++ libkopete/kopetetransfermanager.h	(working copy)
@@ -42,8 +42,11 @@
 public:
 	enum KopeteTransferDirection { Incoming, Outgoing };
 
+	FileTransferInfo();
 	FileTransferInfo( Contact *, const QString&, const unsigned long size, const \
QString &, KopeteTransferDirection di, const unsigned int id, QString \
internalId=QString(), const QPixmap &preview=QPixmap() );  ~FileTransferInfo() {}
+
+	bool isValid() const { return (mContact && mId > 0); }
 	unsigned int transferId() const { return mId; }
 	Contact* contact() const { return mContact; }
 	QString file() const { return mFile; }
@@ -82,10 +85,23 @@
 	 * @brief Adds a file transfer to the Kopete::TransferManager
 	 */
 	Transfer *addTransfer( Contact *contact, const QString& file, const unsigned long \
size, const QString &recipient , FileTransferInfo::KopeteTransferDirection di); +
+	/**
+	 * @brief Adds incoming file transfer request to the Kopete::TransferManager.
+	 **/
 	int askIncomingTransfer( Contact *contact, const QString& file, const unsigned long \
size, const QString& description=QString(), QString internalId=QString(), const \
                QPixmap &preview=QPixmap());
-	void removeTransfer( unsigned int id );
 
 	/**
+	 * @brief Shows save file dialog and accepts/rejects incoming file transfer \
request. +	 **/
+	void saveIncomingTransfer( unsigned int id );
+
+	/**
+	 * @brief Cancels incoming file transfer request.
+	 **/
+	void cancelIncomingTransfer( unsigned int id );
+
+	/**
 	 * @brief Ask the user which file to send when they click Send File.
 	 *
 	 * Possibly ask the user which file to send when they click Send File. Sends a \
signal indicating KUrl to @@ -116,18 +132,23 @@
 	/** @brief Signals the transfer has been rejected */
 	void refused(const Kopete::FileTransferInfo& );
 
+	/** @brief Signals the incoming transfer has been rejected or accepted */
+	void askIncomingDone( unsigned int id );
+
 	/** @brief Send a file */
 	void sendFile(const KUrl &file, const QString &localFile, unsigned int fileSize);
 
 private slots:
-	void slotAccepted(const Kopete::FileTransferInfo&, const QString&);
 	void slotComplete(KJob*);
 
 private:
 	TransferManager( QObject *parent );
 
-	int nextID;
+	void removeTransfer( unsigned int id );
+
+	unsigned int nextID;
 	QMap<unsigned int, Transfer *> mTransfersMap;
+	QMap<unsigned int, FileTransferInfo> mTransferRequestInfoMap;
 };
 
 /**
Index: libkopete/kopetetransfermanager.cpp
===================================================================
--- libkopete/kopetetransfermanager.cpp	(revision 846204)
+++ libkopete/kopetetransfermanager.cpp	(working copy)
@@ -30,12 +30,18 @@
 #include "kopeteuiglobal.h"
 
 #include "kopetetransfermanager.h"
-#include "kopetefileconfirmdialog.h"
 
 /***************************
  *  Kopete::FileTransferInfo *
  ***************************/
 
+Kopete::FileTransferInfo::FileTransferInfo()
+{
+	mId = 0;
+	mContact = 0;
+	mSize = 0;
+}
+
 Kopete::FileTransferInfo::FileTransferInfo(  Kopete::Contact *contact, const \
QString& file, const unsigned long size, const QString &recipient, \
KopeteTransferDirection di, const unsigned int id, QString internalId, const QPixmap \
&preview)  {
 	mContact = contact;
@@ -203,8 +209,7 @@
 
 Kopete::Transfer* Kopete::TransferManager::addTransfer(  Kopete::Contact *contact, \
const QString& file, const unsigned long size, const QString &recipient , \
Kopete::FileTransferInfo::KopeteTransferDirection di)  {
-//	if (nextID != 0)
-		nextID++;
+	nextID++;
 	Kopete::FileTransferInfo info(contact, file, size, recipient,di,  nextID);
 	Kopete::Transfer *trans = new Kopete::Transfer(info, contact);
 	connect(trans, SIGNAL(result(KJob *)), this, SLOT(slotComplete(KJob *)));
@@ -212,36 +217,89 @@
 	return trans;
 }
 
-void Kopete::TransferManager::slotAccepted(const Kopete::FileTransferInfo& info, \
const QString& filename) +int Kopete::TransferManager::askIncomingTransfer( \
Kopete::Contact *contact, const QString& file, const unsigned long size, const \
QString& description, QString internalId, const QPixmap &preview )  {
-	Kopete::Transfer *trans = new Kopete::Transfer(info, filename);
-	connect(trans, SIGNAL(result(KJob *)), this, SLOT(slotComplete(KJob *)));
-	mTransfersMap.insert(info.transferId(), trans);
-	emit accepted(trans,filename);
+	Kopete::ChatSession *cs = contact->manager( Kopete::Contact::CanCreate );
+	if ( !cs )
+		return 0;
+	
+	nextID++;
+	QString dn = contact ? (contact->metaContact() ? \
contact->metaContact()->displayName() : contact->contactId()) : i18n("<unknown>"); +	
+	Kopete::FileTransferInfo info( contact, file, size, dn, \
Kopete::FileTransferInfo::Incoming, nextID, internalId, preview ); \
+	mTransferRequestInfoMap.insert( nextID, info ); +	
+	Kopete::Message msg( contact, cs->myself() );
+	msg.setType( Kopete::Message::TypeFileTransfer );
+	msg.setDirection( Kopete::Message::Inbound );
+	msg.setPlainBody( description );
+	msg.setFileTransferId( nextID );
+	msg.setFileName( file );
+	msg.setFileSize( size );
+	msg.setFilePreview( preview );
+	cs->appendMessage( msg );
+	
+	return nextID;
 }
 
-int Kopete::TransferManager::askIncomingTransfer(  Kopete::Contact *contact, const \
QString& file, const unsigned long size, const QString& description, QString \
internalId, const QPixmap &preview) +void \
Kopete::TransferManager::saveIncomingTransfer( unsigned int id )  {
-//	if (nextID != 0)
-		nextID++;
+	Kopete::FileTransferInfo info = mTransferRequestInfoMap.value( id );
+	if ( !info.isValid() )
+		return;
 
-	QString dn= contact ? (contact->metaContact() ? \
contact->metaContact()->displayName() : contact->contactId()) : i18n("<unknown>"); \
+	KConfigGroup cg( KGlobal::config(), "File Transfer" ); +	const QString defaultPath \
= cg.readEntry( "defaultPath", QDir::homePath() ); +	KUrl url = defaultPath + \
QLatin1String( "/" ) + info.file();  
-	Kopete::FileTransferInfo info(contact, file, size, dn, \
Kopete::FileTransferInfo::Incoming , nextID , internalId, preview); +	for ( ;; )
+	{
+		url = KFileDialog::getSaveUrl( url, QLatin1String( "*" ), 0, i18n( "File Transfer" \
) ); +		if ( !url.isValid() )
+		{
+			emit askIncomingDone( id );
+			emit refused( info );
+			mTransferRequestInfoMap.remove( id );
+			return;
+		}
+		
+		if ( !url.isLocalFile() )
+		{
+			KMessageBox::queuedMessageBox( 0, KMessageBox::Sorry, i18n( "You must provide a \
valid local filename" ) ); +			continue;
+		}
 
-	//FIXME!!! this will not be deleted if it's still open when kopete exits
-	KopeteFileConfirmDialog *diag= new KopeteFileConfirmDialog(info, description , 0 )  \
; +		if ( QFile::exists( url.path() ) )
+		{
+			int ret = KMessageBox::warningContinueCancel( 0, i18n( "The file '%1' already \
exists.\nDo you want to overwrite it ?", url.path() ), +			                           \
i18n( "Overwrite File" ), KStandardGuiItem::save() ); +			if ( ret == \
KMessageBox::Cancel ) +				continue;
+		}
+		break;
+	}
 
-	connect( diag, SIGNAL( accepted(const Kopete::FileTransferInfo&, const QString&)) , \
                this, SLOT( slotAccepted(const Kopete::FileTransferInfo&, const \
                QString&) ) );
-	connect( diag, SIGNAL( refused(const Kopete::FileTransferInfo&)) , this, SIGNAL( \
                refused(const Kopete::FileTransferInfo&) ) );
-	diag->show();
-	return nextID;
+	const QString directory = url.directory();
+	if( !directory.isEmpty() )
+		cg.writeEntry( "defaultPath", directory );
+
+	Kopete::Transfer *trans = new Kopete::Transfer( info, url.path() );
+	connect( trans, SIGNAL(result(KJob *)), this, SLOT(slotComplete(KJob *)) );
+	mTransfersMap.insert( info.transferId(), trans );
+	emit askIncomingDone( id );
+	emit accepted( trans, url.path() );
+	mTransferRequestInfoMap.remove( id );
 }
 
-void Kopete::TransferManager::removeTransfer( unsigned int id )
+void Kopete::TransferManager::cancelIncomingTransfer( unsigned int id )
 {
-	mTransfersMap.remove(id);
-	//we don't need to delete the job, the job get deleted itself
+	Kopete::FileTransferInfo info = mTransferRequestInfoMap.value( id );
+	if ( !info.isValid() )
+		return;
+
+	emit askIncomingDone( id );
+	emit refused( info );
+	mTransferRequestInfoMap.remove( id );
 }
 
 void Kopete::TransferManager::slotComplete(KJob *job)
@@ -305,5 +363,11 @@
 	}
 }
 
+void Kopete::TransferManager::removeTransfer( unsigned int id )
+{
+	mTransfersMap.remove(id);
+	//we don't need to delete the job, the job get deleted itself
+}
+
 #include "kopetetransfermanager.moc"
 
Index: libkopete/kopetemessage.h
===================================================================
--- libkopete/kopetemessage.h	(revision 846204)
+++ libkopete/kopetemessage.h	(working copy)
@@ -34,6 +34,7 @@
 class QTextCodec;
 class QTextDocument;
 class QStringList;
+class QPixmap;
 
 namespace Kopete {
 
@@ -96,7 +97,8 @@
 	enum MessageType
 	{
 		TypeNormal, ///< A typical message
-		TypeAction ///< An IRC-style action.
+		TypeAction, ///< An IRC-style action.
+		TypeFileTransfer ///< A incoming file transfer request message
 	};
 
 	/**
@@ -382,8 +384,68 @@
 	 * @return A string formatted like this: "style=attr"
 	 */
 	QString getHtmlStyleAttribute() const;
-	
+
 	/**
+	 * @brief Set file transfer id
+	 * @param id file transfer id
+	 */
+	void setFileTransferId( uint id );
+
+	/**
+	 * @brief Accessor method for the file transfer id
+	 * @return file transfer id
+	 */
+	uint fileTransferId() const;
+
+	/**
+	 * @brief Set the state of incoming file transfer
+	 * @param disabled flag to indicate if the file transfer request should be enabled \
or disabled. +	 */
+	void setFileTransferDisabled( bool disabled );
+
+	/**
+	 * @brief Accessor method for the file transfer state
+	 * @return if file transfer request should be enable or disable
+	 */
+	bool fileTransferDisabled() const;
+
+	/**
+	 * @brief Set file name of incoming file transfer
+	 * @param fileName file name
+	 */
+	void setFileName( const QString &fileName );
+
+	/**
+	 * @brief Accessor method for the file name of incoming file transfer
+	 * @return file name of incoming file transfer
+	 */
+	QString fileName() const;
+
+	/**
+	 * @brief Set file transfer size
+	 * @param size file transfer size
+	 */
+	void setFileSize( unsigned long size );
+
+	/**
+	 * @brief Accessor method for the file transfer size
+	 * @return file transfer size
+	 */
+	unsigned long fileSize() const;
+
+	/**
+	 * @brief Set file preview icon for file transfer
+	 * @param preview file preview icon
+	 */
+	void setFilePreview( const QPixmap &preview );
+
+	/**
+	 * @brief Accessor method for the file preview icon
+	 * @return file preview icon
+	 */
+	QPixmap filePreview() const;
+
+	/**
 	 * @return The list of classes
 	 * Class are used to give different notification on a message. They are also used \
                in the chatwindow as an HTML class 
 	 */
Index: libkopete/CMakeLists.txt
===================================================================
--- libkopete/CMakeLists.txt	(revision 846204)
+++ libkopete/CMakeLists.txt	(working copy)
@@ -43,7 +43,6 @@
   ui/collapsiblewidget.cpp
   ui/editaccountwidget.cpp
   ui/kopetecontactaction.cpp
-  ui/kopetefileconfirmdialog.cpp
   ui/kopeteinfodialog.cpp
   ui/kopetelistview.cpp
   ui/kopetelistviewitem.cpp
@@ -131,7 +130,6 @@
  ui/addressbookselectorwidget_base.ui
  ui/avatarselectorwidget.ui
  ui/contactaddednotifywidget.ui
- ui/fileconfirmbase.ui
  ui/kopeteawaydialogbase.ui
  ui/kopetepasswordwidgetbase.ui
  ui/metacontactselectorwidget_base.ui
@@ -167,7 +165,6 @@
 ########### install files ###############
 
 install(FILES
- ${CMAKE_CURRENT_BINARY_DIR}/ui_fileconfirmbase.h
  ${CMAKE_CURRENT_BINARY_DIR}/ui_kopeteawaydialogbase.h
  ${CMAKE_CURRENT_BINARY_DIR}/ui_kopetepasswordwidgetbase.h
  ui/accountselector.h
@@ -178,7 +175,6 @@
  ui/avatarselectorwidget.h
  ui/editaccountwidget.h
  ui/kopetecontactaction.h
- ui/kopetefileconfirmdialog.h
  ui/kopeteinfodialog.h
  ui/kopetelistview.h
  ui/kopetelistviewitem.h



_______________________________________________
kopete-devel mailing list
kopete-devel@kde.org
https://mail.kde.org/mailman/listinfo/kopete-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic