Psi Jabber Client

See this page for instructions on how to use Flyspray: http://psi-im.org/wiki/Flyspray

Please Note!

Please do not create tasks here without discussing your bug or feature request on the forums or groupchat psi@conference.psi-im.org, *and* getting explicit confirmation by a developer to add it to flyspray.
Tasklist

FS#531 - Add 'Save as' context menu for vcard photo

Attached to Project: Psi Jabber Client
Opened by Remko Tronçon (spike) - Sunday, 05 February 2006, 13:44 GMT-5
Task Type Feature Request
Category UserInterface
Status Assigned
Assigned To Dmitriy Erlih (KkKKk)
Operating System All
Severity Low
Priority Fluff
Reported Version 0.10
Due in Version Undecided
Due Date Undecided
Percent Complete 0%
Votes 0
Private No

Details

Add 'Save as' context menu for vcard photo.
This task depends upon

View Dependency Graph

Comment by duryodhan (duryodhan) - Saturday, 09 February 2008, 09:21 GMT-5
A context menu (right click menu) to the image would involve subclassing qlabel and creating something like QClickableLabel, which would cause a significant churn. A simpler and cleaner alternative is a button in the ui called save image. This should be pretty easy to implement. What do you think?
Comment by zet (zet) - Saturday, 09 February 2008, 14:07 GMT-5
for example, patch from dion ( http://bombus-im.org/zet/psi/patches/psi-vcard-save.diff ):

<code>
Index: trunk/src/infodlg.cpp
===================================================================
--- trunk.orig/src/infodlg.cpp 2007-11-22 20:25:31.000000000 +0200
+++ trunk/src/infodlg.cpp 2007-11-22 20:26:08.000000000 +0200
@@ -95,6 +95,7 @@
connect(ui_.pb_refresh, SIGNAL(clicked()), this, SLOT(updateStatus()));
connect(ui_.te_desc, SIGNAL(textChanged()), this, SLOT(textChanged()));
connect(ui_.pb_open, SIGNAL(clicked()), this, SLOT(selectPhoto()));
+ connect(ui_.pb_save, SIGNAL(clicked()), this, SLOT(savePhoto()));
connect(ui_.pb_clear, SIGNAL(clicked()), this, SLOT(clearPhoto()));
connect(ui_.pb_close, SIGNAL(clicked()), this, SLOT(close()));

@@ -273,6 +274,7 @@
img_scaled = img;
}
ui_.label_photo->setPixmap(QPixmap(img_scaled));
+ ui_.pb_save->show();
}

void InfoDlg::fieldsEnable(bool x)
@@ -517,6 +519,26 @@
}

/**
+ * Opens a file browser dialog, and if selected, save photo from vcard
+*/
+void InfoDlg::savePhoto()
+{
+ if (!d->photo.isEmpty()) {
+ if (PsiOptions::instance()->getOption("options.ui.last-used-open-path").toString().isEmpty())
+ PsiOptions::instance()->getOption("options.ui.last-used-open-path").toString() = QDir::homeDirPath();
+ QString str=QFileDialog::getSaveFileName(this, tr("Save photo"), PsiOptions::instance()->getOption("options.ui.last-used-open-path").toString(), tr("Images (*.png *.xpm *.jpg *.PNG *.XPM *.JPG"));
+ if (!str.isEmpty())
+ {
+ QFileInfo fi(str);
+ PsiOptions::instance()->getOption("options.ui.last-used-open-path").toString()=fi.dirPath();
+ // Convert imge if required
+ QImage img(d->photo);
+ img.save(str);
+ }
+ }
+}
+
+/**
* Loads the image from the requested URL, and inserts the resized image into the preview box.
* \param path image file to load
*/
@@ -546,6 +568,7 @@

// the picture changed, so notify there are some changes done
d->te_edited = true;
+ ui_.pb_save->hide();
}

/**
Index: trunk/src/infodlg.h
===================================================================
--- trunk.orig/src/infodlg.h 2007-11-22 20:25:11.000000000 +0200
+++ trunk/src/infodlg.h 2007-11-22 20:26:08.000000000 +0200
@@ -63,6 +63,7 @@
void doSubmit();
void textChanged();
void selectPhoto();
+ void savePhoto();
void clearPhoto();

private:
Index: trunk/src/info.ui
===================================================================
--- trunk.orig/src/info.ui 2007-11-22 20:25:11.000000000 +0200
+++ trunk/src/info.ui 2007-11-22 20:26:08.000000000 +0200
@@ -160,6 +160,30 @@
</widget>
</item>
<item>
+ <widget class="QPushButton" name="pb_save" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>&amp;Save...</string>
+ </property>
+ <property name="shortcut" >
+ <string>Alt+S</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>false</bool>
+ </property>
+ <property name="flat" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QPushButton" name="pb_clear" >
<property name="sizePolicy" >
<sizepolicy>
@@ -503,6 +527,7 @@
<tabstop>le_homepage</tabstop>
<tabstop>le_email</tabstop>
<tabstop>pb_open</tabstop>
+ <tabstop>pb_save</tabstop>
<tabstop>pb_clear</tabstop>
<tabstop>pb_submit</tabstop>
<tabstop>pb_refresh</tabstop>
</code>
Comment by duryodhan (duryodhan) - Sunday, 10 February 2008, 04:55 GMT-5
I haven't applied this patch, but looking at the source, it seems that there is the possibility of the button being active when there is no image and then clicking on the button will give nothing. (based on +void InfoDlg::savePhoto()
+{
+ if (!d->photo.isEmpty()) {)

...

maybe you could change that so that the button is disabled when the image isn't present.
Comment by duryodhan (duryodhan) - Monday, 11 February 2008, 06:50 GMT-5
I found somewhere a class called MLabel (somewhere as in inside Psi , mainwin_p.cpp), maybe that could be used to implement the image , then the context menu could have the save as ...
Comment by Dmitriy Erlih (KkKKk) - Saturday, 01 March 2008, 09:32 GMT-5
I've added popup menu with "Save avatar" action, which is activeting on photo label's context menu event.
I think, photo label should have shape QFrame::Box and shadow QFrame::Plain for good looking.
This is the svn diff output:

Index: src/infodlg.cpp
===================================================================
--- src/infodlg.cpp (revision 1069)
+++ src/infodlg.cpp (working copy)
@@ -46,12 +46,22 @@
#include "psioptions.h"
#include "fileutil.h"

+#include <QMenu>
+#include "iconaction.h"
+
using namespace XMPP;

class InfoDlg::Private
{
public:
- Private() {}
+ Private() : saveAvatarMenu(new QMenu),
+ action(new IconAction(saveAvatarMenu,"save avatar action"))
+ {
+ action->setPsiIcon("psi/save");
+ action->setText(QObject::tr("Save avatar"));
+ saveAvatarMenu->addAction(action);
+ }
+ ~Private() { delete saveAvatarMenu; }

int type;
Jid jid;
@@ -64,6 +74,9 @@
bool cacheVCard;
QByteArray photo;
QList<QString> infoRequested;
+
+ QMenu* saveAvatarMenu;
+ IconAction *action;
};

InfoDlg::InfoDlg(int type, const Jid &j, const VCard &vcard, PsiAccount *pa, QWidget *parent, bool cacheVCard)
@@ -99,6 +112,12 @@
connect(ui_.pb_clear, SIGNAL(clicked()), this, SLOT(clearPhoto()));
connect(ui_.pb_close, SIGNAL(clicked()), this, SLOT(close()));

+ d->action->setStatusTip(QObject::tr("Save %1's avatar").arg(d->vcard.nickName()));
+ ui_.label_photo->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui_.label_photo, SIGNAL(customContextMenuRequested(const QPoint&)),
+ SLOT(saveAvatarMenu(const QPoint &)));
+ connect(d->action,SIGNAL(triggered()),SLOT(openSaveAvatarDialog()));
+
if(d->type == Self) {
connect(ui_.pb_submit, SIGNAL(clicked()), this, SLOT(doSubmit()));
}
@@ -632,3 +651,44 @@
updateStatus();
}
}
+
+/**
+ * Save avatar slots
+ */
+void InfoDlg::saveAvatarMenu(const QPoint & point)
+{
+ QAction *saveAvatarAction = d->saveAvatarMenu->actions().first();
+ if(d->photo.isEmpty())
+ saveAvatarAction->setEnabled(false);
+ else
+ saveAvatarAction->setEnabled(true);
+
+ d->saveAvatarMenu->popup(ui_.label_photo->mapToGlobal(point));
+}
+
+void InfoDlg::openSaveAvatarDialog()
+{
+ QString filePath = PsiOptions::instance()->getOption("options.ui.last-used-open-path").toString();
+ if(filePath.isEmpty())
+ filePath = QDir::homeDirPath();
+
+ QString fileName = QFileDialog::getSaveFileName(this, QString(),
+ filePath + "/" + d->vcard.nickName() + ".png",
+ tr("Images (*.png *.xpm *.jpg *.PNG *.XPM *.JPG"));
+
+ if(fileName.isEmpty())
+ return;
+
+ QFileInfo lastPath(fileName);
+ PsiOptions::instance()->getOption("options.ui.last-used-open-path").toString() = lastPath.dirPath();
+
+ QImage avatar;
+ if(!avatar.loadFromData(d->photo))
+ {
+ qDebug("Warning: Can't load data to QImage");
+ return;
+ }
+
+ if(!avatar.save(fileName))
+ QMessageBox::warning(this,tr("Unsupported file format"),tr("Can't save %1 (UNSUPPORTED FILE FORMAT)").arg(fileName));
+}
Index: src/infodlg.h
===================================================================
--- src/infodlg.h (revision 1069)
+++ src/infodlg.h (working copy)
@@ -53,6 +53,9 @@
void closeEvent ( QCloseEvent * e );
void setStatusVisibility(bool visible);

+ void saveAvatarMenu(const QPoint &);
+ void openSaveAvatarDialog();
+
private slots:
void contactAvailable(const Jid &, const Resource &);
void contactUnavailable(const Jid &, const Resource &);

Loading...