initial commit
This commit is contained in:
commit
9d20827c46
2469 changed files with 470994 additions and 0 deletions
16
src/.gitignore
vendored
Normal file
16
src/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/yachat
|
||||
/config.h
|
||||
/Makefile.Debug
|
||||
/Makefile.Release
|
||||
/debug
|
||||
/release
|
||||
/mocinclude.tmp
|
||||
/object_script.*
|
||||
/_rcc
|
||||
/_obj
|
||||
/vc70.pdb
|
||||
/vc70.idb
|
||||
/yachat.ncb
|
||||
/yachat.sln
|
||||
/yachat.suo
|
||||
/yachat.vcproj
|
||||
312
src/about.ui
Normal file
312
src/about.ui
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
<ui version="4.0" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>AboutDlg</class>
|
||||
<widget class="QDialog" name="AboutDlg" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>504</width>
|
||||
<height>320</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>About Psi</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="IconLabel" name="lb_icon" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/logo_48</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_name" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tw_tabs" >
|
||||
<widget class="QWidget" name="tab_about" >
|
||||
<attribute name="title" >
|
||||
<string>About</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_about" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>7</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>A cross-platform Jabber client designed for the Jabber power user.<br>
|
||||
<br>
|
||||
Copyright © 2001 - 2007 by Justin Karneges<br>
|
||||
</string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="URLLabel" name="uRLLabel1" >
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="url" >
|
||||
<string>http://psi-im.org</string>
|
||||
</property>
|
||||
<property name="title" >
|
||||
<string>http://psi-im.org</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_authors" >
|
||||
<attribute name="title" >
|
||||
<string>Authors</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="PsiTextView" name="te_authors" />
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_thanks" >
|
||||
<attribute name="title" >
|
||||
<string>Thanks To</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="PsiTextView" name="te_thanks" />
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_translation" >
|
||||
<attribute name="title" >
|
||||
<string>Translation</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="PsiTextView" name="te_translation" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>7</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_license" >
|
||||
<attribute name="title" >
|
||||
<string>License</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="te_license" >
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>418</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_close" >
|
||||
<property name="text" >
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
<property name="default" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>IconButton</class>
|
||||
<extends></extends>
|
||||
<header>iconbutton.h</header>
|
||||
<container>0</container>
|
||||
<pixmap></pixmap>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>IconLabel</class>
|
||||
<extends></extends>
|
||||
<header>iconlabel.h</header>
|
||||
<container>0</container>
|
||||
<pixmap></pixmap>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PsiTextView</class>
|
||||
<extends></extends>
|
||||
<header>psitextview.h</header>
|
||||
<container>0</container>
|
||||
<pixmap></pixmap>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>URLLabel</class>
|
||||
<extends></extends>
|
||||
<header>urllabel.h</header>
|
||||
<container>0</container>
|
||||
<pixmap></pixmap>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>pb_close</sender>
|
||||
<signal>clicked(bool)</signal>
|
||||
<receiver>AboutDlg</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>436</x>
|
||||
<y>295</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>369</x>
|
||||
<y>299</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
141
src/aboutdlg.cpp
Normal file
141
src/aboutdlg.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* aboutdlg.cpp
|
||||
* Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "applicationinfo.h"
|
||||
#include "aboutdlg.h"
|
||||
#include "textutil.h"
|
||||
|
||||
AboutDlg::AboutDlg(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
ui_.setupUi(this);
|
||||
|
||||
setModal(false);
|
||||
|
||||
ui_.lb_name->setText ( QString("<h3><b>%1 v%2</b></h3>").arg(ApplicationInfo::name()).arg(ApplicationInfo::version()) );
|
||||
|
||||
ui_.te_license->setText ( loadText(":/COPYING") );
|
||||
|
||||
QString lang_name = qApp->translate( "@default", "language_name" );
|
||||
if ( lang_name == "language_name" ) // remove the translation tab, if no translation is used
|
||||
ui_.tw_tabs->removePage ( ui_.tw_tabs->page(3) );
|
||||
|
||||
// fill in Authors tab...
|
||||
QString authors;
|
||||
authors += details(QString::fromUtf8("Justin Karneges"),
|
||||
"justin@affinix.com", "", "",
|
||||
tr("Founder and Original Author"));
|
||||
authors += details(QString::fromUtf8("Kevin Smith"),
|
||||
"kismith@psi-im.org", "", "",
|
||||
tr("Project Lead/Maintainer"));
|
||||
authors += details(QString::fromUtf8("Remko Tronçon"),
|
||||
"remko@psi-im.org", "", "",
|
||||
tr("Lead Developer"));
|
||||
authors += details(QString::fromUtf8("Michail Pishchagin"),
|
||||
"mblsha@psi-im.org", "", "",
|
||||
tr("Lead Widget Developer"));
|
||||
authors += details(QString::fromUtf8("Maciej Niedzielski"),
|
||||
"machekku@psi-im.org", "", "",
|
||||
tr("Developer"));
|
||||
authors += details(QString::fromUtf8("Martin Hostettler"),
|
||||
"martin@psi-im.org", "", "",
|
||||
tr("Developer"));
|
||||
authors += details(QString::fromUtf8("Akito Nozaki"),
|
||||
"anpluto@usa.net", "", "",
|
||||
tr("Miscellaneous Developer"));
|
||||
ui_.te_authors->setText( authors );
|
||||
|
||||
// fill in Thanks To tab...
|
||||
QString thanks;
|
||||
thanks += details(QString::fromUtf8("Jan Niehusmann"),
|
||||
"jan@gondor.com", "", "",
|
||||
tr("Build setup, miscellaneous assistance"));
|
||||
thanks += details(QString::fromUtf8("Everaldo Coelho"),
|
||||
"", "", "http://www.everaldo.com",
|
||||
tr("Many icons are from his Crystal icon theme"));
|
||||
thanks += details(QString::fromUtf8("Jason Kim"),
|
||||
"", "", "",
|
||||
tr("Graphics"));
|
||||
thanks += details(QString::fromUtf8("Hideaki Omuro"),
|
||||
"", "", "",
|
||||
tr("Graphics"));
|
||||
thanks += details(QString::fromUtf8("Bill Myers"),
|
||||
"", "", "",
|
||||
tr("Original Mac Port"));
|
||||
thanks += details(QString::fromUtf8("Eric Smith (Tarkvara Design, Inc.)"),
|
||||
"eric@tarkvara.org", "", "",
|
||||
tr("Mac OS X Port"));
|
||||
thanks += details(QString::fromUtf8("Tony Collins"),
|
||||
"", "", "",
|
||||
tr("Original End User Documentation"));
|
||||
thanks += details(QString::fromUtf8("Hal Rottenberg"),
|
||||
"", "", "",
|
||||
tr("Webmaster, Marketing"));
|
||||
thanks += details(QString::fromUtf8("Mircea Bardac"),
|
||||
"", "", "",
|
||||
tr("Bug Tracker Management"));
|
||||
thanks += details(QString::fromUtf8("Jacek Tomasiak"),
|
||||
"", "", "",
|
||||
tr("Patches"));
|
||||
|
||||
//thanks += tr("Thanks to many others.\n"
|
||||
// "The above list only reflects the contributors I managed to keep track of.\n"
|
||||
// "If you're not included but you think that you must be in the list, contact the developers.");
|
||||
ui_.te_thanks->setText( thanks );
|
||||
|
||||
QString translation = tr(
|
||||
"I. M. Anonymous <note text=\"replace with your real name\"><br>\n"
|
||||
" <a href=\"http://me.com\">http://me.com</a><br>\n"
|
||||
" Jabber: <a href=\"xmpp:me@me.com\">me@me.com</a><br>\n"
|
||||
" <a href=\"mailto:me@me.com\">me@me.com</a><br>\n"
|
||||
" Translator<br>\n"
|
||||
"<br>\n"
|
||||
"Join the translation team today! Go to \n"
|
||||
"<a href=\"http://forum.psi-im.org/forum/14\">\n"
|
||||
"http://forum.psi-im.org/forum/14</a> for further details!"
|
||||
);
|
||||
ui_.te_translation->appendText(translation);
|
||||
}
|
||||
|
||||
QString AboutDlg::loadText( const QString & fileName )
|
||||
{
|
||||
return TextUtil::loadText(fileName);
|
||||
}
|
||||
|
||||
|
||||
QString AboutDlg::details( QString name, QString email, QString jabber, QString www, QString desc )
|
||||
{
|
||||
QString ret;
|
||||
const QString nbsp = " ";
|
||||
ret += name + "<br>\n";
|
||||
if ( !email.isEmpty() )
|
||||
ret += nbsp + "E-mail: " + "<a href=\"mailto:" + email + "\">" + email + "</a><br>\n";
|
||||
if ( !jabber.isEmpty() )
|
||||
ret += nbsp + "Jabber: " + "<a href=\"jabber:" + jabber + "\">" + jabber + "</a><br>\n";
|
||||
if ( !www.isEmpty() )
|
||||
ret += nbsp + "WWW: " + "<a href=\"" + www + "\">" + www + "</a><br>\n";
|
||||
if ( !desc.isEmpty() )
|
||||
ret += nbsp + desc + "<br>\n";
|
||||
ret += "<br>\n";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
44
src/aboutdlg.h
Normal file
44
src/aboutdlg.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* aboutdlg.h
|
||||
* Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ABOUTDLG_H
|
||||
#define ABOUTDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_about.h"
|
||||
|
||||
class AboutDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AboutDlg(QWidget* parent = NULL);
|
||||
|
||||
static QString loadText( const QString & fileName );
|
||||
|
||||
protected:
|
||||
QString details( QString name, QString email, QString jabber, QString www, QString desc );
|
||||
|
||||
private:
|
||||
Ui::AboutDlg ui_;
|
||||
};
|
||||
|
||||
#endif
|
||||
167
src/accountadd.ui
Normal file
167
src/accountadd.ui
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<ui version="4.0" stdsetdef="1" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>AccountAdd</class>
|
||||
<widget class="QDialog" name="AccountAdd" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>465</width>
|
||||
<height>252</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Add Account</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="TextEdit1" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>0</hsizetype>
|
||||
<vsizetype>7</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>32767</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string><qt>Please choose a friendly <b>Name</b> that Psi can use to refer to this account.<br>
|
||||
<br>
|
||||
Click the <b>Register New Account</b> checkbox if you want Psi to try and create an account for you on a remote server. If you are adding an existing Jabber account then leave this box unchecked.</string>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_name" >
|
||||
<property name="text" >
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_name" />
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ck_reg" >
|
||||
<property name="text" >
|
||||
<string>Register new account</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer20" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>130</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="Line3" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::HLine</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="Spacer19" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>118</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_close" >
|
||||
<property name="text" >
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_add" >
|
||||
<property name="text" >
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Alt+A</string>
|
||||
</property>
|
||||
<property name="default" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/addContact</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
</ui>
|
||||
125
src/accountadddlg.cpp
Normal file
125
src/accountadddlg.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* accountadddlg.cpp - dialogs for manipulating PsiAccounts
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "accountadddlg.h"
|
||||
#include "psicon.h"
|
||||
#include "psioptions.h"
|
||||
#include "psiaccount.h"
|
||||
#include "accountregdlg.h"
|
||||
#include "psicontactlist.h"
|
||||
|
||||
AccountAddDlg::AccountAddDlg(PsiCon *_psi, QWidget *parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
setModal(false);
|
||||
psi = _psi;
|
||||
psi->dialogRegister(this);
|
||||
|
||||
setWindowTitle(CAP(caption()));
|
||||
|
||||
connect(pb_close, SIGNAL(clicked()), SLOT(close()));
|
||||
connect(pb_add, SIGNAL(clicked()), SLOT(add()));
|
||||
connect(le_name, SIGNAL(textChanged(const QString &)), SLOT(setAddButton(const QString &)));
|
||||
|
||||
ck_reg->setWhatsThis(
|
||||
tr("Check this option if you don't yet have a Jabber account "
|
||||
"and you want to register one. Note that this will only work "
|
||||
"on servers that allow anonymous registration."));
|
||||
|
||||
QString aname = createNewAccountName(tr("Default"));
|
||||
|
||||
if (PsiOptions::instance()->getOption("options.ui.account.single").toBool()) {
|
||||
le_name->setText("account");
|
||||
lb_name->hide();
|
||||
le_name->hide();
|
||||
}
|
||||
else {
|
||||
le_name->setText(aname);
|
||||
le_name->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
AccountAddDlg::~AccountAddDlg()
|
||||
{
|
||||
psi->dialogUnregister(this);
|
||||
}
|
||||
|
||||
QString AccountAddDlg::createNewAccountName(QString def)
|
||||
{
|
||||
QString aname = def;
|
||||
int n = 0;
|
||||
while(1) {
|
||||
bool taken = false;
|
||||
foreach(PsiAccount* pa, psi->contactList()->accounts()) {
|
||||
if(aname == pa->name()) {
|
||||
taken = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!taken)
|
||||
break;
|
||||
aname = def + '_' + QString::number(++n);
|
||||
}
|
||||
|
||||
return aname;
|
||||
}
|
||||
|
||||
void AccountAddDlg::add()
|
||||
{
|
||||
QString aname = createNewAccountName(le_name->text());
|
||||
le_name->setText( aname );
|
||||
|
||||
if(ck_reg->isChecked()) {
|
||||
AccountRegDlg *w = new AccountRegDlg(psi->proxy(), this);
|
||||
int n = w->exec();
|
||||
if(n != QDialog::Accepted) {
|
||||
delete w;
|
||||
return;
|
||||
}
|
||||
|
||||
Jid jid = w->jid();
|
||||
QString pass = w->pass();
|
||||
bool opt_host = w->useHost();
|
||||
QString host = w->host();
|
||||
int port = w->port();
|
||||
bool legacy_ssl_probe = w->legacySSLProbe();
|
||||
UserAccount::SSLFlag ssl = w->ssl();
|
||||
int proxy = w->proxy();
|
||||
|
||||
delete w;
|
||||
|
||||
psi->createAccount(le_name->text(), jid, pass, opt_host, host, port, legacy_ssl_probe, ssl, proxy);
|
||||
}
|
||||
else {
|
||||
psi->createAccount(le_name->text());
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
void AccountAddDlg::setAddButton(const QString &s)
|
||||
{
|
||||
pb_add->setEnabled(!s.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
|
||||
49
src/accountadddlg.h
Normal file
49
src/accountadddlg.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* accountadddlg.h - dialogs for manipulating PsiAccounts
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTADDDLG_H
|
||||
#define ACCOUNTADDDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_accountadd.h"
|
||||
|
||||
class PsiCon;
|
||||
class QWidget;
|
||||
class QString;
|
||||
|
||||
|
||||
class AccountAddDlg : public QDialog, public Ui::AccountAdd
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountAddDlg(PsiCon *, QWidget *parent=0);
|
||||
~AccountAddDlg();
|
||||
|
||||
private slots:
|
||||
void add();
|
||||
void setAddButton(const QString &);
|
||||
|
||||
private:
|
||||
PsiCon *psi;
|
||||
QString createNewAccountName(QString def);
|
||||
};
|
||||
|
||||
#endif
|
||||
71
src/accountlabel.cpp
Normal file
71
src/accountlabel.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* accountlabel.cpp - simple label to display account name currently in use
|
||||
* Copyright (C) 2006-2007 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "accountlabel.h"
|
||||
#include "psiaccount.h"
|
||||
|
||||
AccountLabel::AccountLabel(QWidget* parent)
|
||||
: QLabel(parent)
|
||||
, showJid_(true)
|
||||
{
|
||||
setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
||||
}
|
||||
|
||||
AccountLabel::~AccountLabel()
|
||||
{
|
||||
}
|
||||
|
||||
PsiAccount* AccountLabel::account() const
|
||||
{
|
||||
return account_;
|
||||
}
|
||||
|
||||
bool AccountLabel::showJid() const
|
||||
{
|
||||
return showJid_;
|
||||
}
|
||||
|
||||
void AccountLabel::setAccount(PsiAccount* account)
|
||||
{
|
||||
account_ = account;
|
||||
if (account) {
|
||||
connect(account, SIGNAL(updatedAccount()), SLOT(updateName()));
|
||||
connect(account, SIGNAL(destroyed()), SLOT(deleteLater()));
|
||||
}
|
||||
updateName();
|
||||
}
|
||||
|
||||
void AccountLabel::setShowJid(bool showJid)
|
||||
{
|
||||
showJid_ = showJid;
|
||||
updateName();
|
||||
}
|
||||
|
||||
void AccountLabel::updateName()
|
||||
{
|
||||
QString text = "...";
|
||||
if (!account_.isNull()) {
|
||||
if (showJid_)
|
||||
text = account_->nameWithJid();
|
||||
else
|
||||
text = account_->name();
|
||||
}
|
||||
setText(text);
|
||||
}
|
||||
50
src/accountlabel.h
Normal file
50
src/accountlabel.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* accountlabel.h - simple label to display account name currently in use
|
||||
* Copyright (C) 2006-2007 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTLABEL_H
|
||||
#define ACCOUNTLABEL_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPointer>
|
||||
|
||||
class PsiAccount;
|
||||
|
||||
class AccountLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool showJid READ showJid WRITE setShowJid)
|
||||
public:
|
||||
AccountLabel(QWidget* parent);
|
||||
~AccountLabel();
|
||||
|
||||
PsiAccount* account() const;
|
||||
bool showJid() const;
|
||||
void setAccount(PsiAccount* account);
|
||||
void setShowJid(bool showJid);
|
||||
|
||||
private slots:
|
||||
void updateName();
|
||||
|
||||
private:
|
||||
QPointer<PsiAccount> account_;
|
||||
bool showJid_;
|
||||
};
|
||||
|
||||
#endif
|
||||
169
src/accountmanage.ui
Normal file
169
src/accountmanage.ui
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
<ui version="4.0" stdsetdef="1" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>AccountManage</class>
|
||||
<widget class="QDialog" name="AccountManage" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>481</width>
|
||||
<height>282</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Jabber Accounts</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="Q3ListView" name="lv_accs" >
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Name</string>
|
||||
</property>
|
||||
<property name="clickable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="resizable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Server</string>
|
||||
</property>
|
||||
<property name="clickable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="resizable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Status</string>
|
||||
</property>
|
||||
<property name="clickable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="resizable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_add" >
|
||||
<property name="text" >
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/addContact</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_modify" >
|
||||
<property name="text" >
|
||||
<string>&Modify</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_remove" >
|
||||
<property name="text" >
|
||||
<string>Rem&ove</string>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer12" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>127</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="Line1" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::HLine</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="Spacer11" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>395</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_close" >
|
||||
<property name="text" >
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Alt+C</string>
|
||||
</property>
|
||||
<property name="default" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
</ui>
|
||||
394
src/accountmanagedlg.cpp
Normal file
394
src/accountmanagedlg.cpp
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* accountmanagedlg.cpp - dialogs for manipulating PsiAccounts
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QtCrypto>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
#include <q3listview.h>
|
||||
#include <q3buttongroup.h>
|
||||
#include "psicon.h"
|
||||
#include "psiaccount.h"
|
||||
#include "common.h"
|
||||
#include "xmpp_tasks.h"
|
||||
#include "proxy.h"
|
||||
#include "miniclient.h"
|
||||
#include "accountadddlg.h"
|
||||
#include "accountmanagedlg.h"
|
||||
#include "ui_accountremove.h"
|
||||
#include "psicontactlist.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// AccountRemoveDlg
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class AccountRemoveDlg : public QDialog, public Ui::AccountRemove
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountRemoveDlg(ProxyManager *, const UserAccount &, QWidget *parent=0);
|
||||
~AccountRemoveDlg();
|
||||
|
||||
protected:
|
||||
// reimplemented
|
||||
//void closeEvent(QCloseEvent *);
|
||||
|
||||
public slots:
|
||||
void done(int);
|
||||
|
||||
private slots:
|
||||
void remove();
|
||||
void bg_clicked(int);
|
||||
|
||||
void client_handshaken();
|
||||
void client_error();
|
||||
void client_disconnected();
|
||||
void unreg_finished();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
|
||||
MiniClient *client;
|
||||
};
|
||||
|
||||
class AccountRemoveDlg::Private
|
||||
{
|
||||
public:
|
||||
Private() {}
|
||||
|
||||
UserAccount acc;
|
||||
QButtonGroup *bg;
|
||||
ProxyManager *proxyman;
|
||||
};
|
||||
|
||||
AccountRemoveDlg::AccountRemoveDlg(ProxyManager *proxyman, const UserAccount &acc, QWidget *parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
setModal(false);
|
||||
d = new Private;
|
||||
d->acc = acc;
|
||||
d->proxyman = proxyman;
|
||||
|
||||
setWindowTitle(CAP(caption()));
|
||||
|
||||
connect(pb_close, SIGNAL(clicked()), SLOT(close()));
|
||||
connect(pb_remove, SIGNAL(clicked()), SLOT(remove()));
|
||||
|
||||
d->bg = new QButtonGroup(0);
|
||||
d->bg->addButton(rb_remove, 0);
|
||||
d->bg->addButton(rb_removeAndUnreg, 1);
|
||||
connect(d->bg, SIGNAL(buttonClicked(int)), SLOT(bg_clicked(int)));
|
||||
rb_remove->setChecked(true);
|
||||
bg_clicked(0);
|
||||
|
||||
pb_close->setFocus();
|
||||
|
||||
client = new MiniClient;
|
||||
connect(client, SIGNAL(handshaken()), SLOT(client_handshaken()));
|
||||
connect(client, SIGNAL(error()), SLOT(client_error()));
|
||||
connect(client, SIGNAL(disconnected()), SLOT(client_disconnected()));
|
||||
}
|
||||
|
||||
AccountRemoveDlg::~AccountRemoveDlg()
|
||||
{
|
||||
delete client;
|
||||
|
||||
delete d->bg;
|
||||
delete d;
|
||||
}
|
||||
|
||||
/*void AccountRemoveDlg::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
e->ignore();
|
||||
reject();
|
||||
}*/
|
||||
|
||||
void AccountRemoveDlg::done(int r)
|
||||
{
|
||||
if(busy->isActive()) {
|
||||
int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to cancel the unregistration?"), tr("&Yes"), tr("&No"));
|
||||
if(n != 0)
|
||||
return;
|
||||
}
|
||||
QDialog::done(r);
|
||||
}
|
||||
|
||||
void AccountRemoveDlg::bg_clicked(int x)
|
||||
{
|
||||
if(x == 0) {
|
||||
lb_pass->setEnabled(false);
|
||||
le_pass->setEnabled(false);
|
||||
}
|
||||
else if(x == 1) {
|
||||
lb_pass->setEnabled(true);
|
||||
le_pass->setEnabled(true);
|
||||
le_pass->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRemoveDlg::remove()
|
||||
{
|
||||
bool unreg = rb_removeAndUnreg->isChecked();
|
||||
|
||||
if(unreg) {
|
||||
if(!d->acc.pass.isEmpty() && le_pass->text() != d->acc.pass) {
|
||||
QMessageBox::information(this, tr("Error"), tr("Password does not match account. Please try again."));
|
||||
le_pass->setFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to remove <b>%1</b> ?").arg(d->acc.name), tr("&Yes"), tr("&No"));
|
||||
if(n != 0)
|
||||
return;
|
||||
|
||||
if(!unreg) {
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
|
||||
busy->start();
|
||||
gb_account->setEnabled(false);
|
||||
pb_remove->setEnabled(false);
|
||||
|
||||
Jid j = d->acc.jid;
|
||||
QString pass = le_pass->text();
|
||||
j.setResource(d->acc.resource);
|
||||
client->connectToServer(j, d->acc.legacy_ssl_probe, d->acc.ssl == UserAccount::SSL_Legacy, d->acc.ssl == UserAccount::SSL_Yes, d->acc.opt_host ? d->acc.host : QString(), d->acc.port, d->proxyman, d->acc.proxy_index, &pass);
|
||||
}
|
||||
|
||||
void AccountRemoveDlg::client_handshaken()
|
||||
{
|
||||
// Workaround for servers that do not send a response to the remove request
|
||||
client->setErrorOnDisconnect(false);
|
||||
|
||||
// try to unregister an account
|
||||
JT_Register *reg = new JT_Register(client->client()->rootTask());
|
||||
connect(reg, SIGNAL(finished()), SLOT(unreg_finished()));
|
||||
reg->unreg();
|
||||
reg->go(true);
|
||||
}
|
||||
|
||||
void AccountRemoveDlg::client_error()
|
||||
{
|
||||
busy->stop();
|
||||
gb_account->setEnabled(true);
|
||||
pb_remove->setEnabled(true);
|
||||
}
|
||||
|
||||
void AccountRemoveDlg::unreg_finished()
|
||||
{
|
||||
JT_Register *reg = (JT_Register *)sender();
|
||||
|
||||
client->close();
|
||||
busy->stop();
|
||||
|
||||
if(reg->success()) {
|
||||
QMessageBox::information(this, tr("Success"), tr("The account was unregistered successfully."));
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
else if(reg->statusCode() != Task::ErrDisc) {
|
||||
gb_account->setEnabled(true);
|
||||
pb_remove->setEnabled(true);
|
||||
QMessageBox::critical(this, tr("Error"), QString(tr("There was an error unregistering the account.\nReason: %1")).arg(reg->statusString()));
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRemoveDlg::client_disconnected()
|
||||
{
|
||||
// Workaround for servers that do not send a response to the remove request
|
||||
busy->stop();
|
||||
QMessageBox::information(this, tr("Success"), tr("The account was unregistered successfully."));
|
||||
accept();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// AccountManageDlg
|
||||
//----------------------------------------------------------------------------
|
||||
class AccountManageItem : public Q3CheckListItem
|
||||
{
|
||||
public:
|
||||
AccountManageItem(Q3ListView *par, PsiAccount *_pa)
|
||||
:Q3CheckListItem(par,"",CheckBox)
|
||||
{
|
||||
pa = _pa;
|
||||
updateInfo();
|
||||
}
|
||||
|
||||
void updateInfo()
|
||||
{
|
||||
const UserAccount &acc = pa->userAccount();
|
||||
setText(0, pa->name());
|
||||
//setPixmap(0, IconsetFactory::icon("psi/account"));
|
||||
Jid j = acc.jid;
|
||||
setText(1, acc.opt_host && acc.host.length() ? acc.host : j.host());
|
||||
setText(2, pa->isActive() ? AccountManageDlg::tr("Active") : AccountManageDlg::tr("Not active"));
|
||||
setOn(pa->enabled());
|
||||
}
|
||||
|
||||
void stateChange( bool s)
|
||||
{
|
||||
if (pa->enabled()!=s)
|
||||
pa->setEnabled(s);
|
||||
updateInfo();
|
||||
}
|
||||
|
||||
int rtti() const
|
||||
{
|
||||
return 8109;
|
||||
}
|
||||
|
||||
PsiAccount *pa;
|
||||
};
|
||||
|
||||
AccountManageDlg::AccountManageDlg(PsiCon *_psi)
|
||||
:QDialog(0)
|
||||
{
|
||||
setupUi(this);
|
||||
setModal(false);
|
||||
psi = _psi;
|
||||
psi->dialogRegister(this);
|
||||
|
||||
setWindowTitle(CAP(caption()));
|
||||
|
||||
// setup signals
|
||||
connect(pb_add, SIGNAL(clicked()), SLOT(add()));
|
||||
connect(pb_modify, SIGNAL(clicked()), SLOT(modify()));
|
||||
connect(pb_remove, SIGNAL(clicked()), SLOT(remove()));
|
||||
connect(pb_close, SIGNAL(clicked()), SLOT(close()));
|
||||
|
||||
connect(lv_accs, SIGNAL(doubleClicked(Q3ListViewItem *)), SLOT(modify(Q3ListViewItem *)));
|
||||
connect(lv_accs, SIGNAL(selectionChanged(Q3ListViewItem *)), SLOT(qlv_selectionChanged(Q3ListViewItem *)));
|
||||
connect(psi, SIGNAL(accountAdded(PsiAccount *)), SLOT(accountAdded(PsiAccount *)));
|
||||
connect(psi, SIGNAL(accountUpdated(PsiAccount *)), SLOT(accountUpdated(PsiAccount *)));
|
||||
connect(psi, SIGNAL(accountRemoved(PsiAccount *)), SLOT(accountRemoved(PsiAccount *)));
|
||||
|
||||
lv_accs->setAllColumnsShowFocus(true);
|
||||
lv_accs->setResizeMode(Q3ListView::LastColumn);
|
||||
|
||||
foreach(PsiAccount* pa, psi->contactList()->accounts())
|
||||
new AccountManageItem(lv_accs, pa);
|
||||
|
||||
if(lv_accs->childCount() > 0)
|
||||
lv_accs->setSelected(lv_accs->firstChild(), true);
|
||||
else
|
||||
qlv_selectionChanged(0);
|
||||
}
|
||||
|
||||
AccountManageDlg::~AccountManageDlg()
|
||||
{
|
||||
psi->dialogUnregister(this);
|
||||
}
|
||||
|
||||
void AccountManageDlg::qlv_selectionChanged(Q3ListViewItem *lvi)
|
||||
{
|
||||
AccountManageItem *i = (AccountManageItem *)lvi;
|
||||
bool ok = i ? true: false;
|
||||
|
||||
pb_modify->setEnabled(ok);
|
||||
pb_remove->setEnabled(ok);
|
||||
}
|
||||
|
||||
void AccountManageDlg::add()
|
||||
{
|
||||
AccountAddDlg *w = new AccountAddDlg(psi, 0);
|
||||
w->show();
|
||||
}
|
||||
|
||||
void AccountManageDlg::modify()
|
||||
{
|
||||
modify(lv_accs->currentItem());
|
||||
}
|
||||
|
||||
void AccountManageDlg::modify(Q3ListViewItem *lvi)
|
||||
{
|
||||
AccountManageItem *i = (AccountManageItem *)lvi;
|
||||
if(!i)
|
||||
return;
|
||||
|
||||
i->pa->modify();
|
||||
}
|
||||
|
||||
void AccountManageDlg::remove()
|
||||
{
|
||||
AccountManageItem *i = (AccountManageItem *)lv_accs->currentItem();
|
||||
if(!i)
|
||||
return;
|
||||
|
||||
if(i->pa->isActive()) {
|
||||
QMessageBox::information(this, tr("Error"), tr("Unable to remove the account, as it is currently active."));
|
||||
return;
|
||||
}
|
||||
|
||||
AccountRemoveDlg *w = new AccountRemoveDlg(psi->proxy(), i->pa->userAccount());
|
||||
int n = w->exec();
|
||||
if(n != QDialog::Accepted) {
|
||||
delete w;
|
||||
return;
|
||||
}
|
||||
delete w;
|
||||
psi->removeAccount(i->pa);
|
||||
}
|
||||
|
||||
void AccountManageDlg::accountAdded(PsiAccount *pa)
|
||||
{
|
||||
new AccountManageItem(lv_accs, pa);
|
||||
}
|
||||
|
||||
void AccountManageDlg::accountUpdated(PsiAccount *pa)
|
||||
{
|
||||
AccountManageItem *i;
|
||||
Q3ListViewItemIterator it(lv_accs);
|
||||
for(; (i = (AccountManageItem *)it.current()) ; ++it) {
|
||||
if(i->pa == pa)
|
||||
break;
|
||||
}
|
||||
if(!i)
|
||||
return;
|
||||
|
||||
i->updateInfo();
|
||||
}
|
||||
|
||||
void AccountManageDlg::accountRemoved(PsiAccount *pa)
|
||||
{
|
||||
AccountManageItem *i;
|
||||
Q3ListViewItemIterator it(lv_accs);
|
||||
for(; (i = (AccountManageItem *)it.current()) ; ++it) {
|
||||
if(i->pa == pa)
|
||||
break;
|
||||
}
|
||||
if(!i)
|
||||
return;
|
||||
|
||||
delete i;
|
||||
|
||||
qlv_selectionChanged(lv_accs->currentItem());
|
||||
}
|
||||
|
||||
#include "accountmanagedlg.moc"
|
||||
|
||||
58
src/accountmanagedlg.h
Normal file
58
src/accountmanagedlg.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* accountmanagedlg.h - dialogs for manipulating PsiAccounts
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTMANAGEDLG_H
|
||||
#define ACCOUNTMANAGEDLG_H
|
||||
|
||||
|
||||
#include "ui_accountmanage.h"
|
||||
|
||||
namespace XMPP
|
||||
{
|
||||
class Jid;
|
||||
class Client;
|
||||
}
|
||||
|
||||
class PsiCon;
|
||||
class PsiAccount;
|
||||
class Q3ListViewItem;
|
||||
|
||||
class AccountManageDlg : public QDialog, public Ui::AccountManage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountManageDlg(PsiCon *);
|
||||
~AccountManageDlg();
|
||||
|
||||
private slots:
|
||||
void qlv_selectionChanged(Q3ListViewItem *);
|
||||
void add();
|
||||
void modify();
|
||||
void modify(Q3ListViewItem *);
|
||||
void remove();
|
||||
void accountAdded(PsiAccount *);
|
||||
void accountUpdated(PsiAccount *);
|
||||
void accountRemoved(PsiAccount *);
|
||||
|
||||
private:
|
||||
PsiCon *psi;
|
||||
};
|
||||
|
||||
#endif
|
||||
1121
src/accountmodify.ui
Normal file
1121
src/accountmodify.ui
Normal file
File diff suppressed because it is too large
Load diff
637
src/accountmodifydlg.cpp
Normal file
637
src/accountmodifydlg.cpp
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* accountmodifydlg.cpp
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "accountmodifydlg.h"
|
||||
#include "psiaccount.h"
|
||||
#include "iconset.h"
|
||||
#include "psioptions.h"
|
||||
#include "jidutil.h"
|
||||
#include "profiles.h"
|
||||
#include "psicon.h"
|
||||
#include "proxy.h"
|
||||
#include "privacymanager.h"
|
||||
#include "privacydlg.h"
|
||||
#include "psicontactlist.h"
|
||||
#ifdef HAVE_PGPUTIL
|
||||
#include "pgpkeydlg.h"
|
||||
#include "pgputil.h"
|
||||
#endif
|
||||
|
||||
AccountModifyDlg::AccountModifyDlg(PsiCon *_psi, QWidget *parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
acc.name = "";
|
||||
setupUi(this);
|
||||
setModal(true);
|
||||
pa = NULL;
|
||||
psi = _psi;
|
||||
init();
|
||||
}
|
||||
|
||||
AccountModifyDlg::AccountModifyDlg(PsiAccount *_pa, QWidget *parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
setModal(false);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
pa = _pa;
|
||||
psi = pa->psi();
|
||||
acc = pa->userAccount();
|
||||
init();
|
||||
}
|
||||
|
||||
void AccountModifyDlg::init()
|
||||
{
|
||||
//connect(pa->psi(), SIGNAL(pgpToggled(bool)), SLOT(pgpToggled(bool)));
|
||||
if (pa)
|
||||
pa->dialogRegister(this);
|
||||
|
||||
setWindowTitle(CAP(caption()));
|
||||
#ifndef Q_WS_MAC
|
||||
setWindowIcon(IconsetFactory::icon("psi/account").icon());
|
||||
#endif
|
||||
|
||||
le_pass->setEnabled(true);
|
||||
le_host->setEnabled(false);
|
||||
lb_host->setEnabled(false);
|
||||
le_port->setEnabled(false);
|
||||
lb_port->setEnabled(false);
|
||||
|
||||
// FIXME: Temporarily removing security level settings
|
||||
ck_req_mutual->hide();
|
||||
cb_security_level->hide();
|
||||
lb_security_level->hide();
|
||||
|
||||
connect(pb_close, SIGNAL(clicked()), SLOT(reject()));
|
||||
connect(ck_host, SIGNAL(toggled(bool)), SLOT(hostToggled(bool)));
|
||||
connect(pb_key, SIGNAL(clicked()), SLOT(chooseKey()));
|
||||
connect(pb_keyclear, SIGNAL(clicked()), SLOT(clearKey()));
|
||||
connect(pb_save, SIGNAL(clicked()), SLOT(save()));
|
||||
connect(ck_automatic_resource, SIGNAL(toggled(bool)), le_resource, SLOT(setDisabled(bool)));
|
||||
connect(ck_automatic_resource, SIGNAL(toggled(bool)), lb_resource, SLOT(setDisabled(bool)));
|
||||
|
||||
gb_pgp->setEnabled(false);
|
||||
|
||||
if (pa) {
|
||||
connect(pb_vcard, SIGNAL(clicked()), SLOT(detailsVCard()));
|
||||
connect(pb_changepw, SIGNAL(clicked()), SLOT(detailsChangePW()));
|
||||
}
|
||||
else {
|
||||
pb_vcard->setEnabled(false);
|
||||
pb_changepw->setEnabled(false);
|
||||
}
|
||||
|
||||
// Hide the name if necessary
|
||||
le_name->setText(acc.name);
|
||||
le_jid->setText(JIDUtil::accountToString(acc.jid,false));
|
||||
|
||||
cb_ssl->addItem(tr("Always"),UserAccount::SSL_Yes);
|
||||
cb_ssl->addItem(tr("When available"),UserAccount::SSL_Auto);
|
||||
cb_ssl->addItem(tr("Never"), UserAccount::SSL_No);
|
||||
cb_ssl->addItem(tr("Legacy SSL"), UserAccount::SSL_Legacy);
|
||||
cb_ssl->setCurrentIndex(cb_ssl->findData(acc.ssl));
|
||||
connect(cb_ssl, SIGNAL(activated(int)), SLOT(sslActivated(int)));
|
||||
|
||||
cb_plain->addItem(tr("Always"),ClientStream::AllowPlain);
|
||||
cb_plain->addItem(tr("Over encrypted connection"), ClientStream::AllowPlainOverTLS);
|
||||
cb_plain->addItem(tr("Never"), ClientStream::NoAllowPlain);
|
||||
cb_plain->setCurrentIndex(cb_plain->findData(acc.allow_plain));
|
||||
|
||||
if (acc.opt_pass)
|
||||
le_pass->setText(acc.pass);
|
||||
|
||||
ck_host->setChecked(acc.opt_host);
|
||||
le_host->setText(acc.host);
|
||||
le_port->setText(QString::number(acc.port));
|
||||
ck_req_mutual->setChecked(acc.req_mutual_auth);
|
||||
ck_legacy_ssl_probe->setChecked(acc.legacy_ssl_probe);
|
||||
|
||||
ck_automatic_resource->setChecked(acc.opt_automatic_resource);
|
||||
le_resource->setText(acc.resource);
|
||||
le_priority->setText(QString::number(acc.priority));
|
||||
|
||||
connect(ck_custom_auth,SIGNAL(toggled(bool)), lb_authid, SLOT(setEnabled(bool)));
|
||||
connect(ck_custom_auth,SIGNAL(toggled(bool)), le_authid, SLOT(setEnabled(bool)));
|
||||
connect(ck_custom_auth,SIGNAL(toggled(bool)), lb_realm, SLOT(setEnabled(bool)));
|
||||
connect(ck_custom_auth,SIGNAL(toggled(bool)), le_realm, SLOT(setEnabled(bool)));
|
||||
ck_custom_auth->setChecked(acc.customAuth);
|
||||
le_authid->setText(acc.authid);
|
||||
le_realm->setText(acc.realm);
|
||||
|
||||
ck_compress->setChecked(acc.opt_compress);
|
||||
ck_auto->setChecked(acc.opt_auto);
|
||||
ck_reconn->setChecked(acc.opt_reconn);
|
||||
ck_log->setChecked(acc.opt_log);
|
||||
ck_keepAlive->setChecked(acc.opt_keepAlive);
|
||||
ck_ignoreSSLWarnings->setChecked(acc.opt_ignoreSSLWarnings);
|
||||
le_dtProxy->setText(acc.dtProxy.full());
|
||||
|
||||
key = acc.pgpSecretKey;
|
||||
updateUserID();
|
||||
#ifdef HAVE_PGPUTIL
|
||||
if(PGPUtil::instance().pgpAvailable()) {
|
||||
gb_pgp->setEnabled(true);
|
||||
}
|
||||
#else
|
||||
gb_pgp->setEnabled(false);
|
||||
#endif
|
||||
|
||||
pc = psi->proxy()->createProxyChooser(tab_connection);
|
||||
replaceWidget(lb_proxychooser, pc);
|
||||
pc->setCurrentItem(acc.proxy_index);
|
||||
|
||||
// Security level
|
||||
cb_security_level->addItem(tr("None"),QCA::SL_None);
|
||||
cb_security_level->addItem(tr("Integrity"),QCA::SL_Integrity);
|
||||
cb_security_level->addItem(tr("Baseline"),QCA::SL_Baseline);
|
||||
cb_security_level->addItem(tr("High"),QCA::SL_High);
|
||||
cb_security_level->addItem(tr("Highest"),QCA::SL_Highest);
|
||||
cb_security_level->setCurrentIndex(cb_security_level->findData(acc.security_level));
|
||||
|
||||
// Name
|
||||
if(le_name->text().isEmpty())
|
||||
le_name->setFocus();
|
||||
else if(le_jid->text().isEmpty())
|
||||
le_jid->setFocus();
|
||||
else
|
||||
pb_save->setFocus();
|
||||
|
||||
// Privacy
|
||||
privacyInitialized = false;
|
||||
lb_customPrivacy->hide();
|
||||
privacyBlockedModel.setSourceModel(&privacyModel);
|
||||
lv_blocked->setModel(&privacyBlockedModel);
|
||||
if (pa) {
|
||||
connect(pa->privacyManager(),SIGNAL(defaultListAvailable(const PrivacyList&)),SLOT(updateBlockedContacts(const PrivacyList&)));
|
||||
connect(pa->privacyManager(),SIGNAL(defaultListError()),SLOT(getDefaultList_error()));
|
||||
connect(pa->privacyManager(),SIGNAL(changeList_error()),SLOT(changeList_error()));
|
||||
connect(pa,SIGNAL(updatedActivity()),SLOT(updatePrivacyTab()));
|
||||
}
|
||||
connect(tab_main,SIGNAL(currentChanged(int)),SLOT(tabChanged(int)));
|
||||
connect(pb_privacy, SIGNAL(clicked()), SLOT(privacyClicked()));
|
||||
connect(pb_removeBlock, SIGNAL(clicked()), SLOT(removeBlockClicked()));
|
||||
connect(pb_addBlock, SIGNAL(clicked()), SLOT(addBlockClicked()));
|
||||
// FIXME: Temporarily disabling blocking
|
||||
pb_removeBlock->hide();
|
||||
pb_addBlock->hide();
|
||||
|
||||
// QWhatsThis helpers
|
||||
cb_plain->setWhatsThis(
|
||||
tr("Normally, Psi logs in using the <i>digest</i> authentication "
|
||||
"method. Check this box to force a plain text login "
|
||||
"to the Jabber server. Use this option only if you have "
|
||||
"problems connecting with the normal login procedure, as it "
|
||||
"makes your connection potentially vulnerable to "
|
||||
"attacks."));
|
||||
ck_auto->setWhatsThis(
|
||||
tr("Automatically login to this account on Psi startup. Useful if "
|
||||
"you have Psi automatically launched when an Internet "
|
||||
"connection is detected."));
|
||||
ck_reconn->setWhatsThis(
|
||||
tr("Makes Psi try to reconnect if the connection was broken. "
|
||||
"Useful, if you have an unstable connection and have to "
|
||||
"reconnect often."));
|
||||
ck_log->setWhatsThis(
|
||||
tr("Keep a log of message history. Disable this "
|
||||
"option if you want to conserve disk space or if you need "
|
||||
"maximum security."));
|
||||
ck_keepAlive->setWhatsThis(
|
||||
tr("Sends so called \"Keep-alive\" packets periodically. "
|
||||
"It is useful if your connection is set to be "
|
||||
"automatically disconnected after a certain period of "
|
||||
"inactivity (for example, by your ISP) and you want to keep it "
|
||||
"up all the time."));
|
||||
ck_ignoreSSLWarnings->setWhatsThis(
|
||||
tr("Ignores all the SSL warnings, for example, about "
|
||||
"incorrect certificates. Useful if your server doesn't "
|
||||
"use a validated SSL certificate and you are "
|
||||
"annoyed with warnings."));
|
||||
cb_ssl->setWhatsThis(
|
||||
tr("Check this option to use an encrypted SSL connection to "
|
||||
"the Jabber server. You may use this option if your "
|
||||
"server supports it and if you have the necessary QCA-OpenSSL "
|
||||
"plugin installed. For more information, check the "
|
||||
"Psi homepage."));
|
||||
ck_compress->setWhatsThis(
|
||||
tr("Check this option to use a compressed connection to "
|
||||
"the Jabber server, if the server supports it."));
|
||||
ck_host->setWhatsThis(
|
||||
tr("Use this option for manual configuration of your Jabber host "
|
||||
"if it is not the same as the host you are connecting to. This option is mostly useful "
|
||||
"if you have some sort of proxy route on your "
|
||||
"local machine (i.e. you connect to localhost), but your "
|
||||
"account is registered on an external server."));
|
||||
le_resource->setWhatsThis(
|
||||
tr("You can have multiple clients connected to the Jabber server "
|
||||
"with your single account. Each login is distinguished by a \"resource\" "
|
||||
"name, which you can specify in this field."));
|
||||
ck_custom_auth->setWhatsThis(
|
||||
tr("This option sets the user (and realm) you want to "
|
||||
"authenticate as. This overrides the Jabber ID you are logging in "
|
||||
"as."));
|
||||
le_priority->setWhatsThis(
|
||||
tr("<p>You can have multiple clients connected to the Jabber "
|
||||
"server with your single account. In such a situation, "
|
||||
"the client with the highest priority (that is specified in "
|
||||
"this field) will be the one that will receive "
|
||||
"all incoming events.</p>"
|
||||
"<p>For example, if you have a permanent connection "
|
||||
"to the Internet at your work location, and have a dial-up at home, "
|
||||
"you can have your Jabber client permanently running at work "
|
||||
"with a low priority, and you can still use the same account "
|
||||
"from home, using a client with higher priority to "
|
||||
"temporary \"disable\" the lower priority client at work.</p>"));
|
||||
|
||||
// Hiding of UI components
|
||||
if ((!pa && acc.name.isEmpty()) || PsiOptions::instance()->getOption("options.ui.account.single").toBool()) {
|
||||
le_name->hide();
|
||||
lb_name->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) {
|
||||
lb_example->hide();
|
||||
lb_jid->setText(tr("Username:"));
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.pgp.enable").toBool()) {
|
||||
gb_pgp->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.privacy.show").toBool())
|
||||
tab_main->removeTab(tab_main->indexOf(tab_privacy));
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.proxy.show").toBool()) {
|
||||
lb_proxy->hide();
|
||||
lb_proxychooser->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.manual-host").toBool()) {
|
||||
ck_host->hide();
|
||||
lb_host->hide();
|
||||
le_host->hide();
|
||||
lb_port->hide();
|
||||
le_port->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.ignore-ssl-warnings").toBool())
|
||||
ck_ignoreSSLWarnings->hide();
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.keepalive").toBool())
|
||||
ck_keepAlive->hide();
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.legacy-ssl-probe").toBool())
|
||||
ck_legacy_ssl_probe->hide();
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.security.show").toBool()) {
|
||||
lb_plain->hide();
|
||||
cb_plain->hide();
|
||||
ck_req_mutual->hide();
|
||||
lb_security_level->hide();
|
||||
cb_security_level->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.security.show").toBool() && !PsiOptions::instance()->getOption("options.ui.account.legacy-ssl-probe").toBool() && !PsiOptions::instance()->getOption("options.ui.account.keepalive").toBool() && !PsiOptions::instance()->getOption("options.ui.account.ignore-ssl-warnings").toBool() && !PsiOptions::instance()->getOption("options.ui.account.manual-host").toBool() && !PsiOptions::instance()->getOption("options.ui.account.proxy.show").toBool()) {
|
||||
tab_main->removeTab(tab_main->indexOf(tab_connection));
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.resource").toBool()) {
|
||||
ck_automatic_resource->hide();
|
||||
lb_resource->hide();
|
||||
le_resource->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.custom-authid").toBool()) {
|
||||
ck_custom_auth->hide();
|
||||
lb_authid->hide();
|
||||
le_authid->hide();
|
||||
lb_realm->hide();
|
||||
le_realm->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.priority").toBool()) {
|
||||
lb_priority->hide();
|
||||
le_priority->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.data-proxy").toBool()) {
|
||||
lb_dtProxy->hide();
|
||||
le_dtProxy->hide();
|
||||
}
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.ui.account.resource").toBool() && !PsiOptions::instance()->getOption("options.ui.account.priority").toBool() && !PsiOptions::instance()->getOption("options.ui.account.data-proxy").toBool()) {
|
||||
tab_main->removeTab(tab_main->indexOf(tab_misc));
|
||||
}
|
||||
|
||||
resize(minimumSizeHint());
|
||||
}
|
||||
|
||||
AccountModifyDlg::~AccountModifyDlg()
|
||||
{
|
||||
if (pa)
|
||||
pa->dialogUnregister(this);
|
||||
}
|
||||
|
||||
void AccountModifyDlg::updateUserID()
|
||||
{
|
||||
if(key.isNull()) {
|
||||
setKeyID(false);
|
||||
}
|
||||
else {
|
||||
setKeyID(true, key.primaryUserId());
|
||||
}
|
||||
}
|
||||
|
||||
void AccountModifyDlg::setKeyID(bool b, const QString &s)
|
||||
{
|
||||
if(b) {
|
||||
lb_keyname->setText(s);
|
||||
lb_keyname->setMinimumWidth(100);
|
||||
lb_keyicon->setEnabled(true);
|
||||
lb_keyname->setEnabled(true);
|
||||
pb_keyclear->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
lb_keyname->setText(tr("No Key Selected"));
|
||||
lb_keyicon->setEnabled(false);
|
||||
lb_keyname->setEnabled(false);
|
||||
pb_keyclear->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
//void AccountModifyDlg::pgpToggled(bool b)
|
||||
//{
|
||||
// if(b) {
|
||||
// gb_pgp->setEnabled(true);
|
||||
// }
|
||||
// else {
|
||||
// gb_pgp->setEnabled(false);
|
||||
// }
|
||||
// updateUserID();
|
||||
//}
|
||||
|
||||
void AccountModifyDlg::setPassword(const QString &pw)
|
||||
{
|
||||
if (!le_pass->text().isEmpty())
|
||||
le_pass->setText(pw);
|
||||
}
|
||||
|
||||
void AccountModifyDlg::sslActivated(int i)
|
||||
{
|
||||
if ((cb_ssl->itemData(i) == UserAccount::SSL_Yes || cb_ssl->itemData(i) == UserAccount::SSL_Legacy) && !checkSSL()) {
|
||||
cb_ssl->setCurrentIndex(cb_ssl->findData(UserAccount::SSL_Auto));
|
||||
}
|
||||
else if (cb_ssl->itemData(i) == UserAccount::SSL_Legacy && !ck_host->isChecked()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Legacy SSL is only available in combination with manual host/port."));
|
||||
cb_ssl->setCurrentIndex(cb_ssl->findData(UserAccount::SSL_Auto));
|
||||
}
|
||||
}
|
||||
|
||||
bool AccountModifyDlg::checkSSL()
|
||||
{
|
||||
if(!QCA::isSupported("tls")) {
|
||||
QMessageBox::critical(this, tr("SSL error"), tr("Cannot enable SSL/TLS. Plugin not found."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccountModifyDlg::hostToggled(bool on)
|
||||
{
|
||||
le_host->setEnabled(on);
|
||||
lb_host->setEnabled(on);
|
||||
le_port->setEnabled(on);
|
||||
lb_port->setEnabled(on);
|
||||
ck_legacy_ssl_probe->setEnabled(!on);
|
||||
ck_legacy_ssl_probe->setChecked(on ? false : acc.legacy_ssl_probe);
|
||||
if (!on && cb_ssl->currentIndex() == cb_ssl->findData(UserAccount::SSL_Legacy)) {
|
||||
cb_ssl->setCurrentIndex(cb_ssl->findData(UserAccount::SSL_Auto));
|
||||
}
|
||||
}
|
||||
|
||||
void AccountModifyDlg::chooseKey()
|
||||
{
|
||||
#ifdef HAVE_PGPUTIL
|
||||
// Show the key dialog
|
||||
QString id = (key.isNull() ? "" : key.keyId());
|
||||
PGPKeyDlg *w = new PGPKeyDlg(PGPKeyDlg::Secret, id, this);
|
||||
w->setWindowTitle(tr("Secret Key"));
|
||||
int r = w->exec();
|
||||
QCA::KeyStoreEntry entry;
|
||||
if(r == QDialog::Accepted)
|
||||
entry = w->keyStoreEntry();
|
||||
delete w;
|
||||
|
||||
if(!entry.isNull()) {
|
||||
key = entry.pgpSecretKey();
|
||||
updateUserID();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AccountModifyDlg::clearKey()
|
||||
{
|
||||
setKeyID(false);
|
||||
key = QCA::PGPKey();
|
||||
}
|
||||
|
||||
void AccountModifyDlg::detailsVCard()
|
||||
{
|
||||
if (pa)
|
||||
pa->changeVCard();
|
||||
}
|
||||
|
||||
void AccountModifyDlg::detailsChangePW()
|
||||
{
|
||||
if (pa) {
|
||||
pa->changePW();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountModifyDlg::save()
|
||||
{
|
||||
/*if(pa && le_name->text().isEmpty()) {
|
||||
QMessageBox::information(this, tr("Error"), tr("You must specify a name for the account before you may save it."));
|
||||
return;
|
||||
}*/
|
||||
|
||||
Jid newJid( JIDUtil::accountFromString(le_jid->text().trimmed()) );
|
||||
if ( newJid.user().isEmpty() || newJid.host().isEmpty() ) {
|
||||
if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) {
|
||||
QMessageBox::information(this, tr("Error"), tr("<i>Username</i> is invalid."));
|
||||
}
|
||||
else {
|
||||
QMessageBox::information(this, tr("Error"), tr("<i>Jabber ID</i> must be specified in the format <i>user@host</i>."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// do not allow duplicate account names
|
||||
if (!pa && le_name->text().isEmpty())
|
||||
le_name->setText(newJid.domain());
|
||||
QString def = le_name->text();
|
||||
QString aname = def;
|
||||
int n = 0;
|
||||
{
|
||||
foreach(PsiAccount* pa, psi->contactList()->accounts())
|
||||
if(aname == pa->name())
|
||||
n++;
|
||||
}
|
||||
|
||||
if ( aname == acc.name )
|
||||
n--;
|
||||
|
||||
if ( n )
|
||||
aname = def + '_' + QString::number(++n);
|
||||
le_name->setText( aname );
|
||||
|
||||
acc.name = le_name->text();
|
||||
acc.jid = JIDUtil::accountFromString(le_jid->text().trimmed()).bare();
|
||||
acc.pass = le_pass->text();
|
||||
acc.opt_pass = !acc.pass.isEmpty();
|
||||
|
||||
acc.opt_host = ck_host->isChecked();
|
||||
acc.host = le_host->text();
|
||||
acc.port = le_port->text().toInt();
|
||||
|
||||
acc.req_mutual_auth = ck_req_mutual->isChecked();
|
||||
if (!ck_host->isChecked())
|
||||
acc.legacy_ssl_probe = ck_legacy_ssl_probe->isChecked();
|
||||
acc.security_level = cb_security_level->itemData(cb_security_level->currentIndex()).toInt();
|
||||
|
||||
acc.opt_automatic_resource = ck_automatic_resource->isChecked();
|
||||
acc.resource = le_resource->text();
|
||||
acc.priority = le_priority->text().toInt();
|
||||
acc.customAuth = ck_custom_auth->isChecked();
|
||||
acc.authid = le_authid->text();
|
||||
acc.realm = le_realm->text();
|
||||
acc.ssl = (UserAccount::SSLFlag) cb_ssl->itemData(cb_ssl->currentIndex()).toInt();
|
||||
acc.allow_plain = (ClientStream::AllowPlainType) cb_plain->itemData(cb_plain->currentIndex()).toInt();
|
||||
acc.opt_compress = ck_compress->isChecked();
|
||||
acc.opt_auto = ck_auto->isChecked();
|
||||
acc.opt_reconn = ck_reconn->isChecked();
|
||||
acc.opt_log = ck_log->isChecked();
|
||||
acc.opt_keepAlive = ck_keepAlive->isChecked();
|
||||
acc.opt_ignoreSSLWarnings = ck_ignoreSSLWarnings->isChecked();
|
||||
acc.dtProxy = le_dtProxy->text();
|
||||
|
||||
acc.pgpSecretKey = key;
|
||||
|
||||
acc.proxy_index = pc->currentItem();
|
||||
|
||||
if(pa && pa->isActive()) {
|
||||
QMessageBox::information(this, tr("Warning"), tr("This account is currently active, so certain changes may not take effect until the next login."));
|
||||
}
|
||||
|
||||
if (pa)
|
||||
pa->setUserAccount(acc);
|
||||
else
|
||||
psi->contactList()->createAccount(acc);
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void AccountModifyDlg::tabChanged(int)
|
||||
{
|
||||
updatePrivacyTab();
|
||||
}
|
||||
|
||||
void AccountModifyDlg::addBlockClicked()
|
||||
{
|
||||
if (!pa)
|
||||
return;
|
||||
|
||||
bool ok;
|
||||
QString input = QInputDialog::getText(NULL, tr("Block contact"), tr("Enter the Jabber ID of the contact to block:"), QLineEdit::Normal, "", &ok);
|
||||
Jid jid(input);
|
||||
if (ok && !jid.isEmpty()) {
|
||||
privacyModel.list().insertItem(0,PrivacyListItem::blockItem(jid.full()));
|
||||
privacyModel.reset();
|
||||
pa->privacyManager()->changeList(privacyModel.list());
|
||||
}
|
||||
}
|
||||
|
||||
void AccountModifyDlg::removeBlockClicked()
|
||||
{
|
||||
if (!pa)
|
||||
return;
|
||||
|
||||
if (lv_blocked->currentIndex().isValid()) {
|
||||
QModelIndex idx = privacyBlockedModel.mapToSource(lv_blocked->currentIndex());
|
||||
privacyModel.removeRow(idx.row(),idx.parent());
|
||||
pa->privacyManager()->changeList(privacyModel.list());
|
||||
}
|
||||
}
|
||||
|
||||
void AccountModifyDlg::privacyClicked()
|
||||
{
|
||||
PrivacyDlg *d = new PrivacyDlg(pa->name(), pa->privacyManager(), this);
|
||||
d->show();
|
||||
}
|
||||
|
||||
void AccountModifyDlg::updatePrivacyTab()
|
||||
{
|
||||
if (tab_main->currentWidget() == tab_privacy) {
|
||||
if (pa && pa->loggedIn()) {
|
||||
if (!privacyInitialized) {
|
||||
lb_privacyStatus->setText(tr("Retrieving blocked contact list ..."));
|
||||
setPrivacyTabEnabled(false);
|
||||
pa->privacyManager()->getDefaultList();
|
||||
}
|
||||
//else {
|
||||
// setPrivacyTabEnabled(true);
|
||||
//}
|
||||
}
|
||||
else {
|
||||
lb_privacyStatus->setText(tr("You are not connected."));
|
||||
privacyInitialized = false;
|
||||
setPrivacyTabEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AccountModifyDlg::setPrivacyTabEnabled(bool b)
|
||||
{
|
||||
ws_privacy->setCurrentWidget(b ? pg_privacy : pg_privacyStatus);
|
||||
}
|
||||
|
||||
void AccountModifyDlg::updateBlockedContacts(const PrivacyList& l)
|
||||
{
|
||||
privacyInitialized = true;
|
||||
privacyModel.setList(l);
|
||||
lb_customPrivacy->setVisible(!l.onlyBlockItems());
|
||||
setPrivacyTabEnabled(true);
|
||||
}
|
||||
|
||||
void AccountModifyDlg::changeList_error()
|
||||
{
|
||||
privacyInitialized = false;
|
||||
updatePrivacyTab();
|
||||
}
|
||||
|
||||
void AccountModifyDlg::getDefaultList_error()
|
||||
{
|
||||
privacyInitialized = true;
|
||||
lb_privacyStatus->setText(tr("Your server does not support blocking."));
|
||||
setPrivacyTabEnabled(false);
|
||||
}
|
||||
|
||||
92
src/accountmodifydlg.h
Normal file
92
src/accountmodifydlg.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* accountmodifydlg.h
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTMODIFYDLG_H
|
||||
#define ACCOUNTMODIFYDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QtCrypto>
|
||||
|
||||
#include "privacylistmodel.h"
|
||||
#include "privacylistblockedmodel.h"
|
||||
#include "ui_accountmodify.h"
|
||||
#include "profiles.h"
|
||||
|
||||
class PsiAccount;
|
||||
class QWidget;
|
||||
class PsiCon;
|
||||
class ProxyChooser;
|
||||
|
||||
class AccountModifyDlg : public QDialog, public Ui::AccountModify
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountModifyDlg(PsiCon *,QWidget *parent=0);
|
||||
AccountModifyDlg(PsiAccount *, QWidget *parent=0);
|
||||
~AccountModifyDlg();
|
||||
|
||||
void setPassword(const QString &);
|
||||
const UserAccount& account() const { return acc; }
|
||||
|
||||
protected:
|
||||
void init();
|
||||
|
||||
private slots:
|
||||
void hostToggled(bool);
|
||||
void sslActivated(int);
|
||||
|
||||
void detailsVCard();
|
||||
void detailsChangePW();
|
||||
|
||||
void save();
|
||||
|
||||
//void pgpToggled(bool);
|
||||
void chooseKey();
|
||||
void clearKey();
|
||||
void tabChanged(int);
|
||||
|
||||
// Privacy
|
||||
void privacyClicked();
|
||||
void updatePrivacyTab();
|
||||
void setPrivacyTabEnabled(bool b);
|
||||
void addBlockClicked();
|
||||
void removeBlockClicked();
|
||||
void updateBlockedContacts(const PrivacyList&);
|
||||
void getDefaultList_error();
|
||||
void changeList_error();
|
||||
|
||||
private:
|
||||
PsiCon *psi;
|
||||
PsiAccount *pa;
|
||||
ProxyChooser *pc;
|
||||
QCA::PGPKey key;
|
||||
UserAccount acc;
|
||||
|
||||
// Privacy
|
||||
PrivacyListModel privacyModel;
|
||||
PrivacyListBlockedModel privacyBlockedModel;
|
||||
bool privacyInitialized;
|
||||
|
||||
void updateUserID();
|
||||
void setKeyID(bool b, const QString &s="");
|
||||
bool checkSSL();
|
||||
};
|
||||
|
||||
#endif
|
||||
304
src/accountreg.ui
Normal file
304
src/accountreg.ui
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
<ui version="4.0" >
|
||||
<class>AccountReg</class>
|
||||
<widget class="QDialog" name="AccountReg" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>384</width>
|
||||
<height>339</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Register Account</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="sw_register" >
|
||||
<property name="currentIndex" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_server" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_server" >
|
||||
<property name="title" >
|
||||
<string>Server</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="lb_jid" >
|
||||
<property name="text" >
|
||||
<string>Please enter the name of the server you wish to register with:</string>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="UpdatingComboBox" name="le_server" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="lb_example" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Example: capulet.com</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_connection" >
|
||||
<property name="title" >
|
||||
<string>Connection settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ck_host" >
|
||||
<property name="text" >
|
||||
<string>Manually Specify Server Host/Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_host" >
|
||||
<property name="text" >
|
||||
<string>Host:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_host" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_port" >
|
||||
<property name="text" >
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_port" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>56</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>56</width>
|
||||
<height>32767</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_ssl" >
|
||||
<property name="text" >
|
||||
<string>Encrypt connection:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cb_ssl" />
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>151</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ck_legacy_ssl_probe" >
|
||||
<property name="text" >
|
||||
<string>Probe legacy SSL port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_proxy" >
|
||||
<property name="text" >
|
||||
<string>Proxy:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_proxychooser" >
|
||||
<property name="text" >
|
||||
<string>proxychooser</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_fields" />
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line2" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::HLine</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="BusyWidget" name="busy" />
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pb_cancel" >
|
||||
<property name="text" >
|
||||
<string>&Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pb_next" >
|
||||
<property name="text" >
|
||||
<string>&Next</string>
|
||||
</property>
|
||||
<property name="default" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
<tabstops>
|
||||
<tabstop>le_server</tabstop>
|
||||
<tabstop>ck_host</tabstop>
|
||||
<tabstop>le_host</tabstop>
|
||||
<tabstop>le_port</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
371
src/accountregdlg.cpp
Normal file
371
src/accountregdlg.cpp
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* accountregdlg.cpp - dialogs for manipulating PsiAccounts
|
||||
* Copyright (C) 2001, 2002, 2006 Justin Karneges, Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QtCrypto>
|
||||
#include <QMessageBox>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "accountregdlg.h"
|
||||
#include "proxy.h"
|
||||
#include "serverlistquerier.h"
|
||||
#include "miniclient.h"
|
||||
#include "xmpp_tasks.h"
|
||||
#include "psioptions.h"
|
||||
#include "jidutil.h"
|
||||
#include "textutil.h"
|
||||
#include "xdata_widget.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
AccountRegDlg::AccountRegDlg(ProxyManager *pm, QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
ui_.setupUi(this);
|
||||
setModal(false);
|
||||
|
||||
// TODO: If the domain is fixed, and the connection settings are fixed, skip first
|
||||
// step
|
||||
|
||||
// Initialize settings
|
||||
ssl_ = UserAccount::SSL_Auto;
|
||||
legacy_ssl_probe_ = true;
|
||||
port_ = 5222;
|
||||
|
||||
// Server select button
|
||||
connect(ui_.le_server,SIGNAL(popup()),SLOT(selectServer()));
|
||||
serverlist_querier_ = new ServerListQuerier(this);
|
||||
connect(serverlist_querier_,SIGNAL(listReceived(const QStringList&)),SLOT(serverListReceived(const QStringList&)));
|
||||
connect(serverlist_querier_,SIGNAL(error(const QString&)),SLOT(serverListError(const QString&)));
|
||||
|
||||
// Manual Host/Port
|
||||
ui_.le_host->setEnabled(false);
|
||||
ui_.lb_host->setEnabled(false);
|
||||
ui_.le_port->setEnabled(false);
|
||||
ui_.lb_port->setEnabled(false);
|
||||
connect(ui_.ck_host, SIGNAL(toggled(bool)), SLOT(hostToggled(bool)));
|
||||
|
||||
// SSL
|
||||
ui_.cb_ssl->addItem(tr("Always"),UserAccount::SSL_Yes);
|
||||
ui_.cb_ssl->addItem(tr("When available"),UserAccount::SSL_Auto);
|
||||
ui_.cb_ssl->addItem(tr("Legacy SSL"), UserAccount::SSL_Legacy);
|
||||
ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(ssl_));
|
||||
connect(ui_.cb_ssl, SIGNAL(activated(int)), SLOT(sslActivated(int)));
|
||||
ui_.ck_legacy_ssl_probe->setChecked(legacy_ssl_probe_);
|
||||
|
||||
// Cancel and next buttons
|
||||
connect(ui_.pb_cancel, SIGNAL(clicked()), SLOT(close()));
|
||||
connect(ui_.pb_next, SIGNAL(clicked()), SLOT(next()));
|
||||
|
||||
// Proxy
|
||||
proxy_manager_ = pm;
|
||||
proxy_chooser_ = proxy_manager_->createProxyChooser(ui_.gb_connection);
|
||||
replaceWidget(ui_.lb_proxychooser, proxy_chooser_);
|
||||
proxy_chooser_->fixTabbing(ui_.ck_legacy_ssl_probe, ui_.pb_cancel);
|
||||
proxy_chooser_->setCurrentItem(0);
|
||||
|
||||
// Fields pane
|
||||
QVBoxLayout *fields_layout = new QVBoxLayout(ui_.page_fields);
|
||||
fields_layout->setMargin(0);
|
||||
fields_container_ = new QScrollArea(ui_.page_fields);
|
||||
fields_layout->addWidget(fields_container_);
|
||||
fields_container_->setWidgetResizable(true);
|
||||
fields_layout->addStretch(20);
|
||||
fields_ = NULL;
|
||||
|
||||
ui_.le_port->setText(QString::number(port_));
|
||||
ui_.le_host->setFocus();
|
||||
|
||||
client_ = new MiniClient;
|
||||
connect(client_, SIGNAL(handshaken()), SLOT(client_handshaken()));
|
||||
connect(client_, SIGNAL(error()), SLOT(client_error()));
|
||||
|
||||
if (!PsiOptions::instance()->getOption("options.account.domain").toString().isEmpty()) {
|
||||
ui_.gb_server->hide();
|
||||
}
|
||||
}
|
||||
|
||||
AccountRegDlg::~AccountRegDlg()
|
||||
{
|
||||
delete client_;
|
||||
}
|
||||
|
||||
void AccountRegDlg::done(int r)
|
||||
{
|
||||
if(ui_.busy->isActive()) {
|
||||
int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to cancel the registration?"), tr("&Yes"), tr("&No"));
|
||||
if(n != 0)
|
||||
return;
|
||||
}
|
||||
client_->close();
|
||||
QDialog::done(r);
|
||||
}
|
||||
|
||||
void AccountRegDlg::sslActivated(int i)
|
||||
{
|
||||
if ((ui_.cb_ssl->itemData(i) == UserAccount::SSL_Yes || ui_.cb_ssl->itemData(i) == UserAccount::SSL_Legacy) && !checkSSL()) {
|
||||
ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(UserAccount::SSL_Auto));
|
||||
}
|
||||
else if (ui_.cb_ssl->itemData(i) == UserAccount::SSL_Legacy && !ui_.ck_host->isChecked()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Legacy SSL is only available in combination with manual host/port."));
|
||||
ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(UserAccount::SSL_Auto));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AccountRegDlg::checkSSL()
|
||||
{
|
||||
if(!QCA::isSupported("tls")) {
|
||||
QMessageBox::information(this, tr("SSL error"), tr("Cannot enable SSL/TLS. Plugin not found."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccountRegDlg::hostToggled(bool on)
|
||||
{
|
||||
ui_.le_host->setEnabled(on);
|
||||
ui_.le_port->setEnabled(on);
|
||||
ui_.lb_host->setEnabled(on);
|
||||
ui_.lb_port->setEnabled(on);
|
||||
if (!on && ui_.cb_ssl->currentIndex() == ui_.cb_ssl->findData(UserAccount::SSL_Legacy)) {
|
||||
ui_.cb_ssl->setCurrentIndex(ui_.cb_ssl->findData(UserAccount::SSL_Auto));
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRegDlg::selectServer()
|
||||
{
|
||||
if (ui_.le_server->count() == 0) {
|
||||
ui_.busy->start();
|
||||
block();
|
||||
serverlist_querier_->getList();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRegDlg::serverListReceived(const QStringList& list)
|
||||
{
|
||||
ui_.busy->stop();
|
||||
unblock();
|
||||
ui_.le_server->clear();
|
||||
ui_.le_server->addItems(list);
|
||||
ui_.le_server->showPopup();
|
||||
}
|
||||
|
||||
void AccountRegDlg::serverListError(const QString& e)
|
||||
{
|
||||
ui_.busy->stop();
|
||||
unblock();
|
||||
QString error = tr("There was an error retrieving the server list");
|
||||
if (!e.isEmpty()) {
|
||||
error += ".\n" + tr("Reason: ") + e;
|
||||
}
|
||||
qWarning(error);
|
||||
//QMessageBox::critical(this, tr("Error"), error);
|
||||
ui_.le_server->setFocus();
|
||||
}
|
||||
|
||||
void AccountRegDlg::next()
|
||||
{
|
||||
if (ui_.sw_register->currentWidget() == ui_.page_server) {
|
||||
|
||||
// Update settings
|
||||
server_ = JIDUtil::accountFromString(ui_.le_server->currentText().trimmed());
|
||||
ssl_ = (UserAccount::SSLFlag) ui_.cb_ssl->itemData(ui_.cb_ssl->currentIndex()).toInt();
|
||||
legacy_ssl_probe_ = ui_.ck_legacy_ssl_probe->isChecked();
|
||||
opt_host_ = ui_.ck_host->isChecked();
|
||||
host_ = ui_.le_host->text();
|
||||
port_ = ui_.le_port->text().toInt();
|
||||
proxy_ = proxy_chooser_->currentItem();
|
||||
|
||||
// Sanity check
|
||||
if (server_.isNull() || !server_.node().isEmpty() || !server_.resource().isEmpty()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("You have entered an invalid server name"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect to the server
|
||||
ui_.busy->start();
|
||||
block();
|
||||
client_->connectToServer(server_, legacy_ssl_probe_, ssl_ == UserAccount::SSL_Legacy, ssl_ == UserAccount::SSL_Yes, opt_host_ ? host_ : QString(), port_, proxy_manager_, proxy_);
|
||||
}
|
||||
else if (ui_.sw_register->currentWidget() == ui_.page_fields) {
|
||||
// Initialize the form
|
||||
XMPP::XData fields;
|
||||
fields.setFields(fields_->fields());
|
||||
|
||||
// Determine the username and password
|
||||
foreach(XMPP::XData::Field field, fields.fields()) {
|
||||
if (field.var() == "username" && !field.value().isEmpty()) {
|
||||
jid_.set(server_.bare(), field.value().at(0), "");
|
||||
}
|
||||
else if (field.var() == "password" && !field.value().isEmpty()) {
|
||||
pass_ = field.value().at(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
ui_.busy->start();
|
||||
block();
|
||||
JT_Register *reg = new JT_Register(client_->client()->rootTask());
|
||||
connect(reg, SIGNAL(finished()), SLOT(setFields_finished()));
|
||||
if (isOld_) {
|
||||
Form form = convertFromXData(fields);
|
||||
form.setJid(server_);
|
||||
reg->setForm(form);
|
||||
}
|
||||
else {
|
||||
reg->setForm(server_,fields);
|
||||
}
|
||||
reg->go(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRegDlg::client_handshaken()
|
||||
{
|
||||
// try to register an account
|
||||
JT_Register *reg = new JT_Register(client_->client()->rootTask());
|
||||
connect(reg, SIGNAL(finished()), SLOT(getFields_finished()));
|
||||
reg->getForm(server_);
|
||||
reg->go(true);
|
||||
}
|
||||
|
||||
void AccountRegDlg::client_error()
|
||||
{
|
||||
ui_.busy->stop();
|
||||
unblock();
|
||||
if (ui_.sw_register->currentWidget() == ui_.page_fields) {
|
||||
// Start over
|
||||
delete fields_;
|
||||
fields_ = NULL;
|
||||
ui_.sw_register->setCurrentWidget(ui_.page_server);
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRegDlg::getFields_finished()
|
||||
{
|
||||
JT_Register *reg = (JT_Register *)sender();
|
||||
ui_.busy->stop();
|
||||
if (reg->success()) {
|
||||
unblock();
|
||||
fields_ = new XDataWidget(ui_.page_fields);
|
||||
XData xdata;
|
||||
if (reg->hasXData()) {
|
||||
isOld_ = false;
|
||||
xdata = reg->xdata();
|
||||
}
|
||||
else {
|
||||
isOld_ = true;
|
||||
xdata = convertToXData(reg->form());
|
||||
}
|
||||
if (xdata.instructions().isEmpty())
|
||||
xdata.setInstructions(tr("Please provide the following information:"));
|
||||
xdata.setInstructions(TextUtil::linkify(xdata.instructions()));
|
||||
fields_->setForm(xdata);
|
||||
fields_container_->setWidget(fields_);
|
||||
fields_container_->updateGeometry();
|
||||
ui_.sw_register->setCurrentWidget(ui_.page_fields);
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(this, tr("Error"), tr("This server does not support registration"));
|
||||
unblock();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRegDlg::setFields_finished()
|
||||
{
|
||||
JT_Register *reg = (JT_Register *)sender();
|
||||
ui_.busy->stop();
|
||||
if (reg->success()) {
|
||||
QMessageBox::information(this, tr("Success"), QString(tr("You have succesfully registered your account with Jabber ID '%1'")).arg(jid_.bare()));
|
||||
client_->close();
|
||||
accept();
|
||||
}
|
||||
else {
|
||||
unblock();
|
||||
QMessageBox::critical(this, tr("Error"), QString(tr("There was an error registering the account.\nReason: %1")).arg(reg->statusString()));
|
||||
}
|
||||
}
|
||||
|
||||
XMPP::XData AccountRegDlg::convertToXData(const XMPP::Form& form)
|
||||
{
|
||||
// Convert the fields
|
||||
XData::FieldList fields;
|
||||
foreach(FormField f, form) {
|
||||
XData::Field field;
|
||||
field.setLabel(f.fieldName());
|
||||
field.setVar(f.realName());
|
||||
field.setRequired(true);
|
||||
if (f.isSecret()) {
|
||||
field.setType(XData::Field::Field_TextPrivate);
|
||||
}
|
||||
else {
|
||||
field.setType(XData::Field::Field_TextSingle);
|
||||
}
|
||||
fields.push_back(field);
|
||||
}
|
||||
|
||||
// Create the form
|
||||
XData xdata;
|
||||
xdata.setInstructions(form.instructions());
|
||||
xdata.setFields(fields);
|
||||
return xdata;
|
||||
}
|
||||
|
||||
XMPP::Form AccountRegDlg::convertFromXData(const XMPP::XData& xdata)
|
||||
{
|
||||
Form form;
|
||||
foreach(XMPP::XData::Field field, xdata.fields()) {
|
||||
if (!field.value().isEmpty()) {
|
||||
FormField f;
|
||||
f.setType(field.var());
|
||||
f.setValue(field.value().at(0));
|
||||
form.push_back(f);
|
||||
}
|
||||
}
|
||||
return form;
|
||||
}
|
||||
|
||||
void AccountRegDlg::block()
|
||||
{
|
||||
if (ui_.sw_register->currentWidget() == ui_.page_server) {
|
||||
ui_.gb_server->setEnabled(false);
|
||||
ui_.gb_connection->setEnabled(false);
|
||||
ui_.pb_next->setEnabled(false);
|
||||
}
|
||||
else if (ui_.sw_register->currentWidget() == ui_.page_fields) {
|
||||
if (fields_)
|
||||
fields_->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AccountRegDlg::unblock()
|
||||
{
|
||||
if (ui_.sw_register->currentWidget() == ui_.page_server) {
|
||||
ui_.gb_server->setEnabled(true);
|
||||
ui_.gb_connection->setEnabled(true);
|
||||
ui_.pb_next->setEnabled(true);
|
||||
}
|
||||
else if (ui_.sw_register->currentWidget() == ui_.page_fields) {
|
||||
ui_.pb_next->setEnabled(true);
|
||||
if (fields_)
|
||||
fields_->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
106
src/accountregdlg.h
Normal file
106
src/accountregdlg.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* accountregdlg.h
|
||||
* Copyright (C) 2001, 2002, 2006 Justin Karneges, Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTREGDLG_H
|
||||
#define ACCOUNTREGDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
#include "profiles.h"
|
||||
#include "xmpp_jid.h"
|
||||
#include "ui_accountreg.h"
|
||||
|
||||
class ProxyManager;
|
||||
class ProxyChooser;
|
||||
class QWidget;
|
||||
class QScrollArea;
|
||||
class QStringList;
|
||||
class MiniClient;
|
||||
class XDataWidget;
|
||||
class ServerListQuerier;
|
||||
namespace XMPP {
|
||||
class Form;
|
||||
class XData;
|
||||
}
|
||||
|
||||
class AccountRegDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountRegDlg(ProxyManager*, QWidget *parent=0);
|
||||
~AccountRegDlg();
|
||||
|
||||
const XMPP::Jid& jid() const { return jid_; }
|
||||
const QString& pass() const { return pass_; }
|
||||
bool useHost() const { return opt_host_; }
|
||||
const QString& host() const { return host_; }
|
||||
int port() const { return port_; }
|
||||
bool legacySSLProbe() { return legacy_ssl_probe_; }
|
||||
UserAccount::SSLFlag ssl() const { return ssl_; }
|
||||
int proxy() const { return proxy_; }
|
||||
|
||||
public slots:
|
||||
void done(int);
|
||||
|
||||
protected:
|
||||
static XMPP::XData convertToXData(const XMPP::Form&);
|
||||
static XMPP::Form convertFromXData(const XMPP::XData&);
|
||||
|
||||
bool checkSSL();
|
||||
void block();
|
||||
void unblock();
|
||||
|
||||
protected slots:
|
||||
void hostToggled(bool);
|
||||
void sslActivated(int);
|
||||
void next();
|
||||
|
||||
void selectServer();
|
||||
void serverListReceived(const QStringList&);
|
||||
void serverListError(const QString&);
|
||||
|
||||
void client_handshaken();
|
||||
void client_error();
|
||||
|
||||
void getFields_finished();
|
||||
void setFields_finished();
|
||||
|
||||
private:
|
||||
Ui::AccountReg ui_;
|
||||
QScrollArea* fields_container_;
|
||||
XDataWidget* fields_;
|
||||
ProxyManager *proxy_manager_;
|
||||
ProxyChooser *proxy_chooser_;
|
||||
ServerListQuerier *serverlist_querier_;
|
||||
MiniClient *client_;
|
||||
bool isOld_;
|
||||
|
||||
// Account settings
|
||||
XMPP::Jid jid_, server_;
|
||||
UserAccount::SSLFlag ssl_;
|
||||
bool opt_host_, legacy_ssl_probe_;
|
||||
QString host_;
|
||||
int port_;
|
||||
QString pass_;
|
||||
int proxy_;
|
||||
};
|
||||
|
||||
#endif
|
||||
170
src/accountremove.ui
Normal file
170
src/accountremove.ui
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<ui version="4.0" stdsetdef="1" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>AccountRemove</class>
|
||||
<widget class="QDialog" name="AccountRemove" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>429</width>
|
||||
<height>173</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Remove Account</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_account" >
|
||||
<property name="title" >
|
||||
<string>Remove Account</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_remove" >
|
||||
<property name="text" >
|
||||
<string>Remove account from Psi only.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_removeAndUnreg" >
|
||||
<property name="text" >
|
||||
<string>Remove account and try to unregister it from the server.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_pass" >
|
||||
<property name="text" >
|
||||
<string>Password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_pass" >
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>32767</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer2" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer3" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="BusyWidget" name="busy" />
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer16" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>179</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_close" >
|
||||
<property name="text" >
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_remove" >
|
||||
<property name="text" >
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
</ui>
|
||||
141
src/accountscombobox.cpp
Normal file
141
src/accountscombobox.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* accountscombobox.cpp
|
||||
* Copyright (C) 2001-2008 Justin Karneges, Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "psicon.h"
|
||||
#include "accountscombobox.h"
|
||||
#include "psiaccount.h"
|
||||
#include "psicontactlist.h"
|
||||
|
||||
AccountsComboBox::AccountsComboBox(QWidget* parent)
|
||||
: QComboBox(parent)
|
||||
, controller_(0)
|
||||
, account_(0)
|
||||
, onlineOnly_(false)
|
||||
, autoHide_(false)
|
||||
{
|
||||
setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed));
|
||||
connect(this, SIGNAL(activated(int)), this, SLOT(changeAccount()));
|
||||
}
|
||||
|
||||
AccountsComboBox::~AccountsComboBox()
|
||||
{
|
||||
}
|
||||
|
||||
PsiAccount* AccountsComboBox::account() const
|
||||
{
|
||||
return account_;
|
||||
}
|
||||
|
||||
void AccountsComboBox::setAccount(PsiAccount* account)
|
||||
{
|
||||
account_ = account;
|
||||
updateAccounts();
|
||||
}
|
||||
|
||||
PsiCon* AccountsComboBox::controller() const
|
||||
{
|
||||
return controller_;
|
||||
}
|
||||
|
||||
void AccountsComboBox::setController(PsiCon* controller)
|
||||
{
|
||||
if (controller_) {
|
||||
disconnect(controller_, SIGNAL(accountCountChanged()), this, SLOT(updateAccounts()));
|
||||
disconnect(controller_, SIGNAL(accountActivityChanged()), this, SLOT(updateAccounts()));
|
||||
}
|
||||
|
||||
controller_ = controller;
|
||||
|
||||
if (controller_) {
|
||||
connect(controller_, SIGNAL(accountCountChanged()), this, SLOT(updateAccounts()));
|
||||
connect(controller_, SIGNAL(accountActivityChanged()), this, SLOT(updateAccounts()));
|
||||
}
|
||||
|
||||
if (controller_->contactList()->haveEnabledAccounts()) {
|
||||
setAccount(controller_->contactList()->enabledAccounts().first());
|
||||
}
|
||||
|
||||
updateAccounts();
|
||||
}
|
||||
|
||||
bool AccountsComboBox::onlineOnly() const
|
||||
{
|
||||
return onlineOnly_;
|
||||
}
|
||||
|
||||
void AccountsComboBox::setOnlineOnly(bool onlineOnly)
|
||||
{
|
||||
onlineOnly_ = onlineOnly;
|
||||
updateAccounts();
|
||||
}
|
||||
|
||||
void AccountsComboBox::changeAccount()
|
||||
{
|
||||
account_ = 0;
|
||||
if (currentIndex() >= 0 && currentIndex() < accounts().count())
|
||||
account_ = accounts().at(currentIndex());
|
||||
emit activated(account_);
|
||||
}
|
||||
|
||||
void AccountsComboBox::updateAccounts()
|
||||
{
|
||||
clear();
|
||||
|
||||
foreach(PsiAccount* account, accounts()) {
|
||||
#ifdef YAPSI
|
||||
addItem(account->jid().bare());
|
||||
#else
|
||||
addItem(account->nameWithJid());
|
||||
#endif
|
||||
}
|
||||
|
||||
if (accounts().indexOf(account_) == -1) {
|
||||
account_ = accounts().isEmpty() ? 0 : accounts().first();
|
||||
emit activated(account_);
|
||||
}
|
||||
setCurrentIndex(accounts().indexOf(account_));
|
||||
|
||||
if (autoHide_) {
|
||||
setVisible(count() > 1);
|
||||
}
|
||||
}
|
||||
|
||||
QList<PsiAccount*> AccountsComboBox::accounts() const
|
||||
{
|
||||
QList<PsiAccount*> result;
|
||||
if (controller_) {
|
||||
foreach(PsiAccount* account, controller_->contactList()->enabledAccounts())
|
||||
if (!onlineOnly_ || account->isAvailable())
|
||||
result << account;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AccountsComboBox::autoHide() const
|
||||
{
|
||||
return autoHide_;
|
||||
}
|
||||
|
||||
void AccountsComboBox::setAutoHide(bool autoHide)
|
||||
{
|
||||
autoHide_ = autoHide;
|
||||
updateAccounts();
|
||||
}
|
||||
64
src/accountscombobox.h
Normal file
64
src/accountscombobox.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* accountscombobox.h
|
||||
* Copyright (C) 2001-2008 Justin Karneges, Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTSCOMBOBOX_H
|
||||
#define ACCOUNTSCOMBOBOX_H
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
class PsiCon;
|
||||
class PsiAccount;
|
||||
|
||||
class AccountsComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountsComboBox(QWidget* parent);
|
||||
~AccountsComboBox();
|
||||
|
||||
PsiAccount* account() const;
|
||||
void setAccount(PsiAccount* account);
|
||||
|
||||
PsiCon* controller() const;
|
||||
void setController(PsiCon* controller);
|
||||
|
||||
bool onlineOnly() const;
|
||||
void setOnlineOnly(bool onlineOnly);
|
||||
|
||||
bool autoHide() const;
|
||||
void setAutoHide(bool autoHide);
|
||||
|
||||
signals:
|
||||
void activated(PsiAccount* account);
|
||||
|
||||
private slots:
|
||||
void changeAccount();
|
||||
void updateAccounts();
|
||||
|
||||
private:
|
||||
PsiCon* controller_;
|
||||
PsiAccount* account_;
|
||||
bool onlineOnly_;
|
||||
bool autoHide_;
|
||||
|
||||
QList<PsiAccount*> accounts() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
217
src/actionlist.cpp
Normal file
217
src/actionlist.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* actionlist.cpp - the customizeable action list
|
||||
* Copyright (C) 2004 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QList>
|
||||
|
||||
#include "actionlist.h"
|
||||
|
||||
#include <qobject.h>
|
||||
#include <q3dict.h>
|
||||
|
||||
#include "iconaction.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ActionList
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class ActionList::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Private() { }
|
||||
Private( const Private & );
|
||||
|
||||
QString name;
|
||||
int id;
|
||||
QStringList sortedActions;
|
||||
Q3Dict<IconAction> actions;
|
||||
|
||||
public slots:
|
||||
void actionDestroyed(QObject *);
|
||||
};
|
||||
|
||||
ActionList::ActionList( QString name, int id, bool autoDelete )
|
||||
{
|
||||
d = new Private();
|
||||
d->actions.setAutoDelete( autoDelete );
|
||||
|
||||
d->name = name;
|
||||
d->id = id;
|
||||
}
|
||||
|
||||
ActionList::ActionList( const ActionList &from )
|
||||
{
|
||||
d = new Private( *from.d );
|
||||
}
|
||||
|
||||
ActionList::~ActionList()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QString ActionList::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
int ActionList::id() const
|
||||
{
|
||||
return d->id;
|
||||
}
|
||||
|
||||
IconAction *ActionList::action( QString name ) const
|
||||
{
|
||||
return d->actions[name];
|
||||
}
|
||||
|
||||
QStringList ActionList::actions() const
|
||||
{
|
||||
return d->sortedActions;
|
||||
}
|
||||
|
||||
void ActionList::addAction( QString name, IconAction *action )
|
||||
{
|
||||
d->sortedActions << name;
|
||||
|
||||
if ( action ) {
|
||||
action->setObjectName( name );
|
||||
d->actions.insert( name, action );
|
||||
d->connect( action, SIGNAL( destroyed(QObject *) ), d, SLOT( actionDestroyed(QObject *) ) );
|
||||
}
|
||||
}
|
||||
|
||||
void ActionList::clear()
|
||||
{
|
||||
d->actions.clear();
|
||||
}
|
||||
|
||||
ActionList::Private::Private( const Private &from )
|
||||
: QObject()
|
||||
{
|
||||
name = from.name;
|
||||
id = from.id;
|
||||
|
||||
actions = from.actions;
|
||||
actions.setAutoDelete( from.actions.autoDelete() );
|
||||
|
||||
sortedActions = from.sortedActions;
|
||||
}
|
||||
|
||||
void ActionList::Private::actionDestroyed(QObject *obj)
|
||||
{
|
||||
bool autoDelete = actions.autoDelete();
|
||||
actions.setAutoDelete( false );
|
||||
|
||||
actions.remove( obj->objectName() );
|
||||
|
||||
actions.setAutoDelete( autoDelete );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// MetaActionList
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class MetaActionList::Private
|
||||
{
|
||||
public:
|
||||
Private() { }
|
||||
|
||||
QList<ActionList*> lists;
|
||||
};
|
||||
|
||||
MetaActionList::MetaActionList()
|
||||
{
|
||||
d = new Private();
|
||||
}
|
||||
|
||||
MetaActionList::~MetaActionList()
|
||||
{
|
||||
while (!d->lists.isEmpty())
|
||||
delete d->lists.takeFirst();
|
||||
delete d;
|
||||
}
|
||||
|
||||
ActionList *MetaActionList::actionList( QString name ) const
|
||||
{
|
||||
foreach(ActionList* a, d->lists) {
|
||||
if (a->name() == name)
|
||||
return a;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<ActionList*> MetaActionList::actionLists( int id ) const
|
||||
{
|
||||
QList<ActionList*> list;
|
||||
|
||||
for ( int i = 0; i < 32; i++ ) {
|
||||
if ( !(id & ( 1 << i )) )
|
||||
continue;
|
||||
|
||||
foreach(ActionList* a, d->lists) {
|
||||
if ( a->id() & ( 1 << i ) )
|
||||
list.append(a);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
ActionList MetaActionList::suitableActions( int id ) const
|
||||
{
|
||||
QList<ActionList*> lists = actionLists( id );
|
||||
ActionList actions("", 0, false);
|
||||
|
||||
foreach(ActionList* list, lists) {
|
||||
QStringList actionList = list->actions();
|
||||
QStringList::Iterator it2 = actionList.begin();
|
||||
for ( ; it2 != actionList.end(); ++it2 )
|
||||
actions.addAction( *it2, list->action( *it2 ) );
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
QStringList MetaActionList::actionLists() const
|
||||
{
|
||||
QStringList names;
|
||||
|
||||
foreach(ActionList* l, d->lists)
|
||||
names << l->name();
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
void MetaActionList::addList( ActionList *list )
|
||||
{
|
||||
if ( list )
|
||||
d->lists.append( list );
|
||||
}
|
||||
|
||||
void MetaActionList::clear()
|
||||
{
|
||||
|
||||
foreach(ActionList* l, d->lists) {
|
||||
l->clear();
|
||||
}
|
||||
}
|
||||
|
||||
#include "actionlist.moc"
|
||||
74
src/actionlist.h
Normal file
74
src/actionlist.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* actionlist.h - the customizeable action list
|
||||
* Copyright (C) 2004 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACTIONLIST_H
|
||||
#define ACTIONLIST_H
|
||||
|
||||
#include <QList>
|
||||
|
||||
class QString;
|
||||
class QStringList;
|
||||
class IconAction;
|
||||
|
||||
class ActionList
|
||||
{
|
||||
public:
|
||||
ActionList(QString name, int id, bool autoDelete = true);
|
||||
ActionList(const ActionList &);
|
||||
~ActionList();
|
||||
|
||||
QString name() const;
|
||||
int id() const;
|
||||
|
||||
IconAction *action( QString name ) const;
|
||||
QStringList actions() const;
|
||||
|
||||
void addAction( QString name, IconAction *action );
|
||||
|
||||
void clear();
|
||||
|
||||
public:
|
||||
class Private;
|
||||
private:
|
||||
Private *d;
|
||||
};
|
||||
|
||||
class MetaActionList
|
||||
{
|
||||
public:
|
||||
MetaActionList();
|
||||
~MetaActionList();
|
||||
|
||||
ActionList *actionList( QString name ) const;
|
||||
QList<ActionList*> actionLists( int id ) const;
|
||||
QStringList actionLists() const;
|
||||
|
||||
ActionList suitableActions( int id ) const;
|
||||
|
||||
void addList( ActionList * );
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
#endif
|
||||
116
src/activeprofiles.cpp
Normal file
116
src/activeprofiles.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* activeprofiles.cpp - Class for interacting with other psi instances
|
||||
* Copyright (C) 2006 Maciej Niedzielski
|
||||
* Copyright (C) 2006-2007 Martin Hostettler
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "activeprofiles.h"
|
||||
#include <QMessageBox>
|
||||
#include "profiles.h"
|
||||
|
||||
|
||||
ActiveProfiles* ActiveProfiles::instance_ = 0;
|
||||
|
||||
/**
|
||||
* \fn virtual ActiveProfiles::~ActiveProfiles();
|
||||
* \brief Destroys the object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn bool ActiveProfiles::isActive(const QString &profile) const;
|
||||
* \brief Returns true if \a profile is running.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn bool ActiveProfiles::isAnyActive() const;
|
||||
* \brief Returns true if there is at least one running Psi instance.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn bool ActiveProfiles::setThisProfile(const QString &profile);
|
||||
* \brief Registeres this application instance as \a profile.
|
||||
* Note: you can call this function multiple times with the same value of \a profile.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void ActiveProfiles::unsetThisProfile();
|
||||
* \brief Unregistered this application profile.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn QString ActiveProfiles::thisProfile() const;
|
||||
* \brief Returns the profile name registered for this application instance.
|
||||
* Returns empty string if no profile is registered.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn ActiveProfiles::ActiveProfiles(const QString &name);
|
||||
* \brief Creates new object and registers this application with its \a name.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Returns the instance of ActiveProfiles.
|
||||
*/
|
||||
ActiveProfiles* ActiveProfiles::instance()
|
||||
{
|
||||
if (!instance_) {
|
||||
instance_ = new ActiveProfiles();
|
||||
}
|
||||
|
||||
return instance_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn ActiveProfiles::ActiveProfiles()
|
||||
* \brief Creates new object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const
|
||||
* \brief Requests Psi instance running \a profile to change status.
|
||||
* If \a profile is empty, other running instance is selected.
|
||||
* If the request cannot be sent, function returns false.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const
|
||||
* \brief Requests Psi instance running \a profile to open \a uri.
|
||||
* If \a profile is empty, other running instance is selected.
|
||||
* If the request cannot be sent, function returns false.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn bool ActiveProfiles::raise(QString profile, bool withUI) const
|
||||
* \brief Raises the main windows of Psi instance running \a profile.
|
||||
* If \a profile is empty, other running instance is selected.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void setStatusRequested(const QString &status, const QString &message)
|
||||
* \brief Signal emitted when other Psi instance requested to change status.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void ActiveProfiles::openUriRequested(const QUrl &uri)
|
||||
* \brief Signal emitted when other Psi instance requested to open \a uri.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void ActiveProfiles::raiseRequested()
|
||||
* \brief Signal emitted when other Psi instance requested to raise main window.
|
||||
*/
|
||||
64
src/activeprofiles.h
Normal file
64
src/activeprofiles.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* activeprofiles.h - Class for interacting with other psi instances
|
||||
* Copyright (C) 2006 Maciej Niedzielski
|
||||
* Copyright (C) 2006-2007 Martin Hostettler
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACTIVEPSIPROFILES_H
|
||||
#define ACTIVEPSIPROFILES_H
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
class ActiveProfiles: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ActiveProfiles* instance();
|
||||
|
||||
bool setThisProfile(const QString &profile);
|
||||
void unsetThisProfile();
|
||||
QString thisProfile() const;
|
||||
|
||||
bool isActive(const QString &profile) const;
|
||||
bool isAnyActive() const;
|
||||
|
||||
bool setStatus(const QString &profile, const QString &status, const QString &message) const;
|
||||
bool openUri(const QString &profile, const QString &uri) const;
|
||||
bool raise(const QString &profile, bool withUI) const;
|
||||
|
||||
~ActiveProfiles();
|
||||
|
||||
signals:
|
||||
void setStatusRequested(const QString &status, const QString &message);
|
||||
void openUriRequested(const QString &uri);
|
||||
void raiseRequested();
|
||||
|
||||
protected:
|
||||
static ActiveProfiles *instance_;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
|
||||
ActiveProfiles();
|
||||
|
||||
friend class PsiConAdapter;
|
||||
friend class PsiMain;
|
||||
};
|
||||
|
||||
#endif
|
||||
241
src/activeprofiles_dbus.cpp
Normal file
241
src/activeprofiles_dbus.cpp
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* activeprofiles_dbus.cpp - Class for interacting with other psi instances
|
||||
* Copyright (C) 2006-2007 Martin Hostettler
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "activeprofiles.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QByteArray>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusInterface>
|
||||
|
||||
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
#include "applicationinfo.h"
|
||||
#include "dbus.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** \brief encodes a string to "[A-Z][a-z][0-9]_-" ascii subset
|
||||
* [A-Z][a-z][0-9] -> [A-Z][a-z][0-9]
|
||||
* / -> _
|
||||
* everything else to "-XX" with XX hex code of char
|
||||
* (slow)
|
||||
*/
|
||||
static QString encodeAlNumD(QString in)
|
||||
{
|
||||
QString out;
|
||||
QByteArray chars = in.toUtf8();
|
||||
bool first = true;
|
||||
foreach(char c, chars) {
|
||||
if (('A' <= c) && (c <= 'z')) {
|
||||
out += (char)c;
|
||||
} else if (('0' <= c) && (c <= '9') && !first) {
|
||||
out += (char)c;
|
||||
} else if ('/' == c) {
|
||||
out += "_";
|
||||
} else {
|
||||
out += QString("-%1").arg(c, 2, 16, QChar('0'));
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/** \brief DBus busname registration helper
|
||||
* \param dbusIface interface of bus
|
||||
* \param name busname to register
|
||||
* \param queue try queueing?
|
||||
* \return got dbus name?
|
||||
*/
|
||||
static bool registerBusname(QDBusConnectionInterface *dbusIface, QString name, bool queue)
|
||||
{
|
||||
bool ok = false;
|
||||
QDBusReply<QDBusConnectionInterface::RegisterServiceReply> reply;
|
||||
reply = dbusIface->registerService(name,
|
||||
queue ? QDBusConnectionInterface::QueueService : QDBusConnectionInterface::DontQueueService,
|
||||
QDBusConnectionInterface::AllowReplacement);
|
||||
if (reply.isValid()) {
|
||||
switch (reply.value()) {
|
||||
case QDBusConnectionInterface::ServiceNotRegistered:
|
||||
qWarning("failed to register dbus name %s:", qPrintable(name));
|
||||
break;
|
||||
case QDBusConnectionInterface::ServiceQueued:
|
||||
qDebug("dbus name %s already taken, queueing", qPrintable(name));
|
||||
break;
|
||||
case QDBusConnectionInterface::ServiceRegistered:
|
||||
ok = true;
|
||||
}
|
||||
} else {
|
||||
qWarning("failed to register dbus name %s: %s", qPrintable(name), qPrintable(reply.error().message()));
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
class ActiveProfiles::Private {
|
||||
public:
|
||||
QString profile;
|
||||
QStringList busNames;
|
||||
bool registerBusnames(QString prof);
|
||||
|
||||
QString dbusName(QString prof);
|
||||
};
|
||||
|
||||
|
||||
QString ActiveProfiles::Private::dbusName(QString prof)
|
||||
{
|
||||
QString name = PSIDBUSNAME;
|
||||
name += ".";
|
||||
name += encodeAlNumD(ApplicationInfo::homeDir()).right(qMax(0,200-name.size()));
|
||||
if (!prof.isEmpty()) {
|
||||
name += ".";
|
||||
name += encodeAlNumD(prof).right(qMax(0,250-name.size()));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ActiveProfiles::Private::registerBusnames(QString prof)
|
||||
{
|
||||
// FIXME move where?
|
||||
if (!QDBusConnection::sessionBus().isConnected()) {
|
||||
qWarning("can't connect to dbus");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface ();
|
||||
|
||||
QString name = PSIDBUSNAME;
|
||||
registerBusname(dbusIface, name, true);
|
||||
busNames << name;
|
||||
name = dbusName(QString());
|
||||
registerBusname(dbusIface, name, true);
|
||||
busNames << name;
|
||||
name = dbusName(prof);
|
||||
busNames << name;
|
||||
return registerBusname(dbusIface, name, false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool ActiveProfiles::isActive(const QString &profile) const
|
||||
{
|
||||
if (!QDBusConnection::sessionBus().isConnected()) {
|
||||
qWarning("can't connect to dbus");
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface ();
|
||||
return dbusIface->isServiceRegistered(d->dbusName(profile));
|
||||
}
|
||||
|
||||
bool ActiveProfiles::isAnyActive() const
|
||||
{
|
||||
return isActive("");
|
||||
}
|
||||
|
||||
|
||||
bool ActiveProfiles::setThisProfile(const QString &profile)
|
||||
{
|
||||
if (profile == d->profile)
|
||||
return true;
|
||||
|
||||
if (profile.isEmpty()) {
|
||||
unsetThisProfile();
|
||||
return true;
|
||||
}
|
||||
bool ok = d->registerBusnames(profile);
|
||||
if (ok) {
|
||||
d->profile = profile;
|
||||
} else {
|
||||
unsetThisProfile();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ActiveProfiles::unsetThisProfile()
|
||||
{
|
||||
QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface ();
|
||||
foreach(QString name, d->busNames) {
|
||||
dbusIface->unregisterService(name);
|
||||
}
|
||||
d->busNames.clear();
|
||||
d->profile = QString::null;
|
||||
}
|
||||
|
||||
QString ActiveProfiles::thisProfile() const
|
||||
{
|
||||
return d->profile;
|
||||
}
|
||||
|
||||
ActiveProfiles::ActiveProfiles()
|
||||
: QObject(QCoreApplication::instance())
|
||||
{
|
||||
d = new ActiveProfiles::Private;
|
||||
}
|
||||
|
||||
ActiveProfiles::~ActiveProfiles()
|
||||
{
|
||||
delete d;
|
||||
d = 0;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const
|
||||
{
|
||||
QDBusInterface(d->dbusName(profile), "/Main", PSIDBUSMAINIF).call(QDBus::NoBlock,
|
||||
"setStatus", status, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const
|
||||
{
|
||||
QDBusInterface(d->dbusName(profile), "/Main", PSIDBUSMAINIF).call(QDBus::NoBlock,
|
||||
"openURI", uri);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::raise(const QString &profile, bool withUI) const
|
||||
{
|
||||
QLabel *lab=0;
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall ( d->dbusName(profile), "/Main", PSIDBUSMAINIF, "raise" );
|
||||
if (withUI) {
|
||||
lab = new QLabel(tr("This psi profile is already running...<br>please wait..."));
|
||||
QTimer::singleShot(250, lab, SLOT(show()));
|
||||
}
|
||||
QDBusMessage rmsg = QDBusConnection::sessionBus().call(msg, QDBus::BlockWithGui, 10000);
|
||||
if (withUI) {
|
||||
lab->hide();
|
||||
delete lab;
|
||||
}
|
||||
if (rmsg.type() == QDBusMessage::ReplyMessage) {
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
82
src/activeprofiles_stub.cpp
Normal file
82
src/activeprofiles_stub.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* activeprofiles_stub.cpp - Class for interacting with other psi instances
|
||||
* Copyright (C) 2006 Maciej Niedzielski
|
||||
* Copyright (C) 2006-2007 Martin Hostettler
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "activeprofiles.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
|
||||
bool ActiveProfiles::isActive(const QString &profile) const
|
||||
{
|
||||
Q_UNUSED(profile);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::isAnyActive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::setThisProfile(const QString &profile)
|
||||
{
|
||||
Q_UNUSED(profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ActiveProfiles::unsetThisProfile()
|
||||
{
|
||||
}
|
||||
|
||||
QString ActiveProfiles::thisProfile() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
ActiveProfiles::ActiveProfiles()
|
||||
: QObject(QCoreApplication::instance())
|
||||
{
|
||||
}
|
||||
|
||||
ActiveProfiles::~ActiveProfiles()
|
||||
{
|
||||
}
|
||||
|
||||
bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const
|
||||
{
|
||||
Q_UNUSED(profile);
|
||||
Q_UNUSED(status);
|
||||
Q_UNUSED(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const
|
||||
{
|
||||
Q_UNUSED(uri);
|
||||
Q_UNUSED(profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::raise(const QString &profile, bool withUI) const
|
||||
{
|
||||
Q_UNUSED(profile);
|
||||
Q_UNUSED(withUI);
|
||||
return true;
|
||||
}
|
||||
368
src/activeprofiles_win.cpp
Normal file
368
src/activeprofiles_win.cpp
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* activeprofiles_win.cpp - Class for interacting with other app instances
|
||||
* Copyright (C) 2006 Maciej Niedzielski
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "activeprofiles.h"
|
||||
#include "applicationinfo.h"
|
||||
#include "psicon.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
Implementor notes:
|
||||
|
||||
This file uses WinAPI a lot. It is important to remember that we still want to support Win9x family.
|
||||
For that reason, we have to use QT_WA macro for functions that exist in two versions.
|
||||
|
||||
Also note that writing QString("x").toLocal8Bit().constData() is a bad idea and must not be done.
|
||||
*/
|
||||
|
||||
class ActiveProfiles::Private : public QWidget
|
||||
{
|
||||
public:
|
||||
Private(ActiveProfiles *aprof) : app(ApplicationInfo::IPCName()), home(ApplicationInfo::homeDir()), profile(""), ap(aprof), mutex(0), changesMutex(0) {
|
||||
|
||||
app.replace('\\', '/'); // '\\' has a special meaning in mutex name
|
||||
home.replace('\\', '/');
|
||||
|
||||
const QString m = QString("%1 ChangesMutex {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app);
|
||||
const QString c = QString("%1 IPC Command {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app);
|
||||
|
||||
QT_WA(
|
||||
changesMutex = CreateMutex(0, FALSE, (LPCWSTR)m.utf16());
|
||||
psiIpcCommand = RegisterWindowMessage((LPCWSTR)c.utf16());
|
||||
,
|
||||
QByteArray a = m.toLocal8Bit(); // must not call constData() of a temp object
|
||||
changesMutex = CreateMutexA(0, FALSE, (LPCSTR)a.constData());
|
||||
a = c.toLocal8Bit();
|
||||
psiIpcCommand = RegisterWindowMessageA((LPCSTR)a.constData());
|
||||
)
|
||||
|
||||
if (!changesMutex) {
|
||||
qWarning("Couldn't create IPC mutex");
|
||||
}
|
||||
if (!psiIpcCommand) {
|
||||
qWarning("Couldn't register IPC WM_message");
|
||||
}
|
||||
}
|
||||
|
||||
QString app, home, profile;
|
||||
ActiveProfiles * const ap;
|
||||
HANDLE mutex, changesMutex;
|
||||
|
||||
QString mutexName(const QString &profile) const {
|
||||
return "ProfileMutex\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}";
|
||||
}
|
||||
|
||||
QString windowName(const QString &profile) const {
|
||||
return "ProfileWindow\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}";
|
||||
}
|
||||
|
||||
void startChanges() {
|
||||
WaitForSingleObject(changesMutex, INFINITE);
|
||||
}
|
||||
|
||||
void endChanges() {
|
||||
ReleaseMutex(changesMutex);
|
||||
}
|
||||
|
||||
void setWindowText(const QString &text) {
|
||||
QT_WA(
|
||||
SetWindowTextW(winId(), (LPCWSTR)text.utf16());
|
||||
,
|
||||
QByteArray a = text.toLocal8Bit();
|
||||
SetWindowTextA(winId(), (LPCSTR)a.constData());
|
||||
)
|
||||
}
|
||||
|
||||
// WM_PSICOMMAND
|
||||
static UINT psiIpcCommand; // = RegisterWindowMessage()
|
||||
static WPARAM raiseCommand; // = 1
|
||||
|
||||
// WM_COPYDATA
|
||||
static const DWORD stringListMessage = 1;
|
||||
|
||||
bool sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const;
|
||||
bool winEvent(MSG *msg, long *result);
|
||||
|
||||
bool sendStringList(const QString &to, const QStringList &list) const;
|
||||
|
||||
QString pickProfile() const;
|
||||
};
|
||||
|
||||
UINT ActiveProfiles::Private::psiIpcCommand = 0;
|
||||
WPARAM ActiveProfiles::Private::raiseCommand = 1;
|
||||
|
||||
QString ActiveProfiles::Private::pickProfile() const
|
||||
{
|
||||
QStringList profiles = getProfilesList();
|
||||
foreach (QString p, profiles) {
|
||||
if (ap->isActive(p)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool ActiveProfiles::Private::sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const
|
||||
{
|
||||
QString profile = to;
|
||||
if (profile.isEmpty()) {
|
||||
profile = pickProfile();
|
||||
}
|
||||
if (profile.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HWND hwnd;
|
||||
QT_WA(
|
||||
hwnd = FindWindowW(0, (LPCWSTR)windowName(to).utf16());
|
||||
,
|
||||
QByteArray a = windowName(to).toLocal8Bit();
|
||||
hwnd = FindWindowA(0, (LPCSTR)a.constData());
|
||||
)
|
||||
|
||||
if (!hwnd)
|
||||
return false;
|
||||
|
||||
SendMessageA(hwnd, message, wParam, lParam);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::Private::sendStringList(const QString &to, const QStringList &list) const
|
||||
{
|
||||
if (to.isEmpty())
|
||||
return false;
|
||||
|
||||
QByteArray ba;
|
||||
|
||||
ba.append(list[0].toUtf8());
|
||||
for (int i = 1; i < list.size(); ++i) {
|
||||
const int z = ba.size();
|
||||
ba.append(" " + list[i].toUtf8());
|
||||
ba[z] = '\0';
|
||||
}
|
||||
|
||||
COPYDATASTRUCT cd;
|
||||
cd.dwData = stringListMessage;
|
||||
cd.cbData = ba.size()+1;
|
||||
cd.lpData = (void*)ba.data();
|
||||
|
||||
return sendMessage(to, WM_COPYDATA, (WPARAM)winId(), (LPARAM)(LPVOID)&cd);
|
||||
}
|
||||
|
||||
bool ActiveProfiles::Private::winEvent(MSG *msg, long *result)
|
||||
{
|
||||
if (msg->message == WM_COPYDATA) {
|
||||
*result = FALSE;
|
||||
COPYDATASTRUCT *cd = (COPYDATASTRUCT *)msg->lParam;
|
||||
if (cd->dwData == stringListMessage) {
|
||||
char *data = (char*)cd->lpData;
|
||||
const char *end = data + cd->cbData - 1;
|
||||
|
||||
// handle this error here, not to worry later
|
||||
if (*end != '\0') {
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList list;
|
||||
|
||||
while (data < end) {
|
||||
QString s = QString::fromUtf8(data);
|
||||
list << s;
|
||||
data += strlen(data) + 1;
|
||||
}
|
||||
|
||||
if (list.count() > 1) {
|
||||
if (list[0] == "openUri") {
|
||||
emit ap->openUriRequested(list.value(1));
|
||||
*result = TRUE;
|
||||
} else if (list[0] == "setStatus") {
|
||||
emit ap->setStatusRequested(list.value(1), list.value(2));
|
||||
*result = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (msg->message == psiIpcCommand) {
|
||||
*result = FALSE;
|
||||
if (msg->wParam == raiseCommand) {
|
||||
emit ap->raiseRequested();
|
||||
*result = TRUE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ActiveProfiles::ActiveProfiles()
|
||||
: QObject(QCoreApplication::instance())
|
||||
, d(0)
|
||||
{
|
||||
#ifndef YAPSI
|
||||
d = new ActiveProfiles::Private(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
ActiveProfiles::~ActiveProfiles()
|
||||
{
|
||||
delete d;
|
||||
d = 0;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::setThisProfile(const QString &profile)
|
||||
{
|
||||
#ifdef YAPSI
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (profile == d->profile)
|
||||
return true;
|
||||
|
||||
if (profile.isEmpty()) {
|
||||
unsetThisProfile();
|
||||
return true;
|
||||
}
|
||||
|
||||
d->startChanges();
|
||||
HANDLE m;
|
||||
QT_WA(
|
||||
m = CreateMutexW(0, TRUE, (LPCWSTR)d->mutexName(profile).utf16());
|
||||
,
|
||||
QByteArray a = d->mutexName(profile).toLocal8Bit();
|
||||
m = CreateMutexA(0, TRUE, (LPCSTR)a.constData());
|
||||
)
|
||||
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
CloseHandle(m);
|
||||
d->endChanges();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (d->mutex) {
|
||||
CloseHandle(d->mutex);
|
||||
}
|
||||
d->mutex = m;
|
||||
d->profile = profile;
|
||||
d->setWindowText(d->windowName(profile));
|
||||
d->endChanges();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveProfiles::unsetThisProfile()
|
||||
{
|
||||
#ifdef YAPSI
|
||||
return;
|
||||
#endif
|
||||
|
||||
d->startChanges();
|
||||
CloseHandle(d->mutex);
|
||||
d->mutex = 0;
|
||||
d->profile = QString::null;
|
||||
d->setWindowText("");
|
||||
d->endChanges();
|
||||
}
|
||||
|
||||
QString ActiveProfiles::thisProfile() const
|
||||
{
|
||||
return d->profile;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::isActive(const QString &profile) const
|
||||
{
|
||||
#ifdef YAPSI
|
||||
return true;
|
||||
#endif
|
||||
|
||||
HANDLE m;
|
||||
QT_WA(
|
||||
m = OpenMutexW(0, FALSE, (LPCWSTR)d->mutexName(profile).utf16());
|
||||
,
|
||||
QByteArray a = d->mutexName(profile).toLocal8Bit();
|
||||
m = OpenMutexA(0, FALSE, (LPCSTR)a.constData());
|
||||
)
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
CloseHandle(m);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ActiveProfiles::isAnyActive() const
|
||||
{
|
||||
#ifdef YAPSI
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return !d->pickProfile().isEmpty();
|
||||
}
|
||||
|
||||
|
||||
bool ActiveProfiles::raise(const QString &profile, bool withUI) const
|
||||
{
|
||||
#ifdef YAPSI
|
||||
return true;
|
||||
#endif
|
||||
|
||||
QLabel *lab = 0;
|
||||
if (withUI) {
|
||||
lab = new QLabel(tr("This psi profile is already running...<br>please wait..."));
|
||||
QTimer::singleShot(250, lab, SLOT(show()));
|
||||
}
|
||||
|
||||
bool res = d->sendMessage(profile, d->psiIpcCommand, d->raiseCommand, 0);
|
||||
|
||||
if (withUI) {
|
||||
lab->hide();
|
||||
delete lab;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const
|
||||
{
|
||||
#ifdef YAPSI
|
||||
return true;
|
||||
#endif
|
||||
|
||||
QStringList list;
|
||||
list << "openUri" << uri;
|
||||
return d->sendStringList(profile.isEmpty()? d->pickProfile() : profile, list);
|
||||
}
|
||||
|
||||
bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const
|
||||
{
|
||||
#ifdef YAPSI
|
||||
return true;
|
||||
#endif
|
||||
|
||||
QStringList list;
|
||||
list << "setStatus" << status << message;
|
||||
return d->sendStringList(profile.isEmpty()? d->pickProfile() : profile, list);
|
||||
}
|
||||
122
src/addurl.ui
Normal file
122
src/addurl.ui
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<ui version="4.0" stdsetdef="1" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>AddUrl</class>
|
||||
<widget class="QDialog" name="AddUrl" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>337</width>
|
||||
<height>123</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Add URL</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="le_desc" />
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="TextLabel1" >
|
||||
<property name="text" >
|
||||
<string>URL:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="TextLabel2" >
|
||||
<property name="text" >
|
||||
<string>Description:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="le_url" />
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer2" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="Spacer1" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>203</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_close" >
|
||||
<property name="text" >
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_ok" >
|
||||
<property name="text" >
|
||||
<string>&OK</string>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Alt+O</string>
|
||||
</property>
|
||||
<property name="default" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
<tabstops>
|
||||
<tabstop>le_url</tabstop>
|
||||
<tabstop>le_desc</tabstop>
|
||||
</tabstops>
|
||||
</ui>
|
||||
439
src/adduser.ui
Normal file
439
src/adduser.ui
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
<ui version="4.0" stdsetdef="1" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>AddUser</class>
|
||||
<widget class="QDialog" name="AddUser" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>601</width>
|
||||
<height>367</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Add User</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="TextEdit1" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>0</hsizetype>
|
||||
<vsizetype>7</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>32767</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string><qt>To add a <b>Jabber</b> user, simply fill out the Jabber ID (and optional nickname and group) at the bottom and press <i>Add</i>.<br>
|
||||
<br>
|
||||
To add a contact from a <b>non-Jabber</b> service, make sure you are registered with the service first (see Service Discovery from the main menu), and then select the service from the box at the top. Follow the instructions in the <i>Service ID Translation</i> box and press the <i>Get Jabber ID</i> button to generate a Jabber ID for the contact.<br>
|
||||
</qt></string>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="TextLabel5" >
|
||||
<property name="text" >
|
||||
<string>Service:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cb_service" >
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Jabber</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer1" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_trans" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title" >
|
||||
<string>Service ID Translation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_transDesc" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>7</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>No description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_transPrompt" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pb_transGet" >
|
||||
<property name="text" >
|
||||
<string>Get Jabber ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="1" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_jid" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconToolButton" name="tb_vCard" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/vCard</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="TextLabel8" >
|
||||
<property name="text" >
|
||||
<string>Group</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_nick" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tb_resolveNick" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Resolve</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="TextLabel7" >
|
||||
<property name="text" >
|
||||
<string>Nickname (optional)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="TextLabel6" >
|
||||
<property name="text" >
|
||||
<string>Jabber ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QComboBox" name="cb_group" >
|
||||
<property name="editable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ck_authreq" >
|
||||
<property name="text" >
|
||||
<string>Request authorization when adding</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer3" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>33</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ck_close" >
|
||||
<property name="text" >
|
||||
<string>Close window after adding</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="Line2" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::HLine</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="BusyWidget" name="busy" />
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer2" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_close" >
|
||||
<property name="text" >
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_add" >
|
||||
<property name="text" >
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Alt+A</string>
|
||||
</property>
|
||||
<property name="default" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/addContact</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction></pixmapfunction>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>BusyWidget</class>
|
||||
<extends></extends>
|
||||
<header location="local" >busywidget.h</header>
|
||||
<sizehint>
|
||||
<width>-1</width>
|
||||
<height>-1</height>
|
||||
</sizehint>
|
||||
<container>0</container>
|
||||
<sizepolicy>
|
||||
<hordata>5</hordata>
|
||||
<verdata>5</verdata>
|
||||
</sizepolicy>
|
||||
<pixmap>image0</pixmap>
|
||||
<properties>
|
||||
<property type="CString" >name</property>
|
||||
<property type="Bool" >enabled</property>
|
||||
<property type="Rect" >geometry</property>
|
||||
<property type="SizePolicy" >sizePolicy</property>
|
||||
<property type="Size" >minimumSize</property>
|
||||
<property type="Size" >maximumSize</property>
|
||||
<property type="Size" >sizeIncrement</property>
|
||||
<property type="Size" >baseSize</property>
|
||||
<property type="Color" >paletteForegroundColor</property>
|
||||
<property type="Color" >paletteBackgroundColor</property>
|
||||
<property type="Pixmap" >paletteBackgroundPixmap</property>
|
||||
<property type="Palette" >palette</property>
|
||||
<property type="BackgroundOrigin" >backgroundOrigin</property>
|
||||
<property type="Font" >font</property>
|
||||
<property type="Cursor" >cursor</property>
|
||||
<property type="String" >caption</property>
|
||||
<property type="Pixmap" >icon</property>
|
||||
<property type="String" >iconText</property>
|
||||
<property type="Bool" >mouseTracking</property>
|
||||
<property type="FocusPolicy" >focusPolicy</property>
|
||||
<property type="Bool" >acceptDrops</property>
|
||||
<property type="Bool" >active</property>
|
||||
</properties>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>IconButton</class>
|
||||
<extends></extends>
|
||||
<header location="local" >iconbutton.h</header>
|
||||
<sizehint>
|
||||
<width>-1</width>
|
||||
<height>-1</height>
|
||||
</sizehint>
|
||||
<container>0</container>
|
||||
<sizepolicy>
|
||||
<hordata>5</hordata>
|
||||
<verdata>5</verdata>
|
||||
</sizepolicy>
|
||||
<pixmap>image0</pixmap>
|
||||
<properties>
|
||||
<property type="CString" >name</property>
|
||||
<property type="Bool" >enabled</property>
|
||||
<property type="Rect" >geometry</property>
|
||||
<property type="SizePolicy" >sizePolicy</property>
|
||||
<property type="Size" >minimumSize</property>
|
||||
<property type="Size" >maximumSize</property>
|
||||
<property type="Size" >sizeIncrement</property>
|
||||
<property type="Size" >baseSize</property>
|
||||
<property type="Color" >paletteForegroundColor</property>
|
||||
<property type="Color" >paletteBackgroundColor</property>
|
||||
<property type="Pixmap" >paletteBackgroundPixmap</property>
|
||||
<property type="Palette" >palette</property>
|
||||
<property type="BackgroundOrigin" >backgroundOrigin</property>
|
||||
<property type="Font" >font</property>
|
||||
<property type="Cursor" >cursor</property>
|
||||
<property type="String" >caption</property>
|
||||
<property type="Pixmap" >icon</property>
|
||||
<property type="String" >iconText</property>
|
||||
<property type="Bool" >mouseTracking</property>
|
||||
<property type="FocusPolicy" >focusPolicy</property>
|
||||
<property type="Bool" >acceptDrops</property>
|
||||
<property type="String" >text</property>
|
||||
<property type="Pixmap" >pixmap</property>
|
||||
<property type="KeySequence" >accel</property>
|
||||
<property type="Bool" >autoRepeat</property>
|
||||
<property type="Bool" >autoDefault</property>
|
||||
<property type="Bool" >default</property>
|
||||
<property type="IconSet" >iconSet</property>
|
||||
<property type="Bool" >toggleButton</property>
|
||||
<property type="Bool" >on</property>
|
||||
<property type="Bool" >flat</property>
|
||||
<property type="Bool" >autoMask</property>
|
||||
<property type="String" >psiIconName</property>
|
||||
<property type="Bool" >textVisible</property>
|
||||
</properties>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>cb_service</tabstop>
|
||||
<tabstop>le_transPrompt</tabstop>
|
||||
<tabstop>pb_transGet</tabstop>
|
||||
<tabstop>le_jid</tabstop>
|
||||
<tabstop>le_nick</tabstop>
|
||||
<tabstop>cb_group</tabstop>
|
||||
<tabstop>ck_authreq</tabstop>
|
||||
<tabstop>ck_close</tabstop>
|
||||
<tabstop>TextEdit1</tabstop>
|
||||
</tabstops>
|
||||
<images>
|
||||
<image name="image0" >
|
||||
<data format="PNG" length="1125" >89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154789cb5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c203e47720000000049454e44ae426082</data>
|
||||
</image>
|
||||
</images>
|
||||
</ui>
|
||||
304
src/adduserdlg.cpp
Normal file
304
src/adduserdlg.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* adduserdlg.cpp - dialog for adding contacts
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "adduserdlg.h"
|
||||
|
||||
#include <qlabel.h>
|
||||
#include <qlayout.h>
|
||||
#include <qpushbutton.h>
|
||||
#include <qmessagebox.h>
|
||||
#include <qcombobox.h>
|
||||
#include <qstringlist.h>
|
||||
#include <qlineedit.h>
|
||||
#include <qcheckbox.h>
|
||||
#include "xmpp_tasks.h"
|
||||
#include "psiaccount.h"
|
||||
#include "psiiconset.h"
|
||||
#include "busywidget.h"
|
||||
#include "common.h"
|
||||
#include "iconwidget.h"
|
||||
#include "tasklist.h"
|
||||
#include "xmpp_vcard.h"
|
||||
#include "vcardfactory.h"
|
||||
#include "infodlg.h"
|
||||
|
||||
class AddUserDlg::Private
|
||||
{
|
||||
public:
|
||||
Private() {}
|
||||
|
||||
PsiAccount *pa;
|
||||
BusyWidget *busy;
|
||||
QStringList services;
|
||||
JT_Gateway *jt;
|
||||
TaskList *tasks;
|
||||
};
|
||||
|
||||
AddUserDlg::AddUserDlg(const QStringList &services, const QStringList &names, const QStringList &groups, PsiAccount *pa)
|
||||
:QDialog(0)
|
||||
{
|
||||
setupUi(this);
|
||||
setModal(false);
|
||||
d = new Private;
|
||||
d->pa = pa;
|
||||
d->pa->dialogRegister(this);
|
||||
connect(d->pa, SIGNAL(updatedActivity()), SLOT(pa_updatedActivity()));
|
||||
d->services = services;
|
||||
d->jt = 0;
|
||||
d->tasks = new TaskList;
|
||||
connect(d->tasks, SIGNAL(started()), busy, SLOT(start()));
|
||||
connect(d->tasks, SIGNAL(finished()), busy, SLOT(stop()));
|
||||
|
||||
setWindowTitle(CAP(caption()));
|
||||
setWindowIcon(IconsetFactory::icon("psi/addContact").icon());
|
||||
|
||||
d->busy = busy;
|
||||
|
||||
QStringList::ConstIterator it1 = services.begin();
|
||||
QStringList::ConstIterator it2 = names.begin();
|
||||
for(; it1 != services.end(); ++it1, ++it2)
|
||||
cb_service->insertItem(PsiIconset::instance()->status(*it1, STATUS_ONLINE).impix(), *it2);
|
||||
connect(cb_service, SIGNAL(activated(int)), SLOT(serviceActivated(int)));
|
||||
|
||||
connect(le_transPrompt, SIGNAL(textChanged(const QString &)), SLOT(le_transPromptChanged(const QString &)));
|
||||
pb_transGet->setEnabled(false);
|
||||
|
||||
QString str = tr("<None>");
|
||||
cb_group->insertItem(str);
|
||||
cb_group->insertStringList(groups);
|
||||
// FIXME: Re-do the hidden group trick the proper way
|
||||
// str = ContactView::tr("Hidden");
|
||||
// if(!groups.contains(str))
|
||||
// cb_group->insertItem(str);
|
||||
cb_group->setAutoCompletion(true);
|
||||
|
||||
pb_add->setDefault(true);
|
||||
connect(pb_add, SIGNAL(clicked()), SLOT(ok()));
|
||||
connect(pb_close, SIGNAL(clicked()), SLOT(cancel()));
|
||||
connect(pb_transGet, SIGNAL(clicked()), SLOT(getTransID()));
|
||||
|
||||
connect(tb_vCard, SIGNAL(clicked()), SLOT(getVCardActivated()));
|
||||
connect(tb_resolveNick, SIGNAL(clicked()), SLOT(resolveNickActivated()));
|
||||
|
||||
connect(le_jid, SIGNAL(textChanged(QString)), SLOT(jid_Changed()));
|
||||
|
||||
ck_authreq->setChecked(true);
|
||||
ck_close->setChecked(true);
|
||||
|
||||
le_jid->setFocus();
|
||||
}
|
||||
|
||||
AddUserDlg::~AddUserDlg()
|
||||
{
|
||||
delete d->tasks;
|
||||
d->pa->dialogUnregister(this);
|
||||
delete d;
|
||||
}
|
||||
|
||||
void AddUserDlg::pa_updatedActivity()
|
||||
{
|
||||
if(!d->pa->loggedIn())
|
||||
close();
|
||||
}
|
||||
|
||||
Jid AddUserDlg::jid() const
|
||||
{
|
||||
return Jid(le_jid->text().stripWhiteSpace());
|
||||
}
|
||||
|
||||
void AddUserDlg::cancel()
|
||||
{
|
||||
le_jid->setText("");
|
||||
le_nick->setText("");
|
||||
cb_group->setCurrentItem(0);
|
||||
reject();
|
||||
}
|
||||
|
||||
void AddUserDlg::ok()
|
||||
{
|
||||
if(le_jid->text().isEmpty()) {
|
||||
QMessageBox::information(this, tr("Add User: Error"), tr("Please fill in the Jabber ID of the person you wish to add."));
|
||||
return;
|
||||
}
|
||||
if(!jid().isValid()) {
|
||||
QMessageBox::information(this, tr("Add User: Error"), tr("The Jabber ID you entered is not valid!\nMake sure you enter a fully qualified Jabber ID."));
|
||||
return;
|
||||
}
|
||||
|
||||
QString gname = cb_group->currentText();
|
||||
QStringList list;
|
||||
if(gname != tr("<None>")) {
|
||||
list += gname;
|
||||
}
|
||||
|
||||
add(jid(), le_nick->text(), list, ck_authreq->isChecked());
|
||||
|
||||
QMessageBox::information(this, tr("Add User: Success"), tr("Added %1 to your roster.").arg(jid().full()));
|
||||
le_jid->setText("");
|
||||
le_nick->setText("");
|
||||
if(ck_close->isChecked()) {
|
||||
cb_group->setCurrentItem(0);
|
||||
accept();
|
||||
} else {
|
||||
le_jid->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void AddUserDlg::serviceActivated(int x)
|
||||
{
|
||||
if(d->jt) {
|
||||
delete d->jt;
|
||||
d->jt = 0;
|
||||
d->busy->stop();
|
||||
}
|
||||
gb_trans->setEnabled(false);
|
||||
le_transPrompt->setText("");
|
||||
|
||||
// Jabber entry
|
||||
if(x == 0)
|
||||
return;
|
||||
--x;
|
||||
|
||||
if(x >= 0 && x < (int)d->services.count()) {
|
||||
d->jt = new JT_Gateway(d->pa->client()->rootTask());
|
||||
connect(d->jt, SIGNAL(finished()), SLOT(jt_getFinished()));
|
||||
d->jt->get(Jid(d->services[x]));
|
||||
d->jt->go(true);
|
||||
d->tasks->append( d->jt );
|
||||
}
|
||||
}
|
||||
|
||||
void AddUserDlg::le_transPromptChanged(const QString &str)
|
||||
{
|
||||
pb_transGet->setEnabled(!str.isEmpty());
|
||||
}
|
||||
|
||||
void AddUserDlg::getTransID()
|
||||
{
|
||||
cb_service->setEnabled(false);
|
||||
le_transPrompt->setEnabled(false);
|
||||
pb_transGet->setEnabled(false);
|
||||
|
||||
d->jt = new JT_Gateway(d->pa->client()->rootTask());
|
||||
connect(d->jt, SIGNAL(finished()), SLOT(jt_setFinished()));
|
||||
d->jt->set(Jid(d->services[cb_service->currentItem()-1]), le_transPrompt->text());
|
||||
d->jt->go(true);
|
||||
d->tasks->append( d->jt );
|
||||
}
|
||||
|
||||
void AddUserDlg::jt_getFinished()
|
||||
{
|
||||
JT_Gateway *jt = d->jt;
|
||||
d->jt = 0;
|
||||
|
||||
if(jt->success()) {
|
||||
gb_trans->setEnabled(true);
|
||||
lb_transDesc->setText(jt->desc());
|
||||
}
|
||||
else {
|
||||
errorGateway(cb_service->currentText(), jt->statusString());
|
||||
}
|
||||
}
|
||||
|
||||
void AddUserDlg::jt_setFinished()
|
||||
{
|
||||
cb_service->setEnabled(true);
|
||||
le_transPrompt->setEnabled(true);
|
||||
pb_transGet->setEnabled(true);
|
||||
|
||||
JT_Gateway *jt = d->jt;
|
||||
d->jt = 0;
|
||||
|
||||
if(jt->success()) {
|
||||
le_jid->setText(jt->prompt());
|
||||
le_nick->setText(le_transPrompt->text());
|
||||
le_transPrompt->setText("");
|
||||
le_jid->setCursorPosition(0);
|
||||
le_nick->setCursorPosition(0);
|
||||
|
||||
le_nick->setFocus();
|
||||
le_nick->selectAll();
|
||||
}
|
||||
else {
|
||||
errorGateway(cb_service->currentText(), jt->statusString());
|
||||
le_transPrompt->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void AddUserDlg::errorGateway(const QString &str, const QString &err)
|
||||
{
|
||||
QMessageBox::information(this, CAP(tr("Error")), tr("<qt>\n"
|
||||
"There was an error getting the Service ID translation information from \"%1\".<br>"
|
||||
"Reason: %2<br>"
|
||||
"<br>"
|
||||
"The service may not support this feature. In this case you "
|
||||
"will need to enter the Jabber ID manually for the contact you wish "
|
||||
"to add. Examples:<br>"
|
||||
"<br>"
|
||||
" jabberuser@somehost.com<br>"
|
||||
" aoluser@[Jabber ID of AIM Transport]<br>"
|
||||
" 1234567@[Jabber ID of ICQ Transport]<br>"
|
||||
" joe%hotmail.com@[Jabber ID of MSN Transport]<br>"
|
||||
" yahooUser@[Jabber ID of Yahoo Transport]<br>"
|
||||
"</qt>"
|
||||
).arg(str).arg(QString(err).replace('\n', "<br>")));
|
||||
}
|
||||
|
||||
void AddUserDlg::getVCardActivated()
|
||||
{
|
||||
const VCard *vcard = VCardFactory::instance()->vcard(jid());
|
||||
|
||||
VCard tmp;
|
||||
if ( vcard )
|
||||
tmp = *vcard;
|
||||
|
||||
InfoDlg *w = new InfoDlg(InfoDlg::Contact, jid(), tmp, d->pa, 0, false);
|
||||
w->show();
|
||||
|
||||
// automatically retrieve info if it doesn't exist
|
||||
if(!vcard)
|
||||
w->doRefresh();
|
||||
}
|
||||
|
||||
void AddUserDlg::resolveNickActivated()
|
||||
{
|
||||
JT_VCard *jt = VCardFactory::instance()->getVCard(jid(), d->pa->client()->rootTask(), this, SLOT(resolveNickFinished()), false);
|
||||
d->tasks->append( jt );
|
||||
}
|
||||
|
||||
void AddUserDlg::resolveNickFinished()
|
||||
{
|
||||
JT_VCard *jt = (JT_VCard *)sender();
|
||||
|
||||
if(jt->success()) {
|
||||
if ( !jt->vcard().nickName().isEmpty() )
|
||||
le_nick->setText( jt->vcard().nickName() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Jid changes to enable the vcard and nick resolution buttons.
|
||||
*/
|
||||
void AddUserDlg::jid_Changed()
|
||||
{
|
||||
bool enableVCardButtons = jid().isValid();
|
||||
tb_vCard->setEnabled(enableVCardButtons);
|
||||
tb_resolveNick->setEnabled(enableVCardButtons);
|
||||
}
|
||||
67
src/adduserdlg.h
Normal file
67
src/adduserdlg.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* adduserdlg.h - dialog for adding contacts
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ADDUSERDLG_H
|
||||
#define ADDUSERDLG_H
|
||||
|
||||
#include "ui_adduser.h"
|
||||
|
||||
class QString;
|
||||
class QStringList;
|
||||
class PsiAccount;
|
||||
namespace XMPP {
|
||||
class Jid;
|
||||
}
|
||||
|
||||
class AddUserDlg : public QDialog, public Ui::AddUser
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AddUserDlg(const QStringList &services, const QStringList &names, const QStringList &groups, PsiAccount *);
|
||||
~AddUserDlg();
|
||||
|
||||
signals:
|
||||
void add(const XMPP::Jid &, const QString &, const QStringList &, bool authReq);
|
||||
|
||||
private slots:
|
||||
void ok();
|
||||
void cancel();
|
||||
void serviceActivated(int);
|
||||
void getTransID();
|
||||
void pa_updatedActivity();
|
||||
void jt_getFinished();
|
||||
void jt_setFinished();
|
||||
void le_transPromptChanged(const QString &);
|
||||
|
||||
void getVCardActivated();
|
||||
void resolveNickActivated();
|
||||
void resolveNickFinished();
|
||||
|
||||
void jid_Changed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
|
||||
XMPP::Jid jid() const;
|
||||
void errorGateway(const QString &str, const QString &err);
|
||||
};
|
||||
|
||||
#endif
|
||||
90
src/adhoc_fileserver.cpp
Normal file
90
src/adhoc_fileserver.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* adhoc_fileserver.cpp - Implementation of a personal ad-hoc fileserver
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <qdir.h>
|
||||
#include <qfileinfo.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "psiaccount.h"
|
||||
#include "adhoc_fileserver.h"
|
||||
#include "xmpp_xdata.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
bool AHFileServer::isAllowed(const Jid& j) const
|
||||
{
|
||||
return manager()->account()->jid().compare(j,false);
|
||||
}
|
||||
|
||||
AHCommand AHFileServer::execute(const AHCommand& c, const Jid& requester)
|
||||
{
|
||||
// Extract the file
|
||||
QString file;
|
||||
if (c.hasData()) {
|
||||
QString fileName, curDir;
|
||||
XData::FieldList fl = c.data().fields();
|
||||
for (unsigned int i=0; i < fl.count(); i++) {
|
||||
if (fl[i].var() == "file" && !(fl[i].value().isEmpty())) {
|
||||
file = fl[i].value().first();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
file = QDir::currentDirPath();
|
||||
}
|
||||
|
||||
if (QFileInfo(file).isDir()) {
|
||||
// Return a form with a filelist
|
||||
XData form;
|
||||
form.setTitle(QObject::tr("Choose file"));
|
||||
form.setInstructions(QObject::tr("Choose a file"));
|
||||
form.setType(XData::Data_Form);
|
||||
XData::FieldList fields;
|
||||
|
||||
XData::Field files_field;
|
||||
files_field.setType(XData::Field::Field_ListSingle);
|
||||
files_field.setVar("file");
|
||||
files_field.setLabel(QObject::tr("File"));
|
||||
files_field.setRequired(true);
|
||||
|
||||
XData::Field::OptionList file_options;
|
||||
QDir d(file);
|
||||
//d.setFilter(QDir::Files|QDir::Hidden|QDir::NoSymLinks);
|
||||
QStringList l = d.entryList();
|
||||
for (QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
|
||||
XData::Field::Option file_option;
|
||||
QFileInfo fi(QDir(file).filePath(*it));
|
||||
file_option.label = *it + (fi.isDir() ? QString(" [DIR]") : QString(" (%1 bytes)").arg(QString::number(fi.size())));
|
||||
file_option.value = QDir(file).absFilePath(*it);
|
||||
file_options += file_option;
|
||||
}
|
||||
files_field.setOptions(file_options);
|
||||
fields += files_field;
|
||||
|
||||
form.setFields(fields);
|
||||
|
||||
return AHCommand::formReply(c, form);
|
||||
}
|
||||
else {
|
||||
QStringList l(file);
|
||||
manager()->account()->sendFiles(requester,l,true);
|
||||
return AHCommand::completedReply(c);
|
||||
}
|
||||
}
|
||||
38
src/adhoc_fileserver.h
Normal file
38
src/adhoc_fileserver.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* adhoc_fileserver.h - Implementation of a personal file server using ad-hoc
|
||||
* commands
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHFILESERVER_H
|
||||
#define AHFILESERVER_H
|
||||
|
||||
#include "adhoc.h"
|
||||
|
||||
class AHFileServer : public AHCommandServer
|
||||
{
|
||||
public:
|
||||
AHFileServer(AHCServerManager* m) : AHCommandServer(m) { }
|
||||
virtual QString node() const
|
||||
{ return QString("http://psi.affinix.com/commands/files"); }
|
||||
virtual bool isAllowed(const Jid&) const;
|
||||
virtual QString name() const { return QString("Send file"); }
|
||||
virtual AHCommand execute(const AHCommand& c, const Jid&);
|
||||
};
|
||||
|
||||
#endif
|
||||
73
src/ahcexecutetask.cpp
Normal file
73
src/ahcexecutetask.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* ahcexecutetask.cpp - Ad-Hoc Command Execute Task
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ahcexecutetask.h"
|
||||
#include "ahcformdlg.h"
|
||||
#include "xmpp_xmlcommon.h"
|
||||
#include "psiaccount.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
AHCExecuteTask::AHCExecuteTask(const Jid& j, const AHCommand& command, Task* t) : Task(t), receiver_(j), command_(command)
|
||||
{
|
||||
}
|
||||
|
||||
void AHCExecuteTask::onGo()
|
||||
{
|
||||
QDomElement e = createIQ(doc(), "set", receiver_.full(), id());
|
||||
e.appendChild(command_.toXml(doc(),true));
|
||||
send(e);
|
||||
}
|
||||
|
||||
bool AHCExecuteTask::take(const QDomElement& e)
|
||||
{
|
||||
if(!iqVerify(e, receiver_, id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Result of a command
|
||||
if (e.attribute("type") == "result") {
|
||||
bool found;
|
||||
QDomElement i = findSubTag(e, "command", &found);
|
||||
if (found) {
|
||||
AHCommand c(i);
|
||||
if (c.status() == AHCommand::Executing) {
|
||||
AHCFormDlg *w = new AHCFormDlg(c,receiver_,client());
|
||||
w->show();
|
||||
}
|
||||
else if (c.status() == AHCommand::Completed && i.childNodes().count() > 0) {
|
||||
AHCFormDlg *w = new AHCFormDlg(c,receiver_,client(), true);
|
||||
w->show();
|
||||
}
|
||||
setSuccess();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Error
|
||||
/*else if (e.attribute("type") == "set") {
|
||||
AHCError err(e);
|
||||
if (err.type() != None) {
|
||||
QMessageBox::critical(0, tr("Error"), AHCommand::error2description(err.type()), QMessageBox::Ok, QMessageBox::NoButton);
|
||||
}
|
||||
return true;
|
||||
}*/
|
||||
setError(e);
|
||||
return false;
|
||||
}
|
||||
43
src/ahcexecutetask.h
Normal file
43
src/ahcexecutetask.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ahcexecutetask.h - Ad-Hoc Command Execute Task
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHCEXECUTETASK_H
|
||||
#define AHCEXECUTETASK_H
|
||||
|
||||
#include "xmpp_task.h"
|
||||
#include "xmpp_jid.h"
|
||||
#include "ahcommand.h"
|
||||
|
||||
class QDomElement;
|
||||
|
||||
class AHCExecuteTask : public XMPP::Task
|
||||
{
|
||||
public:
|
||||
AHCExecuteTask(const XMPP::Jid& j, const AHCommand&, XMPP::Task* t);
|
||||
|
||||
void onGo();
|
||||
bool take(const QDomElement &x);
|
||||
|
||||
private:
|
||||
XMPP::Jid receiver_;
|
||||
AHCommand command_;
|
||||
};
|
||||
|
||||
#endif
|
||||
196
src/ahcformdlg.cpp
Normal file
196
src/ahcformdlg.cpp
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* ahcformdlg.cpp - Ad-Hoc Command Form Dialog
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
|
||||
#include "ahcformdlg.h"
|
||||
#include "ahcommand.h"
|
||||
#include "ahcexecutetask.h"
|
||||
#include "xdata_widget.h"
|
||||
#include "xmpp_client.h"
|
||||
#include "psiaccount.h"
|
||||
#include "busywidget.h"
|
||||
|
||||
AHCFormDlg::AHCFormDlg(const AHCommand& r, const Jid& receiver, XMPP::Client* client, bool final)
|
||||
: QDialog(NULL), receiver_(receiver), client_(client)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
// Save node
|
||||
node_ = r.node();
|
||||
sessionId_ = r.sessionId();
|
||||
|
||||
QVBoxLayout *vb = new QVBoxLayout(this, 11, 6);
|
||||
|
||||
// Instructions
|
||||
if (!r.data().instructions().isEmpty()) {
|
||||
QLabel* lb_instructions = new QLabel(r.data().instructions(),this);
|
||||
vb->addWidget(lb_instructions);
|
||||
}
|
||||
|
||||
// XData form
|
||||
xdata_ = new XDataWidget(this);
|
||||
xdata_->setFields(r.data().fields());
|
||||
vb->addWidget(xdata_);
|
||||
|
||||
vb->addStretch(1);
|
||||
|
||||
// Buttons
|
||||
QHBoxLayout *hb = new QHBoxLayout(vb);
|
||||
pb_complete = pb_cancel = pb_prev = pb_next = 0;
|
||||
if (!final) {
|
||||
|
||||
busy_ = new BusyWidget(this);
|
||||
hb->addWidget(busy_);
|
||||
hb->addItem(new QSpacerItem(20,0,QSizePolicy::Expanding));
|
||||
|
||||
if (r.actions().empty()) {
|
||||
// Single stage dialog
|
||||
pb_complete = new QPushButton(tr("Finish"),this);
|
||||
connect(pb_complete,SIGNAL(clicked()),SLOT(doExecute()));
|
||||
hb->addWidget(pb_complete);
|
||||
}
|
||||
else {
|
||||
// Multi-stage dialog
|
||||
|
||||
// Previous
|
||||
pb_prev = new QPushButton(tr("Previous"),this);
|
||||
if (r.actions().contains(AHCommand::Prev)) {
|
||||
if (r.defaultAction() == AHCommand::Prev) {
|
||||
pb_prev->setDefault(true);
|
||||
pb_prev->setFocus();
|
||||
}
|
||||
connect(pb_prev,SIGNAL(clicked()),SLOT(doPrev()));
|
||||
pb_prev->setEnabled(true);
|
||||
}
|
||||
else
|
||||
pb_prev->setEnabled(false);
|
||||
hb->addWidget(pb_prev);
|
||||
|
||||
// Next
|
||||
pb_next = new QPushButton(tr("Next"),this);
|
||||
if (r.actions().contains(AHCommand::Next)) {
|
||||
if (r.defaultAction() == AHCommand::Next) {
|
||||
connect(pb_next,SIGNAL(clicked()),SLOT(doExecute()));
|
||||
pb_next->setDefault(true);
|
||||
pb_next->setFocus();
|
||||
}
|
||||
else
|
||||
connect(pb_next,SIGNAL(clicked()),SLOT(doNext()));
|
||||
pb_next->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
pb_next->setEnabled(false);
|
||||
}
|
||||
hb->addWidget(pb_next);
|
||||
|
||||
// Complete
|
||||
pb_complete = new QPushButton(tr("Finish"),this);
|
||||
if (r.actions().contains(AHCommand::Complete)) {
|
||||
if (r.defaultAction() == AHCommand::Complete) {
|
||||
connect(pb_complete,SIGNAL(clicked()),SLOT(doExecute()));
|
||||
pb_complete->setDefault(true);
|
||||
pb_complete->setFocus();
|
||||
}
|
||||
else
|
||||
connect(pb_complete,SIGNAL(clicked()),SLOT(doComplete()));
|
||||
pb_complete->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
pb_complete->setEnabled(false);
|
||||
}
|
||||
hb->addWidget(pb_complete);
|
||||
}
|
||||
pb_cancel = new QPushButton(tr("Cancel"), this);
|
||||
connect(pb_cancel, SIGNAL(clicked()),SLOT(doCancel()));
|
||||
hb->addWidget(pb_cancel);
|
||||
}
|
||||
else {
|
||||
hb->addItem(new QSpacerItem(20,0,QSizePolicy::Expanding));
|
||||
|
||||
pb_complete = new QPushButton(tr("Ok"),this);
|
||||
connect(pb_complete,SIGNAL(clicked()),SLOT(close()));
|
||||
hb->addWidget(pb_complete);
|
||||
}
|
||||
|
||||
if (!r.data().title().isEmpty()) {
|
||||
setCaption(QString("%1 (%2)").arg(r.data().title()).arg(receiver.full()));
|
||||
}
|
||||
else {
|
||||
setCaption(QString("%1").arg(receiver.full()));
|
||||
}
|
||||
}
|
||||
|
||||
void AHCFormDlg::doPrev()
|
||||
{
|
||||
busy_->start();
|
||||
AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_,AHCommand::Prev), client_->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(commandExecuted()));
|
||||
t->go(true);
|
||||
}
|
||||
|
||||
void AHCFormDlg::doNext()
|
||||
{
|
||||
busy_->start();
|
||||
AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_,AHCommand::Next),client_->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(commandExecuted()));
|
||||
t->go(true);
|
||||
}
|
||||
|
||||
void AHCFormDlg::doExecute()
|
||||
{
|
||||
busy_->start();
|
||||
AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_),client_->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(commandExecuted()));
|
||||
t->go(true);
|
||||
}
|
||||
|
||||
void AHCFormDlg::doComplete()
|
||||
{
|
||||
busy_->start();
|
||||
AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,data(),sessionId_,AHCommand::Complete), client_->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(commandExecuted()));
|
||||
t->go(true);
|
||||
}
|
||||
|
||||
void AHCFormDlg::doCancel()
|
||||
{
|
||||
busy_->start();
|
||||
AHCExecuteTask* t = new AHCExecuteTask(receiver_,AHCommand(node_,sessionId_,AHCommand::Cancel), client_->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(commandExecuted()));
|
||||
t->go(true);
|
||||
}
|
||||
|
||||
void AHCFormDlg::commandExecuted()
|
||||
{
|
||||
busy_->stop();
|
||||
close();
|
||||
}
|
||||
|
||||
XData AHCFormDlg::data() const
|
||||
{
|
||||
XData x;
|
||||
x.setFields(xdata_->fields());
|
||||
x.setType(XData::Data_Submit);
|
||||
return x;
|
||||
}
|
||||
|
||||
67
src/ahcformdlg.h
Normal file
67
src/ahcformdlg.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* ahcformdlg.h - Ad-Hoc Command Form Dialog
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHCFORMDLG_H
|
||||
#define AHCFORMDLG_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
#include "xmpp_xdata.h"
|
||||
#include "xmpp_jid.h"
|
||||
#include "busywidget.h"
|
||||
|
||||
class QPushButton;
|
||||
class AHCommand;
|
||||
class XDataWidget;
|
||||
namespace XMPP {
|
||||
class Client;
|
||||
}
|
||||
|
||||
class AHCFormDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AHCFormDlg(const AHCommand& r, const XMPP::Jid& receiver, XMPP::Client* client, bool final = false);
|
||||
|
||||
protected:
|
||||
XMPP::XData data() const;
|
||||
|
||||
protected slots:
|
||||
void doPrev();
|
||||
void doNext();
|
||||
void doComplete();
|
||||
void doExecute();
|
||||
void doCancel();
|
||||
void commandExecuted();
|
||||
|
||||
private:
|
||||
QPushButton *pb_prev, *pb_next, *pb_complete, *pb_cancel;
|
||||
XDataWidget *xdata_;
|
||||
XMPP::Jid receiver_;
|
||||
QString node_;
|
||||
XMPP::Client* client_;
|
||||
QString sessionId_;
|
||||
BusyWidget* busy_;
|
||||
};
|
||||
|
||||
#endif
|
||||
365
src/ahcommand.cpp
Normal file
365
src/ahcommand.cpp
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* ahcommand.cpp - Ad-Hoc Command
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "ahcommand.h"
|
||||
#include "xmpp_xdata.h"
|
||||
|
||||
#define AHC_NS "http://jabber.org/protocol/commands"
|
||||
#define XMPPSTANZA_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// AHCommand: The class representing an Ad-Hoc command request or reply.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
AHCommand::AHCommand(const QString& node, const QString& sessionId, Action action) : node_(node), hasData_(false), status_(NoStatus), defaultAction_(NoAction), action_(action), sessionId_(sessionId)
|
||||
{
|
||||
}
|
||||
|
||||
AHCommand::AHCommand(const QString& node, XData data, const QString& sessionId, Action action) : node_(node), hasData_(true), data_(data), status_(NoStatus), defaultAction_(NoAction), action_(action), sessionId_(sessionId)
|
||||
{
|
||||
}
|
||||
|
||||
AHCommand::AHCommand(const QDomElement& q) : hasData_(false), defaultAction_(NoAction)
|
||||
{
|
||||
// Parse attributes
|
||||
QString status = q.attribute("status");
|
||||
setStatus(string2status(status));
|
||||
node_ = q.attribute("node");
|
||||
action_ = string2action(q.attribute("action"));
|
||||
sessionId_ = q.attribute("sessionid");
|
||||
|
||||
// Parse the body
|
||||
for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement e = n.toElement();
|
||||
if (e.isNull())
|
||||
continue;
|
||||
|
||||
QString tag = e.tagName();
|
||||
|
||||
// A form
|
||||
if (tag == "x" && e.attribute("xmlns") =="jabber:x:data") {
|
||||
data_.fromXml(e);
|
||||
hasData_ = true;
|
||||
}
|
||||
|
||||
// Actions
|
||||
else if (tag == "actions") {
|
||||
QString execute = e.attribute("execute");
|
||||
if (!execute.isEmpty())
|
||||
setDefaultAction(string2action(execute));
|
||||
|
||||
for (QDomNode m = e.firstChild(); !m.isNull(); m = m.nextSibling()) {
|
||||
Action a = string2action(m.toElement().tagName());
|
||||
if (a == Prev || a == Next || a == Complete)
|
||||
actions_ += a;
|
||||
}
|
||||
}
|
||||
else if (tag == "note") {
|
||||
XMPP::XData::Field field;
|
||||
field.setType(XMPP::XData::Field::Field_Fixed);
|
||||
field.setValue(QStringList() << e.text());
|
||||
data_.setFields(XMPP::XData::FieldList() << field);
|
||||
hasData_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement AHCommand::toXml(QDomDocument* doc, bool submit) const
|
||||
{
|
||||
QDomElement command = doc->createElement("command");
|
||||
command.setAttribute("xmlns", AHC_NS);
|
||||
if (status_ != NoStatus)
|
||||
command.setAttribute("status",status2string(status()));
|
||||
if (hasData())
|
||||
command.appendChild(data().toXml(doc, submit));
|
||||
if (action_ != Execute)
|
||||
command.setAttribute("action",action2string(action_));
|
||||
command.setAttribute("node", node_);
|
||||
if (!sessionId_.isEmpty())
|
||||
command.setAttribute("sessionid", sessionId_);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
AHCommand AHCommand::formReply(const AHCommand& c, const XData& data)
|
||||
{
|
||||
AHCommand r(c.node(), data, c.sessionId());
|
||||
r.setStatus(AHCommand::Executing);
|
||||
return r;
|
||||
}
|
||||
|
||||
AHCommand AHCommand::formReply(const AHCommand& c, const XData& data, const QString& sessionId)
|
||||
{
|
||||
AHCommand r(c.node(), data, sessionId);
|
||||
r.setStatus(AHCommand::Executing);
|
||||
return r;
|
||||
}
|
||||
|
||||
AHCommand AHCommand::canceledReply(const AHCommand& c)
|
||||
{
|
||||
AHCommand r(c.node(), c.sessionId());
|
||||
r.setStatus(Canceled);
|
||||
return r;
|
||||
}
|
||||
|
||||
AHCommand AHCommand::completedReply(const AHCommand& c)
|
||||
{
|
||||
AHCommand r(c.node(), c.sessionId());
|
||||
r.setStatus(Completed);
|
||||
return r;
|
||||
}
|
||||
|
||||
AHCommand AHCommand::completedReply(const AHCommand& c, const XData& d)
|
||||
{
|
||||
AHCommand r(c.node(), d, c.sessionId());
|
||||
r.setStatus(Completed);
|
||||
return r;
|
||||
}
|
||||
|
||||
//AHCommand AHCommand::errorReply(const AHCommand& c, const AHCError& error)
|
||||
//{
|
||||
// AHCommand r(c.node(), c.sessionId());
|
||||
// r.setError(error);
|
||||
// return r;
|
||||
//}
|
||||
|
||||
void AHCommand::setStatus(Status s)
|
||||
{
|
||||
status_ = s;
|
||||
}
|
||||
|
||||
void AHCommand::setError(const AHCError& e)
|
||||
{
|
||||
error_ = e;
|
||||
}
|
||||
|
||||
void AHCommand::setDefaultAction(Action a)
|
||||
{
|
||||
defaultAction_ = a;
|
||||
}
|
||||
|
||||
QString AHCommand::status2string(Status status)
|
||||
{
|
||||
QString s;
|
||||
switch (status) {
|
||||
case Executing : s = "executing"; break;
|
||||
case Completed : s = "completed"; break;
|
||||
case Canceled : s = "canceled"; break;
|
||||
case NoStatus : s = ""; break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
QString AHCommand::action2string(Action action)
|
||||
{
|
||||
QString s;
|
||||
switch (action) {
|
||||
case Prev : s = "prev"; break;
|
||||
case Next : s = "next"; break;
|
||||
case Cancel : s = "cancel"; break;
|
||||
case Complete : s = "complete"; break;
|
||||
default: break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
AHCommand::Action AHCommand::string2action(const QString& s)
|
||||
{
|
||||
if (s == "prev")
|
||||
return Prev;
|
||||
else if (s == "next")
|
||||
return Next;
|
||||
else if (s == "complete")
|
||||
return Complete;
|
||||
else if (s == "cancel")
|
||||
return Cancel;
|
||||
else
|
||||
return Execute;
|
||||
}
|
||||
|
||||
AHCommand::Status AHCommand::string2status(const QString& s)
|
||||
{
|
||||
if (s == "canceled")
|
||||
return Canceled;
|
||||
else if (s == "completed")
|
||||
return Completed;
|
||||
else if (s == "executing")
|
||||
return Executing;
|
||||
else
|
||||
return NoStatus;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// AHCError: The class representing an Ad-Hoc command error
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
AHCError::AHCError(ErrorType t) : type_(t)
|
||||
{
|
||||
}
|
||||
|
||||
AHCError::AHCError(const QDomElement& e) : type_(None)
|
||||
{
|
||||
QString errorGeneral = "", errorSpecific = "";
|
||||
|
||||
for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement i = n.toElement();
|
||||
if(i.isNull())
|
||||
continue;
|
||||
|
||||
QString tag = i.tagName();
|
||||
|
||||
if ((tag == "bad-request" || tag == "not-allowed" || tag == "forbidden" || tag == "forbidden" || tag == "item-not-found" || tag == "feature-not-implemented") && e.attribute("xmlns") == XMPPSTANZA_NS) {
|
||||
errorGeneral = tag;
|
||||
}
|
||||
else if ((tag == "malformed-action" || tag == "bad-action" || tag == "bad-locale" || tag == "bad-payload" || tag == "bad-sessionid" || tag == "session-expired") && e.attribute("xmlns") == AHC_NS) {
|
||||
errorSpecific = tag;
|
||||
}
|
||||
}
|
||||
|
||||
type_ = strings2error(errorGeneral, errorSpecific);
|
||||
}
|
||||
|
||||
QDomElement AHCError::toXml(QDomDocument* doc) const
|
||||
{
|
||||
QDomElement err = doc->createElement("error");
|
||||
|
||||
// Error handling
|
||||
if (type_ != None) {
|
||||
QString desc, specificCondition = "";
|
||||
switch (type_) {
|
||||
case MalformedAction:
|
||||
desc = "bad-request";
|
||||
specificCondition = "malformed-action";
|
||||
break;
|
||||
case BadAction:
|
||||
desc = "bad-request";
|
||||
specificCondition = "bad-action";
|
||||
break;
|
||||
case BadLocale:
|
||||
desc = "bad-request";
|
||||
specificCondition = "bad-locale";
|
||||
break;
|
||||
case BadPayload:
|
||||
desc = "bad-request";
|
||||
specificCondition = "bad-payload";
|
||||
break;
|
||||
case BadSessionID:
|
||||
desc = "bad-request";
|
||||
specificCondition = "bad-sessionid";
|
||||
break;
|
||||
case SessionExpired:
|
||||
desc = "not-allowed";
|
||||
specificCondition = "session-expired";
|
||||
break;
|
||||
case Forbidden:
|
||||
desc = "forbidden";
|
||||
break;
|
||||
case ItemNotFound:
|
||||
desc = "item-not-found";
|
||||
break;
|
||||
case FeatureNotImplemented:
|
||||
desc = "feature-not-implemented";
|
||||
break;
|
||||
case None:
|
||||
break;
|
||||
}
|
||||
|
||||
// General error condition
|
||||
QDomElement generalElement = doc->createElement(desc);
|
||||
generalElement.setAttribute("xmlns", XMPPSTANZA_NS);
|
||||
err.appendChild(generalElement);
|
||||
|
||||
// Specific error condition
|
||||
if (!specificCondition.isEmpty()) {
|
||||
QDomElement generalElement = doc->createElement(specificCondition);
|
||||
generalElement.setAttribute("xmlns", AHC_NS);
|
||||
err.appendChild(generalElement);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
AHCError::ErrorType AHCError::strings2error(const QString& g, const QString& s)
|
||||
{
|
||||
if (s == "malformed-action")
|
||||
return MalformedAction;
|
||||
if (s == "bad-action")
|
||||
return BadAction;
|
||||
if (s == "bad-locale")
|
||||
return BadLocale;
|
||||
if (s == "bad-payload")
|
||||
return BadPayload;
|
||||
if (s == "bad-sessionid")
|
||||
return BadSessionID;
|
||||
if (s == "session-expired")
|
||||
return SessionExpired;
|
||||
if (g == "forbidden")
|
||||
return Forbidden;
|
||||
if (g == "item-not-found")
|
||||
return ItemNotFound;
|
||||
if (g == "feature-not-implemented")
|
||||
return FeatureNotImplemented;
|
||||
return None;
|
||||
}
|
||||
|
||||
QString AHCError::error2description(const AHCError& e)
|
||||
{
|
||||
QString desc;
|
||||
switch (e.type()) {
|
||||
case MalformedAction:
|
||||
desc = QString("The responding JID does not understand the specified action");
|
||||
break;
|
||||
case BadAction:
|
||||
desc = QString("The responding JID cannot accept the specified action");
|
||||
break;
|
||||
case BadLocale:
|
||||
desc = QString("The responding JID cannot accept the specified language/locale");
|
||||
break;
|
||||
case BadPayload:
|
||||
desc = QString("The responding JID cannot accept the specified payload (eg the data form did not provide one or more required fields)");
|
||||
break;
|
||||
case BadSessionID:
|
||||
desc = QString("The responding JID cannot accept the specified sessionid");
|
||||
break;
|
||||
case SessionExpired:
|
||||
desc = QString("The requesting JID specified a sessionid that is no longer active (either because it was completed, canceled, or timed out)");
|
||||
break;
|
||||
case Forbidden:
|
||||
desc = QString("The requesting JID is not allowed to execute the command");
|
||||
break;
|
||||
case ItemNotFound:
|
||||
desc = QString("The responding JID cannot find the requested command node");
|
||||
break;
|
||||
case FeatureNotImplemented:
|
||||
desc = QString("The responding JID does not support Ad-hoc commands");
|
||||
break;
|
||||
case None:
|
||||
break;
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
112
src/ahcommand.h
Normal file
112
src/ahcommand.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* ahcommand.h - Ad-Hoc Command
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHCOMMAND_H
|
||||
#define AHCOMMAND_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "xmpp_xdata.h"
|
||||
|
||||
class QDomElement;
|
||||
class QDomDocument;
|
||||
|
||||
class AHCError
|
||||
{
|
||||
public:
|
||||
enum ErrorType {
|
||||
None, MalformedAction, BadAction, BadLocale,
|
||||
BadPayload, BadSessionID, SessionExpired, Forbidden, ItemNotFound,
|
||||
FeatureNotImplemented
|
||||
};
|
||||
|
||||
AHCError(ErrorType = None);
|
||||
AHCError(const QDomElement& e);
|
||||
|
||||
ErrorType type() const { return type_; }
|
||||
static QString error2description(const AHCError&);
|
||||
QDomElement toXml(QDomDocument* doc) const;
|
||||
|
||||
protected:
|
||||
static ErrorType strings2error(const QString&, const QString&);
|
||||
|
||||
private:
|
||||
ErrorType type_;
|
||||
};
|
||||
|
||||
|
||||
class AHCommand
|
||||
{
|
||||
public:
|
||||
// Types
|
||||
enum Action { NoAction, Execute, Prev, Next, Complete, Cancel };
|
||||
enum Status { NoStatus, Completed, Executing, Canceled };
|
||||
typedef QList<Action> ActionList;
|
||||
|
||||
// Constructors
|
||||
AHCommand(const QString& node, const QString& sessionId = "", Action action = Execute);
|
||||
AHCommand(const QString& node, XMPP::XData data, const QString& sessionId = "", Action action = Execute);
|
||||
AHCommand(const QDomElement &e);
|
||||
|
||||
// Inspectors
|
||||
const QString& node() const { return node_; }
|
||||
bool hasData() const { return hasData_; }
|
||||
const XMPP::XData& data() const { return data_; }
|
||||
const ActionList& actions() const { return actions_; }
|
||||
Action defaultAction() const { return defaultAction_; }
|
||||
Status status() const { return status_; }
|
||||
Action action() const { return action_; }
|
||||
const QString& sessionId() const { return sessionId_; }
|
||||
const AHCError& error() const { return error_; }
|
||||
|
||||
// XML conversion
|
||||
QDomElement toXml(QDomDocument* doc, bool submit) const;
|
||||
|
||||
// Helper constructors
|
||||
static AHCommand formReply(const AHCommand&, const XMPP::XData&);
|
||||
static AHCommand formReply(const AHCommand&, const XMPP::XData&, const QString& sessionId);
|
||||
static AHCommand canceledReply(const AHCommand&);
|
||||
static AHCommand completedReply(const AHCommand&);
|
||||
static AHCommand completedReply(const AHCommand&, const XMPP::XData&);
|
||||
//static AHCommand errorReply(const AHCommand&, const AHCError&);
|
||||
|
||||
protected:
|
||||
void setStatus(Status s);
|
||||
void setError(const AHCError& e);
|
||||
void setDefaultAction(Action a);
|
||||
|
||||
static QString action2string(Action);
|
||||
static QString status2string(Status);
|
||||
static Action string2action(const QString&);
|
||||
static Status string2status(const QString&);
|
||||
|
||||
private:
|
||||
QString node_;
|
||||
bool hasData_;
|
||||
XMPP::XData data_;
|
||||
Status status_;
|
||||
Action defaultAction_;
|
||||
ActionList actions_;
|
||||
Action action_;
|
||||
QString sessionId_;
|
||||
AHCError error_;
|
||||
};
|
||||
|
||||
#endif
|
||||
207
src/ahcommanddlg.cpp
Normal file
207
src/ahcommanddlg.cpp
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* ahcommanddlg.cpp - Ad-Hoc Command Dialog
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QLayout>
|
||||
#include <QLabel>
|
||||
|
||||
#include "ahcexecutetask.h"
|
||||
#include "ahcommanddlg.h"
|
||||
#include "busywidget.h"
|
||||
#include "psiaccount.h"
|
||||
#include "xmpp_xmlcommon.h"
|
||||
#include "xmpp_client.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
#define AHC_NS "http://jabber.org/protocol/commands"
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static bool operator<(const AHCommandItem &ci1, const AHCommandItem &ci2)
|
||||
{
|
||||
return ci1.name < ci2.name;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// JT_AHCGetList: A Task to retreive the available commands of a client
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
class JT_AHCGetList : public Task
|
||||
{
|
||||
public:
|
||||
JT_AHCGetList(Task* t, const Jid& j);
|
||||
|
||||
void onGo();
|
||||
bool take(const QDomElement &x);
|
||||
|
||||
const QList<AHCommandItem>& commands() const { return commands_; }
|
||||
|
||||
private:
|
||||
Jid receiver_;
|
||||
QList<AHCommandItem> commands_;
|
||||
};
|
||||
|
||||
|
||||
JT_AHCGetList::JT_AHCGetList(Task* t, const Jid& j) : Task(t), receiver_(j)
|
||||
{
|
||||
}
|
||||
|
||||
void JT_AHCGetList::onGo()
|
||||
{
|
||||
QDomElement e = createIQ(doc(), "get", receiver_.full(), id());
|
||||
QDomElement q = doc()->createElement("query");
|
||||
q.setAttribute("xmlns", "http://jabber.org/protocol/disco#items");
|
||||
q.setAttribute("node", AHC_NS);
|
||||
e.appendChild(q);
|
||||
send(e);
|
||||
}
|
||||
|
||||
bool JT_AHCGetList::take(const QDomElement& e)
|
||||
{
|
||||
if(!iqVerify(e, receiver_, id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.attribute("type") == "result") {
|
||||
// Extract commands
|
||||
commands_.clear();
|
||||
bool found;
|
||||
QDomElement commands = findSubTag(e, "query", &found);
|
||||
if(found) {
|
||||
for(QDomNode n = commands.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement i = n.toElement();
|
||||
if(i.isNull())
|
||||
continue;
|
||||
|
||||
if(i.tagName() == "item") {
|
||||
AHCommandItem ci;
|
||||
ci.node = i.attribute("node");
|
||||
ci.name = i.attribute("name");
|
||||
ci.jid = i.attribute("jid");
|
||||
commands_ += ci;
|
||||
}
|
||||
}
|
||||
qSort(commands_);
|
||||
}
|
||||
setSuccess();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
setError(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// JT_AHCommandDlg: Initial command dialog
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
AHCommandDlg::AHCommandDlg(PsiAccount* pa, const Jid& receiver)
|
||||
: QDialog(0), pa_(pa), receiver_(receiver)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
QVBoxLayout *vb = new QVBoxLayout(this, 11, 6);
|
||||
|
||||
// Command list + Buttons
|
||||
QLabel* lb_commands = new QLabel(tr("Command:"),this);
|
||||
vb->addWidget(lb_commands);
|
||||
cb_commands = new QComboBox(this);
|
||||
vb->addWidget(cb_commands);
|
||||
/*pb_info = new QPushButton(tr("Info"), this);
|
||||
hb1->addWidget(pb_info);*/
|
||||
|
||||
// Refresh button
|
||||
//pb_refresh = new QPushButton(tr("Refresh"), this);
|
||||
//hb2->addWidget(pb_refresh);
|
||||
//connect(pb_refresh, SIGNAL(clicked()), SLOT(refreshCommands()));
|
||||
|
||||
vb->addStretch(1);
|
||||
|
||||
// Bottom row
|
||||
QHBoxLayout *hb2 = new QHBoxLayout(vb);
|
||||
busy_ = new BusyWidget(this);
|
||||
hb2->addWidget(busy_);
|
||||
hb2->addItem(new QSpacerItem(20,0,QSizePolicy::Expanding));
|
||||
pb_execute = new QPushButton(tr("Execute"), this);
|
||||
hb2->addWidget(pb_execute);
|
||||
connect(pb_execute, SIGNAL(clicked()), SLOT(executeCommand()));
|
||||
pb_close = new QPushButton(tr("Close"), this);
|
||||
hb2->addWidget(pb_close);
|
||||
connect(pb_close, SIGNAL(clicked()), SLOT(close()));
|
||||
pb_close->setDefault(true);
|
||||
pb_close->setFocus();
|
||||
|
||||
setCaption(QString("Execute Command (%1)").arg(receiver.full()));
|
||||
|
||||
// Load commands
|
||||
refreshCommands();
|
||||
}
|
||||
|
||||
|
||||
void AHCommandDlg::refreshCommands()
|
||||
{
|
||||
cb_commands->clear();
|
||||
pb_execute->setEnabled(false);
|
||||
//pb_info->setEnabled(false);
|
||||
|
||||
busy_->start();
|
||||
JT_AHCGetList* t= new JT_AHCGetList(pa_->client()->rootTask(),receiver_);
|
||||
connect(t,SIGNAL(finished()),SLOT(listReceived()));
|
||||
t->go(true);
|
||||
}
|
||||
|
||||
void AHCommandDlg::listReceived()
|
||||
{
|
||||
JT_AHCGetList* task_list = (JT_AHCGetList*) sender();
|
||||
foreach(AHCommandItem i, task_list->commands()) {
|
||||
cb_commands->insertItem(i.name);
|
||||
commands_.append(i);
|
||||
}
|
||||
pb_execute->setEnabled(cb_commands->count()>0);
|
||||
busy_->stop();
|
||||
}
|
||||
|
||||
void AHCommandDlg::executeCommand()
|
||||
{
|
||||
if (cb_commands->count() > 0) {
|
||||
busy_->start();
|
||||
Jid to(commands_[cb_commands->currentItem()].jid);
|
||||
QString node = commands_[cb_commands->currentItem()].node;
|
||||
AHCExecuteTask* t = new AHCExecuteTask(to,AHCommand(node),pa_->client()->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(commandExecuted()));
|
||||
t->go(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AHCommandDlg::commandExecuted()
|
||||
{
|
||||
busy_->stop();
|
||||
close();
|
||||
}
|
||||
|
||||
void AHCommandDlg::executeCommand(XMPP::Client* c, const XMPP::Jid& to, const QString &node)
|
||||
{
|
||||
AHCExecuteTask* t = new AHCExecuteTask(to,AHCommand(node),c->rootTask());
|
||||
t->go(true);
|
||||
}
|
||||
64
src/ahcommanddlg.h
Normal file
64
src/ahcommanddlg.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* ahcommanddlg.h - Ad-Hoc Command Dialog
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHCOMMANDDLG_H
|
||||
#define AHCOMMANDDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
|
||||
#include "busywidget.h"
|
||||
#include "xmpp_jid.h"
|
||||
|
||||
namespace XMPP {
|
||||
class Client;
|
||||
}
|
||||
|
||||
class PsiAccount;
|
||||
class QObject;
|
||||
class QComboBox;
|
||||
class QPushButton;
|
||||
|
||||
typedef struct { QString jid, node, name; } AHCommandItem;
|
||||
|
||||
class AHCommandDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AHCommandDlg(PsiAccount*, const XMPP::Jid& receiver);
|
||||
static void executeCommand(XMPP::Client*, const XMPP::Jid& j, const QString &node);
|
||||
|
||||
protected slots:
|
||||
void refreshCommands();
|
||||
void listReceived();
|
||||
void executeCommand();
|
||||
void commandExecuted();
|
||||
|
||||
private:
|
||||
PsiAccount* pa_;
|
||||
QPushButton *pb_execute, *pb_close, *pb_refresh /*,*pb_info*/;
|
||||
XMPP::Jid receiver_;
|
||||
QComboBox* cb_commands;
|
||||
QList<AHCommandItem> commands_;
|
||||
BusyWidget* busy_;
|
||||
};
|
||||
|
||||
#endif
|
||||
40
src/ahcommandserver.cpp
Normal file
40
src/ahcommandserver.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ahcommandserver.cpp - Server implementation of JEP-50 (Ad-Hoc Commands)
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ahcommandserver.h"
|
||||
#include "ahcservermanager.h"
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// AHCommandServer: The server-side implementation of an Ad-hoc command.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
AHCommandServer::AHCommandServer(AHCServerManager* manager)
|
||||
: QObject(manager)
|
||||
, manager_(manager)
|
||||
{
|
||||
manager_->addServer(this);
|
||||
}
|
||||
|
||||
AHCommandServer::~AHCommandServer()
|
||||
{
|
||||
manager_->removeServer(this);
|
||||
}
|
||||
|
||||
|
||||
53
src/ahcommandserver.h
Normal file
53
src/ahcommandserver.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* ahcommandserver.h - Server implementation of JEP-50 (Ad-Hoc Commands)
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHCOMMANDSERVER_H
|
||||
#define AHCOMMANDSERVER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class AHCServerManager;
|
||||
class QString;
|
||||
class AHCommand;
|
||||
namespace XMPP {
|
||||
class Jid;
|
||||
}
|
||||
|
||||
class AHCommandServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AHCommandServer(AHCServerManager*);
|
||||
virtual ~AHCommandServer();
|
||||
|
||||
virtual QString name() const = 0;
|
||||
virtual QString node() const = 0;
|
||||
virtual bool isAllowed(const XMPP::Jid&) const { return true; }
|
||||
virtual AHCommand execute(const AHCommand&, const XMPP::Jid& requester) = 0;
|
||||
virtual void cancel(const AHCommand&) { }
|
||||
|
||||
protected:
|
||||
AHCServerManager* manager() const { return manager_; }
|
||||
|
||||
private:
|
||||
AHCServerManager* manager_;
|
||||
};
|
||||
|
||||
#endif
|
||||
265
src/ahcservermanager.cpp
Normal file
265
src/ahcservermanager.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* ahcservermanager.cpp - Server implementation of JEP-50 (Ad-Hoc Commands)
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <qcombobox.h>
|
||||
#include <qmessagebox.h>
|
||||
#include <qpushbutton.h>
|
||||
#include <qlayout.h>
|
||||
|
||||
#include "ahcservermanager.h"
|
||||
#include "ahcommandserver.h"
|
||||
#include "psiaccount.h"
|
||||
|
||||
#include "xmpp_xmlcommon.h"
|
||||
#include "xmpp_tasks.h"
|
||||
#include "xmpp_xdata.h"
|
||||
#include "xdata_widget.h"
|
||||
#include "ahcommand.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
#define AHC_NS "http://jabber.org/protocol/commands"
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// JT_AHCServer: Task to handle ad-hoc command requests
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
class JT_AHCServer : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
JT_AHCServer(Task*, AHCServerManager*);
|
||||
bool take(const QDomElement& e);
|
||||
void sendReply(const AHCommand&, const Jid& to, const QString& id);
|
||||
|
||||
protected:
|
||||
bool commandListQuery(const QDomElement& e);
|
||||
bool commandExecuteQuery(const QDomElement& e);
|
||||
void sendCommandList(const QString& to, const QString& from, const QString& id);
|
||||
|
||||
private:
|
||||
AHCServerManager* manager_;
|
||||
};
|
||||
|
||||
|
||||
JT_AHCServer::JT_AHCServer(Task* t, AHCServerManager* manager) : Task(t), manager_(manager)
|
||||
{
|
||||
}
|
||||
|
||||
bool JT_AHCServer::take(const QDomElement& e)
|
||||
{
|
||||
// Check if it's a query
|
||||
if (e.tagName() != "iq")
|
||||
return false;
|
||||
|
||||
return (commandListQuery(e) || commandExecuteQuery(e));
|
||||
}
|
||||
|
||||
bool JT_AHCServer::commandListQuery(const QDomElement& e)
|
||||
{
|
||||
if (e.attribute("type") == "get") {
|
||||
bool found;
|
||||
QDomElement q = findSubTag(e, "query", &found);
|
||||
if (!found)
|
||||
return false;
|
||||
|
||||
// Disco replies to the AdHoc node
|
||||
if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#items" && q.attribute("node") == AHC_NS) {
|
||||
sendCommandList(e.attribute("from"),e.attribute("to"),e.attribute("id"));
|
||||
return true;
|
||||
}
|
||||
else if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#info" && q.attribute("node") == AHC_NS) {
|
||||
QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
|
||||
QDomElement query = doc()->createElement("query");
|
||||
query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
|
||||
iq.appendChild(query);
|
||||
send(iq);
|
||||
return true;
|
||||
}
|
||||
// Disco replies to specific adhoc nodes
|
||||
else if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#items" && manager_->hasServer(q.attribute("node"), Jid(e.attribute("from")))) {
|
||||
QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
|
||||
QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); query.setAttribute("node",q.attribute("node"));
|
||||
iq.appendChild(query);
|
||||
|
||||
send(iq);
|
||||
return true;
|
||||
}
|
||||
else if (q.attribute("xmlns") == "http://jabber.org/protocol/disco#info" && manager_->hasServer(q.attribute("node"), Jid(e.attribute("from")))) {
|
||||
QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
|
||||
QDomElement query = doc()->createElement("query");
|
||||
query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
|
||||
query.setAttribute("node",q.attribute("node"));
|
||||
iq.appendChild(query);
|
||||
|
||||
QDomElement identity;
|
||||
identity = doc()->createElement("identity");
|
||||
identity.setAttribute("category", "automation");
|
||||
identity.setAttribute("type", "command-node");
|
||||
query.appendChild(identity);
|
||||
|
||||
QDomElement feature;
|
||||
feature = doc()->createElement("feature");
|
||||
feature.setAttribute("var", AHC_NS);
|
||||
query.appendChild(feature);
|
||||
|
||||
feature = doc()->createElement("feature");
|
||||
feature.setAttribute("var", "jabber:x:data");
|
||||
query.appendChild(feature);
|
||||
|
||||
send(iq);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JT_AHCServer::commandExecuteQuery(const QDomElement& e)
|
||||
{
|
||||
if (e.attribute("type") == "set") {
|
||||
bool found;
|
||||
QDomElement q = findSubTag(e, "command", &found);
|
||||
if (found && q.attribute("xmlns") == AHC_NS && manager_->hasServer(q.attribute("node"), Jid(e.attribute("from")))) {
|
||||
AHCommand command(q);
|
||||
manager_->execute(command, Jid(e.attribute("from")), e.attribute("id"));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void JT_AHCServer::sendCommandList(const QString& to, const QString& from, const QString& id)
|
||||
{
|
||||
// Create query element
|
||||
QDomElement iq = createIQ(doc(), "result", to, id);
|
||||
QDomElement query = doc()->createElement("query");
|
||||
query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items");
|
||||
query.setAttribute("node", AHC_NS);
|
||||
iq.appendChild(query);
|
||||
|
||||
// Add all commands
|
||||
foreach(AHCommandServer* c, manager_->commands(Jid(to))) {
|
||||
QDomElement command = doc()->createElement("item");
|
||||
command.setAttribute("jid",from);
|
||||
command.setAttribute("name",c->name());
|
||||
command.setAttribute("node",c->node());
|
||||
query.appendChild(command);
|
||||
}
|
||||
|
||||
// Send the message
|
||||
send(iq);
|
||||
}
|
||||
|
||||
void JT_AHCServer::sendReply(const AHCommand& c, const Jid& to, const QString& id)
|
||||
{
|
||||
// if (c.error().type() != AHCError::None) {
|
||||
QDomElement iq = createIQ(doc(), "result", to.full(), id);
|
||||
QDomElement command = c.toXml(doc(), false);
|
||||
iq.appendChild(command);
|
||||
send(iq);
|
||||
// }
|
||||
// else {
|
||||
// }
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
AHCServerManager::AHCServerManager(PsiAccount *pa)
|
||||
: QObject(pa)
|
||||
, pa_(pa)
|
||||
{
|
||||
server_task_ = new JT_AHCServer(pa_->client()->rootTask(), this);
|
||||
}
|
||||
|
||||
AHCServerManager::~AHCServerManager()
|
||||
{
|
||||
qDeleteAll(servers_);
|
||||
}
|
||||
|
||||
void AHCServerManager::addServer(AHCommandServer* server)
|
||||
{
|
||||
servers_.append(server);
|
||||
}
|
||||
|
||||
void AHCServerManager::removeServer(AHCommandServer* server)
|
||||
{
|
||||
servers_.removeAll(server);
|
||||
}
|
||||
|
||||
AHCServerManager::ServerList AHCServerManager::commands(const Jid& j) const
|
||||
{
|
||||
ServerList list;
|
||||
for (ServerList::ConstIterator it = servers_.begin(); it != servers_.end(); ++it) {
|
||||
if ((*it)->isAllowed(j))
|
||||
list.append(*it);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
void AHCServerManager::execute(const AHCommand& command, const Jid& requester, QString id)
|
||||
{
|
||||
AHCommandServer* c = findServer(command.node());
|
||||
|
||||
// Check if the command is provided
|
||||
if (!c) {
|
||||
//server_task_->sendReply(AHCommand::errorReply(command,AHCError(AHCError::ItemNotFound)), requester, id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the requester is allowed to execute the command
|
||||
if (c->isAllowed(requester)) {
|
||||
if (command.action() == AHCommand::Cancel) {
|
||||
c->cancel(command);
|
||||
server_task_->sendReply(AHCommand::canceledReply(command), requester, id);
|
||||
}
|
||||
else
|
||||
// Execute the command & send back the response
|
||||
server_task_->sendReply(c->execute(command, requester), requester, id);
|
||||
}
|
||||
else {
|
||||
//server_task_->sendReply(AHCommand::errorReply(command,AHCError(AHCError::Forbidden)), requester, id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AHCServerManager::hasServer(const QString& node, const Jid& requester) const
|
||||
{
|
||||
AHCommandServer* c = findServer(node);
|
||||
return c && c->isAllowed(requester);
|
||||
}
|
||||
|
||||
AHCommandServer* AHCServerManager::findServer(const QString& node) const
|
||||
{
|
||||
for (ServerList::ConstIterator it = servers_.begin(); it != servers_.end(); ++it) {
|
||||
if ((*it)->node() == node)
|
||||
return (*it);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#include "ahcservermanager.moc"
|
||||
60
src/ahcservermanager.h
Normal file
60
src/ahcservermanager.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* ahcservermanager.h - Server implementation of JEP-50 (Ad-Hoc Commands)
|
||||
* Copyright (C) 2005 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHCSERVERMANAGER_H
|
||||
#define AHCSERVERMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
|
||||
class AHCommandServer;
|
||||
class AHCommand;
|
||||
class JT_AHCServer;
|
||||
class PsiAccount;
|
||||
class QString;
|
||||
namespace XMPP {
|
||||
class Jid;
|
||||
}
|
||||
|
||||
class AHCServerManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AHCServerManager(PsiAccount* pa);
|
||||
~AHCServerManager();
|
||||
void addServer(AHCommandServer*);
|
||||
void removeServer(AHCommandServer*);
|
||||
|
||||
typedef QList<AHCommandServer*> ServerList;
|
||||
ServerList commands(const XMPP::Jid&) const;
|
||||
void execute(const AHCommand& command, const XMPP::Jid& requester, QString id);
|
||||
PsiAccount* account() const { return pa_; }
|
||||
bool hasServer(const QString& node, const XMPP::Jid&) const;
|
||||
|
||||
protected:
|
||||
AHCommandServer* findServer(const QString& node) const;
|
||||
|
||||
private:
|
||||
PsiAccount* pa_;
|
||||
JT_AHCServer* server_task_;
|
||||
ServerList servers_;
|
||||
};
|
||||
|
||||
#endif
|
||||
84
src/alertable.cpp
Normal file
84
src/alertable.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* alertable.cpp - simplify alert icon plumbing
|
||||
* Copyright (C) 2006 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "alertable.h"
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
#include "alerticon.h"
|
||||
|
||||
/**
|
||||
* Class to simplify alert icon plumbing. You'll have to re-implement
|
||||
* alertFrameUpdated() in your subclass.
|
||||
*/
|
||||
Alertable::Alertable(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
alert_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys alert icon along with itself;
|
||||
*/
|
||||
Alertable::~Alertable()
|
||||
{
|
||||
setAlert(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if alert is set, and false otherwise.
|
||||
*/
|
||||
bool Alertable::alerting() const
|
||||
{
|
||||
return alert_ != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current animation frame of alert, or null QIcon, if
|
||||
* there is no alert.
|
||||
*/
|
||||
QIcon Alertable::currentAlertFrame() const
|
||||
{
|
||||
if (!alert_)
|
||||
return QIcon();
|
||||
|
||||
return alert_->impix().pixmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new AlertIcon based on provided \param icon. If 0 is passed,
|
||||
* alert is cleared.
|
||||
*/
|
||||
void Alertable::setAlert(const PsiIcon* icon)
|
||||
{
|
||||
if (alert_) {
|
||||
alert_->stop();
|
||||
delete alert_;
|
||||
alert_ = 0;
|
||||
}
|
||||
|
||||
if (icon) {
|
||||
alert_ = new AlertIcon(icon);
|
||||
alert_->activated(false);
|
||||
|
||||
connect(alert_, SIGNAL(pixmapChanged()), SLOT(alertFrameUpdated()));
|
||||
alertFrameUpdated();
|
||||
}
|
||||
}
|
||||
49
src/alertable.h
Normal file
49
src/alertable.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* alertable.h - simplify alert icon plumbing
|
||||
* Copyright (C) 2006 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ALERTABLE_H
|
||||
#define ALERTABLE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class AlertIcon;
|
||||
class PsiIcon;
|
||||
class QIcon;
|
||||
|
||||
class Alertable : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Alertable(QObject* parent = 0);
|
||||
~Alertable();
|
||||
|
||||
bool alerting() const;
|
||||
QIcon currentAlertFrame() const;
|
||||
|
||||
void setAlert(const PsiIcon* icon);
|
||||
|
||||
private slots:
|
||||
virtual void alertFrameUpdated() = 0;
|
||||
|
||||
private:
|
||||
AlertIcon* alert_;
|
||||
};
|
||||
|
||||
#endif
|
||||
299
src/alerticon.cpp
Normal file
299
src/alerticon.cpp
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* alerticon.cpp - class for handling animating alert icons
|
||||
* Copyright (C) 2003 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "alerticon.h"
|
||||
#include "common.h"
|
||||
#include <qtimer.h>
|
||||
#include <qapplication.h>
|
||||
//Added by qt3to4:
|
||||
#include <QPixmap>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// MetaAlertIcon
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class MetaAlertIcon : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MetaAlertIcon();
|
||||
~MetaAlertIcon();
|
||||
|
||||
Impix blank16() const;
|
||||
int framenumber() const;
|
||||
|
||||
signals:
|
||||
void updateFrame(int frame);
|
||||
void update();
|
||||
|
||||
public slots:
|
||||
void updateAlertStyle();
|
||||
|
||||
private slots:
|
||||
void animTimeout();
|
||||
|
||||
private:
|
||||
QTimer *animTimer;
|
||||
int frame;
|
||||
Impix _blank16;
|
||||
};
|
||||
|
||||
static MetaAlertIcon *metaAlertIcon = 0;
|
||||
|
||||
MetaAlertIcon::MetaAlertIcon()
|
||||
: QObject(qApp)
|
||||
{
|
||||
animTimer = new QTimer(this);
|
||||
connect(animTimer, SIGNAL(timeout()), SLOT(animTimeout()));
|
||||
animTimer->start(120 * 5);
|
||||
frame = 0;
|
||||
|
||||
// blank icon
|
||||
QImage blankImg(16, 16, QImage::Format_ARGB32);
|
||||
blankImg.fill(0x00000000);
|
||||
_blank16.setImage(blankImg);
|
||||
}
|
||||
|
||||
MetaAlertIcon::~MetaAlertIcon()
|
||||
{
|
||||
}
|
||||
|
||||
Impix MetaAlertIcon::blank16() const
|
||||
{
|
||||
return _blank16;
|
||||
}
|
||||
|
||||
void MetaAlertIcon::animTimeout()
|
||||
{
|
||||
frame = !frame;
|
||||
emit updateFrame(frame);
|
||||
}
|
||||
|
||||
void MetaAlertIcon::updateAlertStyle()
|
||||
{
|
||||
emit update();
|
||||
}
|
||||
|
||||
int MetaAlertIcon::framenumber() const
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// AlertIcon::Private
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class AlertIcon::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Private(AlertIcon *_ai);
|
||||
~Private();
|
||||
|
||||
void init();
|
||||
|
||||
public slots:
|
||||
void update();
|
||||
void activated(bool playSound);
|
||||
void stop();
|
||||
|
||||
void updateFrame(int frame);
|
||||
void pixmapChanged();
|
||||
|
||||
public:
|
||||
AlertIcon *ai;
|
||||
PsiIcon *real;
|
||||
bool isActivated;
|
||||
Impix impix;
|
||||
};
|
||||
|
||||
AlertIcon::Private::Private(AlertIcon *_ai)
|
||||
{
|
||||
if ( !metaAlertIcon )
|
||||
metaAlertIcon = new MetaAlertIcon();
|
||||
|
||||
ai = _ai;
|
||||
real = 0;
|
||||
isActivated = false;
|
||||
}
|
||||
|
||||
AlertIcon::Private::~Private()
|
||||
{
|
||||
if ( isActivated )
|
||||
stop();
|
||||
|
||||
if ( real )
|
||||
delete real;
|
||||
}
|
||||
|
||||
void AlertIcon::Private::init()
|
||||
{
|
||||
connect(metaAlertIcon, SIGNAL(update()), SLOT(update()));
|
||||
connect(real, SIGNAL(iconModified()), SLOT(pixmapChanged()));
|
||||
|
||||
if ( option.alertStyle == 2 && real->isAnimated() )
|
||||
impix = real->frameImpix();
|
||||
else
|
||||
impix = real->impix();
|
||||
}
|
||||
|
||||
void AlertIcon::Private::update()
|
||||
{
|
||||
stop();
|
||||
activated(false);
|
||||
}
|
||||
|
||||
void AlertIcon::Private::activated(bool playSound)
|
||||
{
|
||||
if ( option.alertStyle == 2 && real->isAnimated() ) {
|
||||
if ( !isActivated ) {
|
||||
connect(real, SIGNAL(pixmapChanged()), SLOT(pixmapChanged()));
|
||||
real->activated(playSound);
|
||||
isActivated = true;
|
||||
}
|
||||
}
|
||||
else if ( option.alertStyle == 1 || (option.alertStyle == 2 && !real->isAnimated()) ) {
|
||||
connect(metaAlertIcon, SIGNAL(updateFrame(int)), SLOT(updateFrame(int)));
|
||||
}
|
||||
else {
|
||||
impix = real->impix();
|
||||
emit ai->pixmapChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AlertIcon::Private::stop()
|
||||
{
|
||||
disconnect(metaAlertIcon, SIGNAL(updateFrame(int)), this, SLOT(updateFrame(int)));
|
||||
|
||||
if ( isActivated ) {
|
||||
disconnect(real, SIGNAL(pixmapChanged()), this, SLOT(pixmapChanged()));
|
||||
real->stop();
|
||||
isActivated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AlertIcon::Private::updateFrame(int frame)
|
||||
{
|
||||
if ( !metaAlertIcon ) // just in case
|
||||
metaAlertIcon = new MetaAlertIcon();
|
||||
|
||||
if ( frame )
|
||||
impix = real->impix();
|
||||
else
|
||||
impix = metaAlertIcon->blank16();
|
||||
|
||||
emit ai->pixmapChanged();
|
||||
}
|
||||
|
||||
void AlertIcon::Private::pixmapChanged()
|
||||
{
|
||||
impix = real->frameImpix();
|
||||
|
||||
emit ai->pixmapChanged();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// AlertIcon
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
AlertIcon::AlertIcon(const PsiIcon *icon)
|
||||
{
|
||||
d = new Private(this);
|
||||
if ( icon )
|
||||
d->real = new PsiIcon(*icon);
|
||||
else
|
||||
d->real = new PsiIcon();
|
||||
|
||||
d->init();
|
||||
}
|
||||
|
||||
AlertIcon::~AlertIcon()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool AlertIcon::isAnimated() const
|
||||
{
|
||||
return d->real->isAnimated();
|
||||
}
|
||||
|
||||
const QPixmap &AlertIcon::pixmap() const
|
||||
{
|
||||
return d->impix.pixmap();
|
||||
}
|
||||
|
||||
const QImage &AlertIcon::image() const
|
||||
{
|
||||
return d->impix.image();
|
||||
}
|
||||
|
||||
void AlertIcon::activated(bool playSound)
|
||||
{
|
||||
d->activated(playSound);
|
||||
}
|
||||
|
||||
void AlertIcon::stop()
|
||||
{
|
||||
d->stop();
|
||||
}
|
||||
|
||||
const QIcon &AlertIcon::icon() const
|
||||
{
|
||||
return d->real->icon();
|
||||
}
|
||||
|
||||
const Impix &AlertIcon::impix() const
|
||||
{
|
||||
return d->impix;
|
||||
}
|
||||
|
||||
int AlertIcon::frameNumber() const
|
||||
{
|
||||
if ( option.alertStyle == 2 && d->real->isAnimated() ) {
|
||||
return d->real->frameNumber();
|
||||
}
|
||||
else if ( option.alertStyle == 1 || (option.alertStyle == 2 && !d->real->isAnimated()) ) {
|
||||
return metaAlertIcon->framenumber();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QString &AlertIcon::name() const
|
||||
{
|
||||
return d->real->name();
|
||||
}
|
||||
|
||||
PsiIcon *AlertIcon::copy() const
|
||||
{
|
||||
return new AlertIcon(d->real);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void alertIconUpdateAlertStyle()
|
||||
{
|
||||
if ( !metaAlertIcon )
|
||||
metaAlertIcon = new MetaAlertIcon();
|
||||
|
||||
metaAlertIcon->updateAlertStyle();
|
||||
}
|
||||
|
||||
#include "alerticon.moc"
|
||||
63
src/alerticon.h
Normal file
63
src/alerticon.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* alerticon.h - class for handling animating alert icons
|
||||
* Copyright (C) 2003 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ALERTICON_H
|
||||
#define ALERTICON_H
|
||||
|
||||
#include "iconset.h"
|
||||
|
||||
class QPixmap;
|
||||
class Impix;
|
||||
class QString;
|
||||
class QIcon;
|
||||
class QImage;
|
||||
|
||||
class AlertIcon : public PsiIcon
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AlertIcon(const PsiIcon *icon);
|
||||
~AlertIcon();
|
||||
|
||||
// reimplemented
|
||||
virtual bool isAnimated() const;
|
||||
virtual const QPixmap &pixmap() const;
|
||||
virtual const QImage &image() const;
|
||||
virtual const QIcon & icon() const;
|
||||
virtual const Impix &impix() const;
|
||||
virtual int frameNumber() const;
|
||||
virtual const QString &name() const;
|
||||
|
||||
virtual PsiIcon *copy() const;
|
||||
|
||||
public slots:
|
||||
void activated(bool playSound = true);
|
||||
void stop();
|
||||
|
||||
public:
|
||||
class Private;
|
||||
private:
|
||||
Private *d;
|
||||
friend class Private;
|
||||
};
|
||||
|
||||
void alertIconUpdateAlertStyle();
|
||||
|
||||
#endif
|
||||
216
src/applicationinfo.cpp
Normal file
216
src/applicationinfo.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#if defined(Q_WS_X11) || defined(Q_WS_MAC)
|
||||
#include <sys/stat.h> // chmod
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#if __GNUC__ >= 3
|
||||
# define WINVER 0x0500
|
||||
# define _WIN32_IE 0x0500
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#include "applicationinfo.h"
|
||||
#include "profiles.h"
|
||||
#ifdef HAVE_CONFIG
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "yapsi_revision.h"
|
||||
|
||||
// Constants. These should be moved to a more 'dynamically changeable'
|
||||
// place (like an external file loaded through the resources system)
|
||||
// Should also be overridable through an optional file.
|
||||
|
||||
#define PROG_NAME QString::fromUtf8("Я.Онлайн")
|
||||
#define PROG_CAPS_NODE "http://online.yandex.ru/caps";
|
||||
#define PROG_IPC_NAME "ru.yandex.online"
|
||||
#define PROG_OPTIONS_NS "http://online.yandex.ru/options";
|
||||
#define PROG_STORAGE_NS "http://online.yandex.ru/storage";
|
||||
|
||||
#if defined(Q_WS_X11) && !defined(PSI_DATADIR)
|
||||
#define PSI_DATADIR "/usr/local/share/psi"
|
||||
#endif
|
||||
|
||||
|
||||
QString ApplicationInfo::name()
|
||||
{
|
||||
return PROG_NAME;
|
||||
}
|
||||
|
||||
QString ApplicationInfo::version()
|
||||
{
|
||||
return YAPSI_VERSION + "." + QString::number(YAPSI_REVISION);
|
||||
}
|
||||
|
||||
QString ApplicationInfo::capsNode()
|
||||
{
|
||||
return PROG_CAPS_NODE;
|
||||
}
|
||||
|
||||
QString ApplicationInfo::capsVersion()
|
||||
{
|
||||
return version();
|
||||
}
|
||||
|
||||
QString ApplicationInfo::IPCName()
|
||||
{
|
||||
return PROG_IPC_NAME;
|
||||
}
|
||||
|
||||
QString ApplicationInfo::optionsNS()
|
||||
{
|
||||
return PROG_OPTIONS_NS;
|
||||
}
|
||||
|
||||
QString ApplicationInfo::storageNS()
|
||||
{
|
||||
return PROG_STORAGE_NS;
|
||||
}
|
||||
|
||||
QString ApplicationInfo::resourcesDir()
|
||||
{
|
||||
#if defined(Q_WS_X11)
|
||||
return PSI_DATADIR;
|
||||
#elif defined(Q_WS_WIN)
|
||||
return qApp->applicationDirPath();
|
||||
#elif defined(Q_WS_MAC)
|
||||
return QCoreApplication::instance()->applicationDirPath() + "/../Resources";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief return psi's private read write data directory
|
||||
* unix+mac: $HOME/.psi
|
||||
* environment variable "PSIDATADIR" overrides
|
||||
*/
|
||||
QString ApplicationInfo::homeDir()
|
||||
{
|
||||
// Try the environment override first
|
||||
char *p = getenv("YACHATDATADIR");
|
||||
if(p) {
|
||||
QDir proghome(p);
|
||||
if (!proghome.exists()) {
|
||||
QDir d;
|
||||
d.mkpath(proghome.path());
|
||||
}
|
||||
return proghome.path();
|
||||
}
|
||||
|
||||
#if defined(Q_WS_X11) || defined(Q_WS_MAC)
|
||||
QDir proghome(QDir::homePath() + "/.yachat");
|
||||
if(!proghome.exists()) {
|
||||
QDir home = QDir::home();
|
||||
home.mkdir(".yachat");
|
||||
chmod(QFile::encodeName(proghome.path()), 0700);
|
||||
}
|
||||
return proghome.path();
|
||||
#elif defined(Q_WS_WIN)
|
||||
QString base = QDir::homePath();
|
||||
WCHAR str[MAX_PATH+1] = { 0 };
|
||||
if (SHGetSpecialFolderPathW(0, str, CSIDL_APPDATA, true))
|
||||
base = QString::fromWCharArray(str);
|
||||
|
||||
QDir proghome(base + "/YaChatData");
|
||||
if(!proghome.exists()) {
|
||||
QDir home(base);
|
||||
home.mkdir("YaChatData");
|
||||
}
|
||||
|
||||
return proghome.path();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ApplicationInfo::historyDir()
|
||||
{
|
||||
QDir history(pathToProfile(activeProfile) + "/history");
|
||||
if (!history.exists()) {
|
||||
QDir profile(pathToProfile(activeProfile));
|
||||
profile.mkdir("history");
|
||||
}
|
||||
|
||||
return history.path();
|
||||
}
|
||||
|
||||
QString ApplicationInfo::vCardDir()
|
||||
{
|
||||
QDir vcard(pathToProfile(activeProfile) + "/vcard");
|
||||
if (!vcard.exists()) {
|
||||
QDir profile(pathToProfile(activeProfile));
|
||||
profile.mkdir("vcard");
|
||||
}
|
||||
|
||||
return vcard.path();
|
||||
}
|
||||
|
||||
QString ApplicationInfo::profilesDir()
|
||||
{
|
||||
QString profiles_dir(homeDir() + "/profiles");
|
||||
QDir d(profiles_dir);
|
||||
if(!d.exists()) {
|
||||
QDir d(homeDir());
|
||||
d.mkdir("profiles");
|
||||
}
|
||||
return profiles_dir;
|
||||
}
|
||||
|
||||
QString ApplicationInfo::documentsDir()
|
||||
{
|
||||
#ifdef Q_WS_WIN
|
||||
// http://lists.trolltech.com/qt-interest/2006-10/thread00018-0.html
|
||||
// TODO: haven't a better way been added to Qt since?
|
||||
QSettings settings(QSettings::UserScope, "Microsoft", "Windows");
|
||||
settings.beginGroup("CurrentVersion/Explorer/Shell Folders");
|
||||
return settings.value("Personal").toString();
|
||||
#else
|
||||
return QDir::homePath();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef YAPSI
|
||||
QString ApplicationInfo::yavatarsDir()
|
||||
{
|
||||
QDir yavatars(pathToProfile(activeProfile) + "/yavatars");
|
||||
if (!yavatars.exists()) {
|
||||
QDir profile(pathToProfile(activeProfile));
|
||||
profile.mkdir("yavatars");
|
||||
}
|
||||
|
||||
return yavatars.path();
|
||||
}
|
||||
|
||||
QString ApplicationInfo::yahistoryDir()
|
||||
{
|
||||
QDir yahistory(pathToProfile(activeProfile) + "/yahistory");
|
||||
if (!yahistory.exists()) {
|
||||
QDir profile(pathToProfile(activeProfile));
|
||||
profile.mkdir("yahistory");
|
||||
}
|
||||
|
||||
return yahistory.path();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BREAKPAD
|
||||
QString ApplicationInfo::crashReporterDir()
|
||||
{
|
||||
QString crashReporterDir(homeDir() + "/crash_reporter");
|
||||
QDir d(crashReporterDir);
|
||||
if (!d.exists()) {
|
||||
QDir d(homeDir());
|
||||
d.mkdir("crash_reporter");
|
||||
}
|
||||
return crashReporterDir;
|
||||
}
|
||||
#endif
|
||||
36
src/applicationinfo.h
Normal file
36
src/applicationinfo.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef APPLICATIONINFO_H
|
||||
#define APPLICATIONINFO_H
|
||||
|
||||
class QString;
|
||||
|
||||
class ApplicationInfo
|
||||
{
|
||||
public:
|
||||
// Version info
|
||||
static QString name();
|
||||
static QString version();
|
||||
static QString capsNode();
|
||||
static QString capsVersion();
|
||||
static QString IPCName();
|
||||
|
||||
// Directories
|
||||
static QString homeDir();
|
||||
static QString resourcesDir();
|
||||
static QString profilesDir();
|
||||
static QString historyDir();
|
||||
static QString vCardDir();
|
||||
static QString documentsDir();
|
||||
#ifdef YAPSI
|
||||
static QString yavatarsDir();
|
||||
static QString yahistoryDir();
|
||||
#endif
|
||||
#ifdef HAVE_BREAKPAD
|
||||
static QString crashReporterDir();
|
||||
#endif
|
||||
|
||||
// Namespaces
|
||||
static QString optionsNS();
|
||||
static QString storageNS();
|
||||
};
|
||||
|
||||
#endif
|
||||
747
src/avatars.cpp
Normal file
747
src/avatars.cpp
Normal file
|
|
@ -0,0 +1,747 @@
|
|||
/*
|
||||
* avatars.cpp
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Be more efficient about storing avatars in memory
|
||||
* - Move ovotorChanged() to Avatar, and only listen to the active avatars
|
||||
* being changed.
|
||||
*/
|
||||
|
||||
#include <QDomElement>
|
||||
#include <QtCrypto>
|
||||
#include <QPixmap>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QFile>
|
||||
#include <QBuffer>
|
||||
#include <QPainter>
|
||||
|
||||
#include <qca_basic.h>
|
||||
|
||||
#include "xmpp_xmlcommon.h"
|
||||
#include "xmpp_vcard.h"
|
||||
#include "xmpp_client.h"
|
||||
#include "xmpp_resource.h"
|
||||
#include "xmpp_pubsubitem.h"
|
||||
#include "avatars.h"
|
||||
#include "applicationinfo.h"
|
||||
#include "psiaccount.h"
|
||||
#include "profiles.h"
|
||||
#include "vcardfactory.h"
|
||||
#include "pepmanager.h"
|
||||
#include "pixmaputil.h"
|
||||
|
||||
#ifdef YAPSI
|
||||
#define MAX_AVATAR_SIZE 100
|
||||
#define MAX_AVATAR_DISPLAY_SIZE 100
|
||||
#else
|
||||
#define MAX_AVATAR_SIZE 96
|
||||
#define MAX_AVATAR_DISPLAY_SIZE 64
|
||||
#endif
|
||||
|
||||
using namespace QCA;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static QByteArray scaleAvatar(const QByteArray& b)
|
||||
{
|
||||
//int maxSize = (option.avatarsSize > MAX_AVATAR_SIZE ? MAX_AVATAR_SIZE : option.avatarsSize);
|
||||
int maxSize = AvatarFactory::maxAvatarSize();
|
||||
QImage i(b);
|
||||
if (i.isNull()) {
|
||||
qWarning("AvatarFactory::scaleAvatar(): Null image (unrecognized format?)");
|
||||
return QByteArray();
|
||||
}
|
||||
else if (i.width() > maxSize || i.height() > maxSize) {
|
||||
QImage image = i.scaled(QSize(maxSize, maxSize),
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
QByteArray ba;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
image.save(&buffer, "PNG");
|
||||
return ba;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Avatar: Base class for avatars.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Avatar::Avatar(AvatarFactory* factory)
|
||||
: QObject(factory), factory_(factory)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Avatar::~Avatar()
|
||||
{
|
||||
}
|
||||
|
||||
void Avatar::setImage(const QImage& i)
|
||||
{
|
||||
if (i.width() > MAX_AVATAR_DISPLAY_SIZE || i.height() > MAX_AVATAR_DISPLAY_SIZE) {
|
||||
pixmap_.convertFromImage(i.scaled(QSize(MAX_AVATAR_DISPLAY_SIZE, MAX_AVATAR_DISPLAY_SIZE),
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
else {
|
||||
pixmap_.convertFromImage(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::setImage(const QByteArray& ba)
|
||||
{
|
||||
setImage(QImage(ba));
|
||||
}
|
||||
|
||||
void Avatar::setImage(const QPixmap& p)
|
||||
{
|
||||
if (p.width() > MAX_AVATAR_DISPLAY_SIZE || p.height() > MAX_AVATAR_DISPLAY_SIZE) {
|
||||
pixmap_ = p.scaled(QSize(MAX_AVATAR_DISPLAY_SIZE, MAX_AVATAR_DISPLAY_SIZE),
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
else {
|
||||
pixmap_ = p;
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::resetImage()
|
||||
{
|
||||
pixmap_ = QPixmap();
|
||||
}
|
||||
|
||||
AvatarFactory* Avatar::factory() const
|
||||
{
|
||||
return factory_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CachedAvatar: Base class for avatars which are requested and are to be cached
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class CachedAvatar : public Avatar
|
||||
{
|
||||
public:
|
||||
CachedAvatar(AvatarFactory* factory)
|
||||
: Avatar(factory)
|
||||
{ };
|
||||
virtual void updateHash(const QString& h);
|
||||
QString cachedFileName() const;
|
||||
|
||||
protected:
|
||||
virtual const QString& hash() const { return hash_; }
|
||||
virtual void requestAvatar() { }
|
||||
virtual void avatarUpdated() { }
|
||||
|
||||
virtual bool isCached(const QString& hash);
|
||||
virtual void loadFromCache(const QString& hash);
|
||||
virtual void saveToCache(const QByteArray& data);
|
||||
|
||||
private:
|
||||
QString hash_;
|
||||
};
|
||||
|
||||
void CachedAvatar::updateHash(const QString& h)
|
||||
{
|
||||
if (hash_ != h) {
|
||||
hash_ = h;
|
||||
if (h.isEmpty()) {
|
||||
hash_ = "";
|
||||
resetImage();
|
||||
avatarUpdated();
|
||||
}
|
||||
else if (isCached(h)) {
|
||||
loadFromCache(h);
|
||||
avatarUpdated();
|
||||
}
|
||||
else {
|
||||
resetImage();
|
||||
avatarUpdated();
|
||||
requestAvatar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CachedAvatar::isCached(const QString& h)
|
||||
{
|
||||
return QDir(AvatarFactory::getCacheDir()).exists(h);
|
||||
}
|
||||
|
||||
void CachedAvatar::loadFromCache(const QString& h)
|
||||
{
|
||||
// printf("Loading avatar from cache\n");
|
||||
hash_ = h;
|
||||
setImage(QImage(QDir(AvatarFactory::getCacheDir()).filePath(h)));
|
||||
if (pixmap().isNull()) {
|
||||
qWarning("CachedAvatar::loadFromCache(): Null pixmap. Unsupported format ?");
|
||||
}
|
||||
}
|
||||
|
||||
QString CachedAvatar::cachedFileName() const
|
||||
{
|
||||
return QDir(AvatarFactory::getCacheDir()).filePath(hash_);
|
||||
}
|
||||
|
||||
void CachedAvatar::saveToCache(const QByteArray& data)
|
||||
{
|
||||
QString hash = QCA::Hash("sha1").hashToString(data);
|
||||
hash_ = hash;
|
||||
// printf("Saving %s to cache.\n",hash.latin1());
|
||||
QFile f(cachedFileName());
|
||||
if (f.open(IO_WriteOnly)) {
|
||||
f.writeBlock(data);
|
||||
f.close();
|
||||
}
|
||||
else {
|
||||
printf("Error opening %s for writing.\n",f.name().latin1());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PEPAvatar: PEP Avatars
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class PEPAvatar : public CachedAvatar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PEPAvatar(AvatarFactory* factory, const Jid& jid)
|
||||
: CachedAvatar(factory), jid_(jid)
|
||||
{ };
|
||||
|
||||
void setData(const QString& h, const QString& data) {
|
||||
if (h == hash()) {
|
||||
QByteArray ba = Base64().stringToArray(data).toByteArray();
|
||||
if (!ba.isEmpty()) {
|
||||
saveToCache(ba);
|
||||
setImage(ba);
|
||||
if (pixmap().isNull()) {
|
||||
qWarning("PEPAvatar::setData(): Null pixmap. Unsupported format ?");
|
||||
}
|
||||
emit avatarChanged(jid_);
|
||||
}
|
||||
else
|
||||
qWarning("PEPAvatar::setData(): Received data is empty. Bad encoding ?");
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void avatarChanged(const Jid&);
|
||||
|
||||
protected:
|
||||
void requestAvatar() {
|
||||
factory()->account()->pepManager()->get(jid_,"http://www.xmpp.org/extensions/xep-0084.html#ns-data",hash());
|
||||
}
|
||||
|
||||
void avatarUpdated()
|
||||
{ emit avatarChanged(jid_); }
|
||||
|
||||
private:
|
||||
Jid jid_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VCardAvatar: Avatars coming from VCards of contacts.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class VCardAvatar : public CachedAvatar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VCardAvatar(AvatarFactory* factory, const Jid& jid);
|
||||
|
||||
signals:
|
||||
void avatarChanged(const Jid&);
|
||||
|
||||
public slots:
|
||||
void receivedVCard();
|
||||
|
||||
protected:
|
||||
void requestAvatar();
|
||||
void avatarUpdated()
|
||||
{ emit avatarChanged(jid_); }
|
||||
|
||||
private:
|
||||
Jid jid_;
|
||||
};
|
||||
|
||||
|
||||
VCardAvatar::VCardAvatar(AvatarFactory* factory, const Jid& jid)
|
||||
: CachedAvatar(factory), jid_(jid)
|
||||
{
|
||||
}
|
||||
|
||||
void VCardAvatar::requestAvatar()
|
||||
{
|
||||
VCardFactory::instance()->getVCard(jid_.bare(), factory()->account()->client()->rootTask(), this, SLOT(receivedVCard()));
|
||||
}
|
||||
|
||||
void VCardAvatar::receivedVCard()
|
||||
{
|
||||
const VCard* vcard = VCardFactory::instance()->vcard(jid_);
|
||||
if (vcard) {
|
||||
saveToCache(vcard->photo());
|
||||
setImage(vcard->photo());
|
||||
emit avatarChanged(jid_);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VCardStaticAvatar: VCard static photo avatar (not published through presence)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class VCardStaticAvatar : public CachedAvatar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VCardStaticAvatar(AvatarFactory* factory, const Jid& j);
|
||||
|
||||
public slots:
|
||||
void vcardChanged(const Jid&);
|
||||
|
||||
signals:
|
||||
void avatarChanged(const Jid&);
|
||||
|
||||
private:
|
||||
Jid jid_;
|
||||
|
||||
void setVCard(const VCard* vcard);
|
||||
};
|
||||
|
||||
|
||||
VCardStaticAvatar::VCardStaticAvatar(AvatarFactory* factory, const Jid& j)
|
||||
: CachedAvatar(factory), jid_(j.bare())
|
||||
{
|
||||
const VCard* vcard = VCardFactory::instance()->vcard(jid_);
|
||||
setVCard(vcard);
|
||||
connect(VCardFactory::instance(),SIGNAL(vcardChanged(const Jid&)),SLOT(vcardChanged(const Jid&)));
|
||||
}
|
||||
|
||||
void VCardStaticAvatar::vcardChanged(const Jid& j)
|
||||
{
|
||||
if (j.compare(jid_,false)) {
|
||||
const VCard* vcard = VCardFactory::instance()->vcard(jid_);
|
||||
setVCard(vcard);
|
||||
emit avatarChanged(jid_);
|
||||
}
|
||||
}
|
||||
|
||||
void VCardStaticAvatar::setVCard(const VCard* vcard)
|
||||
{
|
||||
if (vcard && !vcard->photo().isEmpty()) {
|
||||
// TODO: make CachedAvatar automatically call saveToCache in setImage
|
||||
saveToCache(vcard->photo());
|
||||
setImage(vcard->photo());
|
||||
}
|
||||
else {
|
||||
resetImage();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// FileAvatar: Avatars coming from local files.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class FileAvatar : public Avatar
|
||||
{
|
||||
public:
|
||||
FileAvatar(AvatarFactory* factory, const Jid& jid);
|
||||
void import(const QString& file);
|
||||
void removeFromDisk();
|
||||
bool exists();
|
||||
QPixmap getPixmap();
|
||||
const Jid& getJid() const
|
||||
{ return jid_; }
|
||||
|
||||
protected:
|
||||
bool isDirty() const;
|
||||
QString getFileName() const;
|
||||
void refresh();
|
||||
QDateTime lastModified() const
|
||||
{ return lastModified_; }
|
||||
|
||||
private:
|
||||
QDateTime lastModified_;
|
||||
Jid jid_;
|
||||
};
|
||||
|
||||
|
||||
FileAvatar::FileAvatar(AvatarFactory* factory, const Jid& jid)
|
||||
: Avatar(factory), jid_(jid)
|
||||
{
|
||||
}
|
||||
|
||||
void FileAvatar::import(const QString& file)
|
||||
{
|
||||
if (QFileInfo(file).exists()) {
|
||||
QFile source_file(file);
|
||||
QFile target_file(getFileName());
|
||||
if (source_file.open(QIODevice::ReadOnly) && target_file.open(QIODevice::WriteOnly)) {
|
||||
QByteArray ba = source_file.readAll();
|
||||
QByteArray data = scaleAvatar(ba);
|
||||
target_file.write(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileAvatar::removeFromDisk()
|
||||
{
|
||||
QFile f(getFileName());
|
||||
f.remove();
|
||||
}
|
||||
|
||||
bool FileAvatar::exists()
|
||||
{
|
||||
return QFileInfo(getFileName()).exists();
|
||||
}
|
||||
|
||||
QPixmap FileAvatar::getPixmap()
|
||||
{
|
||||
refresh();
|
||||
return pixmap();
|
||||
}
|
||||
|
||||
void FileAvatar::refresh()
|
||||
{
|
||||
if (isDirty()) {
|
||||
if (QFileInfo(getFileName()).exists()) {
|
||||
QImage img(getFileName());
|
||||
setImage(QImage(getFileName()));
|
||||
}
|
||||
else
|
||||
resetImage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString FileAvatar::getFileName() const
|
||||
{
|
||||
QString f = getJid().bare();
|
||||
f.replace('@',"_at_");
|
||||
return QDir(AvatarFactory::getManualDir()).filePath(f);
|
||||
}
|
||||
|
||||
|
||||
bool FileAvatar::isDirty() const
|
||||
{
|
||||
return (pixmap().isNull()
|
||||
|| !QFileInfo(getFileName()).exists()
|
||||
|| QFileInfo(getFileName()).lastModified() > lastModified());
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Avatar factory
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
AvatarFactory::AvatarFactory(PsiAccount* pa) : pa_(pa)
|
||||
{
|
||||
// Register iconset
|
||||
iconset_.addToFactory();
|
||||
|
||||
// Connect signals
|
||||
connect(VCardFactory::instance(),SIGNAL(vcardChanged(const Jid&)),this,SLOT(updateAvatar(const Jid&)));
|
||||
connect(pa_->client(), SIGNAL(resourceAvailable(const Jid &, const Resource &)), SLOT(resourceAvailable(const Jid &, const Resource &)));
|
||||
|
||||
// PEP
|
||||
connect(pa_->pepManager(),SIGNAL(itemPublished(const Jid&, const QString&, const PubSubItem&)),SLOT(itemPublished(const Jid&, const QString&, const PubSubItem&)));
|
||||
connect(pa_->pepManager(),SIGNAL(publish_success(const QString&, const PubSubItem&)),SLOT(publish_success(const QString&,const PubSubItem&)));
|
||||
}
|
||||
|
||||
PsiAccount* AvatarFactory::account() const
|
||||
{
|
||||
return pa_;
|
||||
}
|
||||
|
||||
inline static QPixmap ensureSquareAvatar(const QPixmap& original)
|
||||
{
|
||||
if (original.isNull() || original.width() == original.height())
|
||||
return original;
|
||||
|
||||
int size = qMax(original.width(), original.height());
|
||||
QPixmap square = PixmapUtil::createTransparentPixmap(size, size);
|
||||
|
||||
QPainter p(&square);
|
||||
p.drawPixmap((size - original.width()) / 2, (size - original.height()) / 2, original);
|
||||
|
||||
return square;
|
||||
}
|
||||
|
||||
Avatar* AvatarFactory::getAvatarHelper(const Jid& jid)
|
||||
{
|
||||
// NOTE: ensure that 'jid' is safe from being deleted
|
||||
// in the process of calling 'avatarChanged()' signal
|
||||
|
||||
// Compute the avatar of the user
|
||||
Avatar* av = retrieveAvatar(jid);
|
||||
|
||||
// If the avatar changed since the previous request, notify everybody of this
|
||||
if (av != active_avatars_[jid.full()]) {
|
||||
active_avatars_[jid.full()] = av;
|
||||
active_avatars_[jid.bare()] = av;
|
||||
emit avatarChanged(jid);
|
||||
}
|
||||
|
||||
return av;
|
||||
}
|
||||
|
||||
QPixmap AvatarFactory::getAvatar(XMPP::Jid jid)
|
||||
{
|
||||
Avatar* av = getAvatarHelper(jid);
|
||||
QPixmap pm = (av ? av->getPixmap() : QPixmap());
|
||||
pm = ensureSquareAvatar(pm);
|
||||
|
||||
#ifndef YAPSI
|
||||
// Update iconset
|
||||
PsiIcon icon;
|
||||
icon.setImpix(pm);
|
||||
iconset_.setIcon(QString("avatars/%1").arg(jid.bare()), icon);
|
||||
#endif
|
||||
|
||||
return pm;
|
||||
}
|
||||
|
||||
QString AvatarFactory::getCachedAvatarFileName(XMPP::Jid jid)
|
||||
{
|
||||
Avatar* av = retrieveAvatar(jid);
|
||||
CachedAvatar* cachedAvatar = dynamic_cast<CachedAvatar*>(av);
|
||||
if (cachedAvatar) {
|
||||
return cachedAvatar->cachedFileName();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
Avatar* AvatarFactory::retrieveAvatar(const Jid& jid)
|
||||
{
|
||||
//printf("Retrieving avatar of %s\n", jid.full().latin1());
|
||||
|
||||
// Try finding a file avatar.
|
||||
//printf("File avatar\n");
|
||||
if (!file_avatars_.contains(jid.bare())) {
|
||||
//printf("File avatar not yet loaded\n");
|
||||
file_avatars_[jid.bare()] = new FileAvatar(this, jid);
|
||||
}
|
||||
//printf("Trying file avatar\n");
|
||||
if (!file_avatars_[jid.bare()]->isEmpty())
|
||||
return file_avatars_[jid.bare()];
|
||||
|
||||
//printf("PEP avatar\n");
|
||||
if (pep_avatars_.contains(jid.bare()) && !pep_avatars_[jid.bare()]->isEmpty()) {
|
||||
return pep_avatars_[jid.bare()];
|
||||
}
|
||||
|
||||
// Try finding a vcard avatar
|
||||
//printf("VCard avatar\n");
|
||||
if (vcard_avatars_.contains(jid.bare()) && !vcard_avatars_[jid.bare()]->isEmpty()) {
|
||||
return vcard_avatars_[jid.bare()];
|
||||
}
|
||||
|
||||
// Try finding a static vcard avatar
|
||||
//printf("Static VCard avatar\n");
|
||||
if (!vcard_static_avatars_.contains(jid.bare())) {
|
||||
//printf("Static vcard avatar not yet loaded\n");
|
||||
vcard_static_avatars_[jid.bare()] = new VCardStaticAvatar(this, jid);
|
||||
connect(vcard_static_avatars_[jid.bare()],SIGNAL(avatarChanged(const Jid&)),this,SLOT(updateAvatar(const Jid&)));
|
||||
}
|
||||
if (!vcard_static_avatars_[jid.bare()]->isEmpty()) {
|
||||
return vcard_static_avatars_[jid.bare()];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AvatarFactory::setSelfAvatar(const QString& fileName)
|
||||
{
|
||||
if (!fileName.isEmpty()) {
|
||||
QFile avatar_file(fileName);
|
||||
if (!avatar_file.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
QByteArray avatar_data = scaleAvatar(avatar_file.readAll());
|
||||
QImage avatar_image(avatar_data);
|
||||
if(!avatar_image.isNull()) {
|
||||
// Publish data
|
||||
QDomDocument* doc = account()->client()->doc();
|
||||
QString hash = Hash("sha1").hashToString(avatar_data);
|
||||
QDomElement el = doc->createElement("data");
|
||||
el.setAttribute("xmlns","http://www.xmpp.org/extensions/xep-0084.html#ns-data ");
|
||||
el.appendChild(doc->createTextNode(Base64().arrayToString(avatar_data)));
|
||||
selfAvatarData_ = avatar_data;
|
||||
selfAvatarHash_ = hash;
|
||||
account()->pepManager()->publish("http://www.xmpp.org/extensions/xep-0084.html#ns-data",PubSubItem(hash,el));
|
||||
}
|
||||
}
|
||||
else {
|
||||
QDomDocument* doc = account()->client()->doc();
|
||||
QDomElement meta_el = doc->createElement("metadata");
|
||||
meta_el.setAttribute("xmlns","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata");
|
||||
meta_el.appendChild(doc->createElement("stop"));
|
||||
account()->pepManager()->publish("http://www.xmpp.org/extensions/xep-0084.html#ns-metadata",PubSubItem("current",meta_el));
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarFactory::updateAvatar(const Jid& j)
|
||||
{
|
||||
getAvatar(j);
|
||||
// FIXME: This signal might be emitted twice (first time from getAvatar()).
|
||||
emit avatarChanged(j);
|
||||
}
|
||||
|
||||
void AvatarFactory::importManualAvatar(const Jid& j, const QString& fileName)
|
||||
{
|
||||
FileAvatar(this, j).import(fileName);
|
||||
emit avatarChanged(j);
|
||||
}
|
||||
|
||||
void AvatarFactory::removeManualAvatar(const Jid& j)
|
||||
{
|
||||
FileAvatar(this, j).removeFromDisk();
|
||||
// TODO: Remove from caches. Maybe create a clearManualAvatar() which
|
||||
// removes the file but doesn't remove the avatar from caches (since it'll
|
||||
// be created again whenever the FileAvatar is requested)
|
||||
emit avatarChanged(j);
|
||||
}
|
||||
|
||||
bool AvatarFactory::hasManualAvatar(const Jid& j)
|
||||
{
|
||||
return FileAvatar(this, j).exists();
|
||||
}
|
||||
|
||||
void AvatarFactory::resourceAvailable(const Jid& jid, const Resource& r)
|
||||
{
|
||||
if (r.status().hasPhotoHash()) {
|
||||
QString hash = r.status().photoHash();
|
||||
if (!vcard_avatars_.contains(jid.bare())) {
|
||||
vcard_avatars_[jid.bare()] = new VCardAvatar(this, jid);
|
||||
connect(vcard_avatars_[jid.bare()],SIGNAL(avatarChanged(const Jid&)),this,SLOT(updateAvatar(const Jid&)));
|
||||
}
|
||||
vcard_avatars_[jid.bare()]->updateHash(hash);
|
||||
}
|
||||
}
|
||||
|
||||
QString AvatarFactory::getManualDir()
|
||||
{
|
||||
QDir avatars(pathToProfile(activeProfile) + "/pictures");
|
||||
if (!avatars.exists()) {
|
||||
QDir profile(pathToProfile(activeProfile));
|
||||
profile.mkdir("pictures");
|
||||
}
|
||||
return avatars.path();
|
||||
}
|
||||
|
||||
QString AvatarFactory::getCacheDir()
|
||||
{
|
||||
QDir avatars(ApplicationInfo::homeDir() + "/avatars");
|
||||
if (!avatars.exists()) {
|
||||
QDir home(ApplicationInfo::homeDir());
|
||||
home.mkdir("avatars");
|
||||
}
|
||||
return avatars.path();
|
||||
}
|
||||
|
||||
int AvatarFactory::maxAvatarSize()
|
||||
{
|
||||
return MAX_AVATAR_SIZE;
|
||||
}
|
||||
|
||||
void AvatarFactory::itemPublished(const Jid& jid, const QString& n, const PubSubItem& item)
|
||||
{
|
||||
if (n == "http://www.xmpp.org/extensions/xep-0084.html#ns-data") {
|
||||
if (item.payload().tagName() == "data") {
|
||||
if (pep_avatars_.contains(jid.bare())) {
|
||||
pep_avatars_[jid.bare()]->setData(item.id(),item.payload().text());
|
||||
}
|
||||
}
|
||||
else {
|
||||
qWarning("avatars.cpp: Unexpected item payload");
|
||||
}
|
||||
}
|
||||
else if (n == "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata") {
|
||||
if (!pep_avatars_.contains(jid.bare())) {
|
||||
pep_avatars_[jid.bare()] = new PEPAvatar(this, jid.bare());
|
||||
connect(pep_avatars_[jid.bare()],SIGNAL(avatarChanged(const Jid&)),this, SLOT(updateAvatar(const Jid&)));
|
||||
}
|
||||
QDomElement e;
|
||||
bool found;
|
||||
e = findSubTag(item.payload(), "stop", &found);
|
||||
if (found) {
|
||||
pep_avatars_[jid.bare()]->updateHash("");
|
||||
}
|
||||
else {
|
||||
pep_avatars_[jid.bare()]->updateHash(item.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarFactory::publish_success(const QString& n, const PubSubItem& item)
|
||||
{
|
||||
if (n == "http://www.xmpp.org/extensions/xep-0084.html#ns-data" && item.id() == selfAvatarHash_) {
|
||||
// Publish metadata
|
||||
QDomDocument* doc = account()->client()->doc();
|
||||
QImage avatar_image(selfAvatarData_);
|
||||
QDomElement meta_el = doc->createElement("metadata");
|
||||
meta_el.setAttribute("xmlns","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata");
|
||||
QDomElement info_el = doc->createElement("info");
|
||||
info_el.setAttribute("id",selfAvatarHash_);
|
||||
info_el.setAttribute("bytes",avatar_image.numBytes());
|
||||
info_el.setAttribute("height",avatar_image.height());
|
||||
info_el.setAttribute("width",avatar_image.width());
|
||||
info_el.setAttribute("type",image2type(selfAvatarData_));
|
||||
meta_el.appendChild(info_el);
|
||||
account()->pepManager()->publish("http://www.xmpp.org/extensions/xep-0084.html#ns-metadata",PubSubItem(selfAvatarHash_,meta_el));
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarFactory::clearCache()
|
||||
{
|
||||
foreach(Avatar* a, findChildren<Avatar*>()) {
|
||||
delete a;
|
||||
}
|
||||
active_avatars_.clear();
|
||||
pep_avatars_.clear();
|
||||
file_avatars_.clear();
|
||||
vcard_avatars_.clear();
|
||||
vcard_static_avatars_.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "avatars.moc"
|
||||
128
src/avatars.h
Normal file
128
src/avatars.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* avatars.h
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AVATARS_H
|
||||
#define AVATARS_H
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
|
||||
#include "iconset.h"
|
||||
|
||||
class PsiAccount;
|
||||
class Avatar;
|
||||
class VCardAvatar;
|
||||
class VCardStaticAvatar;
|
||||
class FileAvatar;
|
||||
class PEPAvatar;
|
||||
|
||||
namespace XMPP {
|
||||
class Jid;
|
||||
class Resource;
|
||||
class PubSubItem;
|
||||
}
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class AvatarFactory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AvatarFactory(PsiAccount* pa);
|
||||
|
||||
QPixmap getAvatar(XMPP::Jid jid);
|
||||
QString getCachedAvatarFileName(XMPP::Jid jid);
|
||||
|
||||
PsiAccount* account() const;
|
||||
void setSelfAvatar(const QString& fileName);
|
||||
|
||||
void importManualAvatar(const Jid& j, const QString& fileName);
|
||||
void removeManualAvatar(const Jid& j);
|
||||
bool hasManualAvatar(const Jid& j);
|
||||
|
||||
static QString getManualDir();
|
||||
static QString getCacheDir();
|
||||
static int maxAvatarSize();
|
||||
|
||||
void clearCache();
|
||||
|
||||
signals:
|
||||
void avatarChanged(const Jid&);
|
||||
|
||||
public slots:
|
||||
void updateAvatar(const Jid&);
|
||||
|
||||
protected slots:
|
||||
void itemPublished(const Jid&, const QString&, const PubSubItem&);
|
||||
void publish_success(const QString&, const PubSubItem&);
|
||||
void resourceAvailable(const Jid&, const Resource&);
|
||||
|
||||
protected:
|
||||
Avatar* retrieveAvatar(const Jid& jid);
|
||||
Avatar* getAvatarHelper(const Jid& jid);
|
||||
|
||||
private:
|
||||
QByteArray selfAvatarData_;
|
||||
QString selfAvatarHash_;
|
||||
|
||||
QMap<QString,Avatar*> active_avatars_;
|
||||
QMap<QString,PEPAvatar*> pep_avatars_;
|
||||
QMap<QString,FileAvatar*> file_avatars_;
|
||||
QMap<QString,VCardAvatar*> vcard_avatars_;
|
||||
QMap<QString,VCardStaticAvatar*> vcard_static_avatars_;
|
||||
PsiAccount* pa_;
|
||||
Iconset iconset_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Avatar : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Avatar(AvatarFactory* factory);
|
||||
virtual ~Avatar();
|
||||
virtual QPixmap getPixmap()
|
||||
{ return pixmap(); }
|
||||
virtual bool isEmpty()
|
||||
{ return getPixmap().isNull(); }
|
||||
|
||||
protected:
|
||||
AvatarFactory* factory() const;
|
||||
virtual const QPixmap& pixmap() const
|
||||
{ return pixmap_; }
|
||||
|
||||
virtual void setImage(const QImage&);
|
||||
virtual void setImage(const QByteArray&);
|
||||
virtual void setImage(const QPixmap&);
|
||||
virtual void resetImage();
|
||||
|
||||
private:
|
||||
QPixmap pixmap_;
|
||||
AvatarFactory* factory_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
165
src/bookmarkmanage.ui
Normal file
165
src/bookmarkmanage.ui
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<ui version="4.0" >
|
||||
<class>BookmarkManage</class>
|
||||
<widget class="QDialog" name="BookmarkManage" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>539</width>
|
||||
<height>257</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Manage Bookmarks</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QListView" name="listView" >
|
||||
<property name="dragDropMode" >
|
||||
<enum>QAbstractItemView::InternalMove</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="bookmarkButtonBox" >
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::NoButton</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>Host:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="host" />
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>Room:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="room" />
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<string>Nickname:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLineEdit" name="nickname" />
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<string>Password:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QLineEdit" name="password" >
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" >
|
||||
<widget class="QCheckBox" name="autoJoin" >
|
||||
<property name="text" >
|
||||
<string>Auto-join</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>66</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2" >
|
||||
<widget class="Line" name="line" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>BookmarkManage</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>475</x>
|
||||
<y>252</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>454</x>
|
||||
<y>259</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>BookmarkManage</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>384</x>
|
||||
<y>252</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>352</x>
|
||||
<y>259</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
212
src/bookmarkmanagedlg.cpp
Normal file
212
src/bookmarkmanagedlg.cpp
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* bookmarkmanagedlg.cpp - manage groupchat room bookmarks
|
||||
* Copyright (C) 2008 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bookmarkmanagedlg.h"
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QPushButton>
|
||||
#include <QAction>
|
||||
|
||||
#include "bookmarkmanager.h"
|
||||
#include "psiaccount.h"
|
||||
|
||||
BookmarkManageDlg::BookmarkManageDlg(PsiAccount* account)
|
||||
: QDialog()
|
||||
, account_(account)
|
||||
, model_(0)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
ui_.setupUi(this);
|
||||
account_->dialogRegister(this);
|
||||
|
||||
QAction* removeBookmarkAction = new QAction(this);
|
||||
connect(removeBookmarkAction, SIGNAL(triggered()), SLOT(removeBookmark()));
|
||||
removeBookmarkAction->setShortcuts(QKeySequence::Delete);
|
||||
ui_.listView->addAction(removeBookmarkAction);
|
||||
|
||||
addButton_ = ui_.bookmarkButtonBox->addButton(tr("&Add"), QDialogButtonBox::ActionRole);
|
||||
removeButton_ = ui_.bookmarkButtonBox->addButton(tr("&Remove"), QDialogButtonBox::DestructiveRole);
|
||||
joinButton_ = ui_.bookmarkButtonBox->addButton(tr("&Join"), QDialogButtonBox::ActionRole);
|
||||
connect(addButton_, SIGNAL(clicked()), SLOT(addBookmark()));
|
||||
connect(removeButton_, SIGNAL(clicked()), SLOT(removeBookmark()));
|
||||
connect(joinButton_, SIGNAL(clicked()), SLOT(joinCurrentRoom()));
|
||||
|
||||
model_ = new QStandardItemModel(this);
|
||||
ui_.listView->setModel(model_);
|
||||
connect(ui_.listView->itemDelegate(), SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)), SLOT(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)));
|
||||
connect(ui_.listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(selectionChanged(const QItemSelection&, const QItemSelection&)));
|
||||
|
||||
connect(ui_.host, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem()));
|
||||
connect(ui_.room, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem()));
|
||||
connect(ui_.nickname, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem()));
|
||||
connect(ui_.password, SIGNAL(textEdited(const QString&)), SLOT(updateCurrentItem()));
|
||||
connect(ui_.autoJoin, SIGNAL(clicked(bool)), SLOT(updateCurrentItem()));
|
||||
|
||||
connect(account_->bookmarkManager(), SIGNAL(conferencesChanged(const QList<ConferenceBookmark>&)), SLOT(loadBookmarks()));
|
||||
loadBookmarks();
|
||||
|
||||
QItemSelection dummy;
|
||||
selectionChanged(dummy, dummy);
|
||||
}
|
||||
|
||||
BookmarkManageDlg::~BookmarkManageDlg()
|
||||
{
|
||||
account_->dialogUnregister(this);
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::reject()
|
||||
{
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::accept()
|
||||
{
|
||||
if (account_->checkConnected(this)) {
|
||||
saveBookmarks();
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::loadBookmarks()
|
||||
{
|
||||
model_->clear();
|
||||
|
||||
foreach(ConferenceBookmark c, account_->bookmarkManager()->conferences()) {
|
||||
QStandardItem* item = new QStandardItem(c.name());
|
||||
item->setData(QVariant(c.jid().full()), JidRole);
|
||||
item->setData(QVariant(c.autoJoin()), AutoJoinRole);
|
||||
item->setData(QVariant(c.nick()), NickRole);
|
||||
item->setData(QVariant(c.password()), PasswordRole);
|
||||
appendItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
ConferenceBookmark BookmarkManageDlg::bookmarkFor(const QModelIndex& index) const
|
||||
{
|
||||
return ConferenceBookmark(index.data(Qt::DisplayRole).toString(),
|
||||
index.data(JidRole).toString(),
|
||||
index.data(AutoJoinRole).toBool(),
|
||||
index.data(NickRole).toString(),
|
||||
index.data(PasswordRole).toString());
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::saveBookmarks()
|
||||
{
|
||||
QList<ConferenceBookmark> conferences;
|
||||
for (int row = 0; row < model_->rowCount(); ++row) {
|
||||
QModelIndex index = model_->index(row, 0, QModelIndex());
|
||||
conferences += bookmarkFor(index);
|
||||
}
|
||||
|
||||
account_->bookmarkManager()->setBookmarks(conferences);
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::addBookmark()
|
||||
{
|
||||
QStandardItem* item = new QStandardItem(tr("Unnamed"));
|
||||
appendItem(item);
|
||||
ui_.listView->reset(); // ensure that open editors won't get in our way
|
||||
ui_.listView->setCurrentIndex(item->index());
|
||||
ui_.listView->edit(item->index());
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::removeBookmark()
|
||||
{
|
||||
model_->removeRow(currentIndex().row());
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint)
|
||||
{
|
||||
Q_UNUSED(editor);
|
||||
|
||||
if (hint == QAbstractItemDelegate::SubmitModelCache) {
|
||||
QList<QLineEdit*> lineEdits;
|
||||
lineEdits << ui_.host << ui_.room << ui_.nickname;
|
||||
foreach(QLineEdit* lineEdit, lineEdits) {
|
||||
if (lineEdit->text().isEmpty()) {
|
||||
lineEdit->setFocus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
Q_UNUSED(deselected);
|
||||
|
||||
QModelIndex current;
|
||||
if (!selected.indexes().isEmpty())
|
||||
current = selected.indexes().first();
|
||||
|
||||
XMPP::Jid jid = XMPP::Jid(current.data(JidRole).toString());
|
||||
ui_.host->setText(jid.domain());
|
||||
ui_.room->setText(jid.node());
|
||||
ui_.nickname->setText(current.data(NickRole).toString());
|
||||
ui_.password->setText(current.data(PasswordRole).toString());
|
||||
ui_.autoJoin->setChecked(current.data(AutoJoinRole).toBool());
|
||||
QList<QWidget*> editors;
|
||||
editors << ui_.host << ui_.room << ui_.nickname << ui_.password << ui_.autoJoin;
|
||||
foreach(QWidget* w, editors) {
|
||||
w->setEnabled(current.isValid());
|
||||
}
|
||||
|
||||
removeButton_->setEnabled(current.isValid());
|
||||
updateCurrentItem();
|
||||
}
|
||||
|
||||
XMPP::Jid BookmarkManageDlg::jid() const
|
||||
{
|
||||
XMPP::Jid j;
|
||||
j.set(ui_.host->text(), ui_.room->text());
|
||||
return j;
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::updateCurrentItem()
|
||||
{
|
||||
joinButton_->setEnabled(!jid().domain().isEmpty() && !jid().node().isEmpty() && !ui_.nickname->text().isEmpty());
|
||||
|
||||
QStandardItem* item = model_->item(currentIndex().row());
|
||||
if (item) {
|
||||
item->setData(QVariant(jid().full()), JidRole);
|
||||
item->setData(QVariant(ui_.autoJoin->isChecked()), AutoJoinRole);
|
||||
item->setData(QVariant(ui_.nickname->text()), NickRole);
|
||||
item->setData(QVariant(ui_.password->text()), PasswordRole);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex BookmarkManageDlg::currentIndex() const
|
||||
{
|
||||
if (!ui_.listView->selectionModel()->selectedIndexes().isEmpty())
|
||||
return ui_.listView->selectionModel()->selectedIndexes().first();
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::joinCurrentRoom()
|
||||
{
|
||||
account_->actionJoin(bookmarkFor(currentIndex()), true);
|
||||
}
|
||||
|
||||
void BookmarkManageDlg::appendItem(QStandardItem* item)
|
||||
{
|
||||
item->setDragEnabled(true);
|
||||
item->setDropEnabled(false);
|
||||
model_->invisibleRootItem()->appendRow(item);
|
||||
}
|
||||
84
src/bookmarkmanagedlg.h
Normal file
84
src/bookmarkmanagedlg.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* bookmarkmanagedlg.h - manage groupchat room bookmarks
|
||||
* Copyright (C) 2008 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOOKMARKMANAGEDLG_H
|
||||
#define BOOKMARKMANAGEDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_bookmarkmanage.h"
|
||||
|
||||
class PsiAccount;
|
||||
class QPushButton;
|
||||
class QStandardItemModel;
|
||||
class QStandardItem;
|
||||
class ConferenceBookmark;
|
||||
|
||||
#include "xmpp_jid.h"
|
||||
|
||||
class BookmarkManageDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BookmarkManageDlg(PsiAccount* account);
|
||||
~BookmarkManageDlg();
|
||||
|
||||
public slots:
|
||||
// reimplemented
|
||||
void reject();
|
||||
void accept();
|
||||
|
||||
private:
|
||||
enum Role {
|
||||
// DisplayRole / EditRole
|
||||
JidRole = Qt::UserRole + 0,
|
||||
AutoJoinRole = Qt::UserRole + 1,
|
||||
NickRole = Qt::UserRole + 2,
|
||||
PasswordRole = Qt::UserRole + 3
|
||||
};
|
||||
|
||||
void appendItem(QStandardItem* item);
|
||||
XMPP::Jid jid() const;
|
||||
QModelIndex currentIndex() const;
|
||||
|
||||
private slots:
|
||||
void loadBookmarks();
|
||||
void saveBookmarks();
|
||||
|
||||
private slots:
|
||||
void addBookmark();
|
||||
void removeBookmark();
|
||||
void updateCurrentItem();
|
||||
void joinCurrentRoom();
|
||||
void closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint);
|
||||
void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
|
||||
private:
|
||||
Ui::BookmarkManage ui_;
|
||||
PsiAccount* account_;
|
||||
QStandardItemModel* model_;
|
||||
QPushButton* addButton_;
|
||||
QPushButton* removeButton_;
|
||||
QPushButton* joinButton_;
|
||||
|
||||
ConferenceBookmark bookmarkFor(const QModelIndex& index) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
225
src/bookmarkmanager.cpp
Normal file
225
src/bookmarkmanager.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* bookmarkmanager.cpp
|
||||
* Copyright (C) 2006-2008 Remko Troncon, Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bookmarkmanager.h"
|
||||
|
||||
#include "xmpp_task.h"
|
||||
#include "xmpp_client.h"
|
||||
#include "xmpp_xmlcommon.h"
|
||||
#include "psiaccount.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class BookmarkTask : public Task
|
||||
{
|
||||
public:
|
||||
BookmarkTask(Task* parent) : Task(parent) {
|
||||
}
|
||||
|
||||
void set(const QList<URLBookmark>& urls, const QList<ConferenceBookmark>& conferences) {
|
||||
iq_ = createIQ(doc(), "set", "", id());
|
||||
|
||||
QDomElement prvt = doc()->createElement("query");
|
||||
prvt.setAttribute("xmlns", "jabber:iq:private");
|
||||
iq_.appendChild(prvt);
|
||||
|
||||
QDomElement storage = doc()->createElement("storage");
|
||||
storage.setAttribute("xmlns", "storage:bookmarks");
|
||||
prvt.appendChild(storage);
|
||||
|
||||
foreach(URLBookmark u, urls)
|
||||
storage.appendChild(u.toXml(*doc()));
|
||||
foreach(ConferenceBookmark c, conferences)
|
||||
storage.appendChild(c.toXml(*doc()));
|
||||
}
|
||||
|
||||
void get() {
|
||||
iq_ = createIQ(doc(), "get", "", id());
|
||||
|
||||
QDomElement prvt = doc()->createElement("query");
|
||||
prvt.setAttribute("xmlns", "jabber:iq:private");
|
||||
iq_.appendChild(prvt);
|
||||
|
||||
QDomElement bookmarks = doc()->createElement("storage");
|
||||
bookmarks.setAttribute("xmlns", "storage:bookmarks");
|
||||
prvt.appendChild(bookmarks);
|
||||
}
|
||||
|
||||
void onGo() {
|
||||
send(iq_);
|
||||
}
|
||||
|
||||
bool take(const QDomElement& x) {
|
||||
if(!iqVerify(x, "", id()))
|
||||
return false;
|
||||
|
||||
if(x.attribute("type") == "result") {
|
||||
QDomElement q = queryTag(x);
|
||||
for (QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement e = n.toElement();
|
||||
if (!e.isNull() && e.tagName() == "storage" && e.attribute("xmlns") == "storage:bookmarks") {
|
||||
for (QDomNode m = e.firstChild(); !m.isNull(); m = m.nextSibling()) {
|
||||
QDomElement f = m.toElement();
|
||||
if (f.isNull())
|
||||
continue;
|
||||
|
||||
if (f.tagName() == "url") {
|
||||
URLBookmark u(f);
|
||||
if (!u.isNull())
|
||||
urls_ += u;
|
||||
}
|
||||
else if (f.tagName() == "conference") {
|
||||
ConferenceBookmark c(f);
|
||||
if (!c.isNull())
|
||||
conferences_ += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setSuccess();
|
||||
}
|
||||
else {
|
||||
setError(x);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const QList<URLBookmark>& urls() const {
|
||||
return urls_;
|
||||
}
|
||||
|
||||
const QList<ConferenceBookmark>& conferences() const {
|
||||
return conferences_;
|
||||
}
|
||||
|
||||
private:
|
||||
QDomElement iq_;
|
||||
QList<URLBookmark> urls_;
|
||||
QList<ConferenceBookmark> conferences_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
BookmarkManager::BookmarkManager(PsiAccount* account)
|
||||
: account_(account)
|
||||
, accountAvailable_(false)
|
||||
, isAvailable_(false)
|
||||
{
|
||||
connect(account_, SIGNAL(updatedActivity()), SLOT(accountStateChanged()));
|
||||
}
|
||||
|
||||
bool BookmarkManager::isAvailable() const
|
||||
{
|
||||
return isAvailable_;
|
||||
}
|
||||
|
||||
void BookmarkManager::setIsAvailable(bool available)
|
||||
{
|
||||
if (available != isAvailable_) {
|
||||
isAvailable_ = available;
|
||||
emit availabilityChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QList<URLBookmark> BookmarkManager::urls() const
|
||||
{
|
||||
return urls_;
|
||||
}
|
||||
|
||||
QList<ConferenceBookmark> BookmarkManager::conferences() const
|
||||
{
|
||||
return conferences_;
|
||||
}
|
||||
|
||||
void BookmarkManager::accountStateChanged()
|
||||
{
|
||||
if (!account_->isAvailable()) {
|
||||
setIsAvailable(false);
|
||||
}
|
||||
|
||||
if (account_->isAvailable() && !accountAvailable_) {
|
||||
getBookmarks();
|
||||
}
|
||||
|
||||
accountAvailable_ = account_->isAvailable();
|
||||
}
|
||||
|
||||
void BookmarkManager::getBookmarks()
|
||||
{
|
||||
BookmarkTask* t = new BookmarkTask(account_->client()->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(getBookmarks_finished()));
|
||||
t->get();
|
||||
t->go(true);
|
||||
}
|
||||
|
||||
void BookmarkManager::setBookmarks(const QList<URLBookmark>& urls, const QList<ConferenceBookmark>& conferences)
|
||||
{
|
||||
bool urlsWereChanged = urls_ != urls;
|
||||
bool conferencesWereChanged = conferences_ != conferences;
|
||||
|
||||
urls_ = urls;
|
||||
conferences_ = conferences;
|
||||
BookmarkTask* t = new BookmarkTask(account_->client()->rootTask());
|
||||
connect(t,SIGNAL(finished()),SLOT(setBookmarks_finished()));
|
||||
t->set(urls,conferences);
|
||||
t->go(true);
|
||||
|
||||
if (urlsWereChanged)
|
||||
emit urlsChanged(urls_);
|
||||
if (conferencesWereChanged)
|
||||
emit conferencesChanged(conferences_);
|
||||
}
|
||||
|
||||
void BookmarkManager::setBookmarks(const QList<URLBookmark>& urls)
|
||||
{
|
||||
setBookmarks(urls, conferences());
|
||||
}
|
||||
|
||||
void BookmarkManager::setBookmarks(const QList<ConferenceBookmark>& conferences)
|
||||
{
|
||||
setBookmarks(urls(), conferences);
|
||||
}
|
||||
|
||||
void BookmarkManager::getBookmarks_finished()
|
||||
{
|
||||
BookmarkTask* t = static_cast<BookmarkTask*>(sender());
|
||||
if (t->success()) {
|
||||
bool urlsWereChanged = urls_ != t->urls();
|
||||
bool conferencesWereChanged = conferences_ != t->conferences();
|
||||
urls_ = t->urls();
|
||||
conferences_ = t->conferences();
|
||||
|
||||
if (urlsWereChanged)
|
||||
emit urlsChanged(urls_);
|
||||
if (conferencesWereChanged)
|
||||
emit conferencesChanged(conferences_);
|
||||
|
||||
setIsAvailable(true);
|
||||
}
|
||||
else {
|
||||
setIsAvailable(false);
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarkManager::setBookmarks_finished()
|
||||
{
|
||||
BookmarkTask* t = static_cast<BookmarkTask*>(sender());
|
||||
Q_UNUSED(t);
|
||||
}
|
||||
70
src/bookmarkmanager.h
Normal file
70
src/bookmarkmanager.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* bookmarkmanager.h
|
||||
* Copyright (C) 2006-2008 Remko Troncon, Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOOKMARKMANAGER_H
|
||||
#define BOOKMARKMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
|
||||
#include "conferencebookmark.h"
|
||||
#include "urlbookmark.h"
|
||||
|
||||
class PsiAccount;
|
||||
|
||||
class BookmarkManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BookmarkManager(PsiAccount* account);
|
||||
|
||||
bool isAvailable() const;
|
||||
|
||||
QList<URLBookmark> urls() const;
|
||||
QList<ConferenceBookmark> conferences() const;
|
||||
|
||||
void setBookmarks(const QList<URLBookmark>&, const QList<ConferenceBookmark>&);
|
||||
void setBookmarks(const QList<URLBookmark>&);
|
||||
void setBookmarks(const QList<ConferenceBookmark>&);
|
||||
|
||||
signals:
|
||||
void availabilityChanged();
|
||||
void urlsChanged(const QList<URLBookmark>&);
|
||||
void conferencesChanged(const QList<ConferenceBookmark>&);
|
||||
|
||||
private slots:
|
||||
void getBookmarks_finished();
|
||||
void setBookmarks_finished();
|
||||
void accountStateChanged();
|
||||
|
||||
private:
|
||||
void getBookmarks();
|
||||
void setIsAvailable(bool available);
|
||||
|
||||
private:
|
||||
PsiAccount* account_;
|
||||
bool accountAvailable_;
|
||||
bool isAvailable_;
|
||||
QList<URLBookmark> urls_;
|
||||
QList<ConferenceBookmark> conferences_;
|
||||
};
|
||||
|
||||
#endif
|
||||
12
src/capabilities/capabilities.pri
Normal file
12
src/capabilities/capabilities.pri
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
INCLUDEPATH *= $$PWD
|
||||
DEPENDPATH *= $$PWD
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/capsspec.h \
|
||||
$$PWD/capsregistry.h \
|
||||
$$PWD/capsmanager.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/capsspec.cpp \
|
||||
$$PWD/capsregistry.cpp \
|
||||
$$PWD/capsmanager.cpp
|
||||
294
src/capabilities/capsmanager.cpp
Normal file
294
src/capabilities/capsmanager.cpp
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* capsmanager.cpp
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
// TODO:
|
||||
// - Fallback on another jid if a disco request should fail. This can be
|
||||
// done by keeping a second list of candidate jids to query
|
||||
// - Implement Server Optimization support (Section 5).
|
||||
// - Implement consistency checking (Section 8).
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QPair>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
#include "capsregistry.h"
|
||||
#include "capsmanager.h"
|
||||
|
||||
|
||||
//#define REQUEST_TIMEOUT 3000
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
|
||||
/**
|
||||
* \class CapsManager
|
||||
* \brief A class managing all the capabilities of JIDs and their
|
||||
* clients.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
*/
|
||||
CapsManager::CapsManager(const Jid& jid, CapsRegistry* registry, Protocol::DiscoInfoQuerier* discoInfoQuerier) : jid_(jid), registry_(registry), discoInfoQuerier_(discoInfoQuerier), isEnabled_(true)
|
||||
{
|
||||
connect(registry_,SIGNAL(registered(const CapsSpec&)),SLOT(capsRegistered(const CapsSpec&)));
|
||||
connect(discoInfoQuerier_, SIGNAL(getDiscoInfo_success(const XMPP::Jid&, const QString&, const XMPP::DiscoItem&)), SLOT(getDiscoInfo_success(const XMPP::Jid&, const QString&, const XMPP::DiscoItem&)));
|
||||
connect(discoInfoQuerier_, SIGNAL(getDiscoInfo_error(const XMPP::Jid&, const QString&, int, const QString&)), SLOT(getDiscoInfo_error(const XMPP::Jid&, const QString&, int, const QString&)));
|
||||
}
|
||||
|
||||
CapsManager::~CapsManager()
|
||||
{
|
||||
delete discoInfoQuerier_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether the caps manager is enabled (and does lookups).
|
||||
*/
|
||||
bool CapsManager::isEnabled()
|
||||
{
|
||||
return isEnabled_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enables or disables the caps manager.
|
||||
*/
|
||||
void CapsManager::setEnabled(bool b)
|
||||
{
|
||||
isEnabled_ = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Registers new incoming capabilities information of a JID.
|
||||
* If the features of the entity are unknown, discovery requests are sent to
|
||||
* retrieve the information.
|
||||
*
|
||||
* @param jid The entity's JID
|
||||
* @param node The entity's caps node
|
||||
* @param ver The entity's caps version
|
||||
* @param ext The entity's caps extensions
|
||||
*/
|
||||
void CapsManager::updateCaps(const Jid& jid, const QString& node, const QString& ver, const QString& ext)
|
||||
{
|
||||
if (jid.compare(jid_,false))
|
||||
return;
|
||||
|
||||
CapsSpec c(node,ver,ext);
|
||||
CapsSpecs caps = c.flatten();
|
||||
if (capsSpecs_[jid.full()] != c) {
|
||||
//qDebug() << QString("caps.cpp: Updating caps for %1 (node=%2,ver=%3,ext=%4)").arg(QString(jid.full()).replace('%',"%%")).arg(node).arg(ver).arg(ext);
|
||||
|
||||
// Unregister from all old caps nodes
|
||||
CapsSpecs old_caps = capsSpecs_[jid.full()].flatten();
|
||||
foreach(CapsSpec s, old_caps) {
|
||||
if (s != CapsSpec()) {
|
||||
capsJids_[s].removeAll(jid.full());
|
||||
}
|
||||
}
|
||||
|
||||
if (!node.isEmpty() && !ver.isEmpty()) {
|
||||
// Register with all new caps nodes
|
||||
capsSpecs_[jid.full()] = c;
|
||||
foreach(CapsSpec s, caps) {
|
||||
if (!capsJids_[s].contains(jid.full())) {
|
||||
capsJids_[s].push_back(jid.full());
|
||||
}
|
||||
}
|
||||
|
||||
emit capsChanged(jid);
|
||||
|
||||
// Register new caps and check if we need to discover features
|
||||
if (isEnabled()) {
|
||||
foreach(CapsSpec s, caps) {
|
||||
if (!registry_->isRegistered(s) && capsJids_[s].count() == 1) {
|
||||
//qDebug() << QString("caps.cpp: Sending disco request to %1, node=%2").arg(QString(jid.full()).replace('%',"%%")).arg(node + "#" + s.extensions());
|
||||
discoInfoQuerier_->getDiscoInfo(jid,node + "#" + s.extensions());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Remove all caps specifications
|
||||
qWarning("caps.cpp: Illegal caps info from %s: node=%s, ver=%s",
|
||||
qPrintable(QString(jid.full()).replace('%', "%%")),
|
||||
qPrintable(node),
|
||||
qPrintable(ver));
|
||||
capsSpecs_.remove(jid.full());
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Add to the list of jids
|
||||
foreach(CapsSpec s, caps) {
|
||||
capsJids_[s].push_back(jid.full());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Removes all feature information for a given JID.
|
||||
*
|
||||
* @param jid The entity's JID
|
||||
*/
|
||||
void CapsManager::disableCaps(const Jid& jid)
|
||||
{
|
||||
//qDebug() << QString("caps.cpp: Disabling caps for %1.").arg(QString(jid.full()).replace('%',"%%"));
|
||||
if (capsEnabled(jid)) {
|
||||
CapsSpecs cs = capsSpecs_[jid.full()].flatten();
|
||||
foreach(CapsSpec s, cs) {
|
||||
if (s != CapsSpec()) {
|
||||
capsJids_[s].removeAll(jid.full());
|
||||
}
|
||||
}
|
||||
capsSpecs_.remove(jid.full());
|
||||
emit capsChanged(jid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Called when a reply to disco#info request was received.
|
||||
* If the result was succesful, the resulting features are recorded in the
|
||||
* features database for the requested node, and all the affected jids are
|
||||
* put in the queue for update notification.
|
||||
*/
|
||||
void CapsManager::getDiscoInfo_success(const XMPP::Jid& jid, const QString& node, const XMPP::DiscoItem& item)
|
||||
{
|
||||
//qDebug() << QString("caps.cpp: Disco response from %1, node=%2").arg(QString(jid.full()).replace('%',"%%")).arg(node);
|
||||
// Update features
|
||||
bool ok = false;
|
||||
CapsSpec cs(getCapsSpecForNode(jid, node, ok));
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
registry_->registerCaps(cs,item.identities(),item.features().list());
|
||||
}
|
||||
|
||||
void CapsManager::getDiscoInfo_error(const XMPP::Jid& jid, const QString& node, int, const QString&)
|
||||
{
|
||||
qWarning("capsmanager.cpp: Disco to '%s' at node '%s' failed.",
|
||||
qPrintable(jid.full()),
|
||||
qPrintable(node));
|
||||
}
|
||||
|
||||
|
||||
CapsSpec CapsManager::getCapsSpecForNode(const XMPP::Jid& jid, const QString& disco_node, bool& ok) const
|
||||
{
|
||||
int hash_index = disco_node.indexOf('#');
|
||||
if (hash_index == -1) {
|
||||
qWarning() << "CapsManager: Node" << disco_node << "invalid";
|
||||
ok = false;
|
||||
return CapsSpec();
|
||||
}
|
||||
QString node = disco_node.left(hash_index);
|
||||
QString ext = disco_node.right(disco_node.length() - hash_index - 1);
|
||||
CapsSpec jid_cs = capsSpecs_[jid.full()];
|
||||
if (jid_cs.node() == node) {
|
||||
ok = true;
|
||||
return CapsSpec(node,jid_cs.version(),ext);
|
||||
}
|
||||
else {
|
||||
ok = false;
|
||||
return CapsSpec();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This slot is called whenever capabilities of a client were discovered.
|
||||
* All jids with the corresponding client are updated.
|
||||
*/
|
||||
void CapsManager::capsRegistered(const CapsSpec& cs)
|
||||
{
|
||||
// Notify affected jids.
|
||||
foreach(QString s, capsJids_[cs]) {
|
||||
//qDebug() << QString("caps.cpp: Notifying %1.").arg(s.replace('%',"%%"));
|
||||
emit capsChanged(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether a given JID is broadcastingn its entity capabilities.
|
||||
*/
|
||||
bool CapsManager::capsEnabled(const Jid& jid) const
|
||||
{
|
||||
return capsSpecs_.contains(jid.full());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Requests the list of features of a given JID.
|
||||
*/
|
||||
XMPP::Features CapsManager::features(const Jid& jid) const
|
||||
{
|
||||
//qDebug() << "caps.cpp: Retrieving features of " << jid.full();
|
||||
QStringList f;
|
||||
if (capsEnabled(jid)) {
|
||||
CapsSpecs cs = capsSpecs_[jid.full()].flatten();
|
||||
foreach(CapsSpec s, cs) {
|
||||
//qDebug() << QString(" %1").arg(registry_->features(s).list().join("\n"));
|
||||
f += registry_->features(s).list();
|
||||
}
|
||||
}
|
||||
return Features(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the client name of a given jid.
|
||||
* \param jid the jid to retrieve the client name of
|
||||
*/
|
||||
QString CapsManager::clientName(const Jid& jid) const
|
||||
{
|
||||
if (capsEnabled(jid)) {
|
||||
QString name;
|
||||
CapsSpec cs = capsSpecs_[jid.full()];
|
||||
const DiscoItem::Identities& i = registry_->identities(CapsSpec(cs.node(),cs.version(),cs.version()));
|
||||
if (i.count() > 0) {
|
||||
name = i.first().name;
|
||||
}
|
||||
|
||||
// Try to be intelligent about the name
|
||||
if (name.isEmpty()) {
|
||||
name = cs.node();
|
||||
if (name.startsWith("http://"))
|
||||
name = name.right(name.length() - 7);
|
||||
|
||||
if (name.startsWith("www."))
|
||||
name = name.right(name.length() - 4);
|
||||
|
||||
int cut_pos = name.indexOf("/");
|
||||
if (cut_pos != -1)
|
||||
name = name.left(cut_pos);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the client version of a given jid.
|
||||
*/
|
||||
QString CapsManager::clientVersion(const Jid& jid) const
|
||||
{
|
||||
return (capsEnabled(jid) ? capsSpecs_[jid.full()].version() : QString());
|
||||
}
|
||||
83
src/capabilities/capsmanager.h
Normal file
83
src/capabilities/capsmanager.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* capsmanager.h
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CAPSMANAGER_H
|
||||
#define CAPSMANAGER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
#include "protocol/discoinfoquerier.h"
|
||||
#include "capsspec.h"
|
||||
#include "capsregistry.h"
|
||||
#include "xmpp_features.h"
|
||||
|
||||
namespace XMPP {
|
||||
class Jid;
|
||||
}
|
||||
using namespace XMPP;
|
||||
|
||||
class CapsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CapsManager(const XMPP::Jid&, CapsRegistry* registry, Protocol::DiscoInfoQuerier* discoInfoQuerier);
|
||||
~CapsManager();
|
||||
|
||||
bool isEnabled();
|
||||
void setEnabled(bool);
|
||||
|
||||
void updateCaps(const Jid& jid, const QString& node, const QString& ver, const QString& ext);
|
||||
void disableCaps(const Jid& jid);
|
||||
bool capsEnabled(const Jid& jid) const;
|
||||
XMPP::Features features(const Jid& jid) const;
|
||||
QString clientName(const Jid& jid) const;
|
||||
QString clientVersion(const Jid& jid) const;
|
||||
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted when the feature list of a given JID have changed.
|
||||
*/
|
||||
void capsChanged(const Jid& jid);
|
||||
|
||||
protected:
|
||||
CapsSpec getCapsSpecForNode(const XMPP::Jid& jid, const QString& disco_node, bool& ok) const;
|
||||
|
||||
protected slots:
|
||||
void getDiscoInfo_success(const XMPP::Jid& jid, const QString& node, const XMPP::DiscoItem& item);
|
||||
void getDiscoInfo_error(const XMPP::Jid& jid, const QString& node, int error_code, const QString& error_string);
|
||||
|
||||
void capsRegistered(const CapsSpec&);
|
||||
|
||||
private:
|
||||
XMPP::Jid jid_;
|
||||
QPointer<CapsRegistry> registry_;
|
||||
QPointer<Protocol::DiscoInfoQuerier> discoInfoQuerier_;
|
||||
bool isEnabled_;
|
||||
QMap<QString,CapsSpec> capsSpecs_;
|
||||
QMap<CapsSpec,QList<QString> > capsJids_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
249
src/capabilities/capsregistry.cpp
Normal file
249
src/capabilities/capsregistry.cpp
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* capsregistry.cpp
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QTextCodec>
|
||||
#include <QFile>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "xmpp_features.h"
|
||||
#include "capsregistry.h"
|
||||
#include "iodeviceopener.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
CapsRegistry::CapsInfo::CapsInfo()
|
||||
{
|
||||
updateLastSeen();
|
||||
}
|
||||
|
||||
const XMPP::Features& CapsRegistry::CapsInfo::features() const
|
||||
{
|
||||
return features_;
|
||||
}
|
||||
|
||||
const DiscoItem::Identities& CapsRegistry::CapsInfo::identities() const
|
||||
{
|
||||
return identities_;
|
||||
}
|
||||
|
||||
void CapsRegistry::CapsInfo::setIdentities(const DiscoItem::Identities& i)
|
||||
{
|
||||
identities_ = i;
|
||||
}
|
||||
|
||||
void CapsRegistry::CapsInfo::setFeatures(const XMPP::Features& f)
|
||||
{
|
||||
features_ = f;
|
||||
}
|
||||
|
||||
void CapsRegistry::CapsInfo::updateLastSeen()
|
||||
{
|
||||
lastSeen_ = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
QDomElement CapsRegistry::CapsInfo::toXml(QDomDocument *doc) const
|
||||
{
|
||||
QDomElement info = doc->createElement("info");
|
||||
info.setAttribute("last-seen",lastSeen_.toString(Qt::ISODate));
|
||||
|
||||
// Identities
|
||||
for (DiscoItem::Identities::ConstIterator i = identities_.begin(); i != identities_.end(); ++i) {
|
||||
QDomElement identity = doc->createElement("identity");
|
||||
identity.setAttribute("category",(*i).category);
|
||||
identity.setAttribute("name",(*i).name);
|
||||
identity.setAttribute("type",(*i).type);
|
||||
info.appendChild(identity);
|
||||
}
|
||||
|
||||
// Features
|
||||
foreach(QString f, features_.list()) {
|
||||
QDomElement feature = doc->createElement("feature");
|
||||
feature.setAttribute("node",f);
|
||||
info.appendChild(feature);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void CapsRegistry::CapsInfo::fromXml(const QDomElement& e)
|
||||
{
|
||||
if (e.tagName() != "info") {
|
||||
qWarning("caps.cpp: Invalid info element");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.attribute("last-seen").isEmpty()) {
|
||||
QDateTime last = QDateTime::fromString(e.attribute("last-seen"),Qt::ISODate);
|
||||
if (last.isValid())
|
||||
lastSeen_ = last;
|
||||
else
|
||||
qWarning("Invalid date in caps registry");
|
||||
}
|
||||
|
||||
for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement i = n.toElement();
|
||||
if(i.isNull()) {
|
||||
qWarning("caps.cpp: Null element");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(i.tagName() == "identity") {
|
||||
DiscoItem::Identity id;
|
||||
id.category = i.attribute("category");
|
||||
id.name = i.attribute("name");
|
||||
id.type = i.attribute("type");
|
||||
identities_ += id;
|
||||
}
|
||||
else if (i.tagName() == "feature") {
|
||||
features_.addFeature(i.attribute("node"));
|
||||
}
|
||||
else {
|
||||
qWarning("caps.cpp: Unknown element");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/**
|
||||
* \class CapsRegistry
|
||||
* \brief A singleton class managing the capabilities of clients.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
*/
|
||||
CapsRegistry::CapsRegistry()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convert all capabilities info to XML.
|
||||
*/
|
||||
void CapsRegistry::save(QIODevice& out)
|
||||
{
|
||||
// Generate XML
|
||||
QDomDocument doc;
|
||||
QDomElement capabilities = doc.createElement("capabilities");
|
||||
doc.appendChild(capabilities);
|
||||
QMap<CapsSpec,CapsInfo>::ConstIterator i = capsInfo_.begin();
|
||||
for( ; i != capsInfo_.end(); i++) {
|
||||
QDomElement info = i.value().toXml(&doc);
|
||||
info.setAttribute("node",i.key().node());
|
||||
info.setAttribute("ver",i.key().version());
|
||||
info.setAttribute("ext",i.key().extensions());
|
||||
capabilities.appendChild(info);
|
||||
}
|
||||
|
||||
IODeviceOpener opener(&out, QIODevice::WriteOnly);
|
||||
if (!opener.isOpen()) {
|
||||
qWarning() << "Caps: Unable to open IO device";
|
||||
return;
|
||||
}
|
||||
QTextStream t;
|
||||
t.setDevice(&out);
|
||||
t.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
t << doc.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets the file to save the capabilities info to
|
||||
*/
|
||||
void CapsRegistry::load(QIODevice& in)
|
||||
{
|
||||
// Load settings
|
||||
QDomDocument doc;
|
||||
IODeviceOpener opener(&in, QIODevice::ReadOnly);
|
||||
if (!opener.isOpen()) {
|
||||
qWarning() << "CapsRegistry: Cannot open input device";
|
||||
return;
|
||||
}
|
||||
if (!doc.setContent(&in)) {
|
||||
qWarning() << "CapsRegistry: Cannnot parse input";
|
||||
return;
|
||||
}
|
||||
|
||||
QDomElement caps = doc.documentElement();
|
||||
if (caps.tagName() != "capabilities") {
|
||||
qWarning("caps.cpp: Invalid capabilities element");
|
||||
return;
|
||||
}
|
||||
|
||||
for(QDomNode n = caps.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement i = n.toElement();
|
||||
if(i.isNull()) {
|
||||
qWarning("capsregistry.cpp: Null element");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(i.tagName() == "info") {
|
||||
CapsInfo info;
|
||||
info.fromXml(i);
|
||||
CapsSpec spec(i.attribute("node"),i.attribute("ver"),i.attribute("ext"));
|
||||
capsInfo_[spec] = info;
|
||||
//qDebug() << QString("Read %1 %2 %3").arg(spec.node()).arg(spec.version()).arg(spec.extensions());
|
||||
}
|
||||
else {
|
||||
qWarning("capsregistry.cpp: Unknown element");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Registers capabilities of a client.
|
||||
*/
|
||||
void CapsRegistry::registerCaps(const CapsSpec& spec,const XMPP::DiscoItem::Identities& identities,const XMPP::Features& features)
|
||||
{
|
||||
if (!isRegistered(spec)) {
|
||||
CapsInfo info;
|
||||
info.setIdentities(identities);
|
||||
info.setFeatures(features);
|
||||
capsInfo_[spec] = info;
|
||||
emit registered(spec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if capabilities have been registered.
|
||||
*/
|
||||
bool CapsRegistry::isRegistered(const CapsSpec& spec) const
|
||||
{
|
||||
return capsInfo_.contains(spec);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Retrieves the features of a given caps spec.
|
||||
*/
|
||||
XMPP::Features CapsRegistry::features(const CapsSpec& spec) const
|
||||
{
|
||||
return capsInfo_[spec].features();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves the identities of a given caps spec.
|
||||
*/
|
||||
XMPP::DiscoItem::Identities CapsRegistry::identities(const CapsSpec& spec) const
|
||||
{
|
||||
return capsInfo_[spec].identities();
|
||||
}
|
||||
84
src/capabilities/capsregistry.h
Normal file
84
src/capabilities/capsregistry.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* capsregistry.h
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CAPSREGISTRY_H
|
||||
#define CAPSREGISTRY_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QDateTime>
|
||||
#include <QPair>
|
||||
|
||||
#include "xmpp_features.h"
|
||||
#include "xmpp_discoitem.h"
|
||||
|
||||
#include "capsspec.h"
|
||||
|
||||
class QDomDocument;
|
||||
class QDomElement;
|
||||
|
||||
class CapsRegistry : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CapsRegistry();
|
||||
|
||||
void registerCaps(const CapsSpec&, const XMPP::DiscoItem::Identities&, const XMPP::Features& features);
|
||||
bool isRegistered(const CapsSpec&) const;
|
||||
XMPP::Features features(const CapsSpec&) const;
|
||||
XMPP::DiscoItem::Identities identities(const CapsSpec&) const;
|
||||
|
||||
signals:
|
||||
void registered(const CapsSpec&);
|
||||
|
||||
public slots:
|
||||
void load(QIODevice& target);
|
||||
void save(QIODevice& target);
|
||||
|
||||
private:
|
||||
class CapsInfo
|
||||
{
|
||||
public:
|
||||
CapsInfo();
|
||||
const XMPP::Features& features() const;
|
||||
const XMPP::DiscoItem::Identities& identities() const;
|
||||
|
||||
void setIdentities(const XMPP::DiscoItem::Identities&);
|
||||
void setFeatures(const XMPP::Features&);
|
||||
|
||||
QDomElement toXml(QDomDocument *) const;
|
||||
void fromXml(const QDomElement&);
|
||||
|
||||
protected:
|
||||
void updateLastSeen();
|
||||
|
||||
private:
|
||||
XMPP::Features features_;
|
||||
XMPP::DiscoItem::Identities identities_;
|
||||
QDateTime lastSeen_;
|
||||
};
|
||||
QMap<CapsSpec,CapsInfo> capsInfo_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
118
src/capabilities/capsspec.cpp
Normal file
118
src/capabilities/capsspec.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* capsspec.cpp
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "capsspec.h"
|
||||
|
||||
/**
|
||||
* \class CapsSpec
|
||||
* \brief A class representing an entity capability specification.
|
||||
* An entity capability is a combination of a node, a version, and a set of
|
||||
* extensions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
CapsSpec::CapsSpec()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Basic constructor.
|
||||
* @param node the node
|
||||
* @param ven the version
|
||||
* @param ext the list of extensions (separated by spaces)
|
||||
*/
|
||||
CapsSpec::CapsSpec(const QString& node, const QString& ver, const QString& ext) : node_(node), ver_(ver), ext_(ext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns the node of the capabilities specification.
|
||||
*/
|
||||
const QString& CapsSpec::node() const
|
||||
{
|
||||
return node_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns the version of the capabilities specification.
|
||||
*/
|
||||
const QString& CapsSpec::version() const
|
||||
{
|
||||
return ver_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns the extensions of the capabilities specification.
|
||||
*/
|
||||
const QString& CapsSpec::extensions() const
|
||||
{
|
||||
return ext_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Flattens the caps specification into the set of 'simple'
|
||||
* specifications.
|
||||
* A 'simple' specification is a specification with exactly one extension,
|
||||
* or with the version number as the extension.
|
||||
*
|
||||
* Example: A caps specification with node=http://psi-im.org, version=0.10,
|
||||
* and ext='achat vchat' would be expanded into the following list of specs:
|
||||
* node=http://psi-im.org, ver=0.10, ext=0.10
|
||||
* node=http://psi-im.org, ver=0.10, ext=achat
|
||||
* node=http://psi-im.org, ver=0.10, ext=vchat
|
||||
*/
|
||||
CapsSpecs CapsSpec::flatten() const
|
||||
{
|
||||
CapsSpecs l;
|
||||
l.append(CapsSpec(node(),version(),version()));
|
||||
QStringList exts(extensions().split(" ",QString::SkipEmptyParts));
|
||||
for (QStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) {
|
||||
l.append(CapsSpec(node(),version(),*i));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
bool CapsSpec::operator==(const CapsSpec& s) const
|
||||
{
|
||||
return (node() == s.node() && version() == s.version() && extensions() == s.extensions());
|
||||
}
|
||||
|
||||
bool CapsSpec::operator!=(const CapsSpec& s) const
|
||||
{
|
||||
return !((*this) == s);
|
||||
}
|
||||
|
||||
bool CapsSpec::operator<(const CapsSpec& s) const
|
||||
{
|
||||
return (node() != s.node() ? node() < s.node() :
|
||||
(version() != s.version() ? version() < s.version() :
|
||||
extensions() < s.extensions()));
|
||||
}
|
||||
|
||||
49
src/capabilities/capsspec.h
Normal file
49
src/capabilities/capsspec.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* capsspec.h
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CAPSSPEC_H
|
||||
#define CAPSSPEC_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
class CapsSpec;
|
||||
typedef QList<CapsSpec> CapsSpecs;
|
||||
|
||||
class CapsSpec
|
||||
{
|
||||
public:
|
||||
CapsSpec();
|
||||
CapsSpec(const QString&, const QString&, const QString&);
|
||||
const QString& node() const;
|
||||
const QString& version() const;
|
||||
const QString& extensions() const;
|
||||
CapsSpecs flatten() const;
|
||||
|
||||
bool operator==(const CapsSpec&) const;
|
||||
bool operator!=(const CapsSpec&) const;
|
||||
bool operator<(const CapsSpec&) const;
|
||||
|
||||
private:
|
||||
QString node_, ver_, ext_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
183
src/capabilities/unittest/capsmanagertest.cpp
Normal file
183
src/capabilities/unittest/capsmanagertest.cpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/**
|
||||
* Copyright (C) 2007, Remko Troncon
|
||||
* See COPYING file for the detailed license.
|
||||
*/
|
||||
|
||||
// FIXME: This test suite is far from complete
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||
|
||||
#include "protocol/discoinfoquerier.h"
|
||||
#include "xmpp_jid.h"
|
||||
#include "capsmanager.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class TestDiscoInfoQuerier : public Protocol::DiscoInfoQuerier
|
||||
{
|
||||
public:
|
||||
struct DiscoInfo {
|
||||
XMPP::Jid jid;
|
||||
QString node;
|
||||
XMPP::DiscoItem item;
|
||||
};
|
||||
|
||||
TestDiscoInfoQuerier() {
|
||||
nb_getdiscoinfo_called_ = 0;
|
||||
}
|
||||
|
||||
void getDiscoInfo(const Jid& j, const QString& n) {
|
||||
emitDiscoInfo(j,n);
|
||||
}
|
||||
|
||||
void emitDiscoInfo(const XMPP::Jid& j, const QString& n) {
|
||||
nb_getdiscoinfo_called_++;
|
||||
foreach(DiscoInfo info, infos_) {
|
||||
if (info.jid.compare(j,true) && info.node == n) {
|
||||
emit getDiscoInfo_success(j,n,info.item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addInfo(const XMPP::Jid& j, const QString& n, const XMPP::DiscoItem& it) {
|
||||
DiscoInfo i;
|
||||
i.jid = j;
|
||||
i.node = n;
|
||||
i.item = it;
|
||||
infos_ += i;
|
||||
}
|
||||
|
||||
unsigned int nb_getdiscoinfo_called_;
|
||||
QList<DiscoInfo> infos_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class CapsManagerTest : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(CapsManagerTest);
|
||||
|
||||
CPPUNIT_TEST(testUpdateCaps);
|
||||
|
||||
CPPUNIT_TEST(testCapsEnabled);
|
||||
CPPUNIT_TEST(testCapsEnabled_NoCaps);
|
||||
|
||||
CPPUNIT_TEST(testDisableCaps);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
CapsManagerTest();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void addContact(const QString& jid, const QString& client, const QString& version, const QStringList& capabilities);
|
||||
CapsManager* createManager(const QString& jid);
|
||||
|
||||
void testUpdateCaps();
|
||||
void testCapsEnabled();
|
||||
void testCapsEnabled_NoCaps();
|
||||
void testDisableCaps();
|
||||
|
||||
private:
|
||||
CapsRegistry registry_;
|
||||
TestDiscoInfoQuerier* querier_;
|
||||
CapsManager* manager_;
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CapsManagerTest);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
CapsManagerTest::CapsManagerTest()
|
||||
{
|
||||
}
|
||||
|
||||
void CapsManagerTest::setUp()
|
||||
{
|
||||
manager_ = NULL;
|
||||
querier_ = new TestDiscoInfoQuerier();
|
||||
}
|
||||
|
||||
void CapsManagerTest::tearDown()
|
||||
{
|
||||
delete manager_;
|
||||
}
|
||||
|
||||
CapsManager* CapsManagerTest::createManager(const QString& jid)
|
||||
{
|
||||
manager_ = new CapsManager(jid, ®istry_, querier_);
|
||||
return manager_;
|
||||
}
|
||||
|
||||
void CapsManagerTest::addContact(const QString& jid, const QString& client,
|
||||
const QString& version, const QStringList& capabilities)
|
||||
{
|
||||
XMPP::DiscoItem i;
|
||||
i.setFeatures(XMPP::Features(version + "_f1"));
|
||||
querier_->addInfo(jid, client + "#" + version, i);
|
||||
|
||||
foreach(QString s, capabilities) {
|
||||
XMPP::DiscoItem i2;
|
||||
QStringList f;
|
||||
f << s + "_f1" << s + "_f2";
|
||||
i2.setFeatures(XMPP::Features(f));
|
||||
querier_->addInfo(jid, client + "#" + s, i2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CapsManagerTest::testUpdateCaps()
|
||||
{
|
||||
QStringList capabilities;
|
||||
capabilities << "c1" << "c2" << "c3";
|
||||
addContact("you@example.com/a", "myclient", "myversion", capabilities);
|
||||
CapsManager* manager = createManager("me@example.com");
|
||||
|
||||
manager->updateCaps("you@example.com/a", "myclient", "myversion", "c1 c2");
|
||||
XMPP::Features features(manager->features("you@example.com/a"));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(3U, querier_->nb_getdiscoinfo_called_);
|
||||
CPPUNIT_ASSERT(features.test(QStringList("myversion_f1")));
|
||||
CPPUNIT_ASSERT(features.test(QStringList("c1_f1")));
|
||||
CPPUNIT_ASSERT(features.test(QStringList("c1_f2")));
|
||||
CPPUNIT_ASSERT(features.test(QStringList("c2_f1")));
|
||||
CPPUNIT_ASSERT(features.test(QStringList("c2_f2")));
|
||||
}
|
||||
|
||||
void CapsManagerTest::testCapsEnabled()
|
||||
{
|
||||
QStringList capabilities;
|
||||
capabilities << "c1" << "c2";
|
||||
addContact("you@example.com/a", "myclient", "myversion", capabilities);
|
||||
CapsManager* manager = createManager("me@example.com");
|
||||
|
||||
manager->updateCaps("you@example.com/a", "myclient", "myversion", "c1 c2");
|
||||
|
||||
CPPUNIT_ASSERT(manager->capsEnabled("you@example.com/a"));
|
||||
}
|
||||
|
||||
void CapsManagerTest::testCapsEnabled_NoCaps()
|
||||
{
|
||||
CapsManager* manager = createManager("me@example.com/a");
|
||||
|
||||
CPPUNIT_ASSERT(!manager->capsEnabled("you@example.com/b"));
|
||||
}
|
||||
|
||||
void CapsManagerTest::testDisableCaps()
|
||||
{
|
||||
QStringList capabilities;
|
||||
capabilities << "c1" << "c2";
|
||||
addContact("you@example.com/a", "myclient", "myversion", capabilities);
|
||||
CapsManager* manager = createManager("me@example.com");
|
||||
manager->updateCaps("you@example.com/a", "myclient", "myversion", "c1 c2");
|
||||
|
||||
manager->disableCaps("you@example.com/a");
|
||||
|
||||
CPPUNIT_ASSERT(!manager->capsEnabled("you@example.com/a"));
|
||||
}
|
||||
124
src/capabilities/unittest/capsspectest.cpp
Normal file
124
src/capabilities/unittest/capsspectest.cpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* Copyright (C) 2007, Remko Troncon
|
||||
*/
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||
|
||||
#include "capsspec.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class CapsSpecTest : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(CapsSpecTest);
|
||||
CPPUNIT_TEST(testConstructor);
|
||||
|
||||
CPPUNIT_TEST(testEqualsNotEquals_Equal);
|
||||
CPPUNIT_TEST(testEqualsNotEquals_NotEqual);
|
||||
|
||||
CPPUNIT_TEST(testSmallerThan);
|
||||
CPPUNIT_TEST(testSmallerThan_SameNode);
|
||||
CPPUNIT_TEST(testSmallerThan_SameNodeVersion);
|
||||
CPPUNIT_TEST(testSmallerThan_Equals);
|
||||
|
||||
CPPUNIT_TEST(testFlatten);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
CapsSpecTest();
|
||||
|
||||
void testConstructor();
|
||||
void testFlatten();
|
||||
void testEqualsNotEquals_Equal();
|
||||
void testEqualsNotEquals_NotEqual();
|
||||
void testSmallerThan();
|
||||
void testSmallerThan_SameNode();
|
||||
void testSmallerThan_SameNodeVersion();
|
||||
void testSmallerThan_Equals();
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CapsSpecTest);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
CapsSpecTest::CapsSpecTest()
|
||||
{
|
||||
}
|
||||
|
||||
void CapsSpecTest::testConstructor()
|
||||
{
|
||||
CapsSpec c("a","b","c d");
|
||||
|
||||
CPPUNIT_ASSERT(c.node() == "a");
|
||||
CPPUNIT_ASSERT(c.version() == "b");
|
||||
CPPUNIT_ASSERT(c.extensions() == "c d");
|
||||
}
|
||||
|
||||
void CapsSpecTest::testEqualsNotEquals_Equal()
|
||||
{
|
||||
CapsSpec c1("a","b","c d");
|
||||
CapsSpec c2("a","b","c d");
|
||||
|
||||
CPPUNIT_ASSERT(c1 == c2);
|
||||
CPPUNIT_ASSERT(!(c1 != c2));
|
||||
}
|
||||
|
||||
void CapsSpecTest::testEqualsNotEquals_NotEqual()
|
||||
{
|
||||
CapsSpec c1("a","b","c d");
|
||||
CapsSpec c2("a","e","c d");
|
||||
|
||||
CPPUNIT_ASSERT(!(c1 == c2));
|
||||
CPPUNIT_ASSERT(c1 != c2);
|
||||
}
|
||||
|
||||
void CapsSpecTest::testSmallerThan()
|
||||
{
|
||||
CapsSpec c1("a","b","c");
|
||||
CapsSpec c2("d","e","f");
|
||||
|
||||
CPPUNIT_ASSERT(c1 < c2);
|
||||
CPPUNIT_ASSERT(!(c2 < c1));
|
||||
}
|
||||
|
||||
void CapsSpecTest::testSmallerThan_SameNode()
|
||||
{
|
||||
CapsSpec c1("a","b","c");
|
||||
CapsSpec c2("a","e","f");
|
||||
|
||||
CPPUNIT_ASSERT(c1 < c2);
|
||||
CPPUNIT_ASSERT(!(c2 < c1));
|
||||
}
|
||||
|
||||
void CapsSpecTest::testSmallerThan_SameNodeVersion()
|
||||
{
|
||||
CapsSpec c1("a","b","c");
|
||||
CapsSpec c2("a","b","f");
|
||||
|
||||
CPPUNIT_ASSERT(c1 < c2);
|
||||
CPPUNIT_ASSERT(!(c2 < c1));
|
||||
}
|
||||
|
||||
void CapsSpecTest::testSmallerThan_Equals()
|
||||
{
|
||||
CapsSpec c1("a","b","c");
|
||||
CapsSpec c2("a","b","c");
|
||||
|
||||
CPPUNIT_ASSERT(!(c1 < c2));
|
||||
CPPUNIT_ASSERT(!(c2 < c1));
|
||||
}
|
||||
|
||||
void CapsSpecTest::testFlatten()
|
||||
{
|
||||
CapsSpec c("a","b","c d");
|
||||
|
||||
CapsSpecs cs = c.flatten();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(3, cs.count());
|
||||
CPPUNIT_ASSERT(cs[0] == CapsSpec("a", "b", "b"));
|
||||
CPPUNIT_ASSERT(cs[1] == CapsSpec("a", "b", "c"));
|
||||
CPPUNIT_ASSERT(cs[2] == CapsSpec("a", "b", "d"));
|
||||
}
|
||||
|
||||
3
src/capabilities/unittest/unittest.pri
Normal file
3
src/capabilities/unittest/unittest.pri
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
SOURCES += \
|
||||
$$PWD/capsspectest.cpp \
|
||||
$$PWD/capsmanagertest.cpp
|
||||
165
src/certutil.cpp
Normal file
165
src/certutil.cpp
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
#include <QtCrypto>
|
||||
#include <QStringList>
|
||||
#include <QDomDocument>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
|
||||
#include "applicationinfo.h"
|
||||
#include "certutil.h"
|
||||
|
||||
using namespace QCA;
|
||||
|
||||
/**
|
||||
* \class CertUtil
|
||||
* \brief A class providing utility functions for Certificates.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Returns the list of directories with certificates.
|
||||
*/
|
||||
static QStringList certificateStores()
|
||||
{
|
||||
QStringList l;
|
||||
l += ApplicationInfo::resourcesDir() + "/certs";
|
||||
l += ApplicationInfo::homeDir() + "/certs";
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the collection of all available certificates.
|
||||
* This collection includes the system-wide certificates, as well as any
|
||||
* custom certificate in the Psi-specific cert dirs.
|
||||
*/
|
||||
CertificateCollection CertUtil::allCertificates()
|
||||
{
|
||||
// ONLINE-1864
|
||||
CertificateCollection certs;
|
||||
return certs;
|
||||
|
||||
// CertificateCollection certs(systemStore());
|
||||
QStringList stores = certificateStores();
|
||||
for (QStringList::ConstIterator s = stores.begin(); s != stores.end(); ++s) {
|
||||
QDir store(*s);
|
||||
|
||||
// Read in PEM certificates
|
||||
store.setNameFilters(QStringList("*.crt") + QStringList("*.pem"));
|
||||
QStringList cert_files = store.entryList();
|
||||
for (QStringList::ConstIterator c = cert_files.begin(); c != cert_files.end(); ++c) {
|
||||
//qDebug() << "certutil.cpp: Reading " << store.filePath(*c);
|
||||
ConvertResult result;
|
||||
Certificate cert = Certificate::fromPEMFile(store.filePath(*c),&result);
|
||||
if (result == ConvertGood) {
|
||||
certs.addCertificate(cert);
|
||||
}
|
||||
else {
|
||||
qWarning("certutil.cpp: Invalid PEM certificate: %s", qPrintable(store.filePath(*c)));
|
||||
}
|
||||
}
|
||||
|
||||
// Read in old XML format certificates (DEPRECATED)
|
||||
store.setNameFilter("*.xml");
|
||||
cert_files = store.entryList();
|
||||
for(QStringList::ConstIterator it = cert_files.begin(); it != cert_files.end(); ++it) {
|
||||
qWarning("Loading certificate in obsolete XML format: %s", qPrintable(store.filePath(*it)));
|
||||
QFile f(store.filePath(*it));
|
||||
if(!f.open(QIODevice::ReadOnly))
|
||||
continue;
|
||||
QDomDocument doc;
|
||||
bool ok = doc.setContent(&f);
|
||||
f.close();
|
||||
if(!ok)
|
||||
continue;
|
||||
|
||||
QDomElement base = doc.documentElement();
|
||||
if(base.tagName() != "store")
|
||||
continue;
|
||||
QDomNodeList cl = base.elementsByTagName("certificate");
|
||||
|
||||
for(int n = 0; n < (int)cl.count(); ++n) {
|
||||
QDomElement data = cl.item(n).toElement().elementsByTagName("data").item(0).toElement();
|
||||
if(!data.isNull()) {
|
||||
ConvertResult result;
|
||||
Certificate cert = Certificate::fromDER(Base64().stringToArray(data.text()).toByteArray(),&result);
|
||||
if (result == ConvertGood) {
|
||||
certs.addCertificate(cert);
|
||||
}
|
||||
else {
|
||||
qWarning("certutil.cpp: Invalid XML certificate: %s", qPrintable(store.filePath(*it)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return certs;
|
||||
}
|
||||
|
||||
QString CertUtil::validityToString(QCA::Validity v)
|
||||
{
|
||||
QString s;
|
||||
switch(v)
|
||||
{
|
||||
case QCA::ValidityGood:
|
||||
s = "Validated";
|
||||
break;
|
||||
case QCA::ErrorRejected:
|
||||
s = "Root CA is marked to reject the specified purpose";
|
||||
break;
|
||||
case QCA::ErrorUntrusted:
|
||||
s = "Certificate not trusted for the required purpose";
|
||||
break;
|
||||
case QCA::ErrorSignatureFailed:
|
||||
s = "Invalid signature";
|
||||
break;
|
||||
case QCA::ErrorInvalidCA:
|
||||
s = "Invalid CA certificate";
|
||||
break;
|
||||
case QCA::ErrorInvalidPurpose:
|
||||
s = "Invalid certificate purpose";
|
||||
break;
|
||||
case QCA::ErrorSelfSigned:
|
||||
s = "Certificate is self-signed";
|
||||
break;
|
||||
case QCA::ErrorRevoked:
|
||||
s = "Certificate has been revoked";
|
||||
break;
|
||||
case QCA::ErrorPathLengthExceeded:
|
||||
s = "Maximum certificate chain length exceeded";
|
||||
break;
|
||||
case QCA::ErrorExpired:
|
||||
s = "Certificate has expired";
|
||||
break;
|
||||
case QCA::ErrorExpiredCA:
|
||||
s = "CA has expired";
|
||||
break;
|
||||
case QCA::ErrorValidityUnknown:
|
||||
default:
|
||||
s = "General certificate validation error";
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
QString CertUtil::resultToString(int result, QCA::Validity validity)
|
||||
{
|
||||
QString s;
|
||||
switch(result) {
|
||||
case QCA::TLS::NoCertificate:
|
||||
s = QObject::tr("The server did not present a certificate.");
|
||||
break;
|
||||
case QCA::TLS::Valid:
|
||||
s = QObject::tr("Certificate is valid.");
|
||||
break;
|
||||
case QCA::TLS::HostMismatch:
|
||||
s = QObject::tr("The hostname does not match the one the certificate was issued to.");
|
||||
break;
|
||||
case QCA::TLS::InvalidCertificate:
|
||||
s = validityToString(validity);
|
||||
break;
|
||||
|
||||
default:
|
||||
s = QObject::tr("General certificate validation error.");
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
19
src/certutil.h
Normal file
19
src/certutil.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef CERTUTIL_H
|
||||
#define CERTUTIL_H
|
||||
|
||||
class QString;
|
||||
namespace QCA {
|
||||
class CertificateCollection;
|
||||
}
|
||||
|
||||
class CertUtil
|
||||
{
|
||||
public:
|
||||
static QCA::CertificateCollection allCertificates();
|
||||
static QString resultToString(int result, QCA::Validity);
|
||||
|
||||
protected:
|
||||
static QString validityToString(QCA::Validity);
|
||||
};
|
||||
|
||||
#endif
|
||||
155
src/changepw.ui
Normal file
155
src/changepw.ui
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
<ui version="4.0" stdsetdef="1" >
|
||||
<author></author>
|
||||
<comment></comment>
|
||||
<exportmacro></exportmacro>
|
||||
<class>ChangePassword</class>
|
||||
<widget class="QDialog" name="ChangePassword" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>331</width>
|
||||
<height>149</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Change Password</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLineEdit" name="le_pwver" >
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="le_pwcur" >
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="lb_pwver" >
|
||||
<property name="text" >
|
||||
<string>Confirm new password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="lb_pwcur" >
|
||||
<property name="text" >
|
||||
<string>Current password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="le_pwnew" >
|
||||
<property name="echoMode" >
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="lb_pwnew" >
|
||||
<property name="text" >
|
||||
<string>New password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer2" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="Line1" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::HLine</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="BusyWidget" name="busy" />
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="Spacer1" >
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>110</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_close" >
|
||||
<property name="text" >
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IconButton" name="pb_apply" >
|
||||
<property name="text" >
|
||||
<string>&Apply</string>
|
||||
</property>
|
||||
<property name="psiIconName" stdset="0" >
|
||||
<string>psi/register</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
<tabstops>
|
||||
<tabstop>le_pwcur</tabstop>
|
||||
<tabstop>le_pwnew</tabstop>
|
||||
<tabstop>le_pwver</tabstop>
|
||||
</tabstops>
|
||||
</ui>
|
||||
160
src/changepwdlg.cpp
Normal file
160
src/changepwdlg.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* changepwdlg.cpp - dialog for changing password
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "changepwdlg.h"
|
||||
|
||||
#include <qlayout.h>
|
||||
#include <qlabel.h>
|
||||
#include <qpushbutton.h>
|
||||
#include <qlineedit.h>
|
||||
#include <qmessagebox.h>
|
||||
#include "profiles.h"
|
||||
#include "psiaccount.h"
|
||||
#include "busywidget.h"
|
||||
#include "xmpp_tasks.h"
|
||||
#include "accountmodifydlg.h"
|
||||
#include "iconwidget.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
ChangePasswordDlg::ChangePasswordDlg(PsiAccount *_pa, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
setupUi(this);
|
||||
setModal(false);
|
||||
pa = _pa;
|
||||
pa->dialogRegister(this);
|
||||
|
||||
connect(pa, SIGNAL(disconnected()), SLOT(disc()));
|
||||
|
||||
setWindowTitle(CAP(caption()));
|
||||
|
||||
connect(pb_close, SIGNAL(clicked()), SLOT(close()));
|
||||
connect(pb_apply, SIGNAL(clicked()), SLOT(apply()));
|
||||
}
|
||||
|
||||
ChangePasswordDlg::~ChangePasswordDlg()
|
||||
{
|
||||
pa->dialogUnregister(this);
|
||||
}
|
||||
|
||||
/*void ChangePasswordDlg::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
e->ignore();
|
||||
reject();
|
||||
}*/
|
||||
|
||||
void ChangePasswordDlg::done(int r)
|
||||
{
|
||||
if(busy->isActive())
|
||||
return;
|
||||
QDialog::done(r);
|
||||
}
|
||||
|
||||
void ChangePasswordDlg::apply()
|
||||
{
|
||||
// sanity check
|
||||
if(le_pwcur->text().isEmpty() || le_pwnew->text().isEmpty() || le_pwver->text().isEmpty()) {
|
||||
QMessageBox::information(this, tr("Error"), tr("You must fill out the fields properly before you can proceed."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(le_pwcur->text() != pa->userAccount().pass) {
|
||||
QMessageBox::information(this, tr("Error"), tr("You entered your old password incorrectly. Try again."));
|
||||
le_pwcur->setText("");
|
||||
le_pwcur->setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
if(le_pwnew->text() != le_pwver->text()) {
|
||||
QMessageBox::information(this, tr("Error"), tr("New password and confirmation do not match. Please enter them again."));
|
||||
le_pwnew->setText("");
|
||||
le_pwver->setText("");
|
||||
le_pwnew->setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
busy->start();
|
||||
blockWidgets();
|
||||
|
||||
JT_Register *reg = new JT_Register(pa->client()->rootTask());
|
||||
connect(reg, SIGNAL(finished()), SLOT(finished()));
|
||||
Jid j = pa->userAccount().jid;
|
||||
reg->reg(j.user(), le_pwnew->text());
|
||||
reg->go(true);
|
||||
}
|
||||
|
||||
void ChangePasswordDlg::finished()
|
||||
{
|
||||
busy->stop();
|
||||
|
||||
JT_Register *reg = (JT_Register *)sender();
|
||||
QString err = reg->statusString();
|
||||
int code = reg->statusCode();
|
||||
bool ok = reg->success();
|
||||
if(ok) {
|
||||
UserAccount acc = pa->userAccount();
|
||||
acc.pass = le_pwnew->text();
|
||||
pa->setUserAccount(acc);
|
||||
AccountModifyDlg *amd = pa->findDialog<AccountModifyDlg*>();
|
||||
if(amd)
|
||||
amd->setPassword(acc.pass);
|
||||
|
||||
QMessageBox::information(this, tr("Success"), tr("Successfully changed password."));
|
||||
close();
|
||||
}
|
||||
else {
|
||||
// ignore task disconnect error
|
||||
if(code == Task::ErrDisc)
|
||||
return;
|
||||
|
||||
QMessageBox::critical(this, tr("Error"), QString(tr("There was an error when trying to set the password.\nReason: %1")).arg(QString(err).replace('\n', "<br>")));
|
||||
restoreWidgets();
|
||||
}
|
||||
}
|
||||
|
||||
void ChangePasswordDlg::disc()
|
||||
{
|
||||
busy->stop();
|
||||
close();
|
||||
}
|
||||
|
||||
void ChangePasswordDlg::blockWidgets()
|
||||
{
|
||||
setWidgetsEnabled(false);
|
||||
}
|
||||
|
||||
void ChangePasswordDlg::restoreWidgets()
|
||||
{
|
||||
setWidgetsEnabled(true);
|
||||
}
|
||||
|
||||
void ChangePasswordDlg::setWidgetsEnabled(bool enabled)
|
||||
{
|
||||
lb_pwcur->setEnabled(enabled);
|
||||
lb_pwnew->setEnabled(enabled);
|
||||
lb_pwver->setEnabled(enabled);
|
||||
le_pwcur->setEnabled(enabled);
|
||||
le_pwnew->setEnabled(enabled);
|
||||
le_pwver->setEnabled(enabled);
|
||||
pb_close->setEnabled(enabled);
|
||||
pb_apply->setEnabled(enabled);
|
||||
}
|
||||
54
src/changepwdlg.h
Normal file
54
src/changepwdlg.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* changepwdlg.h - dialog for changing password
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHANGEPWDLG_H
|
||||
#define CHANGEPWDLG_H
|
||||
|
||||
#include "ui_changepw.h"
|
||||
|
||||
class PsiAccount;
|
||||
|
||||
class ChangePasswordDlg : public QDialog, public Ui::ChangePassword
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ChangePasswordDlg(PsiAccount *, QWidget *parent=0);
|
||||
~ChangePasswordDlg();
|
||||
|
||||
protected:
|
||||
//void closeEvent(QCloseEvent *e);
|
||||
|
||||
public slots:
|
||||
void done(int);
|
||||
|
||||
private slots:
|
||||
void apply();
|
||||
void finished();
|
||||
void disc();
|
||||
|
||||
private:
|
||||
void blockWidgets();
|
||||
void restoreWidgets();
|
||||
void setWidgetsEnabled(bool enabled);
|
||||
|
||||
PsiAccount *pa;
|
||||
};
|
||||
|
||||
#endif
|
||||
1073
src/chatdlg.cpp
Normal file
1073
src/chatdlg.cpp
Normal file
File diff suppressed because it is too large
Load diff
187
src/chatdlg.h
Normal file
187
src/chatdlg.h
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* chatdlg.h - dialog for handling chats
|
||||
* Copyright (C) 2001-2007 Justin Karneges, Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHATDLG_H
|
||||
#define CHATDLG_H
|
||||
|
||||
#include "chatdlgbase.h"
|
||||
|
||||
#include "xmpp_receipts.h"
|
||||
#include "xmpp_yadatetime.h"
|
||||
|
||||
namespace XMPP
|
||||
{
|
||||
class Jid;
|
||||
class Message;
|
||||
}
|
||||
using namespace XMPP;
|
||||
|
||||
class PsiAccount;
|
||||
class UserListItem;
|
||||
class QDropEvent;
|
||||
class QDragEnterEvent;
|
||||
|
||||
class ChatDlg : public ChatDlgBase
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
ChatDlg(const Jid& jid, PsiAccount* account, TabManager* tabManager);
|
||||
virtual void init();
|
||||
|
||||
public:
|
||||
static ChatDlg* create(const Jid& jid, PsiAccount* account, TabManager* tabManager);
|
||||
~ChatDlg();
|
||||
|
||||
// reimplemented
|
||||
void setJid(const Jid &);
|
||||
QString getDisplayName() const;
|
||||
|
||||
static QSize defaultSize();
|
||||
bool readyToHide();
|
||||
|
||||
// reimplemented
|
||||
virtual TabbableWidget::State state() const;
|
||||
virtual QString desiredCaption() const;
|
||||
virtual void invalidateTab();
|
||||
|
||||
virtual void receivedPendingMessage();
|
||||
|
||||
signals:
|
||||
void aInfo(const Jid &);
|
||||
void aHistory(const Jid &);
|
||||
void aVoice(const Jid &);
|
||||
void messagesRead(const Jid &);
|
||||
void aSend(const Message &);
|
||||
void aFile(const Jid &);
|
||||
|
||||
/**
|
||||
* Signals if user (re)started/stopped composing
|
||||
*/
|
||||
void composing(bool);
|
||||
|
||||
protected:
|
||||
// reimplemented
|
||||
void closeEvent(QCloseEvent *);
|
||||
void resizeEvent(QResizeEvent *);
|
||||
void hideEvent(QHideEvent *);
|
||||
void showEvent(QShowEvent *);
|
||||
void windowActivationChange(bool);
|
||||
virtual void dropEvent(QDropEvent* event);
|
||||
void dragEnterEvent(QDragEnterEvent* event);
|
||||
|
||||
public slots:
|
||||
// reimplemented
|
||||
virtual void deactivated();
|
||||
virtual void activated();
|
||||
virtual void optionsUpdate();
|
||||
|
||||
virtual void updateContact(const Jid &, bool);
|
||||
void incomingMessage(const Message &);
|
||||
virtual void updateAvatar() = 0;
|
||||
void updateAvatar(const Jid&);
|
||||
|
||||
protected slots:
|
||||
void doInfo();
|
||||
virtual void doHistory();
|
||||
virtual bool doSend();
|
||||
void sendMessage(XMPP::Message m, bool userAction);
|
||||
void doVoice();
|
||||
void doFile();
|
||||
|
||||
private slots:
|
||||
void setKeepOpenFalse();
|
||||
void setWarnSendFalse();
|
||||
virtual void updatePGP();
|
||||
virtual void setPGPEnabled(bool enabled);
|
||||
void encryptedMessageSent(int, bool, int);
|
||||
void slotScroll();
|
||||
void setChatState(XMPP::ChatState s);
|
||||
void updateIsComposing(bool);
|
||||
void setContactChatState(ChatState s);
|
||||
void capsChanged(const Jid&);
|
||||
void setComposing();
|
||||
|
||||
protected slots:
|
||||
void checkComposing();
|
||||
virtual void setLooks();
|
||||
|
||||
// reimplemented
|
||||
virtual void chatEditCreated();
|
||||
|
||||
protected:
|
||||
// reimplemented
|
||||
virtual void doSendMessage(const XMPP::Message& m);
|
||||
|
||||
void resetComposing();
|
||||
virtual void doneSend(const XMPP::Message& m);
|
||||
void setSelfDestruct(int);
|
||||
void deferredScroll();
|
||||
bool isEmoteText(const QString& text);
|
||||
bool isEmoteMessage(const XMPP::Message& m);
|
||||
QString messageText(const QString& text, bool isEmote, bool isHtml = false);
|
||||
QString messageText(const XMPP::Message& m);
|
||||
|
||||
virtual void capsChanged();
|
||||
virtual void contactUpdated(UserListItem* u, int status, const QString& statusString);
|
||||
virtual QString colorString(bool local, SpooledType spooled) const = 0;
|
||||
|
||||
void appendMessage(const Message &, bool local = false);
|
||||
virtual bool isEncryptionEnabled() const;
|
||||
virtual void appendSysMsg(const QString& txt) = 0;
|
||||
#ifndef YAPSI
|
||||
virtual void appendEmoteMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt) = 0;
|
||||
virtual void appendNormalMessage(SpooledType spooled, const QDateTime& time, bool local, QString txt) = 0;
|
||||
#else
|
||||
virtual void appendEmoteMessage(SpooledType spooled, const QDateTime& time, bool local, int spamFlag, QString id, XMPP::MessageReceipt messageReceipt, QString txt, const XMPP::YaDateTime& yaTime, int yaFlags) = 0;
|
||||
virtual void appendNormalMessage(SpooledType spooled, const QDateTime& time, bool local, int spamFlag, QString id, XMPP::MessageReceipt messageReceipt, QString txt, const XMPP::YaDateTime& yaTime, int yaFlags) = 0;
|
||||
#endif
|
||||
virtual void appendMessageFields(const Message& m) = 0;
|
||||
virtual void nicksChanged();
|
||||
|
||||
QString whoNick(bool local) const;
|
||||
|
||||
bool canChatState() const;
|
||||
|
||||
private:
|
||||
QString dispNick_;
|
||||
int status_;
|
||||
QString statusString_;
|
||||
|
||||
bool keepOpen_;
|
||||
bool warnSend_;
|
||||
|
||||
QTimer* selfDestruct_;
|
||||
|
||||
QString key_;
|
||||
int transid_;
|
||||
Message m_;
|
||||
bool lastMessageUserAction_;
|
||||
bool lastWasEncrypted_;
|
||||
|
||||
// Message Events & Chat States
|
||||
QTimer* composingTimer_;
|
||||
bool isComposing_;
|
||||
bool sendComposingEvents_;
|
||||
QString eventId_;
|
||||
ChatState contactChatState_;
|
||||
ChatState lastChatState_;
|
||||
};
|
||||
|
||||
#endif
|
||||
325
src/chatdlg.ui
Normal file
325
src/chatdlg.ui
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
<ui version="4.0" >
|
||||
<class>ChatDlg</class>
|
||||
<widget class="QWidget" name="ChatDlg" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ChatSplitter" name="splitter" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QFrame" name="topFrame" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>3</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="IconLabel" name="lb_status" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_jid" >
|
||||
<property name="focusPolicy" >
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lb_count" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>0</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>Message length</string>
|
||||
</property>
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AccountLabel" name="lb_ident" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>1</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>AccountLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tb_pgp" >
|
||||
<property name="toolTip" >
|
||||
<string>Toggle encryption</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tb_emoticons" >
|
||||
<property name="toolTip" >
|
||||
<string>Select icon</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="popupMode" >
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tb_actions" >
|
||||
<property name="toolTip" >
|
||||
<string>Actions</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize" >
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="popupMode" >
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
<property name="arrowType" >
|
||||
<enum>Qt::DownArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ChatView" name="log" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>3</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy" >
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QFrame" name="bottomFrame" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>4</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolBar" name="toolbar" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>4</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ChatEditProxy" name="mle" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="avatar" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>4</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Avatar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ChatView</class>
|
||||
<extends>QTextEdit</extends>
|
||||
<header>msgmle.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ChatSplitter</class>
|
||||
<extends>QSplitter</extends>
|
||||
<header>chatsplitter.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ChatEditProxy</class>
|
||||
<extends>QTextEdit</extends>
|
||||
<header>chateditproxy.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AccountLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>accountlabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>IconLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>iconlabel.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
405
src/chatdlgbase.cpp
Normal file
405
src/chatdlgbase.cpp
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* chatdlgbase.cpp
|
||||
* Copyright (C) 2010 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "chatdlgbase.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "psiaccount.h"
|
||||
#include "psicon.h"
|
||||
#include "yachatviewmodel.h"
|
||||
#include "yachatdlgshared.h"
|
||||
#include "psioptions.h"
|
||||
#include "yachatview.h"
|
||||
#include "msgmle.h"
|
||||
#include "shortcutmanager.h"
|
||||
#include "xmpp_xmlcommon.h"
|
||||
#include "fileutil.h"
|
||||
#ifdef YAPSI
|
||||
#include "yadayuse.h"
|
||||
#endif
|
||||
|
||||
static const QString textColorOptionPath = "options.ya.chat-window.text-color";
|
||||
|
||||
ChatDlgBase::ChatDlgBase(const Jid& jid, PsiAccount* acc, TabManager* tabManager)
|
||||
: TabbableWidget(jid, acc, tabManager)
|
||||
, highlightersInstalled_(false)
|
||||
#ifdef YAPSI
|
||||
, model_(0)
|
||||
#endif
|
||||
, pending_(0)
|
||||
{
|
||||
#ifdef YAPSI
|
||||
model_ = new YaChatViewModel(account()->deliveryConfirmationManager(), account()->psi()->yaNarodDiskManager());
|
||||
|
||||
connect(model_, SIGNAL(uploadFinished(const QString&, const QString&, qint64)), SLOT(uploadFinished(const QString&, const QString&, qint64)));
|
||||
connect(YaChatDlgShared::instance(account()->psi()), SIGNAL(uploadFile()), SLOT(uploadFile()));
|
||||
connect(YaChatDlgShared::instance(account()->psi()), SIGNAL(uploadRecentFile(const QString&, const QString&, qint64)), SLOT(uploadRecentFile(const QString&, const QString&, qint64)));
|
||||
|
||||
connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionChanged(const QString&)));
|
||||
connect(account(), SIGNAL(updatedActivity()), SLOT(updateModelNotices()));
|
||||
connect(account(), SIGNAL(enabledChanged()), SLOT(updateModelNotices()));
|
||||
QTimer::singleShot(0, this, SLOT(updateModelNotices()));
|
||||
#endif
|
||||
}
|
||||
|
||||
ChatDlgBase::~ChatDlgBase()
|
||||
{
|
||||
account()->dialogUnregister(this);
|
||||
delete model_;
|
||||
}
|
||||
|
||||
void ChatDlgBase::init()
|
||||
{
|
||||
initActions();
|
||||
setShortcuts();
|
||||
initUi();
|
||||
setLooks();
|
||||
|
||||
connect(account(), SIGNAL(updatedActivity()), SLOT(updateSendAction()));
|
||||
connect(account(), SIGNAL(enabledChanged()), SLOT(updateSendAction()));
|
||||
updateSendAction();
|
||||
|
||||
// SyntaxHighlighters modify the QTextEdit in a QTimer::singleShot(0, ...) call
|
||||
// so we need to install our hooks after it fired for the first time
|
||||
QTimer::singleShot(10, this, SLOT(initComposing()));
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
chatView()->setFocusPolicy(Qt::NoFocus);
|
||||
chatEdit()->setFocus();
|
||||
|
||||
account()->dialogRegister(this, jid());
|
||||
}
|
||||
|
||||
QAction* ChatDlgBase::actionSend() const
|
||||
{
|
||||
return act_send_;
|
||||
}
|
||||
|
||||
void ChatDlgBase::initActions()
|
||||
{
|
||||
act_send_ = new QAction(tr("Send"), this);
|
||||
addAction(act_send_);
|
||||
connect(act_send_, SIGNAL(activated()), SLOT(doSend()));
|
||||
|
||||
act_close_ = new QAction(this);
|
||||
addAction(act_close_);
|
||||
connect(act_close_, SIGNAL(activated()), SLOT(close()));
|
||||
|
||||
act_scrollup_ = new QAction(this);
|
||||
addAction(act_scrollup_);
|
||||
connect(act_scrollup_, SIGNAL(activated()), SLOT(scrollUp()));
|
||||
|
||||
act_scrolldown_ = new QAction(this);
|
||||
addAction(act_scrolldown_);
|
||||
connect(act_scrolldown_, SIGNAL(activated()), SLOT(scrollDown()));
|
||||
}
|
||||
|
||||
void ChatDlgBase::setShortcuts()
|
||||
{
|
||||
//act_send_->setShortcuts(ShortcutManager::instance()->shortcuts("chat.send"));
|
||||
act_scrollup_->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-up"));
|
||||
act_scrolldown_->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-down"));
|
||||
|
||||
//if(!option.useTabs) {
|
||||
// act_close_->setShortcuts(ShortcutManager::instance()->shortcuts("common.close"));
|
||||
//}
|
||||
}
|
||||
|
||||
bool ChatDlgBase::doSend()
|
||||
{
|
||||
if (!act_send_->isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chatEdit()->text().trimmed().isEmpty()) {
|
||||
chatEdit()->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chatEdit()->text() == "/clear") {
|
||||
chatEdit()->clear();
|
||||
doClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChatDlgBase::scrollUp()
|
||||
{
|
||||
chatView()->verticalScrollBar()->setValue(chatView()->verticalScrollBar()->value() - chatView()->verticalScrollBar()->pageStep() / 2);
|
||||
}
|
||||
|
||||
void ChatDlgBase::scrollDown()
|
||||
{
|
||||
chatView()->verticalScrollBar()->setValue(chatView()->verticalScrollBar()->value() + chatView()->verticalScrollBar()->pageStep() / 2);
|
||||
}
|
||||
|
||||
bool ChatDlgBase::couldSendMessages() const
|
||||
{
|
||||
return chatEdit()->isEnabled() &&
|
||||
!chatEdit()->text().trimmed().isEmpty() &&
|
||||
account()->isAvailable();
|
||||
}
|
||||
|
||||
void ChatDlgBase::updateSendAction()
|
||||
{
|
||||
#ifndef YAPSI
|
||||
act_send_->setEnabled(couldSendMessages());
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChatDlgBase::chatEditCreated()
|
||||
{
|
||||
chatView()->setDialog(this);
|
||||
chatEdit()->setDialog(this);
|
||||
chatEdit()->setSendAction(act_send_);
|
||||
chatEdit()->installEventFilter(this);
|
||||
disconnect(chatEdit(), SIGNAL(textChanged()), this, SLOT(updateSendAction()));
|
||||
connect(chatEdit(), SIGNAL(textChanged()), this, SLOT(updateSendAction()));
|
||||
|
||||
#ifdef YAPSI
|
||||
chatEdit()->setController(account()->psi());
|
||||
chatEdit()->setUploadFileAction(YaChatDlgShared::instance(account()->psi())->uploadFileAction());
|
||||
chatEdit()->setRecentFilesMenu(YaChatDlgShared::instance(account()->psi())->recentFilesMenu());
|
||||
chatEdit()->setTypographyAction(YaChatDlgShared::instance(account()->psi())->typographyAction());
|
||||
chatEdit()->setEmoticonsAction(YaChatDlgShared::instance(account()->psi())->emoticonsAction());
|
||||
chatEdit()->setCheckSpellingAction(YaChatDlgShared::instance(account()->psi())->checkSpellingAction());
|
||||
chatEdit()->setSendButtonEnabledAction(YaChatDlgShared::instance(account()->psi())->sendButtonEnabledAction());
|
||||
optionChanged(textColorOptionPath);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChatDlgBase::initComposing()
|
||||
{
|
||||
highlightersInstalled_ = true;
|
||||
chatEditCreated();
|
||||
}
|
||||
|
||||
bool ChatDlgBase::highlightersInstalled() const
|
||||
{
|
||||
return highlightersInstalled_;
|
||||
}
|
||||
|
||||
void ChatDlgBase::doClear()
|
||||
{
|
||||
#ifndef YAPSI
|
||||
chatView()->clear();
|
||||
#else
|
||||
model_->doClear();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChatDlgBase::optionChanged(const QString& option)
|
||||
{
|
||||
if (option == textColorOptionPath) {
|
||||
chatView()->setTextColor(PsiOptions::instance()->getOption(textColorOptionPath).value<QColor>());
|
||||
}
|
||||
}
|
||||
|
||||
void ChatDlgBase::updateModelNotices()
|
||||
{
|
||||
model_->setAccountIsOfflineNoticeVisible(!account()->isAvailable());
|
||||
model_->setAccountIsDisabledNoticeVisible(!account()->enabled());
|
||||
}
|
||||
|
||||
YaChatViewModel* ChatDlgBase::model() const
|
||||
{
|
||||
return model_;
|
||||
}
|
||||
|
||||
void ChatDlgBase::setLooks()
|
||||
{
|
||||
// update the font
|
||||
QFont f;
|
||||
f.fromString(option.font[fChat]);
|
||||
chatView()->setFont(f);
|
||||
chatEdit()->setFont(f);
|
||||
}
|
||||
|
||||
void ChatDlgBase::uploadFile()
|
||||
{
|
||||
if (!isActiveTab())
|
||||
return;
|
||||
|
||||
QStringList fileNames = FileUtil::getOpenAnyFileNames(this);
|
||||
if (!fileNames.isEmpty()) {
|
||||
uploadFiles(fileNames);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatDlgBase::uploadRecentFile(const QString& fileName, const QString& url, qint64 size)
|
||||
{
|
||||
if (!isActiveTab())
|
||||
return;
|
||||
|
||||
uploadFinished(fileName, url, size);
|
||||
}
|
||||
|
||||
void ChatDlgBase::uploadFile(const QString& fileName)
|
||||
{
|
||||
account()->psi()->yaNarodDiskManager()->uploadFile(fileName, this, "uploadFileStarted");
|
||||
}
|
||||
|
||||
void ChatDlgBase::uploadFileStarted(const QString& id)
|
||||
{
|
||||
if (id.isEmpty())
|
||||
return;
|
||||
|
||||
// QMap<QString, YaNarodDiskManager::RecentFile> files = account()->psi()->yaNarodDiskManager()->recentFiles();
|
||||
// if (files.contains(id)) {
|
||||
// uploadFinished(files[id].fileName, files[id].url, files[id].size);
|
||||
// }
|
||||
// else {
|
||||
model()->addFileUpload(id);
|
||||
// }
|
||||
}
|
||||
|
||||
void ChatDlgBase::uploadFiles(const QStringList& fileNames)
|
||||
{
|
||||
foreach(const QString& fileName, fileNames) {
|
||||
uploadFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatDlgBase::uploadFinished(const QString& fileName, const QString& url, qint64 size)
|
||||
{
|
||||
#ifdef YAPSI
|
||||
YaDayUse::instance(account()->psi())->stat(135, 70521);
|
||||
#endif
|
||||
|
||||
QDomDocument doc;
|
||||
QDomElement body = doc.createElementNS("http://www.w3.org/1999/xhtml", "body");
|
||||
doc.appendChild(body);
|
||||
QDomElement html = textTag(&doc, "a", YaNarodDiskManager::humanReadableName(fileName, size));
|
||||
html.setAttribute("href", url);
|
||||
body.appendChild(html);
|
||||
|
||||
Message m(jid());
|
||||
m.setType("chat");
|
||||
m.setHTML(body);
|
||||
m.setBody(QString("%1 (%2)")
|
||||
.arg(url)
|
||||
.arg(YaNarodDiskManager::humanReadableSize(size)));
|
||||
doSendMessage(m);
|
||||
}
|
||||
|
||||
void ChatDlgBase::addEmoticon(QString text)
|
||||
{
|
||||
if (!isActiveTab())
|
||||
return;
|
||||
|
||||
chatEdit()->insert(text + " ");
|
||||
}
|
||||
|
||||
|
||||
// FIXME: This should be unnecessary, since these keys are all registered as
|
||||
// actions in the constructor. Somehow, Qt ignores this sometimes (i think
|
||||
// just for actions that have no modifier).
|
||||
void ChatDlgBase::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
QKeySequence key = e->key() + (e->modifiers() & ~Qt::KeypadModifier);
|
||||
if (!option.useTabs && ShortcutManager::instance()->shortcuts("common.close").contains(key)) {
|
||||
close();
|
||||
}
|
||||
else if (ShortcutManager::instance()->shortcuts("chat.send").contains(key)) {
|
||||
doSend();
|
||||
}
|
||||
else if (ShortcutManager::instance()->shortcuts("common.scroll-up").contains(key)) {
|
||||
scrollUp();
|
||||
}
|
||||
else if (ShortcutManager::instance()->shortcuts("common.scroll-down").contains(key)) {
|
||||
scrollDown();
|
||||
}
|
||||
else if (key.toString(QKeySequence::PortableText).contains("Enter") ||
|
||||
key.toString(QKeySequence::PortableText).contains("Return"))
|
||||
{
|
||||
chatEdit()->insert("\n");
|
||||
}
|
||||
else {
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatDlgBase::activated()
|
||||
{
|
||||
doFlash(false);
|
||||
chatEdit()->setFocus();
|
||||
|
||||
if (unreadMessageCount() > 0) {
|
||||
setUnreadMessageCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatDlgBase::desiredCaption() const
|
||||
{
|
||||
QString cap = "";
|
||||
|
||||
if (unreadMessageCount() > 0) {
|
||||
cap += "* ";
|
||||
if (unreadMessageCount() > 1) {
|
||||
cap += QString("[%1] ").arg(unreadMessageCount());
|
||||
}
|
||||
}
|
||||
cap += getDisplayName();
|
||||
return cap;
|
||||
}
|
||||
|
||||
int ChatDlgBase::unreadMessageCount() const
|
||||
{
|
||||
return pending_;
|
||||
}
|
||||
|
||||
void ChatDlgBase::setUnreadMessageCount(int pending)
|
||||
{
|
||||
if (pending_ != pending) {
|
||||
pending_ = pending;
|
||||
invalidateTab();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatDlgBase::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
keyPressEvent(static_cast<QKeyEvent*>(event));
|
||||
if (event->isAccepted())
|
||||
return true;
|
||||
}
|
||||
|
||||
if (chatView()->handleCopyEvent(obj, event, chatEdit()))
|
||||
return true;
|
||||
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void ChatDlgBase::optionsUpdate()
|
||||
{
|
||||
setLooks();
|
||||
setShortcuts();
|
||||
}
|
||||
|
||||
void ChatDlgBase::showEvent(QShowEvent* e)
|
||||
{
|
||||
optionsUpdate();
|
||||
TabbableWidget::showEvent(e);
|
||||
}
|
||||
122
src/chatdlgbase.h
Normal file
122
src/chatdlgbase.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* chatdlgbase.h
|
||||
* Copyright (C) 2010 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHATDLGBASE_H
|
||||
#define CHATDLGBASE_H
|
||||
|
||||
#include "tabbablewidget.h"
|
||||
|
||||
#ifdef YAPSI
|
||||
class YaChatView;
|
||||
typedef YaChatView ChatViewClass;
|
||||
#else
|
||||
class ChatView;
|
||||
typedef ChatView ChatViewClass;
|
||||
#endif
|
||||
class ChatEdit;
|
||||
class YaChatViewModel;
|
||||
|
||||
class ChatDlgBase : public TabbableWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
ChatDlgBase(const Jid& jid, PsiAccount* account, TabManager* tabManager);
|
||||
virtual void init();
|
||||
|
||||
public:
|
||||
~ChatDlgBase();
|
||||
|
||||
void uploadFile(const QString& fileName);
|
||||
void uploadFiles(const QStringList& fileNames);
|
||||
|
||||
// reimplemented
|
||||
virtual QString desiredCaption() const;
|
||||
int unreadMessageCount() const;
|
||||
void setUnreadMessageCount(int pending);
|
||||
|
||||
enum SpooledType {
|
||||
Spooled_None,
|
||||
Spooled_OfflineStorage,
|
||||
Spooled_History,
|
||||
|
||||
Spooled_Sync
|
||||
};
|
||||
|
||||
public slots:
|
||||
virtual void doClear();
|
||||
virtual void optionsUpdate();
|
||||
|
||||
// reimplemented
|
||||
virtual void activated();
|
||||
|
||||
protected slots:
|
||||
virtual bool doSend();
|
||||
void scrollUp();
|
||||
void scrollDown();
|
||||
void updateSendAction();
|
||||
virtual void chatEditCreated();
|
||||
virtual void optionChanged(const QString& option);
|
||||
virtual void updateModelNotices();
|
||||
|
||||
private slots:
|
||||
void initComposing();
|
||||
void addEmoticon(QString text);
|
||||
|
||||
void uploadFile();
|
||||
void uploadRecentFile(const QString& fileName, const QString& url, qint64 size);
|
||||
void uploadFinished(const QString& fileName, const QString& url, qint64 size);
|
||||
|
||||
void uploadFileStarted(const QString& id);
|
||||
|
||||
protected:
|
||||
// reimplemented
|
||||
void keyPressEvent(QKeyEvent *);
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
void showEvent(QShowEvent*);
|
||||
|
||||
virtual void setShortcuts();
|
||||
virtual void initUi() = 0;
|
||||
virtual void doSendMessage(const XMPP::Message& m) = 0;
|
||||
virtual ChatViewClass* chatView() const = 0;
|
||||
virtual ChatEdit* chatEdit() const = 0;
|
||||
#ifdef YAPSI
|
||||
virtual YaChatViewModel* model() const;
|
||||
#endif
|
||||
virtual void setLooks();
|
||||
|
||||
QAction* actionSend() const;
|
||||
virtual bool couldSendMessages() const;
|
||||
bool highlightersInstalled() const;
|
||||
|
||||
private:
|
||||
bool highlightersInstalled_;
|
||||
#ifdef YAPSI
|
||||
YaChatViewModel* model_;
|
||||
#endif
|
||||
|
||||
void initActions();
|
||||
QAction* act_send_;
|
||||
QAction* act_scrollup_;
|
||||
QAction* act_scrolldown_;
|
||||
QAction* act_close_;
|
||||
int pending_;
|
||||
};
|
||||
|
||||
#endif
|
||||
122
src/chateditproxy.cpp
Normal file
122
src/chateditproxy.cpp
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* chateditproxy.cpp - abstraction to change ChatEdit type in runtime
|
||||
* Copyright (C) 2007 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "chateditproxy.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "msgmle.h"
|
||||
#include "psioptions.h"
|
||||
#include "common.h"
|
||||
|
||||
ChatEditProxy::ChatEditProxy(QWidget* parent)
|
||||
: QFrame(parent)
|
||||
, lineEditEnabled_(false)
|
||||
, textEdit_(0)
|
||||
, layout_(0)
|
||||
{
|
||||
layout_ = new QVBoxLayout(this);
|
||||
layout_->setMargin(0);
|
||||
layout_->setSpacing(0);
|
||||
|
||||
connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionsChanged()));
|
||||
optionsChanged();
|
||||
|
||||
if (!textEdit_)
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* If \a enable is true, then the LineEdit is used as internal
|
||||
* QTextEdit. Updates internal layout if necessary.
|
||||
*/
|
||||
void ChatEditProxy::setLineEditEnabled(bool enable)
|
||||
{
|
||||
if (lineEditEnabled_ == enable)
|
||||
return;
|
||||
|
||||
lineEditEnabled_ = enable;
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new QTextEdit basing on ChatEditProxy's properties.
|
||||
*/
|
||||
ChatEdit* ChatEditProxy::createTextEdit()
|
||||
{
|
||||
if (lineEditEnabled())
|
||||
return new LineEdit(this);
|
||||
return new ChatEdit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the QTextDocument and QTextCursor data from \a oldTextEdit
|
||||
* to \a newTextEdit.
|
||||
*
|
||||
* NB: Make sure that all QSyntaxHighlighters are detached prior to calling
|
||||
* this function.
|
||||
*/
|
||||
void ChatEditProxy::moveData(QTextEdit* newTextEdit, QTextEdit* oldTextEdit) const
|
||||
{
|
||||
QTextDocument* doc = oldTextEdit->document();
|
||||
QTextCursor cursor = oldTextEdit->textCursor();
|
||||
|
||||
doc->setParent(newTextEdit);
|
||||
oldTextEdit->setDocument(0);
|
||||
|
||||
newTextEdit->setDocument(doc);
|
||||
newTextEdit->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new QTextEdit and moves data to it from the old one.
|
||||
* Text, selection and cursor position are left intact.
|
||||
*/
|
||||
void ChatEditProxy::updateLayout()
|
||||
{
|
||||
ChatEdit* newEdit = createTextEdit();
|
||||
newEdit->setFrameShape(frameShape());
|
||||
|
||||
if (textEdit_) {
|
||||
// all syntaxhighlighters should be removed while we move
|
||||
// the documents around, and should be reattached afterwards
|
||||
textEdit_->setCheckSpelling(false);
|
||||
newEdit->setCheckSpelling(false);
|
||||
|
||||
moveData(newEdit, textEdit_);
|
||||
|
||||
newEdit->setCheckSpelling(PsiOptions::instance()->getOption("options.ui.spell-check.enabled").toBool());
|
||||
}
|
||||
|
||||
delete textEdit_;
|
||||
textEdit_ = newEdit;
|
||||
layout_->addWidget(textEdit_);
|
||||
emit textEditCreated(textEdit_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ChatEdit widget according to current options.
|
||||
* FIXME: When option.chatLineEdit finally makes it to PsiOptions, make this slot
|
||||
* private.
|
||||
*/
|
||||
void ChatEditProxy::optionsChanged()
|
||||
{
|
||||
setLineEditEnabled(option.chatLineEdit);
|
||||
}
|
||||
68
src/chateditproxy.h
Normal file
68
src/chateditproxy.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* chateditproxy.h - abstraction to change ChatEdit type in runtime
|
||||
* Copyright (C) 2007 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHATEDITPROXY_H
|
||||
#define CHATEDITPROXY_H
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class QTextEdit;
|
||||
class QLayout;
|
||||
class ChatEdit;
|
||||
|
||||
class ChatEditProxy : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ChatEditProxy(QWidget* parent);
|
||||
|
||||
/**
|
||||
* Returns encapsulated QTextEdit widget.
|
||||
*/
|
||||
ChatEdit* chatEdit() const { return textEdit_; }
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Emitted when internal QTextEdit gets replaced with
|
||||
* another one.
|
||||
*/
|
||||
void textEditCreated(QTextEdit* textEdit);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns true if line edit mode is enabled.
|
||||
*/
|
||||
bool lineEditEnabled() const { return lineEditEnabled_; }
|
||||
void setLineEditEnabled(bool enable);
|
||||
|
||||
public slots:
|
||||
void optionsChanged();
|
||||
|
||||
private:
|
||||
virtual ChatEdit* createTextEdit();
|
||||
void moveData(QTextEdit* newTextEdit, QTextEdit* oldTextEdit) const;
|
||||
void updateLayout();
|
||||
|
||||
bool lineEditEnabled_;
|
||||
ChatEdit* textEdit_;
|
||||
QLayout* layout_;
|
||||
};
|
||||
|
||||
#endif
|
||||
167
src/chatsplitter.cpp
Normal file
167
src/chatsplitter.cpp
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* chatsplitter.cpp - QSplitter replacement that masquerades it
|
||||
* Copyright (C) 2007 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "chatsplitter.h"
|
||||
|
||||
#include <QSplitter>
|
||||
#include <QVBoxLayout>
|
||||
#include <QChildEvent>
|
||||
|
||||
#include "psioptions.h"
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* Handy widget that masquerades itself as QSplitter, and could work
|
||||
* in both QSplitter mode, and QSplitter-less mode.
|
||||
*/
|
||||
ChatSplitter::ChatSplitter(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, splitterEnabled_(true)
|
||||
, childrenCollapsible_(true)
|
||||
, splitter_(0)
|
||||
, layout_(0)
|
||||
{
|
||||
connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), SLOT(optionsChanged()));
|
||||
optionsChanged();
|
||||
|
||||
if (!layout_)
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function to fool Qt Designer-generated forms.
|
||||
*/
|
||||
void ChatSplitter::setOrientation(Qt::Orientation orientation)
|
||||
{
|
||||
Q_ASSERT(orientation == Qt::Vertical);
|
||||
Q_UNUSED(orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if child widgets are collapsible in splitter mode.
|
||||
*/
|
||||
bool ChatSplitter::childrenCollapsible() const
|
||||
{
|
||||
return childrenCollapsible_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy function that passes its value to the real splitter.
|
||||
*/
|
||||
void ChatSplitter::setChildrenCollapsible(bool collapsible)
|
||||
{
|
||||
childrenCollapsible_ = collapsible;
|
||||
if (splitter_)
|
||||
splitter_->setChildrenCollapsible(childrenCollapsible_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given \a widget to the splitter's layout after all the
|
||||
* other items. Don't call this function if widget is already added
|
||||
* to the splitter's layout.
|
||||
*/
|
||||
void ChatSplitter::addWidget(QWidget* widget)
|
||||
{
|
||||
Q_ASSERT(!children_.contains(widget));
|
||||
children_ << widget;
|
||||
connect(widget, SIGNAL(destroyed(QObject*)), SLOT(childDestroyed(QObject*)));
|
||||
updateChildLayout(widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* If splitter mode is enabled, the \a list is passed to the
|
||||
* actual splitter. Has no effect otherwise.
|
||||
*/
|
||||
void ChatSplitter::setSizes(const QList<int>& list)
|
||||
{
|
||||
if (splitter_)
|
||||
splitter_->setSizes(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves \a child either to the real QSplitter, or adds it to the
|
||||
* private layout.
|
||||
*/
|
||||
void ChatSplitter::updateChildLayout(QWidget* child)
|
||||
{
|
||||
if (splitterEnabled() && splitter_) {
|
||||
splitter_->addWidget(child);
|
||||
}
|
||||
else {
|
||||
layout_->addWidget(child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes destroyed widget from the splitter's child list.
|
||||
*/
|
||||
void ChatSplitter::childDestroyed(QObject* obj)
|
||||
{
|
||||
Q_ASSERT(obj->isWidgetType());
|
||||
children_.removeAll(static_cast<QWidget*>(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* If \a enable is true, the true QSplitter gets enabled, otherwise
|
||||
* all widgets are managed by QLayout.
|
||||
*/
|
||||
void ChatSplitter::setSplitterEnabled(bool enable)
|
||||
{
|
||||
if (splitterEnabled_ == enable)
|
||||
return;
|
||||
|
||||
splitterEnabled_ = enable;
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates layout and moves all child widgets to the proper position.
|
||||
*/
|
||||
void ChatSplitter::updateLayout()
|
||||
{
|
||||
foreach(QWidget* child, children_)
|
||||
child->setParent(this);
|
||||
|
||||
delete splitter_;
|
||||
delete layout_;
|
||||
splitter_ = new QSplitter(this);
|
||||
splitter_->setChildrenCollapsible(childrenCollapsible_);
|
||||
layout_ = new QVBoxLayout(this);
|
||||
layout_->setMargin(0);
|
||||
#ifdef YAPSI
|
||||
layout_->setSpacing(0);
|
||||
#endif
|
||||
layout_->addWidget(splitter_);
|
||||
splitter_->setOrientation(Qt::Vertical);
|
||||
splitter_->setVisible(splitterEnabled());
|
||||
|
||||
foreach(QWidget* child, children_)
|
||||
updateChildLayout(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates layout according to current options.
|
||||
* FIXME: When option.chatLineEdit finally makes it to PsiOptions, make this slot
|
||||
* private.
|
||||
*/
|
||||
void ChatSplitter::optionsChanged()
|
||||
{
|
||||
setSplitterEnabled(!option.chatLineEdit);
|
||||
}
|
||||
66
src/chatsplitter.h
Normal file
66
src/chatsplitter.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* chatsplitter.h - QSplitter replacement that masquerades it
|
||||
* Copyright (C) 2007 Michail Pishchagin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHATSPLITTER_H
|
||||
#define CHATSPLITTER_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QList>
|
||||
|
||||
class QSplitter;
|
||||
|
||||
class ChatSplitter : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ChatSplitter(QWidget* parent);
|
||||
|
||||
void setOrientation(Qt::Orientation orientation);
|
||||
void addWidget(QWidget* widget);
|
||||
void setSizes(const QList<int>& list);
|
||||
|
||||
bool childrenCollapsible() const;
|
||||
void setChildrenCollapsible(bool collapsible);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns true if all child widgets are managed by QLayout.
|
||||
*/
|
||||
bool splitterEnabled() const { return splitterEnabled_; }
|
||||
void setSplitterEnabled(bool enable);
|
||||
|
||||
public slots:
|
||||
void optionsChanged();
|
||||
|
||||
private slots:
|
||||
void childDestroyed(QObject* obj);
|
||||
|
||||
private:
|
||||
void updateChildLayout(QWidget* child);
|
||||
void updateLayout();
|
||||
|
||||
bool splitterEnabled_;
|
||||
bool childrenCollapsible_;
|
||||
QList<QWidget*> children_;
|
||||
QSplitter* splitter_;
|
||||
QLayout* layout_;
|
||||
};
|
||||
|
||||
#endif
|
||||
486
src/common.cpp
Normal file
486
src/common.cpp
Normal file
|
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* common.cpp - contains all the common variables and functions for Psi
|
||||
* Copyright (C) 2001-2003 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QProcess>
|
||||
#include <QBoxLayout>
|
||||
#include <QRegExp>
|
||||
#include <QFile>
|
||||
#include <QApplication>
|
||||
#include <QSound>
|
||||
#include <QObject>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef Q_WS_X11
|
||||
#include <QX11Info>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <Carbon/Carbon.h> // for HIToolbox/InternetConfig
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#include "profiles.h"
|
||||
#include "rtparse.h"
|
||||
#include "psievent.h"
|
||||
#include "psiiconset.h"
|
||||
#include "applicationinfo.h"
|
||||
|
||||
#ifdef YAPSI
|
||||
#include "yavisualutil.h"
|
||||
#endif
|
||||
|
||||
Qt::WFlags psi_dialog_flags = (Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
|
||||
|
||||
Options option;
|
||||
bool useSound;
|
||||
|
||||
|
||||
QString CAP(const QString &str)
|
||||
{
|
||||
return QString("%1: %2").arg(ApplicationInfo::name()).arg(str);
|
||||
}
|
||||
|
||||
|
||||
// clips plain text
|
||||
QString clipStatus(const QString &str, int width, int height)
|
||||
{
|
||||
QString out = "";
|
||||
int at = 0;
|
||||
int len = str.length();
|
||||
if(len == 0)
|
||||
return out;
|
||||
|
||||
// only take the first "height" lines
|
||||
for(int n2 = 0; n2 < height; ++n2) {
|
||||
// only take the first "width" chars
|
||||
QString line;
|
||||
bool hasNewline = false;
|
||||
for(int n = 0; at < len; ++n, ++at) {
|
||||
if(str.at(at) == '\n') {
|
||||
hasNewline = true;
|
||||
break;
|
||||
}
|
||||
line += str.at(at);
|
||||
}
|
||||
++at;
|
||||
if((int)line.length() > width) {
|
||||
line.truncate(width-3);
|
||||
line += "...";
|
||||
}
|
||||
out += line;
|
||||
if(hasNewline)
|
||||
out += '\n';
|
||||
|
||||
if(at >= len)
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QString encodePassword(const QString &pass, const QString &key)
|
||||
{
|
||||
QString result;
|
||||
int n1, n2;
|
||||
|
||||
if(key.length() == 0)
|
||||
return pass;
|
||||
|
||||
for(n1 = 0, n2 = 0; n1 < pass.length(); ++n1) {
|
||||
ushort x = pass.at(n1).unicode() ^ key.at(n2++).unicode();
|
||||
QString hex;
|
||||
hex.sprintf("%04x", x);
|
||||
result += hex;
|
||||
if(n2 >= key.length())
|
||||
n2 = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString decodePassword(const QString &pass, const QString &key)
|
||||
{
|
||||
QString result;
|
||||
int n1, n2;
|
||||
|
||||
if(key.length() == 0)
|
||||
return pass;
|
||||
|
||||
for(n1 = 0, n2 = 0; n1 < pass.length(); n1 += 4) {
|
||||
ushort x = 0;
|
||||
if(n1 + 4 > pass.length())
|
||||
break;
|
||||
x += QString(pass.at(n1)).toInt(NULL,16)*4096;
|
||||
x += QString(pass.at(n1+1)).toInt(NULL,16)*256;
|
||||
x += QString(pass.at(n1+2)).toInt(NULL,16)*16;
|
||||
x += QString(pass.at(n1+3)).toInt(NULL,16);
|
||||
QChar c(x ^ key.at(n2++).unicode());
|
||||
result += c;
|
||||
if(n2 >= key.length())
|
||||
n2 = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString status2txt(int status)
|
||||
{
|
||||
switch(status) {
|
||||
case STATUS_OFFLINE: return QObject::tr("Offline");
|
||||
case STATUS_AWAY: return QObject::tr("Away");
|
||||
case STATUS_XA: return QObject::tr("Not Available");
|
||||
case STATUS_DND: return QObject::tr("Do not Disturb");
|
||||
case STATUS_CHAT: return QObject::tr("Free for Chat");
|
||||
case STATUS_INVISIBLE: return QObject::tr("Invisible");
|
||||
|
||||
case STATUS_ONLINE:
|
||||
default: return QObject::tr("Online");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString logencode(QString str)
|
||||
{
|
||||
str.replace(QRegExp("\\\\"), "\\\\"); // backslash to double-backslash
|
||||
str.replace(QRegExp("\\|"), "\\p"); // pipe to \p
|
||||
str.replace(QRegExp("\n"), "\\n"); // newline to \n
|
||||
return str;
|
||||
}
|
||||
|
||||
QString logdecode(const QString &str)
|
||||
{
|
||||
QString ret;
|
||||
|
||||
for(int n = 0; n < str.length(); ++n) {
|
||||
if(str.at(n) == '\\') {
|
||||
++n;
|
||||
if(n >= str.length())
|
||||
break;
|
||||
|
||||
if(str.at(n) == 'n')
|
||||
ret.append('\n');
|
||||
if(str.at(n) == 'p')
|
||||
ret.append('|');
|
||||
if(str.at(n) == '\\')
|
||||
ret.append('\\');
|
||||
}
|
||||
else {
|
||||
ret.append(str.at(n));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool fileCopy(const QString &src, const QString &dest)
|
||||
{
|
||||
QFile in(src);
|
||||
QFile out(dest);
|
||||
|
||||
if(!in.open(QIODevice::ReadOnly))
|
||||
return FALSE;
|
||||
if(!out.open(QIODevice::WriteOnly))
|
||||
return FALSE;
|
||||
|
||||
char *dat = new char[16384];
|
||||
int n = 0;
|
||||
while(!in.atEnd()) {
|
||||
n = in.readBlock(dat, 16384);
|
||||
if(n == -1) {
|
||||
delete dat;
|
||||
return FALSE;
|
||||
}
|
||||
out.writeBlock(dat, n);
|
||||
}
|
||||
delete dat;
|
||||
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void soundPlay(const QString &str)
|
||||
{
|
||||
if(str == "!beep") {
|
||||
QApplication::beep();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!QFile::exists(str))
|
||||
return;
|
||||
|
||||
#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
|
||||
QSound::play(str);
|
||||
#else
|
||||
if(!option.player.isEmpty()) {
|
||||
QStringList args;
|
||||
args = QStringList::split(' ', option.player);
|
||||
args += str;
|
||||
QString prog = args.takeFirst();
|
||||
QProcess::startDetached(prog, args);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
XMPP::Status makeStatus(int x, const QString &str, int priority)
|
||||
{
|
||||
XMPP::Status s = makeStatus(x,str);
|
||||
if (priority > 127)
|
||||
s.setPriority(127);
|
||||
else if (priority < -128)
|
||||
s.setPriority(-128);
|
||||
else
|
||||
s.setPriority(priority);
|
||||
return s;
|
||||
}
|
||||
|
||||
XMPP::Status makeStatus(int x, const QString &str)
|
||||
{
|
||||
return XMPP::Status(static_cast<XMPP::Status::Type>(x), str);
|
||||
}
|
||||
|
||||
XMPP::Status::Type makeSTATUS(const XMPP::Status &s)
|
||||
{
|
||||
return s.type();
|
||||
}
|
||||
|
||||
#include <qlayout.h>
|
||||
QLayout *rw_recurseFindLayout(QLayout *lo, QWidget *w)
|
||||
{
|
||||
//printf("scanning layout: %p\n", lo);
|
||||
QLayoutIterator it = lo->iterator();
|
||||
for(QLayoutItem *i; (i = it.current()); ++it) {
|
||||
//printf("found: %p,%p\n", i->layout(), i->widget());
|
||||
QLayout *slo = i->layout();
|
||||
if(slo) {
|
||||
QLayout *tlo = rw_recurseFindLayout(slo, w);
|
||||
if(tlo)
|
||||
return tlo;
|
||||
}
|
||||
else if(i->widget() == w)
|
||||
return lo;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QLayout *rw_findLayoutOf(QWidget *w)
|
||||
{
|
||||
return rw_recurseFindLayout(w->parentWidget()->layout(), w);
|
||||
}
|
||||
|
||||
void replaceWidget(QWidget *a, QWidget *b)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
|
||||
QLayout *lo = rw_findLayoutOf(a);
|
||||
if(!lo)
|
||||
return;
|
||||
//printf("decided on this: %p\n", lo);
|
||||
|
||||
if(lo->inherits("QBoxLayout")) {
|
||||
QBoxLayout *bo = (QBoxLayout *)lo;
|
||||
int n = bo->findWidget(a);
|
||||
bo->insertWidget(n+1, b);
|
||||
delete a;
|
||||
}
|
||||
}
|
||||
|
||||
void closeDialogs(QWidget *w)
|
||||
{
|
||||
// close qmessagebox?
|
||||
QList<QDialog*> dialogs;
|
||||
QObjectList list = w->children();
|
||||
for(QObjectList::Iterator it = list.begin() ; it != list.end(); ++it) {
|
||||
if((*it)->inherits("QDialog"))
|
||||
dialogs.append((QDialog *)(*it));
|
||||
}
|
||||
for(QList<QDialog*>::Iterator w = dialogs.begin(); w != dialogs.end(); ++w) {
|
||||
(*w)->close();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h> // needed for WM_CLASS hinting
|
||||
|
||||
void x11wmClass(Display *dsp, WId wid, QString resName)
|
||||
{
|
||||
char app_name[] = "yachat";
|
||||
|
||||
//Display *dsp = x11Display(); // get the display
|
||||
//WId win = winId(); // get the window
|
||||
XClassHint classhint; // class hints
|
||||
classhint.res_name = (char *)resName.latin1(); // res_name
|
||||
classhint.res_class = app_name; // res_class
|
||||
XSetClassHint(dsp, wid, &classhint); // set the class hints
|
||||
}
|
||||
|
||||
//>>>-- Nathaniel Gray -- Caltech Computer Science ------>
|
||||
//>>>-- Mojave Project -- http://mojave.cs.caltech.edu -->
|
||||
// Copied from http://www.nedit.org/archives/discuss/2002-Aug/0386.html
|
||||
|
||||
// Helper function
|
||||
bool getCardinal32Prop(Display *display, Window win, char *propName, long *value)
|
||||
{
|
||||
Atom nameAtom, typeAtom, actual_type_return;
|
||||
int actual_format_return, result;
|
||||
unsigned long nitems_return, bytes_after_return;
|
||||
long *result_array=NULL;
|
||||
|
||||
nameAtom = XInternAtom(display, propName, False);
|
||||
typeAtom = XInternAtom(display, "CARDINAL", False);
|
||||
if (nameAtom == None || typeAtom == None) {
|
||||
//qDebug("Atoms not interned!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Try to get the property
|
||||
result = XGetWindowProperty(display, win, nameAtom, 0, 1, False,
|
||||
typeAtom, &actual_type_return, &actual_format_return,
|
||||
&nitems_return, &bytes_after_return,
|
||||
(unsigned char **)&result_array);
|
||||
|
||||
if( result != Success ) {
|
||||
//qDebug("not Success");
|
||||
return false;
|
||||
}
|
||||
if( actual_type_return == None || actual_format_return == 0 ) {
|
||||
//qDebug("Prop not found");
|
||||
return false;
|
||||
}
|
||||
if( actual_type_return != typeAtom ) {
|
||||
//qDebug("Wrong type atom");
|
||||
}
|
||||
*value = result_array[0];
|
||||
XFree(result_array);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Get the desktop number that a window is on
|
||||
bool desktopOfWindow(Window *window, long *desktop)
|
||||
{
|
||||
Display *display = QX11Info::display();
|
||||
bool result = getCardinal32Prop(display, *window, (char *)"_NET_WM_DESKTOP", desktop);
|
||||
//if( result )
|
||||
// qDebug("Desktop: " + QString::number(*desktop));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Get the current desktop the WM is displaying
|
||||
bool currentDesktop(long *desktop)
|
||||
{
|
||||
Window rootWin;
|
||||
Display *display = QX11Info::display();
|
||||
bool result;
|
||||
|
||||
rootWin = RootWindow(QX11Info::display(), XDefaultScreen(QX11Info::display()));
|
||||
result = getCardinal32Prop(display, rootWin, (char *)"_NET_CURRENT_DESKTOP", desktop);
|
||||
//if( result )
|
||||
// qDebug("Current Desktop: " + QString::number(*desktop));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
// ripped from advwidget.cpp
|
||||
extern bool ForceForegroundWindow(HWND hwnd);
|
||||
#endif
|
||||
|
||||
void bringToFront(QWidget *widget, bool grabFocus)
|
||||
{
|
||||
Q_ASSERT(widget);
|
||||
QWidget* w = widget->window();
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
// If we're not on the current desktop, do the hide/show trick
|
||||
long dsk, curr_dsk;
|
||||
Window win = w->winId();
|
||||
if(desktopOfWindow(&win, &dsk) && currentDesktop(&curr_dsk)) {
|
||||
if((dsk != curr_dsk) && (dsk != -1)) { // second condition for sticky windows
|
||||
w->hide();
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: multi-desktop hacks for Win and Mac required
|
||||
#endif
|
||||
|
||||
if(w->isMaximized())
|
||||
w->showMaximized();
|
||||
else
|
||||
w->showNormal();
|
||||
|
||||
//if(grabFocus)
|
||||
// w->setActiveWindow();
|
||||
w->raise();
|
||||
w->activateWindow();
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
// ONLINE-1441
|
||||
bool staysOnTop = GetWindowLong(w->winId(), GWL_EXSTYLE) & WS_EX_TOPMOST;
|
||||
if (!staysOnTop && grabFocus) {
|
||||
// ONLINE-914: Work-around for chat window now being properly deactivated
|
||||
// after it got ForceForegroundWindow'd by clicking on Online toaster
|
||||
QWidget tmp;
|
||||
tmp.move(0, Ya::VisualUtil::belowScreenGeometry() + 100);
|
||||
ForceForegroundWindow(tmp.winId());
|
||||
}
|
||||
|
||||
// TODO: unify with AdvancedWidget::bringToFront()
|
||||
ForceForegroundWindow(w->winId());
|
||||
#else
|
||||
Q_UNUSED(grabFocus);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool operator!=(const QMap<QString, QString> &m1, const QMap<QString, QString> &m2)
|
||||
{
|
||||
if ( m1.size() != m2.size() )
|
||||
return true;
|
||||
|
||||
QMap<QString, QString>::ConstIterator it = m1.begin(), it2;
|
||||
for ( ; it != m1.end(); ++it) {
|
||||
it2 = m2.find( it.key() );
|
||||
if ( it2 == m2.end() )
|
||||
return true;
|
||||
if ( it.data() != it2.data() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
265
src/common.h
Normal file
265
src/common.h
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* common.h - contains all the common variables and functions for Psi
|
||||
* Copyright (C) 2001-2003 Justin Karneges
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <QSize>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include <QColor>
|
||||
|
||||
#include "statuspreset.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Options
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
enum {
|
||||
cOnline,
|
||||
cOffline,
|
||||
cAway,
|
||||
cDND,
|
||||
cProfileFore,
|
||||
cProfileBack,
|
||||
cGroupFore,
|
||||
cGroupBack,
|
||||
cListBack,
|
||||
cAnimFront,
|
||||
cAnimBack,
|
||||
cStatus,
|
||||
cNumColors // A guard to store the number of colors
|
||||
};
|
||||
enum { fRoster, fMessage, fChat, fPopup };
|
||||
enum { eMessage, eChat1, eChat2, eHeadline, eSystem, eOnline, eOffline, eSend, eIncomingFT, eFTComplete,
|
||||
#ifdef YAPSI
|
||||
eSubscribe, eUnsubscribe,
|
||||
#endif
|
||||
eSoundLast
|
||||
};
|
||||
enum { dcClose, dcHour, dcDay, dcNever };
|
||||
|
||||
struct Options
|
||||
{
|
||||
QColor color[cNumColors];
|
||||
QString font[4];
|
||||
int smallFontSize; // do not modify or save/load this value! it is calculated at run time!
|
||||
int alertStyle;
|
||||
|
||||
QString systemIconset;
|
||||
QStringList emoticons;
|
||||
QString defaultRosterIconset;
|
||||
QMap<QString, QString> serviceRosterIconset;
|
||||
QMap<QString, QString> customRosterIconset;
|
||||
|
||||
bool useleft, singleclick, hideMenubar, askOnline, askOffline, popupMsgs, popupChats, popupHeadlines, popupFiles, raise;
|
||||
bool alwaysOnTop, noAwaySound, noAwayPopup, noUnlistedPopup, rosterAnim, autoVCardOnLogin, xmlConsoleOnLogin;
|
||||
bool useDock, dockDCstyle, dockHideMW, dockToolMW;
|
||||
bool smallChats, chatLineEdit, useTabs, putTabsAtBottom, usePerTabCloseButton, autoRosterSize, autoRosterSizeGrowTop, autoResolveNicksOnAdd, brushedMetal;
|
||||
|
||||
bool autoCopy; // although this setting is ignored under linux,
|
||||
// it is preserved in case user uses the same config file on different platforms
|
||||
bool useCaps;
|
||||
|
||||
bool oldSmallChats; //Filthy hack, see chat code.
|
||||
int delChats, browser;
|
||||
|
||||
bool useRC;
|
||||
|
||||
int defaultAction;
|
||||
int incomingAs;
|
||||
QStringList recentStatus; //recent status messages
|
||||
QMap<QString,StatusPreset> sp; // Status message presets.
|
||||
|
||||
int asAway, asXa, asOffline;
|
||||
bool use_asAway, use_asXa, use_asOffline;
|
||||
QString asMessage;
|
||||
QString onevent[eSoundLast];
|
||||
|
||||
// Added by Kiko 020621: points to the directory where the trusted
|
||||
// certificates used in validating the server's certificate are kept
|
||||
QString trustCertStoreDir;
|
||||
|
||||
QString player;
|
||||
|
||||
bool ignoreHeadline, ignoreNonRoster, excludeGroupChatsFromIgnore, scrollTo, keepSizes, useEmoticons, alertOpenChats;
|
||||
bool raiseChatWindow, showSubjects, showCounter, chatSays, showGroupCounts;
|
||||
|
||||
QSize sizeEventDlg, sizeChatDlg, sizeTabDlg;
|
||||
bool jidComplete, grabUrls, noGCSound;
|
||||
|
||||
struct ToolbarPrefs {
|
||||
bool dirty;
|
||||
|
||||
QString name;
|
||||
bool on;
|
||||
bool locked;
|
||||
bool stretchable;
|
||||
QStringList keys;
|
||||
|
||||
Qt::Dock dock;
|
||||
int index;
|
||||
bool nl;
|
||||
int extraOffset;
|
||||
};
|
||||
QMap< QString, QList<ToolbarPrefs> > toolbars;
|
||||
|
||||
// groupchat highlighting/nick colouring
|
||||
bool gcHighlighting, gcNickColoring;
|
||||
QStringList gcHighlights, gcNickColors;
|
||||
|
||||
bool clNewHeadings;
|
||||
bool outlineHeadings;
|
||||
|
||||
// passive popups
|
||||
bool ppIsOn;
|
||||
bool ppMessage, ppHeadline, ppChat, ppOnline, ppStatus, ppOffline, ppFile;
|
||||
int ppJidClip, ppStatusClip, ppTextClip, ppHideTime;
|
||||
QColor ppBorderColor;
|
||||
|
||||
// Bouncing of the dock (Mac OS X)
|
||||
typedef enum { NoBounce, BounceOnce, BounceForever } BounceDockSetting;
|
||||
BounceDockSetting bounceDock;
|
||||
|
||||
struct {
|
||||
bool roster, services;
|
||||
} lockdown;
|
||||
|
||||
bool useTransportIconsForContacts;
|
||||
|
||||
// roster sorting styles
|
||||
enum Roster_ContactSortStyle {
|
||||
ContactSortStyle_Status = 0,
|
||||
ContactSortStyle_Alpha
|
||||
};
|
||||
Roster_ContactSortStyle rosterContactSortStyle;
|
||||
|
||||
enum Roster_GroupSortStyle {
|
||||
GroupSortStyle_Alpha = 0,
|
||||
GroupSortStyle_Rank
|
||||
};
|
||||
Roster_GroupSortStyle rosterGroupSortStyle;
|
||||
|
||||
enum Roster_AccountSortStyle {
|
||||
AccountSortStyle_Alpha = 0,
|
||||
AccountSortStyle_Rank
|
||||
};
|
||||
Roster_AccountSortStyle rosterAccountSortStyle;
|
||||
|
||||
bool discoItems, discoInfo;
|
||||
|
||||
bool autoAuth, notifyAuth;
|
||||
|
||||
// event priority
|
||||
enum { EventPriorityDontCare = -1 };
|
||||
int eventPriorityHeadline;
|
||||
int eventPriorityChat;
|
||||
int eventPriorityMessage;
|
||||
int eventPriorityAuth;
|
||||
int eventPriorityFile;
|
||||
int eventPriorityRosterExchange;
|
||||
|
||||
// Message events
|
||||
bool messageEvents;
|
||||
bool inactiveEvents;
|
||||
|
||||
int dtPort;
|
||||
QString dtExternal;
|
||||
|
||||
// Last used path remembering
|
||||
QString lastPath;
|
||||
QString lastSavePath;
|
||||
|
||||
//background images
|
||||
QString chatBgImage, rosterBgImage;
|
||||
};
|
||||
|
||||
extern
|
||||
Options option;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Status
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "xmpp_status.h"
|
||||
|
||||
#define STATUS_OFFLINE XMPP::Status::Offline
|
||||
#define STATUS_ONLINE XMPP::Status::Online
|
||||
#define STATUS_AWAY XMPP::Status::Away
|
||||
#define STATUS_XA XMPP::Status::XA
|
||||
#define STATUS_DND XMPP::Status::DND
|
||||
#define STATUS_INVISIBLE XMPP::Status::Invisible
|
||||
#define STATUS_CHAT XMPP::Status::FFC
|
||||
|
||||
#define STATUS_ASK 100
|
||||
#define STATUS_NOAUTH 101
|
||||
#define STATUS_ERROR 102
|
||||
|
||||
QString status2txt(int status);
|
||||
XMPP::Status makeStatus(int, const QString &);
|
||||
XMPP::Status makeStatus(int, const QString &, int);
|
||||
XMPP::Status::Type makeSTATUS(const XMPP::Status &);
|
||||
QString clipStatus(const QString &str, int width, int height);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Widget tools
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void bringToFront(QWidget *w, bool grabFocus = true);
|
||||
void replaceWidget(QWidget *, QWidget *);
|
||||
void closeDialogs(QWidget *);
|
||||
#ifdef Q_WS_X11
|
||||
#include <QWidget>
|
||||
void x11wmClass(Display *dsp, WId wid, QString resName);
|
||||
#define X11WM_CLASS(x) x11wmClass(x11Display(), winId(), (x));
|
||||
#else
|
||||
#define X11WM_CLASS(x) /* dummy */
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// History utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QString logencode(QString);
|
||||
QString logdecode(const QString &);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Misc.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QString CAP(const QString &str);
|
||||
|
||||
QString encodePassword(const QString &, const QString &);
|
||||
QString decodePassword(const QString &, const QString &);
|
||||
|
||||
bool operator!=(const QMap<QString, QString> &, const QMap<QString, QString> &);
|
||||
|
||||
bool fileCopy(const QString &src, const QString &dest);
|
||||
|
||||
void soundPlay(const QString &);
|
||||
|
||||
extern Qt::WFlags psi_dialog_flags;
|
||||
extern bool useSound;
|
||||
|
||||
#endif
|
||||
29
src/conf_iris.pri
Normal file
29
src/conf_iris.pri
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
include(../conf.pri)
|
||||
windows:include(../conf_windows.pri)
|
||||
CONFIG += iris_bundle
|
||||
|
||||
# don't build iris apps
|
||||
CONFIG += no_tests
|
||||
|
||||
# use qca from psi if necessary
|
||||
qca-static {
|
||||
DEFINES += QCA_STATIC
|
||||
INCLUDEPATH += $$PWD/../third-party/qca/qca/include/QtCrypto
|
||||
}
|
||||
else {
|
||||
CONFIG += crypto
|
||||
}
|
||||
|
||||
# use zlib from psi if necessary
|
||||
psi-zip {
|
||||
INCLUDEPATH += $$PWD/tools/zip/minizip/win32
|
||||
}
|
||||
|
||||
mac {
|
||||
# Universal binaries
|
||||
qc_universal {
|
||||
CONFIG += x86 x86_64
|
||||
QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.5.sdk
|
||||
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.5
|
||||
}
|
||||
}
|
||||
125
src/conferencebookmark.cpp
Normal file
125
src/conferencebookmark.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* conferencebookmark.cpp
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "conferencebookmark.h"
|
||||
#include "xmpp_xmlcommon.h"
|
||||
|
||||
ConferenceBookmark::ConferenceBookmark(const QString& name, const XMPP::Jid& jid, bool auto_join, const QString& nick, const QString& password)
|
||||
: name_(name)
|
||||
, jid_(jid)
|
||||
, auto_join_(auto_join)
|
||||
, nick_(nick)
|
||||
, password_(password)
|
||||
{
|
||||
}
|
||||
|
||||
ConferenceBookmark::ConferenceBookmark(const QDomElement& el)
|
||||
: auto_join_(false)
|
||||
{
|
||||
fromXml(el);
|
||||
}
|
||||
|
||||
void ConferenceBookmark::setName(const QString& name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
const QString& ConferenceBookmark::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
const XMPP::Jid& ConferenceBookmark::jid() const
|
||||
{
|
||||
return jid_;
|
||||
}
|
||||
|
||||
bool ConferenceBookmark::autoJoin() const
|
||||
{
|
||||
return auto_join_;
|
||||
}
|
||||
|
||||
const QString& ConferenceBookmark::nick() const
|
||||
{
|
||||
return nick_;
|
||||
}
|
||||
|
||||
const QString& ConferenceBookmark::password() const
|
||||
{
|
||||
return password_;
|
||||
}
|
||||
|
||||
bool ConferenceBookmark::isNull() const
|
||||
{
|
||||
return name_.isEmpty() && jid_.isEmpty();
|
||||
}
|
||||
|
||||
void ConferenceBookmark::fromXml(const QDomElement& e)
|
||||
{
|
||||
jid_ = e.attribute("jid");
|
||||
name_ = e.attribute("name");
|
||||
if (e.attribute("autojoin") == "true" || e.attribute("autojoin") == "1")
|
||||
auto_join_ = true;
|
||||
|
||||
for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement i = n.toElement();
|
||||
if (i.isNull())
|
||||
continue;
|
||||
else if (i.tagName() == "nick") {
|
||||
nick_ = i.text();
|
||||
}
|
||||
else if (i.tagName() == "password") {
|
||||
password_ = i.text();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement ConferenceBookmark::toXml(QDomDocument& doc) const
|
||||
{
|
||||
QDomElement e = doc.createElement("conference");
|
||||
e.setAttribute("jid",jid_.full());
|
||||
e.setAttribute("name",name_);
|
||||
if (auto_join_)
|
||||
e.setAttribute("autojoin","true");
|
||||
if (!nick_.isEmpty())
|
||||
e.appendChild(textTag(&doc,"nick",nick_));
|
||||
if (!password_.isEmpty())
|
||||
e.appendChild(textTag(&doc,"password",password_));
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool ConferenceBookmark::operator==(const ConferenceBookmark & other) const
|
||||
{
|
||||
return
|
||||
name_ == other.name_ &&
|
||||
jid_.full() == other.jid_.full() &&
|
||||
auto_join_ == other.auto_join_ &&
|
||||
nick_ == other.nick_ &&
|
||||
password_ == other.password_;
|
||||
}
|
||||
|
||||
bool ConferenceBookmark::operator!=(const ConferenceBookmark& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
60
src/conferencebookmark.h
Normal file
60
src/conferencebookmark.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* conferencebookmark.h
|
||||
* Copyright (C) 2006 Remko Troncon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFERENCEBOOKMARK_H
|
||||
#define CONFERENCEBOOKMARK_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "xmpp_jid.h"
|
||||
|
||||
class QDomElement;
|
||||
class QDomDocument;
|
||||
|
||||
class ConferenceBookmark
|
||||
{
|
||||
public:
|
||||
ConferenceBookmark(const QString& name, const XMPP::Jid& jid, bool auto_join, const QString& nick = QString(), const QString& password = QString());
|
||||
ConferenceBookmark(const QDomElement&);
|
||||
|
||||
void setName(const QString& name);
|
||||
const QString& name() const;
|
||||
const XMPP::Jid& jid() const;
|
||||
bool autoJoin() const;
|
||||
const QString& nick() const;
|
||||
const QString& password() const;
|
||||
|
||||
bool isNull() const;
|
||||
|
||||
void fromXml(const QDomElement&);
|
||||
QDomElement toXml(QDomDocument&) const;
|
||||
|
||||
bool operator==(const ConferenceBookmark& other) const;
|
||||
bool operator!=(const ConferenceBookmark& other) const;
|
||||
|
||||
private:
|
||||
QString name_;
|
||||
XMPP::Jid jid_;
|
||||
bool auto_join_;
|
||||
QString nick_;
|
||||
QString password_;
|
||||
};
|
||||
|
||||
#endif
|
||||
396
src/contactlistgroup.cpp
Normal file
396
src/contactlistgroup.cpp
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* contactlistgroup.cpp - flat contact list group class
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contactlistgroup.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include "contactlistitemproxy.h"
|
||||
#include "contactlistgroupmenu.h"
|
||||
#include "contactlistmodel.h"
|
||||
#include "psicontact.h"
|
||||
#include "contactlistgroupstate.h"
|
||||
#include "contactlistgroupcache.h"
|
||||
#include "fakegroupcontact.h"
|
||||
|
||||
static QString GROUP_DELIMITER = "::";
|
||||
|
||||
/**
|
||||
* Flat group class.
|
||||
*/
|
||||
ContactListGroup::ContactListGroup(ContactListModel* model, ContactListGroup* parent)
|
||||
: ContactListItem()
|
||||
, model_(model)
|
||||
, parent_(parent)
|
||||
, updateOnlineContactsTimer_(0)
|
||||
, haveOnlineContacts_(false)
|
||||
{
|
||||
updateOnlineContactsTimer_ = new QTimer(this);
|
||||
connect(updateOnlineContactsTimer_, SIGNAL(timeout()), SLOT(updateOnlineContactsFlag()));
|
||||
updateOnlineContactsTimer_->setSingleShot(true);
|
||||
updateOnlineContactsTimer_->setInterval(100);
|
||||
}
|
||||
|
||||
ContactListGroup::~ContactListGroup()
|
||||
{
|
||||
foreach(PsiContact* contact, contacts_)
|
||||
removeContact(contact);
|
||||
}
|
||||
|
||||
QString ContactListGroup::fullName() const
|
||||
{
|
||||
QStringList name;
|
||||
const ContactListGroup* group = this;
|
||||
while (group) {
|
||||
if (!group->name().isEmpty())
|
||||
name.prepend(group->name());
|
||||
group = group->parent();
|
||||
}
|
||||
return name.join(groupDelimiter());
|
||||
}
|
||||
|
||||
const QString& ContactListGroup::groupDelimiter()
|
||||
{
|
||||
return GROUP_DELIMITER;
|
||||
}
|
||||
|
||||
void ContactListGroup::setGroupDelimiter(const QString& str)
|
||||
{
|
||||
GROUP_DELIMITER = str;
|
||||
}
|
||||
|
||||
QString ContactListGroup::sanitizeGroupName(const QString& name) const
|
||||
{
|
||||
return name.split(groupDelimiter(), QString::SkipEmptyParts).join(groupDelimiter());
|
||||
}
|
||||
|
||||
QStringList ContactListGroup::sanitizeGroupNames(const QStringList& names) const
|
||||
{
|
||||
QStringList sanitized;
|
||||
foreach(QString name, names) {
|
||||
sanitized.append(sanitizeGroupName(name));
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
ContactListModel::Type ContactListGroup::type() const
|
||||
{
|
||||
return ContactListModel::GroupType;
|
||||
}
|
||||
|
||||
const QString& ContactListGroup::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
void ContactListGroup::setName(const QString& name)
|
||||
{
|
||||
model()->renameGroup(this, name);
|
||||
}
|
||||
|
||||
void ContactListGroup::internalSetName(const QString& name)
|
||||
{
|
||||
if (!name_.isNull())
|
||||
model_->groupCache()->removeGroup(this);
|
||||
|
||||
name_ = name;
|
||||
|
||||
if (!name_.isNull())
|
||||
model_->groupCache()->addGroup(this);
|
||||
}
|
||||
|
||||
bool ContactListGroup::isExpandable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContactListGroup::expanded() const
|
||||
{
|
||||
return model()->groupState()->groupExpanded(this);
|
||||
}
|
||||
|
||||
void ContactListGroup::setExpanded(bool expanded)
|
||||
{
|
||||
model()->groupState()->setGroupExpanded(this, expanded);
|
||||
}
|
||||
|
||||
bool ContactListGroup::isEditable() const
|
||||
{
|
||||
bool result = false;
|
||||
foreach(ContactListItemProxy* proxy, items_) {
|
||||
if (proxy->item()) {
|
||||
if (proxy->item()->isEditable()) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result && model()->contactList()->haveAvailableAccounts();
|
||||
}
|
||||
|
||||
bool ContactListGroup::isRemovable() const
|
||||
{
|
||||
bool result = false;
|
||||
foreach(ContactListItemProxy* proxy, items_) {
|
||||
if (proxy->item()) {
|
||||
if (proxy->item()->isRemovable()) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result && isEditable();
|
||||
}
|
||||
|
||||
ContactListItemMenu* ContactListGroup::contextMenu(ContactListModel* model)
|
||||
{
|
||||
return new ContactListGroupMenu(this, model);
|
||||
}
|
||||
|
||||
void ContactListGroup::addItem(ContactListItemProxy* item)
|
||||
{
|
||||
Q_ASSERT(!items_.contains(item));
|
||||
int index = items_.count();
|
||||
model_->itemAboutToBeInserted(this, index);
|
||||
items_.append(item);
|
||||
model_->insertedItem(this, index);
|
||||
updateOnlineContactsTimer_->start();
|
||||
}
|
||||
|
||||
void ContactListGroup::removeItem(ContactListItemProxy* item)
|
||||
{
|
||||
int index = items_.indexOf(item);
|
||||
Q_ASSERT(index != -1);
|
||||
model_->itemAboutToBeRemoved(this, index);
|
||||
items_.remove(index);
|
||||
delete item;
|
||||
model_->removedItem(this, index);
|
||||
updateOnlineContactsTimer_->start();
|
||||
}
|
||||
|
||||
void ContactListGroup::addContact(PsiContact* contact, QStringList contactGroups)
|
||||
{
|
||||
if (contactGroups.isEmpty())
|
||||
return;
|
||||
|
||||
if (findContact(contact))
|
||||
return;
|
||||
Q_ASSERT(!contacts_.contains(contact));
|
||||
// qWarning("ContactListGroup(%x)::addContact: %s (items = %d, contacts = %d)", this, qPrintable(contact->jid().full()), items_.count(), contacts_.count());
|
||||
contacts_.append(contact);
|
||||
addItem(new ContactListItemProxy(this, contact));
|
||||
|
||||
model_->groupCache()->addContact(this, contact);
|
||||
}
|
||||
|
||||
void ContactListGroup::removeContact(PsiContact* contact)
|
||||
{
|
||||
int index = contacts_.indexOf(contact);
|
||||
Q_ASSERT(index != -1);
|
||||
// qWarning("ContactListGroup(%x)::removeContact: %s (items = %d, contacts = %d)", this, qPrintable(contact->jid().full()), items_.count(), contacts_.count());
|
||||
removeItem(findContact(contact));
|
||||
contacts_.remove(index);
|
||||
|
||||
model_->groupCache()->removeContact(this, contact);
|
||||
}
|
||||
|
||||
// Some room for future optimizations here
|
||||
ContactListItemProxy* ContactListGroup::findContact(PsiContact* contact) const
|
||||
{
|
||||
foreach(ContactListItemProxy* item, items_)
|
||||
if (item->item() == contact)
|
||||
return item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ContactListItemProxy* ContactListGroup::findGroup(ContactListGroup* group) const
|
||||
{
|
||||
foreach(ContactListItemProxy* item, items_)
|
||||
if (item->item() == group)
|
||||
return item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ContactListGroup::contactUpdated(PsiContact* contact)
|
||||
{
|
||||
ContactListItemProxy* item = findContact(contact);
|
||||
if (!item)
|
||||
return;
|
||||
updateOnlineContactsTimer_->start();
|
||||
model_->updatedItem(item);
|
||||
}
|
||||
|
||||
void ContactListGroup::contactGroupsChanged(PsiContact* contact, QStringList contactGroups)
|
||||
{
|
||||
if (contactGroups.isEmpty()) {
|
||||
if (contacts_.contains(contact))
|
||||
removeContact(contact);
|
||||
}
|
||||
else if (!findContact(contact)) {
|
||||
addContact(contact, contactGroups);
|
||||
}
|
||||
|
||||
updateOnlineContactsTimer_->start();
|
||||
}
|
||||
|
||||
ContactListItemProxy* ContactListGroup::item(int index) const
|
||||
{
|
||||
Q_ASSERT(index >= 0);
|
||||
Q_ASSERT(index < items_.count());
|
||||
return items_.at(index);
|
||||
}
|
||||
|
||||
int ContactListGroup::itemsCount() const
|
||||
{
|
||||
return items_.count();
|
||||
}
|
||||
|
||||
// Some room for optimizations here
|
||||
int ContactListGroup::indexOf(const ContactListItem* item) const
|
||||
{
|
||||
for (int i = 0; i < items_.count(); ++i)
|
||||
if (items_.at(i)->item() == item)
|
||||
return i;
|
||||
Q_ASSERT(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ContactListGroup* ContactListGroup::parent() const
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
QModelIndex ContactListGroup::toModelIndex() const
|
||||
{
|
||||
if (!parent())
|
||||
return QModelIndex();
|
||||
|
||||
int index = parent()->indexOf(this);
|
||||
return model()->itemProxyToModelIndex(parent()->item(index), index);
|
||||
}
|
||||
|
||||
const QVector<ContactListItemProxy*>& ContactListGroup::items() const
|
||||
{
|
||||
return items_;
|
||||
}
|
||||
|
||||
bool ContactListGroup::haveOnlineContacts() const
|
||||
{
|
||||
return haveOnlineContacts_;
|
||||
}
|
||||
|
||||
int ContactListGroup::contactsCount() const
|
||||
{
|
||||
return contacts_.count();
|
||||
}
|
||||
|
||||
void ContactListGroup::updateOnlineContactsFlag()
|
||||
{
|
||||
updateOnlineContactsTimer_->stop();
|
||||
if (!parent())
|
||||
return;
|
||||
|
||||
bool haveOnlineContacts = false;
|
||||
foreach(ContactListItemProxy* item, items_) {
|
||||
PsiContact* contact = 0;
|
||||
ContactListGroup* group = 0;
|
||||
if ((contact = dynamic_cast<PsiContact*>(item->item()))) {
|
||||
if (contact->isOnline()) {
|
||||
haveOnlineContacts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((group = dynamic_cast<ContactListGroup*>(item->item()))) {
|
||||
if (group->haveOnlineContacts()) {
|
||||
haveOnlineContacts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (haveOnlineContacts_ != haveOnlineContacts) {
|
||||
haveOnlineContacts_ = haveOnlineContacts;
|
||||
if (parent()) {
|
||||
parent()->updateOnlineContactsFlag();
|
||||
model_->updatedGroupVisibility(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ContactListGroup::isFake() const
|
||||
{
|
||||
if (items_.count() != contacts_.count())
|
||||
return false;
|
||||
|
||||
foreach(PsiContact* contact, contacts_) {
|
||||
if (!contact->isFake())
|
||||
return false;
|
||||
}
|
||||
|
||||
return name().startsWith(FakeGroupContact::defaultGroupName());
|
||||
}
|
||||
|
||||
bool ContactListGroup::compare(const ContactListItem* other) const
|
||||
{
|
||||
// this code creates very weird user experience
|
||||
// const PsiContact* contact = dynamic_cast<const PsiContact*>(other);
|
||||
// if (contact) {
|
||||
// if (isFake())
|
||||
// return true;
|
||||
// }
|
||||
|
||||
const ContactListGroup* group = dynamic_cast<const ContactListGroup*>(other);
|
||||
if (group) {
|
||||
int order = model()->groupState()->groupOrder(group) - model()->groupState()->groupOrder(this);
|
||||
if (order) {
|
||||
return order > 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ContactListItem::compare(other);
|
||||
}
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
void ContactListGroup::dumpTree(int indent) const
|
||||
{
|
||||
dumpInfo(this, 0);
|
||||
foreach(ContactListItemProxy* item, items_) {
|
||||
ContactListGroup* group = dynamic_cast<ContactListGroup*>(item->item());
|
||||
if (group)
|
||||
dumpTree(indent + 1);
|
||||
else
|
||||
dumpInfo(item->item(), indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ContactListGroup::dumpInfo(const ContactListItem* item, int indent) const
|
||||
{
|
||||
qWarning("%sname = '%s', type = %s", qPrintable(QString(indent, ' ')),
|
||||
qPrintable(item->name()),
|
||||
dynamic_cast<const ContactListGroup*>(item) ? "group" : "contact");
|
||||
}
|
||||
|
||||
void ContactListGroup::dumpTree() const
|
||||
{
|
||||
dumpTree(0);
|
||||
}
|
||||
#endif
|
||||
115
src/contactlistgroup.h
Normal file
115
src/contactlistgroup.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* contactlistgroup.h - flat contact list group class
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONTACTLISTGROUP_H
|
||||
#define CONTACTLISTGROUP_H
|
||||
|
||||
#include "contactlistitem.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QModelIndex>
|
||||
|
||||
class QTimer;
|
||||
|
||||
class PsiContact;
|
||||
class ContactListModel;
|
||||
class ContactListItemMenu;
|
||||
class ContactListItemProxy;
|
||||
|
||||
class ContactListGroup : public ContactListItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ContactListGroup(ContactListModel* model, ContactListGroup* parent);
|
||||
~ContactListGroup();
|
||||
|
||||
ContactListItemProxy* item(int index) const;
|
||||
int itemsCount() const;
|
||||
int indexOf(const ContactListItem* item) const;
|
||||
|
||||
ContactListModel* model() const { return model_; }
|
||||
|
||||
ContactListGroup* parent() const;
|
||||
QModelIndex toModelIndex() const;
|
||||
|
||||
bool isFake() const;
|
||||
bool haveOnlineContacts() const;
|
||||
int contactsCount() const;
|
||||
|
||||
// QStringList:
|
||||
// 1. Пустой, значит добавлять ни в коем случае не надо
|
||||
// 2. Элемент — пустая строка — это значит что надо добавлять в General-группу
|
||||
// 3. Элементы — непустые строки — названия групп, включая сепараторы (сплитить отдельно)
|
||||
virtual void addContact(PsiContact* contact, QStringList contactGroups);
|
||||
virtual void contactUpdated(PsiContact* contact);
|
||||
// модель фильтрует группы перед запуском contactGroupsChanged
|
||||
virtual void contactGroupsChanged(PsiContact* contact, QStringList contactGroups);
|
||||
|
||||
QString fullName() const;
|
||||
|
||||
// reimplemented
|
||||
virtual ContactListModel::Type type() const;
|
||||
virtual const QString& name() const;
|
||||
virtual void setName(const QString& name);
|
||||
virtual bool isEditable() const;
|
||||
virtual bool isRemovable() const;
|
||||
virtual bool isExpandable() const;
|
||||
virtual bool expanded() const;
|
||||
virtual void setExpanded(bool expanded);
|
||||
virtual ContactListItemMenu* contextMenu(ContactListModel* model);
|
||||
virtual bool compare(const ContactListItem* other) const;
|
||||
|
||||
static const QString& groupDelimiter();
|
||||
static void setGroupDelimiter(const QString&);
|
||||
QString sanitizeGroupName(const QString&) const;
|
||||
QStringList sanitizeGroupNames(const QStringList& names) const;
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
void dumpTree() const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void addItem(ContactListItemProxy* item);
|
||||
void removeItem(ContactListItemProxy* item);
|
||||
ContactListItemProxy* findContact(PsiContact* contact) const;
|
||||
ContactListItemProxy* findGroup(ContactListGroup* group) const;
|
||||
const QVector<ContactListItemProxy*>& items() const;
|
||||
void internalSetName(const QString& name);
|
||||
|
||||
public slots:
|
||||
void updateOnlineContactsFlag();
|
||||
|
||||
private:
|
||||
ContactListModel* model_;
|
||||
ContactListGroup* parent_;
|
||||
QTimer* updateOnlineContactsTimer_;
|
||||
QString name_;
|
||||
QVector<PsiContact*> contacts_;
|
||||
QVector<ContactListItemProxy*> items_;
|
||||
bool haveOnlineContacts_;
|
||||
|
||||
void removeContact(PsiContact* contact);
|
||||
#ifdef UNIT_TEST
|
||||
void dumpInfo(const ContactListItem* item, int indent) const;
|
||||
void dumpTree(int indent) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
100
src/contactlistgroupcache.cpp
Normal file
100
src/contactlistgroupcache.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* contactlistgroupcache.cpp - contact list group cache
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contactlistgroupcache.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include "contactlistgroup.h"
|
||||
#include "psicontact.h"
|
||||
|
||||
ContactListGroupCache::ContactListGroupCache(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ContactListGroupCache::~ContactListGroupCache()
|
||||
{
|
||||
}
|
||||
|
||||
QStringList ContactListGroupCache::groups() const
|
||||
{
|
||||
return groups_.keys();
|
||||
}
|
||||
|
||||
QList<ContactListGroup*> ContactListGroupCache::groupsFor(PsiContact* contact) const
|
||||
{
|
||||
return contacts_[contact];
|
||||
}
|
||||
|
||||
ContactListGroup* ContactListGroupCache::findGroup(const QString& fullName) const
|
||||
{
|
||||
return groups_[fullName];
|
||||
}
|
||||
|
||||
void ContactListGroupCache::addContact(ContactListGroup* group, PsiContact* contact)
|
||||
{
|
||||
Q_ASSERT(group);
|
||||
Q_ASSERT(contact);
|
||||
if (!contacts_.contains(contact))
|
||||
contacts_[contact] = QList<ContactListGroup*>();
|
||||
|
||||
if (!contacts_[contact].contains(group))
|
||||
contacts_[contact] << group;
|
||||
}
|
||||
|
||||
void ContactListGroupCache::removeContact(ContactListGroup* group, PsiContact* contact)
|
||||
{
|
||||
Q_ASSERT(group);
|
||||
Q_ASSERT(contact);
|
||||
if (contacts_[contact].contains(group))
|
||||
contacts_[contact].remove(group);
|
||||
|
||||
if (contacts_[contact].isEmpty())
|
||||
contacts_.remove(contact);
|
||||
}
|
||||
|
||||
void ContactListGroupCache::addGroup(ContactListGroup* group)
|
||||
{
|
||||
Q_ASSERT(group);
|
||||
groups_[group->fullName()] = group;
|
||||
}
|
||||
|
||||
void ContactListGroupCache::removeGroup(ContactListGroup* group)
|
||||
{
|
||||
groups_.remove(group->fullName());
|
||||
}
|
||||
|
||||
bool ContactListGroupCache::hasContacts(bool onlineOnly) const
|
||||
{
|
||||
bool result = false;
|
||||
QHashIterator<PsiContact*, QList<ContactListGroup*> > it(contacts_);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (!it.key()->isHidden()) {
|
||||
if (onlineOnly && !it.key()->isOnline())
|
||||
continue;
|
||||
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
53
src/contactlistgroupcache.h
Normal file
53
src/contactlistgroupcache.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* contactlistgroupcache.h - contact list group cache
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONTACTLISTGROUPCACHE_H
|
||||
#define CONTACTLISTGROUPCACHE_H
|
||||
|
||||
#include <QHash>
|
||||
|
||||
class ContactListGroup;
|
||||
class PsiContact;
|
||||
|
||||
class ContactListGroupCache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ContactListGroupCache(QObject *parent);
|
||||
~ContactListGroupCache();
|
||||
|
||||
QStringList groups() const;
|
||||
bool hasContacts(bool onlineOnly) const;
|
||||
|
||||
QList<ContactListGroup*> groupsFor(PsiContact* contact) const;
|
||||
ContactListGroup* findGroup(const QString& fullName) const;
|
||||
|
||||
void addContact(ContactListGroup* group, PsiContact* contact);
|
||||
void removeContact(ContactListGroup* group, PsiContact* contact);
|
||||
|
||||
void addGroup(ContactListGroup* group);
|
||||
void removeGroup(ContactListGroup* group);
|
||||
|
||||
private:
|
||||
QHash<PsiContact*, QList<ContactListGroup*> > contacts_;
|
||||
QHash<QString, ContactListGroup*> groups_;
|
||||
};
|
||||
|
||||
#endif
|
||||
117
src/contactlistgroupmenu.cpp
Normal file
117
src/contactlistgroupmenu.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* contactlistgroupmenu.cpp - context menu for contact list groups
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contactlistgroupmenu.h"
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
#include "iconaction.h"
|
||||
#include "iconset.h"
|
||||
#include "contactlistgroup.h"
|
||||
#include "psioptions.h"
|
||||
#include "shortcutmanager.h"
|
||||
#include "psicontactlist.h"
|
||||
|
||||
class ContactListGroupMenu::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QPointer<ContactListGroup> group;
|
||||
IconAction* act_rename;
|
||||
QAction* act_removeGroupAndContacts;
|
||||
QAction* act_addGroup;
|
||||
|
||||
public:
|
||||
Private(ContactListGroupMenu* menu, ContactListGroup* _group)
|
||||
: QObject(0)
|
||||
, group(_group)
|
||||
, menu_(menu)
|
||||
{
|
||||
connect(menu, SIGNAL(aboutToShow()), SLOT(updateActions()));
|
||||
|
||||
act_rename = new IconAction("", tr("Re&name"), menu->shortcuts("contactlist.rename"), this, "act_rename");
|
||||
connect(act_rename, SIGNAL(activated()), this, SLOT(rename()));
|
||||
|
||||
act_removeGroupAndContacts = new QAction(tr("&Remove"), this);
|
||||
act_removeGroupAndContacts->setShortcuts(ShortcutManager::instance()->shortcuts("contactlist.delete"));
|
||||
connect(act_removeGroupAndContacts, SIGNAL(activated()), SLOT(removeGroupAndContacts()));
|
||||
|
||||
act_addGroup = new QAction(tr("&Add group..."), this);
|
||||
connect(act_addGroup, SIGNAL(activated()), SLOT(addGroup()));
|
||||
|
||||
updateActions();
|
||||
|
||||
// menu->addAction(act_sendMessage);
|
||||
menu->addAction(act_rename);
|
||||
// menu->addSeparator();
|
||||
// menu->addAction(act_removeGroup); // disassociates all contacts with this group
|
||||
menu->addAction(act_removeGroupAndContacts); // removes all contacts within this group
|
||||
menu->addAction(act_addGroup);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void updateActions()
|
||||
{
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
act_rename->setEnabled(group->isEditable());
|
||||
act_removeGroupAndContacts->setEnabled(group->isRemovable());
|
||||
act_addGroup->setEnabled(group->model()->contactList()->haveAvailableAccounts());
|
||||
}
|
||||
|
||||
void rename()
|
||||
{
|
||||
if (group) {
|
||||
// group->contactList()->emitRename();
|
||||
menu_->model()->renameSelectedItem();
|
||||
}
|
||||
}
|
||||
|
||||
void removeGroupAndContacts()
|
||||
{
|
||||
if (group) {
|
||||
emit menu_->removeSelection();
|
||||
}
|
||||
}
|
||||
|
||||
void addGroup()
|
||||
{
|
||||
if (group) {
|
||||
emit menu_->addGroup();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ContactListGroupMenu* menu_;
|
||||
};
|
||||
|
||||
ContactListGroupMenu::ContactListGroupMenu(ContactListGroup* group, ContactListModel* model)
|
||||
: ContactListItemMenu(group, model)
|
||||
{
|
||||
d = new Private(this, group);
|
||||
}
|
||||
|
||||
ContactListGroupMenu::~ContactListGroupMenu()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
#include "contactlistgroupmenu.moc"
|
||||
44
src/contactlistgroupmenu.h
Normal file
44
src/contactlistgroupmenu.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* contactlistgroupmenu.h - context menu for contact list groups
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PSICONTACTGROUPMENU_H
|
||||
#define PSICONTACTGROUPMENU_H
|
||||
|
||||
#include "contactlistitemmenu.h"
|
||||
|
||||
class ContactListGroup;
|
||||
|
||||
class ContactListGroupMenu : public ContactListItemMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ContactListGroupMenu(ContactListGroup* contact, ContactListModel* model);
|
||||
~ContactListGroupMenu();
|
||||
|
||||
signals:
|
||||
void removeSelection();
|
||||
void addGroup();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* d;
|
||||
};
|
||||
|
||||
#endif
|
||||
225
src/contactlistgroupstate.cpp
Normal file
225
src/contactlistgroupstate.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* contactlistgroupstate.cpp - saves state of groups in a contact list model
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contactlistgroupstate.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QStringList>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "contactlistmodel.h"
|
||||
#include "contactlistgroup.h"
|
||||
#include "psioptions.h"
|
||||
#include "xmpp_xmlcommon.h"
|
||||
|
||||
static const QString groupStateOptionPath = "options.ya.main-window.contact-list.group-state.%1";
|
||||
|
||||
ContactListGroupState::ContactListGroupState(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
orderChangedTimer_ = new QTimer(this);
|
||||
connect(orderChangedTimer_, SIGNAL(timeout()), SIGNAL(orderChanged()));
|
||||
orderChangedTimer_->setSingleShot(true);
|
||||
orderChangedTimer_->setInterval(0);
|
||||
|
||||
saveGroupStateTimer_ = new QTimer(this);
|
||||
connect(saveGroupStateTimer_, SIGNAL(timeout()), SLOT(save()));
|
||||
saveGroupStateTimer_->setSingleShot(true);
|
||||
saveGroupStateTimer_->setInterval(1000);
|
||||
}
|
||||
|
||||
ContactListGroupState::~ContactListGroupState()
|
||||
{
|
||||
}
|
||||
|
||||
bool ContactListGroupState::groupExpanded(const ContactListGroup* group) const
|
||||
{
|
||||
Q_ASSERT(group);
|
||||
QString fullName = group->fullName();
|
||||
if (expanded_.contains(fullName))
|
||||
return expanded_[fullName];
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContactListGroupState::setGroupExpanded(const ContactListGroup* group, bool expanded)
|
||||
{
|
||||
Q_ASSERT(group);
|
||||
expanded_[group->fullName()] = expanded;
|
||||
saveGroupStateTimer_->start();
|
||||
}
|
||||
|
||||
ContactListGroupState::GroupExpandedState ContactListGroupState::groupExpandedState() const
|
||||
{
|
||||
return expanded_;
|
||||
}
|
||||
|
||||
void ContactListGroupState::restoreGroupExpandedState(ContactListGroupState::GroupExpandedState groupExpandedState)
|
||||
{
|
||||
expanded_ = groupExpandedState;
|
||||
}
|
||||
|
||||
int ContactListGroupState::groupOrder(const ContactListGroup* group) const
|
||||
{
|
||||
Q_ASSERT(group);
|
||||
QString fullName = group->fullName();
|
||||
if (order_.contains(fullName))
|
||||
return order_[fullName];
|
||||
if (group->isFake())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ContactListGroupState::setGroupOrder(const ContactListGroup* group, int order)
|
||||
{
|
||||
orderChangedTimer_->start();
|
||||
saveGroupStateTimer_->start();
|
||||
|
||||
Q_ASSERT(group);
|
||||
order_[group->fullName()] = order;
|
||||
}
|
||||
|
||||
void ContactListGroupState::updateGroupList(const ContactListModel* model)
|
||||
{
|
||||
GroupExpandedState newExpanded;
|
||||
QMap<QString, int> newOrder;
|
||||
|
||||
foreach(QString group, groupNames(model, QModelIndex(), QStringList())) {
|
||||
if (expanded_.contains(group))
|
||||
if (!expanded_[group])
|
||||
newExpanded[group] = expanded_[group];
|
||||
|
||||
if (order_.contains(group))
|
||||
newOrder[group] = order_[group];
|
||||
}
|
||||
|
||||
expanded_ = newExpanded;
|
||||
order_ = newOrder;
|
||||
}
|
||||
|
||||
QStringList ContactListGroupState::groupNames(const ContactListModel* model, const QModelIndex& parent, QStringList parentName) const
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
for (int row = 0; row < model->rowCount(parent); ++row) {
|
||||
QModelIndex index = model->index(row, 0, parent);
|
||||
if (model->indexType(index) == ContactListModel::GroupType) {
|
||||
QStringList groupName = parentName;
|
||||
groupName << index.data().toString();
|
||||
foreach(QString name, groupNames(model, index, groupName)) {
|
||||
if (!result.contains(name))
|
||||
result += name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
for (int len = 1; len < parentName.count() + 1; ++len)
|
||||
result += QStringList(parentName.mid(0, len)).join(ContactListGroup::groupDelimiter());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ContactListGroupState::load(const QString& id)
|
||||
{
|
||||
expanded_.clear();
|
||||
order_.clear();
|
||||
|
||||
id_ = id;
|
||||
if (id_.isEmpty())
|
||||
return;
|
||||
|
||||
QDomDocument doc;
|
||||
if (!doc.setContent(PsiOptions::instance()->getOption(groupStateOptionPath.arg(id_)).toString()))
|
||||
return;
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
if (root.tagName() != "group-state" || root.attribute("version") != "1.0")
|
||||
return;
|
||||
|
||||
{
|
||||
QDomElement expanded = findSubTag(root, "expanded", 0);
|
||||
if (!expanded.isNull()) {
|
||||
for (QDomNode n = expanded.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement e = n.toElement();
|
||||
if (e.isNull())
|
||||
continue;
|
||||
|
||||
if (e.tagName() == "item") {
|
||||
expanded_[e.attribute("fullName")] = e.text() == "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
QDomElement order = findSubTag(root, "order", 0);
|
||||
if (!order.isNull()) {
|
||||
for (QDomNode n = order.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
||||
QDomElement e = n.toElement();
|
||||
if (e.isNull())
|
||||
continue;
|
||||
|
||||
if (e.tagName() == "item") {
|
||||
order_[e.attribute("fullName")] = e.text().toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ContactListGroupState::save()
|
||||
{
|
||||
if (id_.isEmpty())
|
||||
return;
|
||||
|
||||
QDomDocument doc;
|
||||
QDomElement root = doc.createElement("group-state");
|
||||
root.setAttribute("version", "1.0");
|
||||
doc.appendChild(root);
|
||||
|
||||
{
|
||||
QDomElement expanded = XMLHelper::emptyTag(&doc, "expanded");
|
||||
root.appendChild(expanded);
|
||||
|
||||
QMap<QString, bool>::iterator i = expanded_.begin();
|
||||
for (; i != expanded_.end(); ++i) {
|
||||
if (i.value() == false) {
|
||||
QDomElement item = textTag(&doc, "item", "false");
|
||||
item.setAttribute("fullName", i.key());
|
||||
expanded.appendChild(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
QDomElement order = XMLHelper::emptyTag(&doc, "order");
|
||||
root.appendChild(order);
|
||||
|
||||
QMap<QString, int>::iterator i = order_.begin();
|
||||
for (; i != order_.end(); ++i) {
|
||||
if (i.value() != 0) {
|
||||
QDomElement item = textTag(&doc, "item", QString::number(i.value()));
|
||||
item.setAttribute("fullName", i.key());
|
||||
order.appendChild(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PsiOptions::instance()->setOption(groupStateOptionPath.arg(id_), doc.toString());
|
||||
}
|
||||
73
src/contactlistgroupstate.h
Normal file
73
src/contactlistgroupstate.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* contactlistgroupstate.h - saves state of groups in a contact list model
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONTACTLISTGROUPSTATE_H
|
||||
#define CONTACTLISTGROUPSTATE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
|
||||
class ContactListModel;
|
||||
class ContactListGroup;
|
||||
|
||||
class QTimer;
|
||||
class QModelIndex;
|
||||
class QDomElement;
|
||||
class QDomDocument;
|
||||
|
||||
class ContactListGroupState : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QMap<QString, bool> GroupExpandedState;
|
||||
|
||||
ContactListGroupState(QObject* parent = 0);
|
||||
~ContactListGroupState();
|
||||
|
||||
bool groupExpanded(const ContactListGroup* group) const;
|
||||
void setGroupExpanded(const ContactListGroup* group, bool expanded);
|
||||
|
||||
GroupExpandedState groupExpandedState() const;
|
||||
void restoreGroupExpandedState(GroupExpandedState groupExpandedState);
|
||||
|
||||
int groupOrder(const ContactListGroup* group) const;
|
||||
void setGroupOrder(const ContactListGroup* group, int order);
|
||||
|
||||
void updateGroupList(const ContactListModel* model);
|
||||
|
||||
void load(const QString& id);
|
||||
|
||||
public slots:
|
||||
void save();
|
||||
|
||||
signals:
|
||||
void orderChanged();
|
||||
|
||||
private:
|
||||
QTimer* orderChangedTimer_;
|
||||
QTimer* saveGroupStateTimer_;
|
||||
QString id_;
|
||||
GroupExpandedState expanded_;
|
||||
QMap<QString, int> order_;
|
||||
|
||||
QStringList groupNames(const ContactListModel* model, const QModelIndex& parent, QStringList parentName) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
99
src/contactlistitem.cpp
Normal file
99
src/contactlistitem.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* contactlistitem.cpp - base class for contact list items
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contactlistitem.h"
|
||||
|
||||
#include "psicontact.h"
|
||||
|
||||
ContactListItem::ContactListItem(QObject* parent)
|
||||
: QObject(parent)
|
||||
, editing_(false)
|
||||
{
|
||||
}
|
||||
|
||||
ContactListItem::~ContactListItem()
|
||||
{
|
||||
}
|
||||
|
||||
bool ContactListItem::isEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContactListItem::isDragEnabled() const
|
||||
{
|
||||
return isEditable();
|
||||
}
|
||||
|
||||
bool ContactListItem::isRemovable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContactListItem::isExpandable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContactListItem::expanded() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ContactListItem::setExpanded(bool expanded)
|
||||
{
|
||||
Q_UNUSED(expanded);
|
||||
}
|
||||
|
||||
ContactListItemMenu* ContactListItem::contextMenu(ContactListModel* model)
|
||||
{
|
||||
Q_UNUSED(model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ContactListItem::isFixedSize() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContactListItem::compare(const ContactListItem* other) const
|
||||
{
|
||||
const PsiContact* left = dynamic_cast<const PsiContact*>(this);
|
||||
const PsiContact* right = dynamic_cast<const PsiContact*>(other);
|
||||
if (!left ^ !right) {
|
||||
return !right;
|
||||
}
|
||||
return comparisonName() < other->comparisonName();
|
||||
}
|
||||
|
||||
const QString& ContactListItem::comparisonName() const
|
||||
{
|
||||
return name();
|
||||
}
|
||||
|
||||
bool ContactListItem::editing() const
|
||||
{
|
||||
return editing_;
|
||||
}
|
||||
|
||||
void ContactListItem::setEditing(bool editing)
|
||||
{
|
||||
editing_ = editing;
|
||||
}
|
||||
64
src/contactlistitem.h
Normal file
64
src/contactlistitem.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* contactlistitem.h - base class for contact list items
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONTACTLISTITEM_H
|
||||
#define CONTACTLISTITEM_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "contactlistmodel.h"
|
||||
|
||||
class ContactListItemMenu;
|
||||
|
||||
class ContactListItem : public QObject
|
||||
{
|
||||
public:
|
||||
ContactListItem(QObject* parent = 0);
|
||||
virtual ~ContactListItem();
|
||||
|
||||
virtual ContactListModel::Type type() const = 0;
|
||||
|
||||
virtual const QString& name() const = 0;
|
||||
virtual void setName(const QString& name) = 0;
|
||||
virtual const QString& comparisonName() const;
|
||||
|
||||
virtual bool isEditable() const;
|
||||
virtual bool isDragEnabled() const;
|
||||
virtual bool isRemovable() const;
|
||||
|
||||
virtual bool isExpandable() const;
|
||||
virtual bool expanded() const;
|
||||
virtual void setExpanded(bool expanded);
|
||||
|
||||
virtual ContactListItemMenu* contextMenu(ContactListModel* model);
|
||||
|
||||
virtual bool isFixedSize() const;
|
||||
|
||||
virtual bool compare(const ContactListItem* other) const;
|
||||
|
||||
virtual bool editing() const;
|
||||
virtual void setEditing(bool editing);
|
||||
|
||||
private:
|
||||
bool editing_;
|
||||
};
|
||||
|
||||
#endif
|
||||
73
src/contactlistitemmenu.cpp
Normal file
73
src/contactlistitemmenu.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* contactlistitemmenu.cpp - base class for contact list item context menus
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contactlistitemmenu.h"
|
||||
|
||||
#include "shortcutmanager.h"
|
||||
|
||||
ContactListItemMenu::ContactListItemMenu(ContactListItem* item, ContactListModel* model)
|
||||
: QMenu(0)
|
||||
, item_(item)
|
||||
, model_(model)
|
||||
{
|
||||
}
|
||||
|
||||
ContactListItemMenu::~ContactListItemMenu()
|
||||
{
|
||||
}
|
||||
|
||||
ContactListItem* ContactListItemMenu::item() const
|
||||
{
|
||||
return item_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all actions which objectNames are present in \param actionNames.
|
||||
*/
|
||||
void ContactListItemMenu::removeActions(QStringList actionNames)
|
||||
{
|
||||
foreach(QString actionName, actionNames) {
|
||||
foreach(QAction* action, actions()) {
|
||||
if (action->objectName() == actionName) {
|
||||
delete action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QAction*> ContactListItemMenu::availableActions() const
|
||||
{
|
||||
QList<QAction*> result;
|
||||
foreach(QAction* action, actions())
|
||||
if (!action->isSeparator())
|
||||
result << action;
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QKeySequence> ContactListItemMenu::shortcuts(const QString& name) const
|
||||
{
|
||||
return ShortcutManager::instance()->shortcuts(name);
|
||||
}
|
||||
|
||||
ContactListModel* ContactListItemMenu::model() const
|
||||
{
|
||||
return model_;
|
||||
}
|
||||
52
src/contactlistitemmenu.h
Normal file
52
src/contactlistitemmenu.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* contactlistitemmenu.h - base class for contact list item context menus
|
||||
* Copyright (C) 2008 Yandex LLC (Michail Pishchagin)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONTACTLISTITEMMENU_H
|
||||
#define CONTACTLISTITEMMENU_H
|
||||
|
||||
#include <QMenu>
|
||||
#include <QList>
|
||||
|
||||
class ContactListModel;
|
||||
class ContactListItem;
|
||||
class QAction;
|
||||
|
||||
class ContactListItemMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ContactListItemMenu(ContactListItem* item, ContactListModel* model);
|
||||
virtual ~ContactListItemMenu();
|
||||
|
||||
virtual ContactListItem* item() const;
|
||||
|
||||
virtual void removeActions(QStringList actionNames);
|
||||
virtual QList<QAction*> availableActions() const;
|
||||
|
||||
protected:
|
||||
QList<QKeySequence> shortcuts(const QString& name) const;
|
||||
ContactListModel* model() const;
|
||||
|
||||
private:
|
||||
ContactListItem* item_;
|
||||
ContactListModel* model_;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue