@ -0,0 +1,8 @@ | |||
*.pro.user | |||
Makefile | |||
moc_* | |||
*.o | |||
*.so.* | |||
ui_* | |||
*.so | |||
qcp/qcp |
@ -0,0 +1,16 @@ | |||
# ------------------------------------------------- | |||
# Project created by QtCreator 2010-07-21T19:59:16 | |||
# ------------------------------------------------- | |||
QT += network | |||
# QT -= gui | |||
TARGET = qcp | |||
TEMPLATE = lib | |||
DEFINES += LIBQCP_LIBRARY | |||
SOURCES += qcp.cpp \ | |||
qcpmodel.cpp | |||
HEADERS += qcp.h \ | |||
libqcp_global.h \ | |||
qcpmodel.h | |||
TARGETDEPS += ../libqtavahi/libqtavahi.so | |||
LIBS += ../libqtavahi/libqtavahi.so |
@ -0,0 +1,12 @@ | |||
#ifndef LIBQCP_GLOBAL_H | |||
#define LIBQCP_GLOBAL_H | |||
#include <QtCore/qglobal.h> | |||
#if defined(LIBQCP_LIBRARY) | |||
# define LIBQCPSHARED_EXPORT Q_DECL_EXPORT | |||
#else | |||
# define LIBQCPSHARED_EXPORT Q_DECL_IMPORT | |||
#endif | |||
#endif // LIBQCP_GLOBAL_H |
@ -0,0 +1,61 @@ | |||
#include "qcp.h" | |||
#define SERVICETYPE "_qcp._tcp" | |||
namespace QCP { | |||
Browse::Browse(QObject *parent) | |||
: QObject(parent), m_av_browse(new Avahi::Browse(SERVICETYPE, this)) { | |||
connect(m_av_browse, SIGNAL(found(Avahi::Service)), this, SLOT(foundService(Avahi::Service))); | |||
connect(m_av_browse, SIGNAL(lost(Avahi::Service)), this, SLOT(lostService(Avahi::Service))); | |||
connect(m_av_browse, SIGNAL(started()), this, SIGNAL(started())); | |||
connect(m_av_browse, SIGNAL(stopped()), this, SIGNAL(stopped())); | |||
} | |||
WatchShare *Browse::watch(const Avahi::Service &service, QObject *parent) { | |||
ShareData *sd = shareData(service); | |||
WatchShare *ws; | |||
if (!sd) return 0; | |||
sd->watcherList.append(ws = new WatchShare(parent, Share(this, service))); | |||
ws->m_list_it = sd->watcherList.end()-1; | |||
return ws; | |||
} | |||
void Browse::removeWatch(WatcherList::iterator it, const Avahi::Service &service) { | |||
ShareData *sd = shareData(service); | |||
if (!sd || WatcherList::iterator() == it) return; | |||
sd->watcherList.erase(it); | |||
} | |||
void Browse::foundService(Avahi::Service s) { | |||
ShareData *sd = new ShareData(); | |||
s.setData(sd); | |||
emit found(Share(this, s)); | |||
} | |||
void Browse::lostService(Avahi::Service s) { | |||
emit lost(Share(this, s)); | |||
ShareData *sd = shareData(s); | |||
if (0 != sd) { | |||
while (!sd->watcherList.empty()) { | |||
WatchShare *ws = sd->watcherList.first(); | |||
emit ws->lost(); | |||
if (ws == sd->watcherList.first()) { | |||
ws->m_list_it = WatcherList::iterator(); | |||
sd->watcherList.pop_front(); | |||
} | |||
} | |||
delete sd; | |||
} | |||
sd->data = 0; | |||
} | |||
WatchShare *Share::watch(QObject *parent) { | |||
return m_browse->watch(m_service, parent); | |||
} | |||
} | |||
@ -0,0 +1,107 @@ | |||
#ifndef QCP_H | |||
#define QCP_H | |||
#include "libqcp_global.h" | |||
#include <QObject> | |||
#include <QLinkedList> | |||
#include "../libqtavahi/qtavahi.h" | |||
namespace QCP { | |||
class LIBQCPSHARED_EXPORT Share; | |||
class LIBQCPSHARED_EXPORT WatchShare; | |||
class LIBQCPSHARED_EXPORT Browse; | |||
} | |||
namespace QCP { | |||
/* The private data of the Avahi::Service instances belongs to QCP ! :) */ | |||
class LIBQCPSHARED_EXPORT Browse : public QObject { | |||
Q_OBJECT | |||
private: | |||
friend class QCP::Share; | |||
friend class QCP::WatchShare; | |||
typedef QLinkedList<WatchShare*> WatcherList; | |||
struct ShareData { | |||
WatcherList watcherList; | |||
void *data; | |||
}; | |||
public: | |||
Browse(QObject *parent = 0); | |||
Avahi::Browse* avahiBrowse() { return m_av_browse; } | |||
inline bool start() { return m_av_browse->start(); } | |||
inline void stop() { m_av_browse->stop(); } | |||
signals: | |||
void found(QCP::Share s); | |||
void lost(QCP::Share s); | |||
void started(); | |||
void stopped(); | |||
private slots: | |||
void foundService(Avahi::Service s); | |||
void lostService(Avahi::Service s); | |||
private: | |||
WatchShare *watch(const Avahi::Service &service, QObject *parent); | |||
void removeWatch(WatcherList::iterator it, const Avahi::Service &service); | |||
static inline ShareData* shareData(const Avahi::Service &service) { | |||
return static_cast<ShareData*>(service.data()); | |||
} | |||
Avahi::Browse *m_av_browse; | |||
}; | |||
class LIBQCPSHARED_EXPORT Share { | |||
private: | |||
friend class QCP::Browse; | |||
friend class QCP::WatchShare; | |||
public: | |||
inline Share(QCP::Browse *browse, Avahi::Service service) : m_browse(browse), m_service(service) { } | |||
public: | |||
Avahi::Service avahiService() const { return m_service; } | |||
WatchShare *watch(QObject *parent = 0); | |||
void* data() const { Browse::ShareData *sd = Browse::shareData(m_service); return sd ? sd->data : 0; } | |||
void setData(void *data) const { Browse::ShareData *sd = Browse::shareData(m_service); if (sd) sd->data = data; } | |||
private: | |||
QCP::Browse *m_browse; | |||
Avahi::Service m_service; | |||
}; | |||
class LIBQCPSHARED_EXPORT WatchShare : public QObject { | |||
Q_OBJECT | |||
friend class QCP::Share; | |||
friend class QCP::Browse; | |||
private: | |||
inline WatchShare(QObject *parent, Share share) : QObject(parent), m_share(share) { } | |||
public: | |||
virtual ~WatchShare() { | |||
m_share.m_browse->removeWatch(m_list_it, m_share.m_service); | |||
} | |||
inline Share share() { return m_share; } | |||
signals: | |||
void lost(); | |||
private: | |||
Share m_share; | |||
Browse::WatcherList::iterator m_list_it; | |||
}; | |||
} | |||
#endif // QCP_H |
@ -0,0 +1,91 @@ | |||
#include "qcpmodel.h" | |||
namespace QCP { | |||
namespace model { | |||
Entry::Entry(Row *parent, const Avahi::Service &s, const QCP::Share &share) | |||
: Avahi::model::Entry(parent, s), m_share(share) { | |||
} | |||
QVariant Entry::data(int col, int role) { | |||
switch (role) { | |||
case Qt::DisplayRole: | |||
switch (col) { | |||
case 0: return service.hostname(); | |||
case 1: return QString("%1:%2").arg(service.address().toString()).arg(service.port()); | |||
case 2: return "Hello World!"; | |||
} | |||
// case Qt::UserRole | |||
default: | |||
return QVariant(); | |||
} | |||
return QVariant(); | |||
} | |||
EntryList::EntryList(Row *parent, const Avahi::ServiceKey &k) | |||
: Avahi::model::EntryList(parent, k) { } | |||
int EntryList::columnCount() { | |||
return 3; | |||
} | |||
QVariant EntryList::data(int col, int role) { | |||
switch (role) { | |||
case Qt::DisplayRole: | |||
switch (col) { | |||
case 0: return key.name; | |||
} | |||
// case Qt::UserRole | |||
default: | |||
return QVariant(); | |||
} | |||
return QVariant(); | |||
} | |||
Avahi::model::Entry* EntryList::newEntry(const Avahi::Service &s, void *priv) { | |||
QCP::Share *share = static_cast< QCP::Share* >(priv); | |||
return new Entry(this, s, *share); | |||
} | |||
int Root::columnCount() { | |||
return 3; | |||
} | |||
EntryList* Root::newList(const Avahi::ServiceKey &k) { | |||
return new EntryList(this, k); | |||
} | |||
} | |||
BrowseModel::BrowseModel(QObject *parent) | |||
: Avahi::BrowseModel(new QCP::model::Root(), parent), m_browse(new QCP::Browse(this)) { | |||
connect(m_browse, SIGNAL(found(QCP::Share)), this, SLOT(foundShare(QCP::Share))); | |||
connect(m_browse, SIGNAL(lost(QCP::Share)), this, SLOT(lostShare(QCP::Share))); | |||
m_browse->start(); | |||
} | |||
QVariant BrowseModel::headerData(int section, Qt::Orientation orientation, int role) const { | |||
if (orientation != Qt::Horizontal) return QVariant(); | |||
switch (role) { | |||
case Qt::DisplayRole: | |||
switch (section) { | |||
case 0: return "Name"; | |||
case 1: return "Address"; | |||
case 2: return "Version"; | |||
} | |||
break; | |||
} | |||
return QVariant(); | |||
} | |||
void BrowseModel::foundShare(QCP::Share s) { | |||
insert(s.avahiService(), &s); | |||
} | |||
void BrowseModel::lostShare(QCP::Share s) { | |||
remove(s.avahiService()); | |||
} | |||
} |
@ -0,0 +1,59 @@ | |||
#ifndef QCPMODEL_H | |||
#define QCPMODEL_H | |||
#include "qcp.h" | |||
#include "../libqtavahi/qtavahimodel.h" | |||
namespace QCP { | |||
namespace model { | |||
class LIBQCPSHARED_EXPORT Entry : public Avahi::model::Entry { | |||
public: | |||
Entry(Row *parent, const Avahi::Service &s, const QCP::Share &share); | |||
virtual QVariant data(int col, int role); | |||
protected: | |||
QCP::Share m_share; | |||
}; | |||
class LIBQCPSHARED_EXPORT EntryList : public Avahi::model::EntryList { | |||
public: | |||
EntryList(Row *parent, const Avahi::ServiceKey &k); | |||
virtual int columnCount(); | |||
virtual QVariant data(int col, int role); | |||
protected: | |||
virtual Avahi::model::Entry* newEntry(const Avahi::Service &s, void *priv); | |||
}; | |||
class LIBQCPSHARED_EXPORT Root : public Avahi::model::Root { | |||
public: | |||
virtual int columnCount(); | |||
protected: | |||
virtual EntryList* newList(const Avahi::ServiceKey &k); | |||
}; | |||
} | |||
class LIBQCPSHARED_EXPORT BrowseModel : public Avahi::BrowseModel { | |||
Q_OBJECT | |||
public: | |||
BrowseModel(QObject *parent = 0); | |||
QVariant headerData(int section, Qt::Orientation orientation, int role) const; | |||
QCP::Browse *browse() { return m_browse; } | |||
protected slots: | |||
void foundShare(QCP::Share s); | |||
void lostShare(QCP::Share s); | |||
private: | |||
QCP::Browse *m_browse; | |||
}; | |||
} | |||
#endif // QCPMODEL_H |
@ -0,0 +1,17 @@ | |||
# ------------------------------------------------- | |||
# Project created by QtCreator 2010-07-23T21:04:59 | |||
# ------------------------------------------------- | |||
QT += network | |||
QT -= gui | |||
TARGET = qtavahi | |||
TEMPLATE = lib | |||
DEFINES += LIBQTAVAHI_LIBRARY | |||
SOURCES += qtavahi.cpp \ | |||
qtavahimodel.cpp | |||
HEADERS += qtavahi.h \ | |||
libqtavahi_global.h \ | |||
qtavahi_p.h \ | |||
qtavahimodel.h | |||
LIBS += -lavahi-common \ | |||
-lavahi-client \ | |||
-lavahi-qt4 |
@ -0,0 +1,12 @@ | |||
#ifndef LIBQTAVAHI_GLOBAL_H | |||
#define LIBQTAVAHI_GLOBAL_H | |||
#include <QtCore/qglobal.h> | |||
#if defined(LIBQTAVAHI_LIBRARY) | |||
# define LIBQTAVAHISHARED_EXPORT Q_DECL_EXPORT | |||
#else | |||
# define LIBQTAVAHISHARED_EXPORT Q_DECL_IMPORT | |||
#endif | |||
#endif // LIBQTAVAHI_GLOBAL_H |
@ -0,0 +1,563 @@ | |||
#include "qtavahi.h" | |||
#include <avahi-client/client.h> | |||
#include <avahi-client/lookup.h> | |||
#include <avahi-client/publish.h> | |||
#include <avahi-common/alternative.h> | |||
#include <avahi-common/error.h> | |||
#include <avahi-common/malloc.h> | |||
#include <avahi-qt4/qt-watch.h> | |||
#include <QSize> | |||
#include <QtEndian> | |||
#include <netinet/in.h> | |||
namespace Avahi { | |||
static QHostAddress fromAvahiAddress(const AvahiAddress *address, AvahiIfIndex interface) { | |||
switch (address->proto) { | |||
case AVAHI_PROTO_INET: | |||
return QHostAddress(qFromBigEndian((quint32) address->data.ipv4.address)); | |||
case AVAHI_PROTO_INET6: { | |||
struct sockaddr_in6 a; | |||
memset(&a, 0, sizeof(a)); | |||
a.sin6_family = AF_INET6; | |||
a.sin6_scope_id = interface; | |||
memcpy(a.sin6_addr.s6_addr, address->data.ipv6.address, 16); | |||
return QHostAddress((const sockaddr*) &a); | |||
} | |||
case AVAHI_PROTO_UNSPEC: | |||
return QHostAddress(); | |||
} | |||
return QHostAddress(); | |||
} | |||
namespace priv { | |||
static void browsep_client_callback(AvahiClient *c, AvahiClientState state, void * userdata); | |||
static void browsep_browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, | |||
const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata); | |||
static void browsep_resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, | |||
const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, | |||
uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata); | |||
} | |||
} | |||
namespace Avahi { | |||
namespace priv { | |||
class BrowseP { | |||
public: | |||
static const ::AvahiPoll *m_qtpoll; | |||
QString m_serviceType; | |||
bool m_initialized; | |||
bool m_running; | |||
::AvahiClient *m_client; | |||
::AvahiServiceBrowser *m_browser; | |||
QByteArray m_service_type; | |||
Avahi::Browse *m_parent; | |||
QHash<ServiceKey, Service> m_list; | |||
BrowseP(QString servicetype, Browse *parent) | |||
: m_serviceType(servicetype), | |||
m_initialized(false), m_running(false), m_client(0), m_browser(0), | |||
m_service_type(servicetype.toUtf8()), m_parent(parent) { | |||
int err; | |||
if (!m_qtpoll) { | |||
if (!(m_qtpoll = avahi_qt_poll_get())) { | |||
qWarning("avahi_qt_poll_get failed"); | |||
return; | |||
} | |||
} | |||
if (!(m_client = avahi_client_new(m_qtpoll, (AvahiClientFlags) 0, browsep_client_callback, this, &err))) { | |||
qWarning("avahi_client_new failed: %s", avahi_strerror(err)); | |||
return; | |||
} | |||
m_initialized = true; | |||
} | |||
void clearList() { | |||
QList<Service> l = m_list.values(); | |||
m_list.clear(); | |||
for (int i = 0; i < l.size(); ++i) { | |||
emit m_parent->lost(l.at(i)); | |||
} | |||
} | |||
void release() { | |||
stop(); | |||
if (!m_initialized) return; | |||
if (m_client) { | |||
avahi_client_free(m_client); | |||
m_client = 0; | |||
} | |||
m_initialized = false; | |||
} | |||
~BrowseP() { | |||
release(); | |||
} | |||
void client_callback(AvahiClient *c, AvahiClientState state) { | |||
switch (state) { | |||
case AVAHI_CLIENT_S_RUNNING: | |||
break; | |||
case AVAHI_CLIENT_FAILURE: | |||
qWarning("avahi client failure: %s", avahi_strerror(avahi_client_errno(c))); | |||
release(); | |||
break; | |||
case AVAHI_CLIENT_S_COLLISION: | |||
case AVAHI_CLIENT_S_REGISTERING: | |||
break; | |||
case AVAHI_CLIENT_CONNECTING: | |||
break; | |||
} | |||
} | |||
void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, | |||
const char *name, const char *type, const char *domain, AvahiLookupResultFlags /* flags */) { | |||
if (!m_browser) m_browser = b; | |||
Q_ASSERT(m_browser == b); | |||
if (protocol != AVAHI_PROTO_INET && protocol != AVAHI_PROTO_INET6) return; /* ignore non IPv[46] for now */ | |||
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */ | |||
switch (event) { | |||
case AVAHI_BROWSER_FAILURE: | |||
qWarning("(Browser) %s", avahi_strerror(avahi_client_errno(m_client))); | |||
release(); | |||
return; | |||
case AVAHI_BROWSER_NEW: | |||
qDebug("(Browser) NEW: service '%s' of type '%s' in domain '%s'", name, type, domain); | |||
/* We ignore the returned resolver object. In the callback | |||
* function we free it. If the server is terminated before | |||
* the callback function is called the server will free | |||
* the resolver for us. */ | |||
if (!(avahi_service_resolver_new(m_client, interface, protocol, name, type, domain, protocol, (AvahiLookupFlags) 0, browsep_resolve_callback, this))) { | |||
qWarning("Failed to resolve service '%s' on '%s': %s", name, domain, avahi_strerror(avahi_client_errno(m_client))); | |||
} | |||
break; | |||
case AVAHI_BROWSER_REMOVE: { | |||
ServiceKey k(interface, protocol, name, domain); | |||
Service s = m_list.value(k); | |||
if (s.valid()) { | |||
m_list.remove(k); | |||
emit m_parent->lost(s); | |||
} | |||
} | |||
break; | |||
case AVAHI_BROWSER_ALL_FOR_NOW: | |||
break; | |||
case AVAHI_BROWSER_CACHE_EXHAUSTED: | |||
break; | |||
} | |||
} | |||
void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, | |||
const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, | |||
uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags /* flags */) { | |||
Q_ASSERT(r); | |||
// if (protocol != AVAHI_PROTO_INET) goto done; /* ignore non IPv4 for now */ | |||
if (protocol != AVAHI_PROTO_INET && protocol != AVAHI_PROTO_INET6) goto done; /* ignore non IPv[46] for now */ | |||
/* Called whenever a service has been resolved successfully or timed out */ | |||
switch (event) { | |||
case AVAHI_RESOLVER_FAILURE: | |||
qDebug("(Resolver) Failed to resolve service '%s' of type '%s' at '%s' in domain '%s': %s", name, type, host_name, domain, avahi_strerror(avahi_client_errno(m_client))); | |||
break; | |||
case AVAHI_RESOLVER_FOUND: { | |||
qDebug("(Resolver) found service '%s' of type '%s' at '%s' in domain '%s'", name, type, host_name, domain); | |||
QHash<QString, QString> qtxt; | |||
AvahiStringList *psl; | |||
for (psl = txt ; psl ; psl = psl->next) { | |||
QString e = QString::fromUtf8((const char*) psl->text, psl->size), key, value; | |||
int eqPos = e.indexOf(QChar('"')); | |||
if (eqPos == 0) continue; /* ignore empty keys */ | |||
if (eqPos < -1) { /* "boolean" */ | |||
key = e; | |||
} else { | |||
key = e.left(eqPos - 1); | |||
value = e.mid(eqPos + 1); | |||
} | |||
key = key.toLower(); | |||
qtxt.insert(key, value); | |||
} | |||
ServiceKey k(interface, protocol, name, domain); | |||
Service s = m_list.value(k); | |||
if (s.valid()) { | |||
m_list.remove(k); | |||
emit m_parent->lost(s); | |||
} | |||
s = Service(QString::fromUtf8(name), QString::fromUtf8(host_name), QString::fromUtf8(domain), fromAvahiAddress(address, interface), interface, protocol, port, qtxt); | |||
m_list.insert(k, s); | |||
emit m_parent->found(s); | |||
} | |||
} | |||
done: | |||
avahi_service_resolver_free(r); | |||
} | |||
bool start() { | |||
if (m_running) return true; | |||
if (!m_initialized) return false; | |||
clearList(); | |||
if (NULL == (m_browser = avahi_service_browser_new(m_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, m_service_type.constData(), NULL, (AvahiLookupFlags) 0, browsep_browse_callback, this))) { | |||
qWarning("Failed to create service browser: %s", avahi_strerror(avahi_client_errno(m_client))); | |||
return false; | |||
} | |||
emit m_parent->started(); | |||
m_running = true; | |||
return true; | |||
} | |||
void stop() { | |||
clearList(); | |||
if (m_running) { | |||
emit m_parent->stopped(); | |||
m_running = false; | |||
} | |||
if (m_browser) { | |||
avahi_service_browser_free(m_browser); | |||
m_browser = 0; | |||
} | |||
} | |||
}; | |||
const AvahiPoll *BrowseP::m_qtpoll = 0; | |||
static void browsep_client_callback(AvahiClient *c, AvahiClientState state, void * userdata) { | |||
BrowseP *p = static_cast<BrowseP*>(userdata); | |||
p->client_callback(c, state); | |||
} | |||
static void browsep_browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, | |||
const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata) { | |||
BrowseP *p = static_cast<BrowseP*>(userdata); | |||
p->browse_callback(b, interface, protocol, event, name, type, domain, flags); | |||
} | |||
static void browsep_resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, | |||
const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, | |||
uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata) { | |||
BrowseP *p = static_cast<BrowseP*>(userdata); | |||
p->resolve_callback(r, interface, protocol, event, name, type, domain, host_name, address, port, txt, flags); | |||
} | |||
static void announcep_client_callback(AvahiClient *c, AvahiClientState state, void * userdata); | |||
static void announcep_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata); | |||
class AnnounceP { | |||
public: | |||
static const AvahiPoll *m_qtpoll; | |||
QString m_serviceType, m_name; | |||
quint16 m_port; | |||
QHash<QString,QString> m_txt; | |||
bool m_initialized; | |||
bool m_running; | |||
AvahiClient *m_client; | |||
AvahiEntryGroup *m_group; | |||
QByteArray m_service_type; | |||
Announce *m_parent; | |||
char *m_raw_name; /* avahi string */ | |||
QList<QByteArray> m_txt_list; | |||
::AvahiStringList *m_raw_txt; | |||
AnnounceP(QString serviceType, QString name, quint16 port, QHash<QString,QString> txt, Announce *parent) | |||
: m_serviceType(serviceType), m_name(name), m_port(port), m_txt(txt), | |||
m_initialized(false), m_running(false), m_client(0), m_group(0), | |||
m_service_type(serviceType.toUtf8()), m_parent(parent), | |||
m_raw_name(avahi_strdup(name.toUtf8().constData())), m_raw_txt(0) { | |||
int err; | |||
QHashIterator<QString, QString> i(m_txt); | |||
while (i.hasNext()) { | |||
QByteArray a; | |||
i.next(); | |||
if (i.value().isNull()) { | |||
m_txt_list.append(a = i.key().toUtf8()); | |||
} else { | |||
m_txt_list.append(a = QString("%1=%2").arg(i.key(), i.value()).toUtf8()); | |||
} | |||
AvahiStringList *l = avahi_string_list_new(a.constData(), NULL); | |||
l->next = m_raw_txt; | |||
m_raw_txt = l; | |||
} | |||
if (!m_qtpoll) { | |||
if (!(m_qtpoll = avahi_qt_poll_get())) { | |||
qWarning("avahi_qt_poll_get failed"); | |||
return; | |||
} | |||
} | |||
if (!(m_client = avahi_client_new(m_qtpoll, (AvahiClientFlags) 0, announcep_client_callback, this, &err))) { | |||
qWarning("avahi_client_new failed: %s", avahi_strerror(err)); | |||
return; | |||
} | |||
m_initialized = true; | |||
start(); | |||
} | |||
void release() { | |||
if (m_running) { | |||
m_running = false; | |||
} | |||
if (!m_initialized) return; | |||
if (m_group) { | |||
qDebug("avahi unregister service"); | |||
avahi_entry_group_reset(m_group); | |||
avahi_entry_group_free(m_group); | |||
m_group = 0; | |||
} | |||
if (m_client) { | |||
avahi_client_free(m_client); | |||
m_client = 0; | |||
} | |||
m_initialized = false; | |||
emit m_parent->stopped(); | |||
} | |||
~AnnounceP() { | |||
release(); | |||
if (m_raw_name) { | |||
avahi_free(m_raw_name); | |||
m_raw_name = 0; | |||
} | |||
if (m_raw_txt) { | |||
avahi_string_list_free(m_raw_txt); | |||
m_raw_txt = 0; | |||
} | |||
} | |||
void client_callback(AvahiClient *c, AvahiClientState state) { | |||
m_client = c; | |||
switch (state) { | |||
case AVAHI_CLIENT_S_RUNNING: | |||
create_services(); | |||
break; | |||
case AVAHI_CLIENT_FAILURE: | |||
qDebug("avahi client failure"); | |||
release(); | |||
break; | |||
case AVAHI_CLIENT_S_COLLISION: | |||
case AVAHI_CLIENT_S_REGISTERING: | |||
if (m_group) { | |||
avahi_entry_group_reset(m_group); | |||
} | |||
break; | |||
case AVAHI_CLIENT_CONNECTING: | |||
break; | |||
} | |||
} | |||
void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state) { | |||
m_group = g; | |||
switch (state) { | |||
case AVAHI_ENTRY_GROUP_ESTABLISHED : | |||
emit m_parent->established(); | |||
break; | |||
case AVAHI_ENTRY_GROUP_COLLISION : | |||
{ | |||
char *n = avahi_alternative_service_name(m_raw_name); | |||
avahi_free(m_raw_name); | |||
m_raw_name = n; | |||
m_name = QString::fromUtf8(m_raw_name); | |||
} | |||
/* And recreate the services */ | |||
avahi_entry_group_reset(m_group); | |||
create_services(); | |||
/* same name should result in AVAHI_ERR_COLLISION in create_services, emit collision there. */ | |||
break; | |||
case AVAHI_ENTRY_GROUP_FAILURE : | |||
qDebug("Entry group failure: %s", avahi_strerror(avahi_client_errno(m_client))); | |||
release(); | |||
break; | |||
case AVAHI_ENTRY_GROUP_UNCOMMITED: | |||
case AVAHI_ENTRY_GROUP_REGISTERING: | |||
break; | |||
} | |||
} | |||
bool create_services() { | |||
int ret; | |||
if (!m_group) { | |||
if (!(m_group = avahi_entry_group_new(m_client, announcep_entry_group_callback, this))) { | |||
qDebug("avahi_entry_group_new failed: %s", avahi_strerror(avahi_client_errno(m_client))); | |||
release(); | |||
return false; | |||
} | |||
} | |||
again: | |||
if (avahi_entry_group_is_empty(m_group)) { | |||
if ((ret = avahi_entry_group_add_service_strlst(m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags) 0, m_raw_name, m_service_type.constData(), NULL, NULL, m_port, m_raw_txt)) < 0) { | |||
if (ret == AVAHI_ERR_COLLISION) | |||
goto collision; | |||
qDebug("Failed to add '%s': %s", m_service_type.constData(), avahi_strerror(ret)); | |||
release(); | |||
return false; | |||
} | |||
if ((ret = avahi_entry_group_commit(m_group)) < 0) { | |||
qDebug("Failed to commit entry group: %s", avahi_strerror(ret)); | |||
release(); | |||
return false; | |||
} | |||
} | |||
return true; | |||
collision: | |||
qDebug("avahi name collision: %s, trying a new one", m_raw_name); | |||
{ | |||
char *n = avahi_alternative_service_name(m_raw_name); | |||
avahi_free(m_raw_name); | |||
m_raw_name = n; | |||
m_name = QString::fromUtf8(m_raw_name); | |||
} | |||
avahi_entry_group_reset(m_group); | |||
emit m_parent->collision(); | |||
goto again; | |||
} | |||
bool start() { | |||
if (m_running) return true; | |||
if (!m_initialized) return false; | |||
m_running = true; | |||
emit m_parent->started(); | |||
return true; | |||
} | |||
void stop() { | |||
release(); | |||
} | |||
}; | |||
const AvahiPoll *AnnounceP::m_qtpoll = 0; | |||
static void announcep_client_callback(AvahiClient *c, AvahiClientState state, void * userdata) { | |||
AnnounceP *p = static_cast<AnnounceP*>(userdata); | |||
p->client_callback(c, state); | |||
} | |||
static void announcep_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { | |||
AnnounceP *p = static_cast<AnnounceP*>(userdata); | |||
p->entry_group_callback(g, state); | |||
} | |||
} | |||
/* public interfaces */ | |||
Browse::Browse(QString serviceType, QObject *parent) | |||
: QObject(parent), m_priv(new priv::BrowseP(serviceType, this)) { | |||
} | |||
Browse::~Browse() { | |||
delete m_priv; | |||
m_priv = 0; | |||
} | |||
bool Browse::start() { | |||
return m_priv->start(); | |||
} | |||
void Browse::stop() { | |||
m_priv->stop(); | |||
} | |||
QString Browse::serviceType() const { | |||
return m_priv->m_serviceType; | |||
} | |||
QList<Service> Browse::currentList() const { | |||
return m_priv->m_list.values(); | |||
} | |||
Announce::Announce(QString serviceType, QString name, quint16 port, QHash<QString,QString> txt, QObject *parent) | |||
: QObject(parent), m_priv(new priv::AnnounceP(serviceType, name, port, txt, this)) { | |||
} | |||
Announce::~Announce() { | |||
delete m_priv; | |||
m_priv = 0; | |||
} | |||
bool Announce::start() { | |||
return m_priv->start(); | |||
} | |||
void Announce::stop() { | |||
m_priv->stop(); | |||
} | |||
QString Announce::serviceType() const { | |||
return m_priv->m_serviceType; | |||
} | |||
QString Announce::name() const { | |||
return m_priv->m_name; | |||
} | |||
quint16 Announce::port() const { | |||
return m_priv->m_port; | |||
} | |||
QHash<QString, QString> Announce::txt() const { | |||
return m_priv->m_txt; | |||
} | |||
QString Announce::txt(QString key) const { | |||
return m_priv->m_txt.value(key); | |||
} | |||
} |
@ -0,0 +1,186 @@ | |||
#ifndef QTAVAHI_H | |||
#define QTAVAHI_H | |||
#include <QObject> | |||
#include "libqtavahi_global.h" | |||
namespace Avahi { | |||
class LIBQTAVAHISHARED_EXPORT Service; | |||
class LIBQTAVAHISHARED_EXPORT ServiceKey; | |||
class LIBQTAVAHISHARED_EXPORT Browse; | |||
class LIBQTAVAHISHARED_EXPORT Announce; | |||
} | |||
/* we need this before #include <QHash> so it finds our qHash function */ | |||
inline uint qHash(const Avahi::ServiceKey& k); | |||
#include <QHostAddress> | |||
#include <QAbstractItemModel> | |||
#include <QAtomicInt> | |||
#include <QString> | |||
#include <QHash> | |||
#include "qtavahi_p.h" | |||
namespace Avahi { | |||
class LIBQTAVAHISHARED_EXPORT Service { | |||
public: | |||
inline Service() : m_priv(0) { } | |||
inline Service(QString name, QString hostname, QString domain, QHostAddress address, int interface, int protocol, quint16 port, QHash<QString, QString> txt) | |||
: m_priv(new Avahi::priv::ServiceP(name, hostname, domain, address, interface, protocol, port, txt)) { } | |||
inline Service(const Service &s) : m_priv(0) { assign(s.m_priv); } | |||
inline Service &operator=(const Service &s) { assign(s.m_priv); return *this; } | |||
~Service() { assign(0); } | |||
inline QString name() const { return m_priv ? m_priv->m_name : QString(); } | |||
inline QString hostname() const { return m_priv ? m_priv->m_hostname : QString(); } | |||
inline QString domain() const { return m_priv ? m_priv->m_domain : QString(); } | |||
inline QHostAddress address() const { return m_priv ? m_priv->m_address : QHostAddress(); } | |||
inline quint16 port() const { return m_priv ? m_priv->m_port : 0; } | |||
inline QHash<QString, QString> txt() const { return m_priv ? m_priv->m_txt : QHash<QString, QString>(); } | |||
inline QString txt(QString key) const { return m_priv ? m_priv->m_txt.value(key) : QString(); } | |||
inline bool valid() const { return 0 != m_priv; } | |||
/* save custom data for a service (the service is probably associated with a Browse instance, so all | |||
code using the same Browse instance uses the same private data here */ | |||
inline void* data() const { return m_priv ? m_priv->m_data : 0; } | |||
inline void setData(void *data) const { if (m_priv) m_priv->m_data = data; } | |||
private: | |||
friend class Avahi::ServiceKey; | |||
inline void assign(Avahi::priv::ServiceP *p) { | |||
if (p == m_priv) return; | |||
if (p) p->ref(); | |||
if (m_priv) m_priv->deref(); | |||
m_priv = p; | |||
} | |||
Avahi::priv::ServiceP *m_priv; | |||
}; | |||
class LIBQTAVAHISHARED_EXPORT ServiceKey { | |||
public: | |||
inline ServiceKey(int interface, int protocol, const char *name, const char *domain) | |||
: interface(interface), protocol(protocol), name(QString::fromUtf8(name)), domain(QString::fromUtf8(domain)) { | |||
} | |||
inline ServiceKey(int interface, int protocol, QString name, QString domain) | |||
: interface(interface), protocol(protocol), name(name), domain(domain) { | |||
} | |||
inline ServiceKey(const Service &s) | |||
: interface(-1), protocol(-1), name(), domain() { | |||
if (s.m_priv) { | |||
interface = s.m_priv->m_interface; | |||
protocol = s.m_priv->m_protocol; | |||
name = s.m_priv->m_name; | |||
domain = s.m_priv->m_domain; | |||
} | |||
} | |||
int interface; /* AvahiIfIndex */ | |||
int protocol; /* AvahiProtocol */ | |||
QString name; | |||
QString domain; | |||
}; | |||
inline bool operator==(const ServiceKey &a, const ServiceKey &b) { | |||
return a.interface == b.interface && a.protocol == b.protocol && a.name == b.name && a.domain == b.domain; | |||
} | |||
inline bool operator<(const ServiceKey &a, const ServiceKey &b) { | |||
if (a.interface < b.interface) return true; | |||
if (a.interface > b.interface) return false; | |||
if (a.protocol < b.protocol) return true; | |||
if (a.protocol > b.protocol) return false; | |||
if (a.name < b.name) return true; | |||
if (a.name > b.name) return false; | |||
return a.domain < b.domain; | |||
} | |||
inline bool operator>(const ServiceKey &a, const ServiceKey &b) { return b < a; } | |||
inline bool operator<=(const ServiceKey &a, const ServiceKey &b) { return !(b < a); } | |||
inline bool operator>=(const ServiceKey &a, const ServiceKey &b) { return !(a < b); } | |||
class LIBQTAVAHISHARED_EXPORT Browse : public QObject { | |||
Q_OBJECT | |||
private: | |||
Q_DISABLE_COPY(Browse); | |||
public: | |||
typedef Avahi::priv::Protocol Protocol; | |||
inline Browse(QString servtype, Protocol prot, QObject *parent = 0) { | |||
Browse(Avahi::priv::serv_prot2str(servtype, prot), parent); | |||
} | |||
Browse(QString serviceType, QObject *parent = 0); | |||
virtual ~Browse(); | |||
bool start(); | |||
void stop(); | |||
QString serviceType() const; | |||
QList<Service> currentList() const; | |||
private: | |||
void clearList(); | |||
signals: | |||
void found(Avahi::Service i); | |||
void lost(Avahi::Service i); | |||
void started(); | |||
void stopped(); | |||
private: | |||
Avahi::priv::BrowseP *m_priv; | |||
friend class Avahi::priv::BrowseP; | |||
}; | |||
class LIBQTAVAHISHARED_EXPORT Announce : public QObject { | |||
Q_OBJECT | |||
private: | |||
Q_DISABLE_COPY(Announce); | |||
public: | |||
typedef Avahi::priv::Protocol Protocol; | |||
inline Announce(QString servtype, Protocol prot, QString name, quint16 port, QHash<QString,QString> txt, QObject *parent = 0) { | |||
Announce(Avahi::priv::serv_prot2str(servtype, prot), name, port, txt, parent); | |||
} | |||
Announce(QString serviceType, QString name, quint16 port, QHash<QString,QString> txt, QObject *parent = 0); | |||
virtual ~Announce(); | |||
QString serviceType() const; | |||
QString name() const; | |||
quint16 port() const; | |||
QHash<QString, QString> txt() const; | |||
QString txt(QString key) const; | |||
bool start(); | |||
void stop(); | |||
signals: | |||
void established(); /* the name may have been changed after collisions */ | |||
void collision(); | |||
void started(); | |||
void stopped(); | |||
private: | |||
Avahi::priv::AnnounceP *m_priv; | |||
friend class Avahi::priv::AnnounceP; | |||
}; | |||
} | |||
QT_BEGIN_NAMESPACE | |||
inline uint qHash(const Avahi::ServiceKey& k) { | |||
return qHash(k.interface ^ k.protocol) ^ qHash(k.name) ^ qHash(k.domain); | |||
} | |||
QT_END_NAMESPACE | |||
#endif // QTAVAHI_H |
@ -0,0 +1,50 @@ | |||
#ifndef QTAVAHI_P_H | |||
#define QTAVAHI_P_H | |||
namespace Avahi { | |||
namespace priv { | |||
class LIBQTAVAHISHARED_EXPORT ServiceP; | |||
class BrowseP; | |||
class AnnounceP; | |||
}; | |||
} | |||
namespace Avahi { | |||
namespace priv { | |||
class LIBQTAVAHISHARED_EXPORT ServiceP { | |||
private: | |||
friend class Avahi::Service; | |||
friend class Avahi::ServiceKey; | |||
friend class Avahi::Browse; | |||
inline ServiceP(QString name, QString hostname, QString domain, QHostAddress address, int interface, int protocol, quint16 port, QHash<QString, QString> txt) | |||
: m_ref(1), m_name(name), m_hostname(hostname), m_domain(domain), m_address(address), m_interface(interface), m_protocol(protocol), m_port(port), m_txt(txt), m_data(0) { } | |||
Q_DISABLE_COPY(ServiceP); | |||
inline void ref() { m_ref.ref(); } | |||
inline void deref() { if (!m_ref.deref()) { delete this; } } | |||
QAtomicInt m_ref; | |||
QString m_name, m_hostname, m_domain; | |||
QHostAddress m_address; | |||
int m_interface, m_protocol; | |||
quint16 m_port; | |||
QHash<QString, QString> m_txt; | |||
void* m_data; | |||
}; | |||
typedef enum { TCP, UDP } Protocol; | |||
inline LIBQTAVAHISHARED_EXPORT QString serv_prot2str(QString service, Protocol prot) { | |||
switch (prot) { | |||
case TCP: return QString("_%1._tcp").arg(service); break; | |||
case UDP: return QString("_%1._udp").arg(service); break; | |||
default: return service; | |||
} | |||
} | |||
} | |||
} | |||
#endif // QTAVAHI_P_H |
@ -0,0 +1,91 @@ | |||
#include "qtavahimodel.h" | |||
namespace Avahi { | |||
namespace model { | |||
Row::~Row() { } | |||
int Row::columnCount() { return 0; } /* columns of child rows */ | |||
Row* Row::index(int /* row */) { return 0; } | |||
int Row::rowCount() { return 0; } | |||
Row* RowList::index(int row) { | |||
return list.value(row); | |||
} | |||
int RowList::rowCount() { | |||
return list.length(); | |||
} | |||
QVariant Root::data(int , int ) { return QVariant(); } | |||
} | |||
BrowseModel::BrowseModel(Avahi::model::Root *root, QObject *parent) | |||
: QAbstractItemModel(parent), m_root(root) { } | |||
BrowseModel::Row *BrowseModel::getRow(const QModelIndex &index) const { | |||
if (index.isValid()) { | |||
return static_cast< Row* >(index.internalPointer()); | |||
} else { | |||
return m_root; | |||
} | |||
} | |||
int BrowseModel::columnCount(const QModelIndex & parent) const { | |||
Row *row = getRow(parent); | |||
return row ? row->columnCount() : 0; | |||
} | |||
QVariant BrowseModel::data(const QModelIndex & index, int role) const { | |||
Row *row = getRow(index); | |||
return row ? row->data(index.column(), role) : QVariant(); | |||
} | |||
QModelIndex BrowseModel::index(int row, int column, const QModelIndex & parent) const { | |||
Row *r = getRow(parent); | |||
if (!r) return QModelIndex(); /* invalid */ | |||
Row *child = r->index(row); | |||
if (!child) return QModelIndex(); /* invalid */ | |||
return createIndex(row, column, (void*) child); | |||
} | |||
QModelIndex BrowseModel::parent(const QModelIndex & index) const { | |||
Row *row = getRow(index); | |||
if (!row) return QModelIndex(); /* invalid */ | |||
Row *p = row->parent(); | |||
if (!p || p == m_root) return QModelIndex(); | |||
return createIndex(0, 0, (void*) p); | |||
} | |||
int BrowseModel::rowCount(const QModelIndex & parent) const { | |||
Row *row = getRow(parent); | |||
return row ? row->rowCount() : 0; | |||
} | |||
Avahi::ServiceKey BrowseModel::key(const Avahi::Service &s) { | |||
Avahi::ServiceKey k(s); | |||
k.interface = k.protocol = -1; | |||
return k; | |||
} | |||
void BrowseModel::insert(const Avahi::Service &s, void *priv) { | |||
Avahi::ServiceKey k = key(s); | |||
if (m_services.contains(k)) { | |||
EntryList *el = m_services.value(k); | |||
beginInsertRows(createIndex(0, 0, (void*) el), 0, 0); | |||
el->list.push_front(el->newEntry(s, priv)); | |||
endInsertRows(); | |||
} else { | |||
EntryList *el = m_root->newList(k); | |||
QMap<Avahi::ServiceKey, EntryList*> tmp(m_services); | |||
tmp.insert(k, el); | |||
int row = tmp.keys().indexOf(k); | |||
beginInsertRows(QModelIndex(), row, row); | |||
m_services = tmp; | |||
m_root->list.insert(row, el); | |||
endInsertRows(); | |||
beginInsertRows(createIndex(0, 0, (void*) el), 0, 0); | |||
el->list.push_front(el->newEntry(s, priv)); | |||
endInsertRows(); | |||
} | |||
} | |||
void BrowseModel::remove(const Avahi::Service &) { | |||
} | |||
} |
@ -0,0 +1,115 @@ | |||
#ifndef QTAVAHIMODEL_H | |||
#define QTAVAHIMODEL_H | |||
#include "qtavahi.h" | |||
#include <QAbstractItemModel> | |||
namespace Avahi { | |||
class BrowseModel; | |||
namespace model { | |||
class Row { | |||
public: | |||
Row(Row *parent) : m_parent(parent) { } | |||
Row() : m_parent(0) { } | |||
virtual ~Row(); | |||
virtual int columnCount(); /* columns of child rows */ | |||
virtual QVariant data(int col, int role) = 0; | |||
virtual Row* index(int row); | |||
virtual int rowCount(); | |||
Row *parent() { return m_parent; } | |||
protected: | |||
Row *m_parent; | |||
}; | |||
class RowList : public Row { | |||
public: | |||
typedef QList< Row* > List; | |||
RowList(Row *parent) : Row(parent) { } | |||
RowList() : Row() { } | |||
virtual int columnCount() = 0; /* columns of child rows */ | |||
virtual Row* index(int row); | |||
virtual int rowCount(); | |||
protected: | |||
friend class Avahi::BrowseModel; | |||
List list; | |||
}; | |||
class Entry : public Row { | |||
public: | |||
Entry(Row *parent, const Avahi::Service &s) : Row(parent), service(s) { } | |||
protected: | |||
friend class Avahi::BrowseModel; | |||
Avahi::Service service; | |||
}; | |||
class EntryList : public RowList { | |||
public: | |||
EntryList(Row *parent, const Avahi::ServiceKey &k) : RowList(parent), key(k) { } | |||
protected: | |||
friend class Avahi::BrowseModel; | |||
virtual Entry* newEntry(const Avahi::Service &s, void *priv) = 0; | |||
Avahi::ServiceKey key; | |||
}; | |||
class Root : public RowList { | |||
public: | |||
virtual QVariant data(int , int ); | |||
protected: | |||
friend class Avahi::BrowseModel; | |||
virtual EntryList* newList(const Avahi::ServiceKey &k) = 0; | |||
}; | |||
} | |||
class BrowseModel : public QAbstractItemModel { | |||
Q_OBJECT | |||
protected: | |||
typedef Avahi::model::Row Row; | |||
typedef Avahi::model::RowList RowList; | |||
typedef Avahi::model::Entry Entry; | |||
typedef Avahi::model::EntryList EntryList; | |||
Avahi::model::Root *m_root; | |||
BrowseModel(Avahi::model::Root *root, QObject *parent = 0); | |||
Row *getRow(const QModelIndex &index) const; | |||
public: | |||
int columnCount(const QModelIndex & parent) const; | |||
QVariant data(const QModelIndex & index, int role) const; | |||
QModelIndex index(int row, int column, const QModelIndex & parent) const; | |||
QModelIndex parent(const QModelIndex & index) const; | |||
int rowCount(const QModelIndex & parent) const; | |||
QVariant headerData(int section, Qt::Orientation orientation, int role) const = 0; | |||
protected: | |||
virtual Avahi::ServiceKey key(const Avahi::Service &s); | |||
void insert(const Avahi::Service &s, void *priv); | |||
void remove(const Avahi::Service &s); | |||
private: | |||
Avahi::Browse *m_browse; | |||
QMap<Avahi::ServiceKey, EntryList*> m_services; | |||
}; | |||
} | |||
#endif // QCPMODEL_H |
@ -0,0 +1,2 @@ | |||
TEMPLATE = subdirs | |||
SUBDIRS = libqtavahi libqcp qcp |
@ -0,0 +1 @@ | |||
../libqcp/libqcp.so.1 |
@ -0,0 +1 @@ | |||
../libqtavahi/libqtavahi.so.1 |
@ -0,0 +1,9 @@ | |||
#include <QtGui/QApplication> | |||
#include "mainwindow.h" | |||
int main(int argc, char *argv[]) { | |||
QApplication a(argc, argv); | |||
MainWindow w; | |||
w.show(); | |||
return a.exec(); | |||
} |
@ -0,0 +1,26 @@ | |||
#include "mainwindow.h" | |||
#include "ui_mainwindow.h" | |||
MainWindow::MainWindow(QWidget *parent) : | |||
QMainWindow(parent), | |||
ui(new Ui::MainWindow) { | |||
ui->setupUi(this); | |||
m_browsemodel = new QCP::BrowseModel(this); | |||
ui->viewShares->setModel(m_browsemodel); | |||
} | |||
MainWindow::~MainWindow() { | |||
delete ui; | |||
} | |||
void MainWindow::changeEvent(QEvent *e) { | |||
QMainWindow::changeEvent(e); | |||
switch (e->type()) { | |||
case QEvent::LanguageChange: | |||
ui->retranslateUi(this); | |||
break; | |||
default: | |||
break; | |||
} | |||
} |
@ -0,0 +1,27 @@ | |||
#ifndef MAINWINDOW_H | |||
#define MAINWINDOW_H | |||
#include <QMainWindow> | |||
#include "../libqcp/qcp.h" | |||
#include "../libqcp/qcpmodel.h" | |||
namespace Ui { | |||
class MainWindow; | |||
} | |||
class MainWindow : public QMainWindow { | |||
Q_OBJECT | |||
public: | |||
MainWindow(QWidget *parent = 0); | |||
~MainWindow(); | |||
protected: | |||
void changeEvent(QEvent *e); | |||
private: | |||
Ui::MainWindow *ui; | |||
QCP::BrowseModel *m_browsemodel; | |||
}; | |||
#endif // MAINWINDOW_H |
@ -0,0 +1,55 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<ui version="4.0"> | |||
<class>MainWindow</class> | |||
<widget class="QMainWindow" name="MainWindow"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>600</width> | |||
<height>400</height> | |||
</rect> | |||
</property> | |||
<property name="windowTitle"> | |||
<string>MainWindow</string> | |||
</property> | |||
<widget class="QWidget" name="centralWidget"> | |||
<layout class="QHBoxLayout" name="horizontalLayout"> | |||
<item> | |||
<widget class="QGroupBox" name="groupBox"> | |||
<property name="title"> | |||
<string>Shares</string> | |||
</property> | |||
<layout class="QHBoxLayout" name="horizontalLayout_2"> | |||
<item> | |||
<widget class="QTreeView" name="viewShares"/> | |||
</item> | |||
</layout> | |||
</widget> | |||
</item> | |||
</layout> | |||
</widget> | |||
<widget class="QMenuBar" name="menuBar"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>600</width> | |||
<height>23</height> | |||
</rect> | |||
</property> | |||
</widget> | |||
<widget class="QToolBar" name="mainToolBar"> | |||
<attribute name="toolBarArea"> | |||
<enum>TopToolBarArea</enum> | |||
</attribute> | |||
<attribute name="toolBarBreak"> | |||
<bool>false</bool> | |||
</attribute> | |||
</widget> | |||
<widget class="QStatusBar" name="statusBar"/> | |||
</widget> | |||
<layoutdefault spacing="6" margin="11"/> | |||
<resources/> | |||
<connections/> | |||
</ui> |
@ -0,0 +1,21 @@ | |||
#------------------------------------------------- | |||
# | |||
# Project created by QtCreator 2010-07-24T12:24:31 | |||
# | |||
#------------------------------------------------- | |||
QT += network | |||
TARGET = qcp | |||
TEMPLATE = app | |||
SOURCES += main.cpp\ | |||
mainwindow.cpp | |||
HEADERS += mainwindow.h | |||
FORMS += mainwindow.ui | |||
TARGETDEPS += ../libqcp/libqcp.so ../libqtavahi/libqtavahi.so | |||
LIBS += ../libqcp/libqcp.so ../libqtavahi/libqtavahi.so |