QXMPP extensions not calling - c++

I'm making one xmpp client and I have a lot doubts in extensions ..
I did need get a list of old messages with one user, so .. I'm using the QXmppArchiveManager class for that. So I make one class like that:
...
class QXmppArchiveManager;
class MessageController : public QXmppClient
{
...
private:
QNetworkAccessManager *nam_;
QXmppClient *xmppClient_;
QXmppArchiveManager *archiveMng_;
QDateTime m_startDate;
QDateTime m_endDate;
protected slots:
virtual void onConnected();
virtual void onMessageReceived(const QXmppMessage &);
virtual void archiveListReceived(const QList<QXmppArchiveChat> &chats, const QXmppResultSetReply &rsmReply);
}
And implements
...
void MessageController::onConnected() //before client connects listener...
{
QXmppResultSetQuery rsmQuery;
rsmQuery.setMax(0);
m_startDate = QDateTime::currentDateTime().addDays(-201);
m_endDate = QDateTime::currentDateTime();
archiveMng_->listCollections("", m_startDate, m_endDate, rsmQuery);
}
void MessageController::connect()
{
xmppClient_ = new QXmppClient();
QObject::connect( xmppClient_, SIGNAL( connected() ), this, SLOT( onConnected() ) );
QObject::connect( xmppClient_, SIGNAL( messageReceived( QXmppMessage ) ), this, SLOT( onMessageReceived( QXmppMessage ) ) );
archiveMng_ = new QXmppArchiveManager;
xmppClient_->addExtension(archiveMng_);
QObject::connect(archiveMng_, SIGNAL(archiveChatReceived(QXmppArchiveChat, QXmppResultSetReply)),
SLOT(archiveChatReceived(QXmppArchiveChat, QXmppResultSetReply)));
QObject::connect(archiveMng_, SIGNAL(archiveListReceived(QList<QXmppArchiveChat>, QXmppResultSetReply)),
SLOT(archiveListReceived(QList<QXmppArchiveChat>, QXmppResultSetReply)));
xmppClient_->logger()->setLoggingType( QXmppLogger::StdoutLogging );
QXmppConfiguration config;
config.setDomain("(censored)");
config.setHost("(censored)");
config.setPort(5222);
config.setUser((censored));
config.setPassword((censored));
config.setResource("Android-Client");
xmppClient_->connectToServer( config );
}
void MessageController::archiveChatReceived(const QXmppArchiveChat &chat, const QXmppResultSetReply &rsmReply)
{
qDebug() << "archiveChatReceived";
}
void MessageController::archiveListReceived(const QList<QXmppArchiveChat> &chats, const QXmppResultSetReply &rsmReply)
{
qDebug() << "archiveListReceived";
}
The problem is ... this code not called this listeners, in this case not call "archiveListReceived".
How I can fix that ?
Thanks

I found the problem, in this case my openfire xmpp server not working for archive, so ... I'm install the open-archive plugin for it!

Related

How to make slot work at time when calling function?

I have a function and connection between a slot and a signal.
Check the code below:
void NetworkAccessManager::sendPOST(QString url)
{
QNetworkCookieJar *cookieJar = new QNetworkCookieJar(manager_);
manager_->setCookieJar(cookieJar);
QNetworkRequest request(url);
QByteArray postData;
postData.append("j_username=admin&");
postData.append("j_password=admin");
manager_->post(request, postData);
connect(manager_, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinishedSlot(QNetworkReply *)));
}
void NetworkAccessManager::replyFinishedSlot(QNetworkReply *reply)
{
...
cookie = "...";
}
Code above owned by class NetworkAccessManager. Variable cookie is public and I need to change its value in replyFinishedSlot.
I try to use the function sendPOST() in constructer of another class and it works, but slot doing nothing and cookie varaible is empty. What do I do wrong?
Here's the code inside another class:
NetworkAccessManager *manager = new NetworkAccessManager();
manager->sendPOST("http://example.com");
qDebug() << "cookies: " << manager->cookies;
I guess that slot may not work because I never emit signal finished(), but I am not sure where should I emit this because my code shouldn't work with the user interface.
I have found a couple of problem solutions.
First one
I am saving the cookie in a file. Here's the code:
void NetworkAccessManager::replyFinishedSlot(QNetworkReply *reply)
{
...
QFile cookieFile("cookie.txt");
if (cookieFile.open(QIODevice::WriteOnly))
{
cookieFile.write(cookies.toUtf8());
cookieFile.close();
}
...
}
Here's the constructer of class where I use the function
NetworkAccessManager *manager = new NetworkAccessManager();
manager->sendPOST("http://example.com");
QString cookies = "";
QFile cookieFile("cookie.txt");
if (cookieFile.exists() && cookieFile.open(QIODevice::ReadOnly))
{
cookies = cookieFile.readAll();
cookieFile.close();
}
QMap<QString, QString> elements;
elements.insert("cookies", cookies);
Second one
I use a signal to send the info to QML (I transferred my NetworkAccessManager class to WebViewModel).
.h
class WebViewModel : public QObject
{
Q_OBJECT
public:
explicit WebViewModel(QObject *parent = nullptr);
~WebViewModel();
void sendPOST(QString url);
private slots:
void replyFinishedSlot(QNetworkReply *);
private:
QNetworkAccessManager *manager_;
signals:
void finished(QNetworkReply *);
void cookieReady(QString thisCookie);
};
.cpp
WebViewModel::WebViewModel(QObject* parent)
: QObject(parent)
{
manager_ = new QNetworkAccessManager(this);
sendPOST("http://example.com");
}
WebViewModel::~WebViewModel()
{
delete manager_;
}
void WebViewModel::sendPOST(QString url)
{
...
connect(manager_, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinishedSlot(QNetworkReply *)));
...
}
void WebViewModel::replyFinishedSlot(QNetworkReply *reply)
{
if(reply->error())
{
...
}
else
{
...
QString cookieString = cookie[0].name() + "=" + cookie[0].value() + "; domain=" + cookie[0].domain() + "; path=" + cookie[0].path();
emit cookieReady(cookieString);//the signal sends my variable to .qml
...
}
}
.qml
Connections {
target: WebViewModel
onCookieReady: {
testCookies = thisCookie
//thisCookie variable wasn't declared in the .qml file, thisCookie variable
//is accessible by signal void cookieReady(QString thisCookie) from .h C++
//and MUST have exactly the same name in .qml file as in .h file
}
}

QT SQL notification with payload

I'm currently working on applciation that will add to table view new row, that was inserted into db's table. I started with basic class to handle notifies and setted up triggers:
CREATE OR REPLACE FUNCTION notify_tableIWantToObserve_update()
RETURNS trigger AS $$
DECLARE
BEGIN
PERFORM pg_notify(
CAST('tableIWantToObserve_update' AS text),
(NEW.tableIWantToObserve_id)::text);
return new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tRIGGER_notify_tableIWantToObserve_update
AFTER UPDATE
ON tableIWantToObserve
FOR EACH ROW
EXECUTE PROCEDURE notify_tableIWantToObserve_update();
So it will jsut send notfy with id of updated row in payload. That is what i want - becous reloading whole table just won't do the trick later.
I checked documentaton of QSqlDriver
http://doc.qt.io/qt-5/qsqldriver.html#notification-1
With it, I created my "handler":
// That's its constructor
MyDB = new QSqlDatabase(QSqlDatabase::addDatabase("QPSQL", "Main"));
//Removed my data from here (just fro sake of this post)
MyDB->setHostName("-");
MyDB->setPort(0);
MyDB->setDatabaseName("-");
MyDB->setUserName("-");
MyDB->setPassword("-");
MyDB->open();
if( MyDB->isOpen() )
{
qDebug()<<"Connected to DB!";
QObject::connect(
MyDB->driver(),
SIGNAL(notification(const QString&, QSqlDriver::NotificationSource, const QVariant)),
this,
SLOT(slot_DBNotification_Recieved_NotifiAndPayload((const QString&, const QVariant)));
);
}
else
qDebug()<<"NOT connected to DB!";
But it jsut wont work. Only with driver's signal useing single QString it will connect it - version i needed (with additional info) wont connect.
I updated my QT to 5.7, but still even in QTCreater, it just shows me that driver's signal is only with single string.
Is there any fix for that? I realy need to use that signal to retrieve that updated row id.
EDIT 1:
that slot of my handler:
void NotifiHandlerr::slot_DBNotification_Recieved_NotifiAndPayload(const QString& MSG, const QVariant &payload)
{
qDebug() << "I WAS NOTIFIED ABOUT : " + MSG+" WITH DATA : "+payload.toString();
}
EDIT 2:
I tried to add QSqlDriver::NotificationSource as argument in my slot, but i couldn't - it still repeated error in .h that NotificationSource wasn't declared.
EDIT 3:
I'm adding here most of the code (handler class)
// WHOLE .h
#include <QDebug>
#include <QObject>
#include <QString>
#include <QSqlDatabase>
#include <QSqlDriver>
#include <QVariant>
#include <QSqlDriverPlugin>
#include <qsqldriver.h>
class Handler : public QObject
{
Q_OBJECT
public slots:
void slot_DBNotification_Recieved_NotifiAndPayload
(const QString& name, QSqlDriver::NotificationSource source, const QVariant& payload);
public:
explicit Handler();
~Handler();
private:
QSqlDatabase MyDB;
};
//WHOLE .cpp
#include "Handler.h"
Handler::Handler()
{
MyDB = new QSqlDatabase(QSqlDatabase::addDatabase("QPSQL", "Main"));
MyDB->setHostName("-");
MyDB->setPort(0);
MyDB->setDatabaseName("-");
MyDB->setUserName("-");
MyDB->setPassword("-");
MyDB->open();
if( MyDB->isOpen() )
{
qDebug()<<"Connected to DB!";
MyDB->driver()->subscribeToNotification("tableIWantToObserve_update");
QObject::connect(
MyDB->driver(),
SIGNAL(notification(const QString&, QSqlDriver::NotificationSource, const QVariant)),
this,
SLOT(slot_DBNotification_Recieved_NotifiAndPayload((const QString&, const QVariant)));
);
}
else
qDebug()<<"NOT connected to DB!";
}
Handler::~Handler()
{
MyDB->driver()->unsubscribeFromNotification("tableIWantToObserve_update");
MyDB->cloe();
}
void NotificationMaster::slot_DBNotification_Recieved_NotifiAndPayload
(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload)
{
qDebug() << "I WAS NOTIFIED ABOUT : " + name+" WITH DATA : "+payload.toString();
}
And just to eliminate this idea - I added
QT += sql
in my .pro file
Your slot has a wrong signature, Here is how you should define it.
In your header file:
//in order to be able to use the enum QSqlDriver::NotificationSource
#include <QSqlDriver>
...
...
class Handler : public QObject{
Q_OBJECT
public:
explicit Handler(QObject *parent = 0);
~Handler();
...
...
...
public slots:
void SqlNotification(const QString& name, QSqlDriver::NotificationSource source,
const QVariant& payload);
...
...
};
and in the constructor, when you are connecting the slot, you should subscribe to the notification first:
QSqlDatabase::database().driver()->subscribeToNotification("notification_name");
connect(QSqlDatabase::database().driver(),
SIGNAL(notification(QString,QSqlDriver::NotificationSource,QVariant)), this,
SLOT(SqlNotification(QString,QSqlDriver::NotificationSource,QVariant)));
You may need to unsubscribe in the destructor(since you don't want to receive the notification any more):
QSqlDatabase::database().driver()->unsubscribeFromNotification("notification_name");
and your slot implementation:
void Handler::SqlNotification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload){
switch(source){
case QSqlDriver::UnknownSource:
qDebug() << "unkown source, name: " << name << "payload:" << payload.toString();
break;
case QSqlDriver::SelfSource:
qDebug() << "self source, name: " << name << "payload:" << payload.toString();
break;
case QSqlDriver::OtherSource:
qDebug() << "other source, name: " << name << "payload:" << payload.toString();
break;
}
}
Code posted by me and in anserw were more-or-less correct, but what need to be done is to recreate whoel project in newer version of qt creator so it will resolve issiues with missing functions and namespaces itself. Just create new project and paste all files there.

Limit QKeySequence/QKeySequenceEdit to only one shortcut

Is it possible to limit QKeySequence to show only one shortcut in QKeySequenceEdit? Currently now it supports up to 4 shortcuts. My application supports key sequences of only one shortcut, e.g. Ctrl+A or Ctrl+C and not e.g. Ctrl+A, D or Ctrl+C, X, Z.
Is it possible to limit QKeySequence or QKeySequenceEdit to just one key sequence?
Solved it, not the best solution but quick...If you want something more customize, I think you have to build it yourself...
customkeysequenceedit.h:
#ifndef CUSTOMKEYSEQUENCEEDIT_H
#define CUSTOMKEYSEQUENCEEDIT_H
#include <QKeySequenceEdit>
class QKeyEvent;
class CustomKeySequenceEdit : public QKeySequenceEdit
{
Q_OBJECT
public:
explicit CustomKeySequenceEdit(QWidget *parent = 0);
~CustomKeySequenceEdit();
protected:
void keyPressEvent(QKeyEvent *pEvent);
};
#endif // CUSTOMKEYSEQUENCEEDIT_H
customkeysequenceedit.cpp:
#include "customkeysequenceedit.h"
#include <QKeyEvent>
CustomKeySequenceEdit::CustomKeySequenceEdit(QWidget *parent) : QKeySequenceEdit(parent) { }
CustomKeySequenceEdit::~CustomKeySequenceEdit() { }
void CustomKeySequenceEdit::keyPressEvent(QKeyEvent *pEvent)
{
QKeySequenceEdit::keyPressEvent(pEvent);
QKeySequence seq(QKeySequence::fromString(keySequence().toString().split(", ").first()));
setKeySequence(seq);
}
You can use the [] operator of QKeySequence: http://doc.qt.io/qt-5/qkeysequence.html#operator-5b-5d
So in your interface constructor, write this:
connect(ui->editShortcut, &QKeySequenceEdit::editingFinished,
this, &dialog::truncateShortcut);
And add this private method to your dialog class:
void dialog::truncateShortcut()
{
int value = ui->editShortcut->keySequence()[0];
QKeySequence shortcut(value);
ui->editShortcut->setKeySequence(shortcut);
}
Doing that, you fully respect the API and don't depend on the , character, which is quite risky.
Most answers is to truncate shortcut after the input done. Anyway, it will show more than one shorcut in the process of inputing, which is kind of annoying.
I found a solutioin that will not even show more than one shorcut.
After one shortcut is inputed, finish the input via clear focus and setKeySequence via override QKeySequenceEdit class keyPressEvent function.
What's more, this method is very easy and graceful!
First create a class myKeySequenceEdit inheriated from QKeySequenceEdit, and below is the codes:
mykeysequenceedit.h:
#ifndef MYKEYSEQUENCEEDIT_H
#define MYKEYSEQUENCEEDIT_H
#include <QKeySequenceEdit>
#include <QWidget>
class myKeySequenceEdit : public QKeySequenceEdit
{
Q_OBJECT
public:
myKeySequenceEdit(QWidget *parent = nullptr);
void keyPressEvent(QKeyEvent *) override;
};
#endif // MYKEYSEQUENCEEDIT_H
mykeysequenceedit.cpp:
#include "mykeysequenceedit.h"
myKeySequenceEdit::myKeySequenceEdit(QWidget *parent) : QKeySequenceEdit(parent) {}
void myKeySequenceEdit::keyPressEvent(QKeyEvent *event)
{
QKeySequenceEdit::keyPressEvent(event);
if (this->keySequence().count() > 0) {
QKeySequenceEdit::setKeySequence(this->keySequence());
emit editingFinished(); // Optinal, depend on if you need the editingFinished signal to be triggered
}
}
My take on this: why would we like to wait in edit mode, if just singular shortcut is wanted. Thus interrupting edit immediately on success:
inline bool QKeySequence_valid( const QKeySequence& accelerator ){
return !accelerator.isEmpty() && accelerator[0] != Qt::Key_unknown;
}
class Single_QKeySequenceEdit : public QKeySequenceEdit
{
protected:
void keyPressEvent( QKeyEvent *e ) override {
QKeySequenceEdit::keyPressEvent( e );
if( QKeySequence_valid( keySequence() ) )
editingFinished();
}
};
Real implementation, because i was struggling to find one of this sort:
class Single_QKeySequenceEdit : public QKeySequenceEdit
{
protected:
void keyPressEvent( QKeyEvent *e ) override {
QKeySequenceEdit::keyPressEvent( e );
if( QKeySequence_valid( keySequence() ) )
clearFocus(); // trigger editingFinished(); via losing focus 🙉
// because this can still receive focus loss b4 getting deleted (practically because modal msgbox)
// and two editingFinished(); b no good
}
void focusOutEvent( QFocusEvent *event ) override {
editingFinished();
}
bool event( QEvent *event ) override { // comsume ALL key presses including Tab
if( event->type() == QEvent::KeyPress ){
keyPressEvent( static_cast<QKeyEvent*>( event ) );
return true;
}
return QKeySequenceEdit::event( event );
}
};
void accelerator_edit( QTreeWidgetItem *item ){
auto edit = new Single_QKeySequenceEdit;
QObject::connect( edit, &QKeySequenceEdit::editingFinished, [item, edit](){
const QKeySequence accelerator = edit->keySequence();
item->treeWidget()->setItemWidget( item, 1, nullptr );
if( QKeySequence_valid( accelerator ) )
accelerator_alter( item, accelerator );
} );
item->treeWidget()->setItemWidget( item, 1, edit );
edit->setFocus(); // track sanity gently via edit being focused property
}

QTableView clearSelection fails with ASSERT: "!isEmpty()" in file /usr/include/qt4/QtCore/qlist.h, line 282

I have this class:
class MyWidget : public QWidget {
Q_OBJECT
public:
...
public slot:
void select( const QItemSelection& selected, const QItemSelection& deselected);
private:
QTableView* view;
MyModelClass* model;
}
In my cunstructor:
view->setEditTriggers( QAbstractItemView::NoEditTriggers );
view->setSelectionMode( QAbstractItemView::SelectionMode::SingleSelection );
view->setSelectionBehavior( QAbstractItemView::SelectionBehavior::SelectRows );
connect( view->selectionModel( ), SIGNAL( selectionChanged ( const QItemSelection&, const QItemSelection& ) ), this, SLOT( select( const QItemSelection&, const QItemSelection& ) ) );
// and few other things
In my slot implementation:
void MyWidget::select( const QItemSelection& selected, const QItemSelection& deselected ) {
//... doing few things
// at the end:
view->clearSelection();
// tried view->selectionModel()->clear() and view->selectionModel()->clearSelection() too
// but got the same result
}
It compiles just right, but when I run and do a selection it crashes at the end with this error message:
ASSERT: "!isEmpty()" in file /usr/include/qt4/QtCore/qlist.h, line 282
I tried other tricks as well:
Reimplementing showEvent method and calling clearSelection from that context, but didn't help :(
My Qt version is 4.8.1. Any help would be nice. Thanks in advance.
Well... it was a pretty dumb mistake. As vahancho said, it implied a recursive call. I had to add a line to my select function to skip the second ( recursive ) call.
if( selected.indexes( ).empty( ) ) return;
It was my big mistake, but maybe it helps others too.

Is this Qt DBus signal connection code correct?

This is my first time using DBus so I'm not entirely sure if I'm going about this the right way. I'm attempting to connect the the Ubuntu One DBus service and obtain login credentials for my app, however the slots I've connected to the DBus return signals detailed here never seem to be firing, despite a positive result being returned during the connection.
Before I start looking for errors in the details relating to this specific service, could someone please tell me if this code would even work in the first place, or if I'm done something wrong here?
int main()
{
UbuntuOneDBus *u1Dbus = new UbuntuOneDBus;
u1Dbus->init();
}
class UbuntuOneDBus : public QObject
{
Q_OBJECT
QString busName;
QString path;
QString interface;
QString method;
QString signature;
void connectReturnSignals();
private slots:
void credentialsFound();
void credentialsNotFound();
void credentialsError();
public:
UbuntuOneDBus();
void init();
};
UbuntuOneDBus::UbuntuOneDBus()
{
busName = "com.ubuntuone.Credentials";
path = "/credentials";
interface = "com.ubuntuone.CredentialsManagement";
method = "register";
signature = "a{ss}";
connectReturnSignals();
}
void UbuntuOneDBus::init()
{
QDBusMessage message = QDBusMessage::createMethodCall( busName, path, interface, method );
QDBusConnection::sessionBus().send( message );
}
void UbuntuOneDBus::connectReturnSignals()
{
QDBusConnection::sessionBus().connect( busName, path, interface, "CredentialsFound", this, SLOT( credentialsFound() ) );
QDBusConnection::sessionBus().connect( busName, path, interface, "CredentialsNotFound", this, SLOT( credentialsNotFound() ) );
QDBusConnection::sessionBus().connect( busName, path, interface, "CredentialsError", this, SLOT( credentialsError() ) );
}
void UbuntuOneDBus::credentialsFound()
{
qDebug() << "Credentials found";
}
void UbuntuOneDBus::credentialsNotFound()
{
std::cout << "Credentials not found" << std::endl;
}
void UbuntuOneDBus::credentialsError()
{
std::cout << "Credentials error" << std::endl;
}
I think that you forgot to run
QDBusConnection QDBusConnection::connectToBus ( BusType type,
const QString & name )
and then check
bool QDBusConnection::isConnected () const
before invoking
void UbuntuOneDBus::connectReturnSignals()
or run program with some flags, but this should be easier.
I don't want what is your goal but maybe you should also try
bool QDBusConnection::registerObject ( const QString & path, QObject * object,
RegisterOptions options = ExportAdaptors )
Here some documentation:
connectToBus
isConnected
registerObject