From: unknown Date: Wed, 25 Mar 2009 22:58:10 +0000 (+0100) Subject: - First commit! X-Git-Url: https://gitweb.aptx.org/?a=commitdiff_plain;h=a2c6fcecf195bb2016e86318689486827981cab1;p=aniplayer-old.git - First commit! --- diff --git a/aniplayer.pro b/aniplayer.pro new file mode 100644 index 0000000..03327aa --- /dev/null +++ b/aniplayer.pro @@ -0,0 +1,8 @@ +CONFIG += ordered +TEMPLATE = subdirs + +#CONFIG += browserplugin + + +SUBDIRS += lib \ + src diff --git a/init b/init deleted file mode 100644 index e69de29..0000000 diff --git a/lib/anidbudpclient/abstractcommand.cpp b/lib/anidbudpclient/abstractcommand.cpp new file mode 100644 index 0000000..a9cd0b5 --- /dev/null +++ b/lib/anidbudpclient/abstractcommand.cpp @@ -0,0 +1,38 @@ +#include "abstractcommand.h" + +AbstractCommand::AbstractCommand(QObject *parent) : QObject(parent) +{ + m_replyCode = UNKNOWN_REPLY; +} + +AbstractCommand::~AbstractCommand() +{ + +} + +Command AbstractCommand::rawCommand() const +{ + return Command("", QVariantMap()); +} + +bool AbstractCommand::waitForResult() const +{ + return false; +} + +void AbstractCommand::setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client) +{ + Q_UNUSED(client); + m_replyCode = replyCode; + m_rawReply = reply; +} + +QString AbstractCommand::rawReply() const +{ + return m_rawReply; +} + +AbstractCommand::ReplyCode AbstractCommand::replyCode() const +{ + return m_replyCode; +} diff --git a/lib/anidbudpclient/abstractcommand.h b/lib/anidbudpclient/abstractcommand.h new file mode 100644 index 0000000..7f7fa4b --- /dev/null +++ b/lib/anidbudpclient/abstractcommand.h @@ -0,0 +1,178 @@ +#ifndef ABSTRACTCOMMAND_H +#define ABSTRACTCOMMAND_H + +#include "anidbudpclient_global.h" +#include +#include +#include + +class AniDBUdpClient; + +typedef QPair Command; + +class ANIDBUDPCLIENTSHARED_EXPORT AbstractCommand : public QObject +{ + Q_OBJECT + Q_ENUMS(ReplyCode); + +public: + enum ReplyCode; + + AbstractCommand(QObject *parent = 0); + virtual ~AbstractCommand(); + + virtual Command rawCommand() const; + + virtual bool waitForResult() const; + + virtual void setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client); + virtual QString rawReply() const; + + virtual ReplyCode replyCode() const; + +signals: + void replyReady(bool success = false); + +public: + enum ReplyCode + { + CLIENT_DESTROYED = -1, + UNKNOWN_REPLY = 0, + // POSITIVE 2XX + LOGIN_ACCEPTED = 200, //a + LOGIN_ACCEPTED_NEW_VER = 201, //a + LOGGED_OUT = 203, //a + RESOURCE = 205, //d + STATS = 206, //b + TOP = 207, //b + UPTIME = 208, //b + ENCRYPTION_ENABLED = 209, //c + + MYLIST_ENTRY_ADDED = 210, //a + MYLIST_ENTRY_DELETED = 211, //a + + ADDED_FILE = 214, //e + ADDED_STREAM = 215, //e + + ENCODING_CHANGED = 219, //c + + FILE = 220, //a + MYLIST = 221, //a + MYLIST_STATS = 222, //b + + ANIME = 230, //b + ANIME_BEST_MATCH = 231, //b + RANDOMANIME = 232, //b + ANIME_DESCRIPTION = 233, //b + + EPISODE = 240, //b + PRODUCER = 245, //b + GROUP = 250, //b + + BUDDY_LIST = 253, //c + BUDDY_STATE = 254, //c + BUDDY_ADDED = 255, //c + BUDDY_DELETED = 256, //c + BUDDY_ACCEPTED = 257, //c + BUDDY_DENIED = 258, //c + + VOTED = 260, //b + VOTE_FOUND = 261, //b + VOTE_UPDATED = 262, //b + VOTE_REVOKED = 263, //b + + NOTIFICATION_ENABLED = 270, //a + NOTIFICATION_NOTIFY = 271, //a + NOTIFICATION_MESSAGE = 272, //a + NOTIFICATION_BUDDY = 273, //c + NOTIFICATION_SHUTDOWN = 274, //c + PUSHACK_CONFIRMED = 280, //a + NOTIFYACK_SUCCESSFUL_M = 281, //a + NOTIFYACK_SUCCESSFUL_N = 282, //a + NOTIFICATION = 290, //a + NOTIFYLIST = 291, //a + NOTIFYGET_MESSAGE = 292, //a + NOTIFYGET_NOTIFY = 293, //a + + SENDMSG_SUCCESSFUL = 294, //a + USER = 295, //d + + // AFFIRMATIVE/NEGATIVE 3XX + PONG = 300, //a + AUTHPONG = 301, //c + NO_SUCH_RESOURCE = 305, //d + API_PASSWORD_NOT_DEFINED = 309, //c + + FILE_ALREADY_IN_MYLIST = 310, //a + MYLIST_ENTRY_EDITED = 311, //a + MULTIPLE_MYLIST_ENTRIES = 312, //e + + SIZE_HASH_EXISTS = 314, //c + INVALID_DATA = 315, //c + STREAMNOID_USED = 316, //c + + NO_SUCH_FILE = 320, //a + NO_SUCH_ENTRY = 321, //a + MULTIPLE_FILES_FOUND = 322, //b + + NO_SUCH_ANIME = 330, //b + NO_SUCH_ANIME_DESCRIPTION = 333, //b + NO_SUCH_EPISODE = 340, //b + NO_SUCH_PRODUCER = 345, //b + NO_SUCH_GROUP = 350, //b + + BUDDY_ALREADY_ADDED = 355, //c + NO_SUCH_BUDDY = 356, //c + BUDDY_ALREADY_ACCEPTED = 357, //c + BUDDY_ALREADY_DENIED = 358, //c + + NO_SUCH_VOTE = 360, //b + INVALID_VOTE_TYPE = 361, //b + INVALID_VOTE_VALUE = 362, //b + PERMVOTE_NOT_ALLOWED = 363, //b + ALREADY_PERMVOTED = 364, //b + + NOTIFICATION_DISABLED = 370, //a + NO_SUCH_PACKET_PENDING = 380, //a + NO_SUCH_ENTRY_M = 381, //a + NO_SUCH_ENTRY_N = 382, //a + + NO_SUCH_MESSAGE = 392, //a + NO_SUCH_NOTIFY = 393, //a + NO_SUCH_USER = 394, //a + + // NEGATIVE 4XX + NOT_LOGGED_IN = 403, //a + + NO_SUCH_MYLIST_FILE = 410, //a + NO_SUCH_MYLIST_ENTRY = 411, //a + + + // CLIENT SIDE FAILURE 5XX + LOGIN_FAILED = 500, //a + LOGIN_FIRST = 501, //a + ACCESS_DENIED = 502, //a + CLIENT_VERSION_OUTDATED = 503, //a + CLIENT_BANNED = 504, //a + ILLEGAL_INPUT_OR_ACCESS_DENIED = 505, //a + INVALID_SESSION = 506, //a + NO_SUCH_ENCRYPTION_TYPE = 509, //c + ENCODING_NOT_SUPPORTED = 519, //c + + BANNED = 555, //a + UNKNOWN_COMMAND = 598, //a + + + // SERVER SIDE FAILURE 6XX + INTERNAL_SERVER_ERROR = 600, //a + ANIDB_OUT_OF_SERVICE = 601, //a + SERVER_BUSY = 602, //d + API_VIOLATION = 666, //a + }; + +protected: + QString m_rawReply; + ReplyCode m_replyCode; +}; + +#endif // ABSTRACTCOMMAND_H diff --git a/lib/anidbudpclient/anidbudpclient.cpp b/lib/anidbudpclient/anidbudpclient.cpp new file mode 100644 index 0000000..3ab0057 --- /dev/null +++ b/lib/anidbudpclient/anidbudpclient.cpp @@ -0,0 +1,555 @@ +#include "anidbudpclient.h" + +#include +#include + +#include + +#include + +const QByteArray AniDBUdpClient::clientName = CLIENT_NAME; +const int AniDBUdpClient::clientVersion = CLIENT_VERSION; +const int AniDBUdpClient::protocolVersion = PROTOCOL_VERSION; + +AniDBUdpClient::AniDBUdpClient(QObject *parent) : QObject(parent) +{ +qDebug() << "Api instance init!"; + m_state = DisconnectedState; + m_error = NoError; + m_errorString; + m_idlePolicy = DoNothingIdlePolicy; + + disconnecting = false; + authCommand = 0; + authenticateOnConnect = false; + + socket = new QUdpSocket(this); + QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readReplies())); + + commandTimer = new QTimer(this); + QObject::connect(commandTimer, SIGNAL(timeout()), this, SLOT(sendNextCommand())); + + idleTimer = new QTimer(this); + QObject::connect(idleTimer, SIGNAL(timeout()), this, SLOT(idleTimeout())); + + m_localPort = 9001; + m_host = "api.anidb.info"; + m_hostPort = 9000; + + authCommand = new AuthCommand(this); + QObject::connect(authCommand, SIGNAL(replyReady(bool)), this, SLOT(doAuthenticate(bool))); + + commandTimer->setSingleShot(false); + setFloodInterval(5); +} + +AniDBUdpClient::~AniDBUdpClient() +{ + disconnect(); + clearCommandQueue(); +} + +QString AniDBUdpClient::host() const +{ + return m_host; +} + +void AniDBUdpClient::setHost(const QString &host, quint16 port) +{ + m_host = host; + if (port) + m_hostPort = port; + m_hostAddress = QHostAddress(); +} + +quint16 AniDBUdpClient::hostPort() const +{ + return m_hostPort; +} + +void AniDBUdpClient::setHostPort(quint16 port) +{ + m_hostPort = port; +} + +quint16 AniDBUdpClient::localPort() const +{ + return m_localPort; +} + +void AniDBUdpClient::setLocalPort(quint16 port) +{ + m_localPort = port; +} + +QString AniDBUdpClient::user() const +{ + return m_user; +} + +void AniDBUdpClient::setUser(const QString &user) +{ + // All usernames are lowercaase + m_user = user.toLower(); +} + +QString AniDBUdpClient::pass() const +{ + return m_pass; +} + +void AniDBUdpClient::setPass(const QString &pass) +{ + m_pass = pass; +} + +bool AniDBUdpClient::compression() const +{ + return m_compression; +} + +void AniDBUdpClient::setCompression(bool compress) +{ + m_compression = compress; +} + +int AniDBUdpClient::floodInterval() const +{ + return m_floodInterval; +} + +void AniDBUdpClient::setFloodInterval(int interval) +{ + m_floodInterval = interval; + commandTimer->setInterval(m_floodInterval * 1000); +} + +AniDBUdpClient::IdlePolicy AniDBUdpClient::idlePolicy() const +{ + return m_idlePolicy; +} + +void AniDBUdpClient::setIdlePolicy(IdlePolicy policy) +{ + m_idlePolicy = policy; +} + + +AniDBUdpClient::State AniDBUdpClient::state() const +{ + return m_state; +} + +AniDBUdpClient::Error AniDBUdpClient::error() const +{ + return m_error; +} + +QString AniDBUdpClient::errorString() const +{ + return m_errorString; +} + +bool AniDBUdpClient::isIdle() +{ + return m_idle; +} + +void AniDBUdpClient::clearCommandQueue() +{ + // Delete all unsent commands that are managed by the client. + while (!commandQueue.empty()) + { + AbstractCommand *cmd = commandQueue.dequeue(); + if (!cmd->waitForResult()) + { + // These would be deleted anyway + delete cmd; + } + else + { + // Send CLIENT_DESTROYED to indicate that no real reply will come. + cmd->setRawReply(AbstractCommand::CLIENT_DESTROYED, "", this); + } + } +} + +void AniDBUdpClient::connect() +{ +qDebug() << "Conneting"; + if (state() == ReconnectingState) + { + authenticate(); + return; + } + + if (state() != DisconnectedState) + return; + + changeState(ConnectingState); + + if (!m_hostAddress.isNull()) + { + doConnect(); + return; + } + QHostInfo::lookupHost(m_host, this, SLOT(lookedUp(QHostInfo))); +} + +void AniDBUdpClient::disconnect(bool graceful) +{ +qDebug() << "Disconneting" << (graceful ? "gracefully" : ""); + if (graceful) + { + disconnecting = true; + return; + } + changeState(DisconnectedState); +} + +void AniDBUdpClient::send(AbstractCommand *command) +{ + if (state() < ConnectingState) + connect(); + + enqueueCommand(command); +} + +void AniDBUdpClient::sendRaw(QByteArray command) +{ +qDebug() << QString("Sending RAW command: %1").arg(command.constData()); + enqueueCommand(new RawCommand(command)); +} + +void AniDBUdpClient::lookedUp(QHostInfo hostInfo) +{ +qDebug() << "Host lookup finished"; + if (hostInfo.error() != QHostInfo::NoError) + { + qDebug() << "Lookup failed:" << hostInfo.errorString(); + changeState(ErrorState); + m_error = HostLookupError; + m_errorString = hostInfo.errorString(); + return; + } + m_hostAddress = hostInfo.addresses()[0]; + doConnect(); +} + + +void AniDBUdpClient::doConnect() +{ + if (socket->bind(QHostAddress::Any, m_localPort)) + { +qDebug() << "Successful connection"; + authenticate(); + } + else + { + changeState(ErrorState); + m_error = BindError; + m_errorString = socket->errorString(); +qDebug() << QString("Bind on Address: %1 port: %2 failed").arg(m_hostAddress.toString()).arg(m_localPort); + } +} + +void AniDBUdpClient::authenticate() +{ + authCommand->setUser(m_user); + authCommand->setPass(m_pass); + + enqueueCommand(authCommand, true); + changeState(ReconnectingState); +} + +void AniDBUdpClient::doAuthenticate(bool success) +{ +qDebug() << "doAuthenticate init"; + if (success) + { +qDebug() << "success!"; + m_sessionId = authCommand->sessionId().toUtf8(); + changeState(ConnectedState); + } + else + { + changeState(ErrorState); + m_error = AuthenticationError; + } + + authenticateOnConnect = false; +} + +void AniDBUdpClient::logout() +{ + if (state() != ConnectedState) + // We are not logged in other states, don't try to logout again. + return; + + enqueueCommand(new RawCommand("LOGOUT"), true); + changeState(ReconnectingState); + m_sessionId = ""; +} + +void AniDBUdpClient::enqueueCommand(AbstractCommand *command, bool first) +{ + if (first) + { + commandQueue.push_front(command); + } + else + { + commandQueue.enqueue(command); + } + + leaveIdleState(); +} + +void AniDBUdpClient::sendNextCommand() +{ + if (commandQueue.isEmpty()) + { + enterIdleState(); + return; + } + + sendCommand(commandQueue.dequeue()); +} + +void AniDBUdpClient::sendCommand(AbstractCommand *command) +{ + Command cmdPair = command->rawCommand(); + QByteArray datagram = buildCmd(cmdPair.first, cmdPair.second); + + QByteArray commandId = nextCommandId(); + + datagram += datagram.contains(" ") ? "&" : " "; + datagram += "tag=" + commandId; + + if (m_sessionId.length()) + datagram += "&s=" + m_sessionId; + + if (command->waitForResult()) + { + sentCommands[commandId] = command; + } + else + { + command->deleteLater(); + } + +qDebug() << QString("SENDING datagram:\n\t%1\nto: %2 ([%3]:%4)") + .arg(datagram.constData()) + .arg(m_host) + .arg(m_hostAddress.toString()) + .arg(m_hostPort); + + socket->writeDatagram(datagram, m_hostAddress, m_hostPort); +} + +void AniDBUdpClient::readReplies() +{ + while (socket->hasPendingDatagrams()) + { + char data[UDP_DATAGRAM_MAXIMUM_SIZE]; + int size; + QHostAddress sender; + quint16 senderPort; + size = socket->readDatagram(data, UDP_DATAGRAM_MAXIMUM_SIZE, &sender, &senderPort); + + QByteArray tmp(data, size); + + if (sender != m_hostAddress) + { + qDebug() << QString("Recieved datagram from unknown host: %1 port: %2\nRaw datagram contents:%3\nDiscarding datagram.") + .arg(sender.toString()) + .arg(senderPort) + .arg(tmp.constData()); + continue; + } + + if (m_compression && tmp.mid(0, 2) == "00") + { +qDebug() << "COMPRESSED DATAGRAM = " << tmp; + tmp = qUncompress(tmp); + } + + QString reply = QString::fromUtf8(tmp); + + qDebug() << QString("Recieved datagram from [%1]:%2\nRaw datagram contents:%3") + .arg(m_host) + .arg(senderPort) + .arg(reply); + + QByteArray commandId = tmp.mid(0, 5); + + // Do not parse reply for commands not waiting for a reply. + if (!sentCommands.contains(commandId)) + { +qDebug() << QString("Command with id: %1 is not waiting for a reply, discarding").arg(commandId.constData()); + continue; + } +qDebug() << QString("Sending reply to command with id: %1").arg(commandId.constData()); + + // tag + space = 5 + 1 + QByteArray replyCodeText = tmp.mid(6, 3); + + bool ok; + int replyCodeInt = replyCodeText.toInt(&ok); + AbstractCommand::ReplyCode replyCode = AbstractCommand::UNKNOWN_REPLY; + if (ok) + { + replyCode = AbstractCommand::ReplyCode(replyCodeInt); + } + + AbstractCommand *cmd = sentCommands.take(commandId); + + // Requeue command and reauthenticate if not logged in. + if (replyCode == AbstractCommand::LOGIN_FIRST + || replyCode == AbstractCommand::INVALID_SESSION) + { +qDebug() << "LOGIN FIRST required, authing"; + enqueueCommand(cmd); + authenticate(); + continue; + } + // tag + space + replyCode + space = 5 + 1 + 3 + 1 + reply = reply.mid(10); + + cmd->setRawReply(replyCode, reply, this); + } +} + +void AniDBUdpClient::enterIdleState() +{ + if (m_idle) + return; +qDebug() << "Entering idle state"; + m_idle = true; + + switch (m_idlePolicy) + { + case DoNothingIdlePolicy: + case KeepAliveIdlePolicy: + commandTimer->stop(); + idleTimer->start(); + break; + case LogoutIdlePolicy: + default: + idleTimeout(); + break; + } + +} + +void AniDBUdpClient::leaveIdleState() +{ + // Don't do anything untill connected! + if (state() < ReconnectingState) + return; + + if (!m_idle) + return; +qDebug() << "Leaving idle state"; + m_idle = false; + + idleTimer->stop(); + + sendNextCommand(); + commandTimer->start(); +} + +void AniDBUdpClient::idleTimeout() +{ + logout(); +} + + +QByteArray AniDBUdpClient::buildCmd(const QString &cmd, const QVariantMap &args) +{ + QString result = cmd; + for (QVariantMap::const_iterator it = args.constBegin(); it != args.constEnd(); ++it) + { + if (!it.value().canConvert(QVariant::String)) + { + qWarning("Passed value cannot be converted to string!"); + continue; + } + + // The string version of bool is "true" or "false", but hte API expects 1 or 0 + QString value; + if (it.value().type() == QVariant::Bool) + { + value = it.value().toBool() ? "1" : "0"; + } + else + { + value = it.value().toString(); + } + + if (it == args.constBegin()) + result += QString(" %1=%2").arg(it.key(), value); + else + result += QString("&%1=%2").arg(it.key(), value); + } + return result.toUtf8(); +} + +void AniDBUdpClient::changeState(State newState) +{ + if (newState == m_state) + return; + + State oldState = m_state; + + // BEFORE statechange + switch(newState) + { + case DisconnectedState: + + if (m_sessionId.length()) + logout(); + + socket->close(); + m_sessionId = ""; + emit disconnected(); +// break; + case ErrorState: + commandTimer->stop(); + break; + default: + break; + } + + m_state = newState; + + // AFTER statechange + switch (newState) + { + case ReconnectingState: + leaveIdleState(); + break; + case ConnectedState: + // Do not wait for the timer floodInterval seconds for the first command. + emit connected(); + break; + default: + break; + } + +qDebug() << "State changed from" << oldState << "to" << newState; + emit stateChanged(newState, oldState); +} + +QByteArray AniDBUdpClient::nextCommandId(int len) +{ + static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; + static const int numChars = sizeof(chars) - 1; + + QByteArray result(len, '-'); + while (len--) + result[len] = chars[qrand() % numChars]; + +qDebug() << QString("Generated id %1").arg(result.constData()); + return result; +} diff --git a/lib/anidbudpclient/anidbudpclient.h b/lib/anidbudpclient/anidbudpclient.h new file mode 100644 index 0000000..28c681a --- /dev/null +++ b/lib/anidbudpclient/anidbudpclient.h @@ -0,0 +1,205 @@ +#ifndef ANIDBUDPCLIENT_H +#define ANIDBUDPCLIENT_H + +#include "anidbudpclient_global.h" +#include +#include +#include +#include +#include +#include + +#include "authcommand.h" + +class QUdpSocket; +class QTimer; + +class AbstractCommand; +class AuthCommand; + + +#define CLIENT_NAME "anidbudpclient" +#define CLIENT_VERSION 0x000001 +#define PROTOCOL_VERSION 3 + +class ANIDBUDPCLIENTSHARED_EXPORT AniDBUdpClient : public QObject +{ + Q_OBJECT + Q_ENUMS(State Error IdlePolicy AbstractCommand::ReplyCode); + + Q_PROPERTY(QString host READ host WRITE setHost); + Q_PROPERTY(quint16 hostPort READ hostPort WRITE setHostPort); + Q_PROPERTY(quint16 localPort READ localPort WRITE setLocalPort); + + Q_PROPERTY(QString user READ user WRITE setUser); + Q_PROPERTY(QString pass READ pass WRITE setPass); + + /* + Send commands in \interval seconds intervals + */ + Q_PROPERTY(int floodInterval READ floodInterval WRITE setFloodInterval); + + Q_PROPERTY(IdlePolicy idlePolicy READ idlePolicy WRITE setIdlePolicy); + Q_PROPERTY(State state READ state); + Q_PROPERTY(Error error READ error); + Q_PROPERTY(QString errorString READ errorString); + +public: + static const QByteArray clientName; + static const int clientVersion; + static const int protocolVersion; + + enum State + { + ErrorState = -1, + DisconnectedState, + ConnectingState, + ReconnectingState, + ConnectedState, + }; + + enum Error + { + NoError, + BindError, + HostLookupError, + HostUnreachableError, + AuthenticationError, + BannedError, + UnknownError, + }; + + enum IdlePolicy + { + DoNothingIdlePolicy, + LogoutIdlePolicy, + KeepAliveIdlePolicy, + }; + + AniDBUdpClient(QObject *parent = 0); + virtual ~AniDBUdpClient(); + + // ------------------ Properties ------------------ + QString host() const; + void setHost(const QString &host, quint16 port = 0); + quint16 hostPort() const; + void setHostPort(quint16 port); + quint16 localPort() const; + void setLocalPort(quint16 port); + + QString user() const; + void setUser(const QString &user); + QString pass() const; + void setPass(const QString &user); + + bool compression() const; + void setCompression(bool compress); + + int floodInterval() const; + void setFloodInterval(int interval); + + IdlePolicy idlePolicy() const; + void setIdlePolicy(IdlePolicy policy); + + State state() const; + Error error() const; + QString errorString() const; + + bool isIdle(); + + // ---------------- END Properties ---------------- + + void clearCommandQueue(); + +public slots: + void connect(); + + /* + Disconnect from host. + If \graceful is true send all enququed messages first. + */ + void disconnect(bool graceful = false); + + void authenticate(); + + void send(AbstractCommand *command); + void sendRaw(QByteArray command); + +signals: + void connected(); + void disconnected(); + + void pong(); + void uptime(); + + void stateChanged(State newState, State oldState); + +private slots: + void lookedUp(QHostInfo hostInfo); + void doConnect(); + void doAuthenticate(bool success); + + void logout(); + + + void enqueueCommand(AbstractCommand *command, bool first = false); + void sendNextCommand(); + void sendCommand(AbstractCommand *command); + + void readReplies(); + + void enterIdleState(); + void leaveIdleState(); + + void idleTimeout(); + +private: + QByteArray buildCmd(const QString &cmd, const QVariantMap &args); + + void changeState(State newState); + QByteArray nextCommandId(int len = 5); + + QTimer *commandTimer; + QTimer *idleTimer; + QTimer *replyTimeoutTimer; + + QQueue commandQueue; + QMap sentCommands; + QUdpSocket *socket; + + + + // Connection params + QString m_host; + QHostAddress m_hostAddress; + quint16 m_hostPort; + quint16 m_localPort; + + int m_floodInterval; + + // Auth params + QString m_user; + QString m_pass; + + bool m_compression; + + QByteArray m_sessionId; + + // Misc params + IdlePolicy m_idlePolicy; + State m_state; + Error m_error; + QString m_errorString; + + bool disconnecting; + bool m_idle; + + AuthCommand *authCommand; + bool authenticateOnConnect; + + + static const int UDP_DATAGRAM_MAXIMUM_SIZE = 1400; + static const int UDP_API_INACTIVITY_LOGOUT = 30 * 60; +}; + +#endif // ANIDBUDPCLIENT_H diff --git a/lib/anidbudpclient/anidbudpclient.pri b/lib/anidbudpclient/anidbudpclient.pri new file mode 100644 index 0000000..8af8ec6 --- /dev/null +++ b/lib/anidbudpclient/anidbudpclient.pri @@ -0,0 +1,5 @@ +QT *= network +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +LIBS += -lanidbudpclient +LIBS += -L$$DESTDIR diff --git a/lib/anidbudpclient/anidbudpclient.pro b/lib/anidbudpclient/anidbudpclient.pro new file mode 100644 index 0000000..75e6829 --- /dev/null +++ b/lib/anidbudpclient/anidbudpclient.pro @@ -0,0 +1,23 @@ +# ------------------------------------------------- +# Project created by QtCreator 2009-03-22T14:53:52 +# ------------------------------------------------- +QT += network +QT -= gui +TEMPLATE = lib +TARGET = anidbudpclient +DESTDIR = ../../build +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +QT *= network +DEFINES += ANIDBUDPCLIENT_LIBRARY +SOURCES += anidbudpclient.cpp \ + abstractcommand.cpp \ + authcommand.cpp \ + rawcommand.cpp \ + mylistaddcommand.cpp +HEADERS += anidbudpclient.h \ + anidbudpclient_global.h \ + abstractcommand.h \ + authcommand.h \ + rawcommand.h \ + mylistaddcommand.h diff --git a/lib/anidbudpclient/anidbudpclient_global.h b/lib/anidbudpclient/anidbudpclient_global.h new file mode 100644 index 0000000..2b578d2 --- /dev/null +++ b/lib/anidbudpclient/anidbudpclient_global.h @@ -0,0 +1,12 @@ +#ifndef ANIDBUDPCLIENT_GLOBAL_H +#define ANIDBUDPCLIENT_GLOBAL_H + +#include + +#if defined(ANIDBUDPCLIENT_LIBRARY) +# define ANIDBUDPCLIENTSHARED_EXPORT Q_DECL_EXPORT +#else +# define ANIDBUDPCLIENTSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // ANIDBUDPCLIENT_GLOBAL_H diff --git a/lib/anidbudpclient/authcommand.cpp b/lib/anidbudpclient/authcommand.cpp new file mode 100644 index 0000000..871aba6 --- /dev/null +++ b/lib/anidbudpclient/authcommand.cpp @@ -0,0 +1,73 @@ +#include "authcommand.h" + +#include "anidbudpclient.h" + +AuthCommand::AuthCommand(QObject *parent) : AbstractCommand(parent) +{ + m_compression = false; +} + +AuthCommand::AuthCommand(QString user, QString pass, QObject *parent) : AbstractCommand(parent) +{ + m_user = user; + m_pass = pass; +} + +void AuthCommand::setUser(const QString &user) +{ + m_user = user; +} + +void AuthCommand::setPass(const QString &pass) +{ + m_pass = pass; +} + +void AuthCommand::setCompression(bool compress) +{ + m_compression = compress; +} + +bool AuthCommand::waitForResult() const +{ + return true; +} + +Command AuthCommand::rawCommand() const +{ + Command command; + + command.first = "AUTH"; + + command.second["user"] = m_user; + command.second["pass"] = m_pass; + command.second["protover"] = AniDBUdpClient::protocolVersion; + command.second["client"] = AniDBUdpClient::clientName.constData(); + command.second["clientver"] = AniDBUdpClient::clientVersion; + command.second["enc"] = "UTF8"; + command.second["comp"] = m_compression; + return command; +} + +QString AuthCommand::sessionId() const +{ + return m_sessionId; +} + +void AuthCommand::setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client) +{ +qDebug() << replyCode; + AbstractCommand::setRawReply(replyCode, reply, client); + + switch(replyCode) + { + case LOGIN_ACCEPTED: + case LOGIN_ACCEPTED_NEW_VER: + m_sessionId = m_rawReply.mid(0, m_rawReply.indexOf(" ")); + emit replyReady(true); + break; + default: +qDebug() << "ERROR CODE: " << replyCode; + emit replyReady(false); + } +} diff --git a/lib/anidbudpclient/authcommand.h b/lib/anidbudpclient/authcommand.h new file mode 100644 index 0000000..ab88016 --- /dev/null +++ b/lib/anidbudpclient/authcommand.h @@ -0,0 +1,36 @@ +#ifndef AUTHCOMMAND_H +#define AUTHCOMMAND_H + +#include "abstractcommand.h" + +class AuthCommand : public AbstractCommand +{ + Q_OBJECT + +public: + AuthCommand(QObject *parent = 0); + AuthCommand(QString user, QString pass, QObject *parent = 0); + + void setUser(const QString &user); + void setPass(const QString &pass); + + void setCompression(bool compress); + + bool waitForResult() const; + + Command rawCommand() const; + QString sessionId() const; + + void setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client); + + + +private: + QString m_user; + QString m_pass; + QString m_sessionId; + + bool m_compression; +}; + +#endif // AUTHCOMMAND_H diff --git a/lib/anidbudpclient/mylistaddcommand.cpp b/lib/anidbudpclient/mylistaddcommand.cpp new file mode 100644 index 0000000..e8fa659 --- /dev/null +++ b/lib/anidbudpclient/mylistaddcommand.cpp @@ -0,0 +1,163 @@ +#include "mylistaddcommand.h" + +#include +#include +#include +#include + +#include "anidbudpclient.h" + +MylistAddCommand::MylistAddCommand(QString file, QObject *parent) : AbstractCommand(parent) +{ + m_file = file; + m_size = QFileInfo(file).size(); + mylistId = 0; + + connect(&futureWatcher, SIGNAL(finished()), this, SLOT(completeHash())); +} + +QString MylistAddCommand::file() const +{ + return m_file; +} + +QByteArray MylistAddCommand::ed2kHash() const +{ + return m_ed2k; +} + +int MylistAddCommand::fileSize() const +{ + return m_size; +} + +bool MylistAddCommand::markWatched() const +{ + return m_markWatched; +} + +void MylistAddCommand::setMarkWatched(bool mark) +{ + m_markWatched = mark; +} + +bool MylistAddCommand::waitForResult() const +{ + return true; +} + +Command MylistAddCommand::rawCommand() const +{ + Command command; + switch (mylistId) + { + case 0: + command.first = "MYLIST"; + command.second["size"] = m_size; + command.second["ed2k"] = m_ed2k.constData(); + return command; + break; + case -1: + command.first = "MYLISTADD"; + command.second["size"] = m_size; + command.second["ed2k"] = m_ed2k.constData(); + command.second["state"] = 1; + command.second["viewed"] = m_markWatched; + return command; + break; + default: + command.first = "MYLISTADD"; + command.second["lid"] = mylistId; + command.second["viewed"] = m_markWatched; + command.second["edit"] = 1; + return command; + break; + } +} + +void MylistAddCommand::setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client) +{ + AbstractCommand::setRawReply(replyCode, reply, client); + + switch (mylistId) + { + case 0: + switch(replyCode) + { + case MYLIST: + { + QString reply = m_rawReply.mid(m_rawReply.indexOf("\n")); + QStringList parts = reply.split('|', QString::KeepEmptyParts); +qDebug() << "PARTS" << parts; + mylistId = parts[0].toInt(); +qDebug() << "Mylist ID: " << mylistId; + if (!mylistId) + { +qDebug() << "FAILED to read Mylist ID"; + emit replyReady(false); + } + client->send(this); + } + break; + default: + mylistId = -1; + client->send(this); + break; + } + break; + default: + switch(replyCode) + { + case MYLIST_ENTRY_ADDED: + case MYLIST_ENTRY_EDITED: + case FILE_ALREADY_IN_MYLIST: + emit replyReady(true); + break; + default: + emit replyReady(false); + break; + } + break; + } + + +} + +void MylistAddCommand::hash() +{ + future = QtConcurrent::run(this, &MylistAddCommand::doHash, m_file); + futureWatcher.setFuture(future); +} + +void MylistAddCommand::completeHash() +{ + if (!future.isFinished()) + { +qDebug() << "WTF?"; + return; + } + m_ed2k = QByteArray(future); + emit hashComplete(); +} + +QByteArray MylistAddCommand::doHash(QString file) +{ +qDebug() << "hash thread init"; + QFile f(file); + if (!f.open(QIODevice::ReadOnly)) + return QByteArray(); + + QCryptographicHash ed2k(QCryptographicHash::Md4); + char *data = new char[ED2K_PART_SIZE]; + int size; + while (!f.atEnd()) + { + size = f.read(data, ED2K_PART_SIZE); + ed2k.addData(QCryptographicHash::hash(QByteArray(data, size), QCryptographicHash::Md4)); +qDebug() << "hashing..."; + } + f.close(); + delete[] data; +qDebug() << "hashing... complete!"; + return ed2k.result().toHex(); +} diff --git a/lib/anidbudpclient/mylistaddcommand.h b/lib/anidbudpclient/mylistaddcommand.h new file mode 100644 index 0000000..122921f --- /dev/null +++ b/lib/anidbudpclient/mylistaddcommand.h @@ -0,0 +1,56 @@ +#ifndef MYLISTADDCOMMAND_H +#define MYLISTADDCOMMAND_H + +#include "anidbudpclient_global.h" +#include "abstractcommand.h" + +#include +#include + + +class ANIDBUDPCLIENTSHARED_EXPORT MylistAddCommand : public AbstractCommand +{ + Q_OBJECT + +public: + MylistAddCommand(QString file, QObject *parent = 0); + + QString file() const; + QByteArray ed2kHash() const; + int fileSize() const; + + bool markWatched() const; + void setMarkWatched(bool mark); + + + bool waitForResult() const; + + Command rawCommand() const; + + void setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client); + + void hash(); + +signals: + void hashComplete(); + +private slots: + void completeHash(); + +private: + QByteArray doHash(QString file); + QFuture future; + QFutureWatcher futureWatcher; + + bool m_markWatched; + + int m_size; + QByteArray m_ed2k; + QString m_file; + + int mylistId; + + static const qint64 ED2K_PART_SIZE = 9728000; +}; + +#endif // MYLISTADDCOMMAND_H diff --git a/lib/anidbudpclient/rawcommand.cpp b/lib/anidbudpclient/rawcommand.cpp new file mode 100644 index 0000000..2b3ebf9 --- /dev/null +++ b/lib/anidbudpclient/rawcommand.cpp @@ -0,0 +1,11 @@ +#include "rawcommand.h" + +RawCommand::RawCommand(const QString &command, QObject *parent) : AbstractCommand(parent) +{ + m_command = command; +} + +Command RawCommand::rawCommand() const +{ + return Command(m_command, QVariantMap()); +} diff --git a/lib/anidbudpclient/rawcommand.h b/lib/anidbudpclient/rawcommand.h new file mode 100644 index 0000000..990ffa4 --- /dev/null +++ b/lib/anidbudpclient/rawcommand.h @@ -0,0 +1,20 @@ +#ifndef RAWCOMMAND_H +#define RAWCOMMAND_H + +#include "anidbudpclient_global.h" +#include "abstractcommand.h" + +class ANIDBUDPCLIENTSHARED_EXPORT RawCommand : public AbstractCommand +{ + Q_OBJECT + +public: + + RawCommand(const QString &command, QObject *parent = 0); + + Command rawCommand() const; +private: + QString m_command; +}; + +#endif // RAWCOMMAND_H diff --git a/lib/browserplugin-solution/INSTALL.TXT b/lib/browserplugin-solution/INSTALL.TXT new file mode 100644 index 0000000..3b6c155 --- /dev/null +++ b/lib/browserplugin-solution/INSTALL.TXT @@ -0,0 +1,182 @@ +INSTALLATION INSTRUCTIONS + +These instructions refer to the package you are installing as +some-package.tar.gz or some-package.zip. The .zip file is intended for use +on Windows. + +The directory you choose for the installation will be referred to as +your-install-dir. + +Note to Qt Visual Studio Integration users: In the instructions below, +instead of building from command line with nmake, you can use the menu +command 'Qt->Open Solution from .pro file' on the .pro files in the +example and plugin directories, and then build from within Visual +Studio. + +Unpacking and installation +-------------------------- + +1. Unpack the archive if you have not done so already. + + On Unix and Mac OS X (in a terminal window): + + cd your-install-dir + gunzip some-package.tar.gz + tar xvf some-package.tar + + This creates the subdirectory some-package containing the files. + + On Windows: + + Unpack the .zip archive by right-clicking it in explorer and + choosing "Extract All...". If your version of Windows does not + have zip support, you can use the infozip tools available + from: + + ftp://ftp.trolltech.com/util/infozip.exe + + If you are using the infozip tools (in a command prompt window): + + cd your-install-dir + unzip some-package.zip + +2. Enter the package directory and configure the package: + + cd some-package + qmake + + The qmake command will prompt you in some cases for further + information. Answer these questions and carefully read the license text + before accepting the license conditions. The package can't be used if + you don't accept the license conditions. + +3. To build the examples (for Qt Solutions components) or the application + (for Qt Solutions tools): + + make + + Or if you are using Microsoft Visual C++: + + nmake + + The example programs are located in the example or examples + subdirectory. + + For Qt Solutions plugins (e.g. image formats), both debug and + release versions of the plugin are built by default when + appropriate, since in some cases the release Qt library will not + load a debug plugin, and vice versa. The plugins are automatically + installed into the plugins directory of your Qt installation. + + Plugins may be built statically, i.e. as a library that will be + linked into your application executable, and so will not need to + be redistributed as a separate plugin DLL to end users. Static + building is required if Qt itself is built statically. To do it, + just add "static" to the CONFIG variable in the plugin/plugin.pro + file before building. Refer to the "Static Plugins" section in the + chapter "How to Create Qt Plugins" for explanation of how to use a + static plugin in your application. The source code of the example + program(s) will also typically contain the relevant instructions + as comments. + +4. Some of the widget components are provided with plugins for Qt + Designer. To build and install the plugin, cd into the + some-package/plugin directory and give the commands + + qmake + make [or nmake if your are using Microsoft Visual Studio] + + Restart Qt Designer to make it load the new widget plugin. + + Note: If you are using the built-in Qt Designer from the Qt Visual + Studio Integration, you will need to manually copy the plugin DLL + file, i.e. copy + %QTDIR%\plugins\designer\some-component.dll + to the Qt Visual Studio Integration plugin path, typically: + C:\Program Files\Trolltech\Qt VS Integration\plugins + + Note: If you for some reason are using a Qt Designer that is built + in debug mode, you will need to build the plugin in debug mode + also. Edit the file plugin.pro in the plugin directory, changing + 'release' to 'debug' in the CONFIG line, before running qmake. + + +Using a component in your project +--------------------------------- + +The directory your-install-dir/some-package/src includes all the +source code for the component. To use this component in your project: + +1. Add the following line + + include(your-install-dir/some-package/src/some-package.pri) + + to the project's .pro file. + +2. Run qmake on the project's .pro file. + +This adds the package's sources and headers to the SOURCES and HEADERS +qmake variables respectively, and update INCLUDEPATH to contain the +package's src directory. Additionally, the .pri file may include some +dependencies needed by the package. + +To include a header file from the package in your sources, you can now +simply use: + + #include + +or alternatively, in Qt 4 style: + + #include + + +Install documentation +--------------------- + +The HTML documentation for the package's classes is located in the +your-install-dir/some-package/doc/html/index.html. You can open this +file with any web browser. + +To install the documentation into Qt Assistant (for Qt version 4.4 and +later): + +1. In Assistant, open the Edit->Preferences dialog and choose the + Documentation tab. Click the Add... button and select the file + your-install-dir/some-package/doc/html/some-package.qch + +For Qt versions prior to 4.4, do instead the following: + +1. The directory your-install-dir/some-package/doc/html contains a + file called some-package.dcf. Execute the following commands in a + shell, command prompt or terminal window: + + cd your-install-dir/some-package/doc/html/ + assistant -addContentFile some-package.dcf + +The next time you start Qt Assistant, you can access the package's +documentation. + + +Removing the documentation from assistant +----------------------------------------- + +If you want to remove the documentation from Qt Assistant, do as +follows, for Qt version 4.4 and later: + +1. In Assistant, open the Edit->Preferences dialog and choose the + Documentation tab. In the list of Registered Documentation, select + the item com.trolltech.qtsolutions.some-package_version, and click + the Remove button. + +For Qt versions prior to 4.4, do instead the following: + +1. The directory your-install-dir/some-package/doc/html contains a + file called some-package.dcf. Execute the following commands in a + shell, command prompt or terminal window: + + cd your-install-dir/some-package/doc/html/ + assistant -removeContentFile some-package.dcf + + +Enjoy! :) +- The Qt Solutions Team. diff --git a/lib/browserplugin-solution/LICENSE.GPL b/lib/browserplugin-solution/LICENSE.GPL new file mode 100644 index 0000000..7daa506 --- /dev/null +++ b/lib/browserplugin-solution/LICENSE.GPL @@ -0,0 +1,349 @@ +The Qt Solutions are copyright (C) 2003-2005 Trolltech AS + +You may use, distribute and copy the Qt Solution(s) under the terms of +GNU General Public License version 2, which is displayed below. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- diff --git a/lib/browserplugin-solution/Makefile b/lib/browserplugin-solution/Makefile new file mode 100644 index 0000000..74140da --- /dev/null +++ b/lib/browserplugin-solution/Makefile @@ -0,0 +1,126 @@ +############################################################################# +# Makefile for building: browserplugin-solution +# Generated by qmake (2.01a) (Qt 4.5.0) on: Sun Mar 22 15:03:18 2009 +# Project: browserplugin-solution.pro +# Template: app +# Command: c:\Qt\4.5.0\bin\qmake.exe -spec c:\Qt\4.5.0\mkspecs\win32-msvc2008 -win32 CONFIG+=debug_and_release -o Makefile browserplugin-solution.pro +############################################################################# + +####### Compiler, tools and options + +CC = cl +CXX = cl +DEFINES = -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT +CFLAGS = -nologo -Zm200 -Zc:wchar_t- -MP5 $(DEFINES) +CXXFLAGS = -nologo -Zm200 -Zc:wchar_t- -MP5 $(DEFINES) +INCPATH = -I"c:\Qt\4.5.0\mkspecs\win32-msvc2008" +LINK = link +LFLAGS = /NOLOGO +LIBS = +QMAKE = c:\Qt\4.5.0\bin\qmake.exe +IDC = c:\Qt\4.5.0\bin\idc.exe +IDL = midl +ZIP = zip -r -9 +DEF_FILE = +RES_FILE = +COPY = copy /y +COPY_FILE = $(COPY) +COPY_DIR = xcopy /s /q /y /i +DEL_FILE = del +DEL_DIR = rmdir +MOVE = move +CHK_DIR_EXISTS= if not exist +MKDIR = mkdir +INSTALL_FILE = $(COPY_FILE) +INSTALL_PROGRAM = $(COPY_FILE) +INSTALL_DIR = $(COPY_DIR) + +####### Output directory + +OBJECTS_DIR = . + +####### Files + +SOURCES = +OBJECTS = +DIST = +QMAKE_TARGET = browserplugin-solution +DESTDIR = #avoid trailing-slash linebreak +TARGET = browserplugin-solution.exe +DESTDIR_TARGET = browserplugin-solution.exe + +####### Implicit rules + +.SUFFIXES: .c .cpp .cc .cxx + +{.}.cpp{}.obj:: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<< + $< +<< + +{.}.cc{}.obj:: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<< + $< +<< + +{.}.cxx{}.obj:: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<< + $< +<< + +{.}.c{}.obj:: + $(CC) -c $(CFLAGS) $(INCPATH) -Fo @<< + $< +<< + +####### Build rules + +first: all +all: Makefile $(DESTDIR_TARGET) + +$(DESTDIR_TARGET): $(OBJECTS) + $(LINK) $(LFLAGS) /OUT:$(DESTDIR_TARGET) @<< + $(OBJECTS) $(LIBS) +<< + + +Makefile: browserplugin-solution.pro c:\Qt\4.5.0\mkspecs\win32-msvc2008\qmake.conf c:\Qt\4.5.0\mkspecs\qconfig.pri \ + c:\Qt\4.5.0\mkspecs\features\qt_functions.prf \ + c:\Qt\4.5.0\mkspecs\features\qt_config.prf \ + c:\Qt\4.5.0\mkspecs\features\exclusive_builds.prf \ + c:\Qt\4.5.0\mkspecs\features\default_pre.prf \ + c:\Qt\4.5.0\mkspecs\features\win32\default_pre.prf + $(QMAKE) -spec c:\Qt\4.5.0\mkspecs\win32-msvc2008 -win32 CONFIG+=debug_and_release -o Makefile browserplugin-solution.pro +c:\Qt\4.5.0\mkspecs\qconfig.pri: +c:\Qt\4.5.0\mkspecs\features\qt_functions.prf: +c:\Qt\4.5.0\mkspecs\features\qt_config.prf: +c:\Qt\4.5.0\mkspecs\features\exclusive_builds.prf: +c:\Qt\4.5.0\mkspecs\features\default_pre.prf: +c:\Qt\4.5.0\mkspecs\features\win32\default_pre.prf: +qmake: FORCE + @$(QMAKE) -spec c:\Qt\4.5.0\mkspecs\win32-msvc2008 -win32 CONFIG+=debug_and_release -o Makefile browserplugin-solution.pro + +dist: + $(ZIP) browserplugin-solution.zip $(SOURCES) $(DIST) ..\..\aniplayer.pro c:\Qt\4.5.0\mkspecs\qconfig.pri c:\Qt\4.5.0\mkspecs\features\qt_functions.prf c:\Qt\4.5.0\mkspecs\features\qt_config.prf c:\Qt\4.5.0\mkspecs\features\exclusive_builds.prf c:\Qt\4.5.0\mkspecs\features\default_pre.prf c:\Qt\4.5.0\mkspecs\features\win32\default_pre.prf + +clean: compiler_clean + -$(DEL_FILE) browserplugin-solution.exp browserplugin-solution.pdb browserplugin-solution.ilk vc*.pdb vc*.idb + +distclean: clean + -$(DEL_FILE) $(DESTDIR_TARGET) + -$(DEL_FILE) Makefile + +compiler_clean: + + + +####### Compile + +####### Install + +install: FORCE + +uninstall: FORCE + +FORCE: + diff --git a/lib/browserplugin-solution/README.TXT b/lib/browserplugin-solution/README.TXT new file mode 100644 index 0000000..df36182 --- /dev/null +++ b/lib/browserplugin-solution/README.TXT @@ -0,0 +1,7 @@ +Browser Plugin v2.3 + +The QtBrowserPlugin solution is useful for implementing plugins +for web browser. + + + diff --git a/lib/browserplugin-solution/doc/html/classic.css b/lib/browserplugin-solution/doc/html/classic.css new file mode 100644 index 0000000..0ff9e7d --- /dev/null +++ b/lib/browserplugin-solution/doc/html/classic.css @@ -0,0 +1,131 @@ +h3.fn,span.fn +{ + margin-left: 1cm; + text-indent: -1cm; +} + +a:link +{ + color: #004faf; + text-decoration: none +} + +a:visited +{ + color: #672967; + text-decoration: none +} + +a.obsolete +{ + color: #661100; + text-decoration: none +} + +a.compat +{ + color: #661100; + text-decoration: none +} + +a.obsolete:visited +{ + color: #995500; + text-decoration: none +} + +a.compat:visited +{ + color: #995500; + text-decoration: none +} + +td.postheader +{ + font-family: sans-serif +} + +tr.address +{ + font-family: sans-serif +} + +body +{ + background: #ffffff; + color: black +} + +table tr.odd { + background: #f0f0f0; + color: black; +} + +table tr.even { + background: #e4e4e4; + color: black; +} + +table.annotated th { + padding: 3px; + text-align: left +} + +table.annotated td { + padding: 3px; +} + +table tr pre +{ + padding-top: none; + padding-bottom: none; + padding-left: none; + padding-right: none; + border: none; + background: none +} + +tr.qt-style +{ + background: #a2c511; + color: black +} + +body pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +span.preprocessor, span.preprocessor a +{ + color: darkblue; +} + +span.comment +{ + color: darkred; + font-style: italic +} + +span.string,span.char +{ + color: darkgreen; +} + +.title +{ + text-align: center +} + +.subtitle +{ + font-size: 0.8em +} + +.small-subtitle +{ + font-size: 0.65em +} diff --git a/lib/browserplugin-solution/doc/html/developingplugins.html b/lib/browserplugin-solution/doc/html/developingplugins.html new file mode 100644 index 0000000..0a5aba5 --- /dev/null +++ b/lib/browserplugin-solution/doc/html/developingplugins.html @@ -0,0 +1,231 @@ + + + + + + Developing Plugins + + + + + + + +
  Home

Developing Plugins
+

+

The QtBrowserPlugin solution makes it easy to write browser plugins that can be used in Netscape, Mozilla FireFox, Opera, and any other web browser supporting the "npruntime" API:

+

http://www.mozilla.org/projects/plugins/ http://www.mozilla.org/projects/plugins/npruntime.html

+

Current versions of Microsoft Internet Explorer do not support this API. However, you can use the ActiveQt framework to compile a single plugin library that works with all web browsers.

+ + +

Implementing plugins

+

Since any QWidget or QObject subclass can be turned into a plugin with little effort it is usually easiest to do the development as a stand-alone Qt application - debugging plugins is cumbersome.

+

Make sure that the subclasses you want to export use the Q_OBJECT macro and provide a default constructor. Use the Q_CLASSINFO macro to specify a list of MIME types each of your classes supports, and export the classes through the QtNPFactory macros:

+
 QTNPFACTORY_BEGIN("Qt-based Graph Plugin", "A Qt-based LiveConnected plug-in that graphs numeric data");
+     QTNPCLASS(Graph)
+ QTNPFACTORY_END()
+

Include the qtbrowserplugin.pri in your .pro file, and regenerate the makefile with qmake. The resulting makefile will generate a shared library with a file name starting with "np" - this is required by all browsers to recognize the library as a plugin.

+ +

Windows specific notes

+

On Windows it is required to link a version resource into the plugin library. To do that, create an .rc file (a plain-text file) and add it to the RC_FILE variable of your project. The .rc file needs to contain a version description like here:

+
 1 VERSIONINFO
+  FILEVERSION 1,0,0,1
+  PRODUCTVERSION 1,0,0,1
+  FILEFLAGSMASK 0x3fL
+ #ifdef _DEBUG
+  FILEFLAGS 0x1L
+ #else
+  FILEFLAGS 0x0L
+ #endif
+  FILEOS 0x4L
+  FILETYPE 0x2L
+  FILESUBTYPE 0x0L
+ BEGIN
+     BLOCK "StringFileInfo"
+     BEGIN
+         BLOCK "040904e4"
+         BEGIN
+             VALUE "Comments", "\0"
+             VALUE "CompanyName", "Trolltech\0"
+             VALUE "FileDescription", "grapher\0"
+             VALUE "FileExtents", "g1n\0"
+             VALUE "FileOpenName", "Graphable data (*.g1n)\0"
+             VALUE "FileVersion", "1, 0, 0, 1\0"
+             VALUE "InternalName", "grapher\0"
+             VALUE "LegalCopyright", "Copyright  1997 Trolltech ASA\0"
+             VALUE "LegalTrademarks", "\0"
+             VALUE "MIMEType", "application/x-graphable\0"
+             VALUE "OriginalFilename", "grapher.dll\0"
+             VALUE "PrivateBuild", "\0"
+             VALUE "ProductName", "Trolltech grapher\0"
+             VALUE "ProductVersion", "1, 0, 0, 1\0"
+             VALUE "SpecialBuild", "\0"
+         END
+     END
+     BLOCK "VarFileInfo"
+     BEGIN
+         VALUE "Translation", 0x409, 1252
+     END
+ END
+ +

Enabling ActiveX support

+

To build a plugin project with ActiveX support, use ActiveQt's QAxServer module by adding the following line to your project:

+

CONFIG += qaxserver

+

Also, add the following line to your resource file

+

1 TYPELIB "thisfile.rc"

+

In your plugin code, use Q_CLASSINFO and the QAxFactory macros as usual.

+

When you build the plugin, then ActiveQt will perform the build steps required to turn the plugin library into an ActiveX control server which provides your plugin classes not only to browsers supporting the npruntime API, but also to browsers supporting ActiveX controls (i.e. Internet Explorer).

+

However, not that calling QtNPBindable APIs will not do anything when the browser does not support the npruntime API. In some cases, QAxBindable provides equivalent APIs (i.e. for reading incoming data).

+ +

Unix specific notes

+

On Unix/Linux, QtBrowserPlugin uses the XEmbed protocol. This is a fairly recent addition to the NPP plugin API. At the time of writing, it is not supported by the Opera and Konqueror browsers. Firefox and other Mozilla/Gecko-based browsers do support it.

+

Update: Opera version 9.50 will support the XEmbed protocol. QtBrowserPlugin is tested successfully with the beta release of Opera 9.50. One known issue: Opera does not automatically register the extension part of the MIME description. If required, work around by adding it manually in the Preferences->Advanced->Download dialog. (e.g. add "g1n" to "application/x-graphable" to make the grapher example work).

+ +

Known Issues on Unix/Linux

+

There are two known issues that may cause the plugin to crash on initialization, possibly taking the browser down with it:

+
    +
  • Double initialization of glib/threading. This is fixed in Qt 4.3.1 and later.
  • +
  • Symbol clash with other instances of the Qt libraries. Although Firefox/Gecko itself does not use Qt, it is not uncommon on Linux that another plugin or style engine is present that will load the Qt dynamic libraries. When another plugin based on the Qt 4 dynamically libraries are added, some symbol clashes between the different Qt instances will occur, leading to a crash. With Qt 4.4 and later, this is easily worked around by configuring your Qt build to use a separate namespace. Just add the -qtnamespace=SomeNamespace option to configure. For Qt 4.3, it is possible to work around this by building the Qt 4 library statically, and link them into the plugin executable with a special linker option. See qtbrowserplugin.pri for details.
  • +
+

In addition, Firefox may emit this warning when initializing the plugin: _XEMBED_INFO property has wrong type. This is fixed in Qt 4.3.1 and later.

+ +

Mac OSX specific notes

+

To build a browser plugin on Mac, two plain-text resource files are needed: an Info.plist file and a .r file. To create these files, it is easiest to use the ones provided with the QtBrowserPlugin examples as templates, editing as necessary. Then add them to your project (.pro file) like this:

+
    QMAKE_INFO_PLIST = Info.plist
+    REZ_FILES += grapher.r
+    rsrc_files.files = grapher.rsrc
+    rsrc_files.path = Contents/Resources
+    QMAKE_BUNDLE_DATA += rsrc_files
+ +

Known Issues on Mac

+
    +
  • After navigating away from the webpage with the plugin, and then back again, the plugin no longer shows up or runs. No workaround currently known.
  • +
  • Some painting issues. Fixed in Qt 4.3.1 and later.
  • +
+ +

Installing and using Plugins

+

Most browsers provide a UI to display all loaded plugins. Use this functionality to diagnose problems.

+

The plugin will need to load the Qt libraries at runtime (unless they are statically linked into the plugin). Hence, the required Qt dynamic libraries (at least QtCore, QtGui, and QtNetwork) must be located in a directory which the system searches for DLLs. This may or may not include the directory where the plugin itself is located, depending on the OS and browser.

+

Windows, Netscape-style browsers: To install the plugin, copy the plugin library in the "plugins" directory of the browser. See src/qtbrowserplugin.pri for some typical paths.

+

Windows, Internet Explorer: The Makefile generated by qmake by default runs the necessary commands to register the plugin as an ActiveX server (if CONFIG includes qaxserver). To unregister, use the following command:

+
 c:\Qt-x.y.z\bin\idc.exe path\to\myplugin.dll /unregserver
+

Mac: The build will result in a directory called myplugin.plugin. To install, copy this directory with all contents to /Library/Internet Plugins.

+

Unix: Copy the file myplugin.so to the browser or system plugin directory, typically /usr/lib/browser-plugins. The path to the Qt libraries may be set in the LD_LIBRARY_PATH environment variable of the browser process.

+ +

Using the plugin in HTML

+

Different browser support different embedding tags, but the following should work with Netscape, FireFox, Opera and Internet Explorer (if the plugin has been compiled as an ActiveX server as well).

+ +

Object with data:

+

Objects can be initialized with a data file, which will be delivered to the plugin at some point after plugin creation to the plugin through the QtNPBindable::readData() virtual function.

+
 <object type="application/x-graphable" data="graph.g1n" width=50% height=300>
+ Plugin not installed!
+ </object>
+
 <object data="http://doc.trolltech.com/3.3/graph.g1n" width=50% height=300>
+ Plugin not installed!
+ </object>
+

Note that some browsers will not display or immediately unload the plugin if the data file does not exist, while other browsers will display the plugin without ever calling readData().

+ +

Objects without data:

+
 <embed type="trivial/very" [property]=[value]>
+ +

Not working with all browsers

+
    +
  • <embed src=...> Internet Explorer does not receive data
  • +
  • <object type=...> Opera does not display plugin without data attribute
  • +
  • <object classid=...> FireFox and Netscape don't display
  • +
  • <object type=... data=...><param ...> Internet Explorer does not receive data
  • +
+

For additional information, see http://devedge-temp.mozilla.org/library/manuals

+ +

Scripting

+

Plugins embedded into browsers that support the respecive NPAPI extensions as well as ActiveX controls can be accessed from JavaScript in the HTML page.

+
   <object id="ScriptableObject" TYPE=trivial/very WIDTH=200 HEIGHT=100 text="Very Scriptable!"> </object>
+
+   <script language=JavaScript>
+

Before the object can be accessed, some browsers require it to be located based on the id in the object tag.

+ +

JavaScript calling slots and properties

+
   var ScriptableObject = document.getElementById('ScriptableObject');
+

Object properties and public slots can then be accessed as usual. The QtBrowserPlugin implementation supports properties and slots that have parameters and types that QVariant can be convert to and from strings, or that are QObjects. Only public slots and scriptable properties are exposed. If the QObject class sets a "ToSuperClass" Q_CLASSINFO, then only slots and properties up to the specified superclass are exposed. See the QAxServer documentation provided with Qt for more information.

+ +

The plugin calling JavaScript

+

JavaScript functions can be connected to Qt signals emitted by the Qt plugin object.

+
   ScriptableObject.text = 'This is some text'
+
+   var oldText
+   ScriptableObject.mouseDown = function()
+   {
+     oldText = ScriptableObject.text
+     ScriptableObject.text = 'Mouse Down'
+   }
+
+   ScriptableObject.mouseMove = function(x, y)
+   {
+     ScriptableObject.text = 'Mouse at ' + x + ',' + y
+   }
+
+   ScriptableObject.mouseUp = function()
+   {
+     ScriptableObject.text = oldText
+   }
+   </script>
+

Assign a function to a property of the object with the same name as the signal. Overloads (i.e. two signal with the same name, but different parameters) are not possible.

+
   <!-- Special hookup code required for Internet Explorer -->
+   <!--[if IE]>
+   <script language=JScript>
+   function ScriptableObject::mouseDown() { ScriptableObject.mouseDown() }
+   function ScriptableObject::mouseMove(x, y) { ScriptableObject.mouseMove(x, y) }
+   function ScriptableObject::mouseUp() { ScriptableObject.mouseUp() }
+   </script>
+

Internet Explorer requires a special syntax that is not compatible with other browsers, but the IE-specific function can just call the other functions.

+ +

Using plugins in forms

+

Plugin objects can be embedded as form elements. To specify which property value the plugin should report to the form upon submission, specify the name of the property as the DefaultProperty using a Q_CLASSINFO entry:

+
 Q_OBJECT
+ Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless")
+ Q_CLASSINFO("DefaultProperty", "text")
+

In the HTML page, embed the object as usual:

+
 <form method="get" action="http://www.server.com/search.asp">
+ <table>
+ <tr>
+  <td>Search:</td>
+  <td><object type="trivial/very" name="text" WIDTH=100 HEIGHT=20></object></td>
+  <td><input type="submit" value="Check"></td>
+ </tr>
+ </table>
+ </form>
+

Clicking the button will make the browser request a URL

+

http://www.server.com/search.asp?text=[value from object]

+

The property type needs to be convertible to a string.

+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/images/qt-logo.png b/lib/browserplugin-solution/doc/html/images/qt-logo.png new file mode 100644 index 0000000..fa3c518 Binary files /dev/null and b/lib/browserplugin-solution/doc/html/images/qt-logo.png differ diff --git a/lib/browserplugin-solution/doc/html/images/trolltech-logo.png b/lib/browserplugin-solution/doc/html/images/trolltech-logo.png new file mode 100644 index 0000000..7b119aa Binary files /dev/null and b/lib/browserplugin-solution/doc/html/images/trolltech-logo.png differ diff --git a/lib/browserplugin-solution/doc/html/index.html b/lib/browserplugin-solution/doc/html/index.html new file mode 100644 index 0000000..d3a1180 --- /dev/null +++ b/lib/browserplugin-solution/doc/html/index.html @@ -0,0 +1,54 @@ + + + + + + Browser Plugin + + + + + + + +
  Home

Browser Plugin
+

+ +

Description

+

The QtBrowserPlugin solution is useful for implementing plugins for web browser.

+

The project provides a framework that makes it simple to export widgets and objects as plugins for web browsers supporting the Netscape LiveConnect APIs.

+

Supported web browsers are Netscape, Mozilla FireFox and Opera. Internet Explorer is supported when the plugin supports ActiveX via ActiveQt.

+

This Qt Solutions component is for Qt 4. For Qt 3 Solutions, please visit the Qt 3 Solutions Catalog.

+ +

Guidelines

+ + +

Classes

+ + +

Examples

+ + +

Tested platforms

+
    +
  • Qt 4.3, 4.4 / Windows XP, Vista / MSVC.NET 2005
  • +
  • [experimental] Qt 4.3, 4.4 / Linux / gcc
  • +
  • [experimental] Qt 4.3, 4.4 / MacOS X / gcc
  • +
+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-grapher.html b/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-grapher.html new file mode 100644 index 0000000..687f6de --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-grapher.html @@ -0,0 +1,412 @@ + + + + + + Grapher Plugin + + + + + + + +
  Home

Grapher Plugin
+

+ +

Implementation:

+
 /****************************************************************************
+ **
+ ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved.
+ **
+ ** This file is part of a Qt Solutions component.
+ **
+ ** This file may be used under the terms of the GNU General Public
+ ** License version 2.0 as published by the Free Software Foundation
+ ** and appearing in the file LICENSE.GPL included in the packaging of
+ ** this file.  Please review the following information to ensure GNU
+ ** General Public Licensing requirements will be met:
+ ** http://www.trolltech.com/products/qt/opensource.html
+ **
+ ** If you are unsure which license is appropriate for your use, please
+ ** review the following information:
+ ** http://www.trolltech.com/products/qt/licensing.html or contact the
+ ** Trolltech sales department at sales@trolltech.com.
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+ #include <QtGui>
+ #include <qtbrowserplugin.h>
+
+ #ifdef QAXSERVER
+ #include <ActiveQt/QAxBindable>
+ #endif
+
+ class Graph : public QWidget, public QtNPBindable
+ #ifdef QAXSERVER
+             , public QAxBindable
+ #endif
+ {
+     Q_OBJECT
+     Q_ENUMS(GraphStyle)
+     Q_PROPERTY(GraphStyle graphStyle READ graphStyle WRITE setGraphStyle)
+
+     Q_CLASSINFO("ClassID", "{2e5b2715-46b2-4831-ba9b-6a3b195d5ec8}")
+     Q_CLASSINFO("InterfaceID", "{94581136-3c0c-46cc-97a1-066061356d43}")
+     Q_CLASSINFO("EventsID", "{8c191b77-1894-45c7-9d6b-201dede95410}")
+
+     Q_CLASSINFO("MIME", "application/x-graphable:g1n:Graphable ASCII numeric data")
+ public:
+     Graph(QWidget *parent = 0);
+     ~Graph();
+
+     enum GraphStyle
+     {
+         Pie,
+         Bar
+     };
+     void setGraphStyle(GraphStyle style);
+     GraphStyle graphStyle() const;
+
+     bool readData(QIODevice *source, const QString &format);
+     bool writeData(QIODevice *sink);
+
+     void transferComplete(const QString &url, int id, Reason r);
+
+ protected:
+     void timerEvent(QTimerEvent*);
+     void enterEvent(QEvent *);
+     void leaveEvent(QEvent *);
+     void paintEvent(QPaintEvent*);
+     void mousePressEvent(QMouseEvent *me);
+
+     void paintWait();
+     void paintBar(QPaintEvent*);
+     void paintPie(QPaintEvent*);
+
+ private slots:
+     void stylePie();
+     void styleBar();
+     void aboutPlugin();
+     void aboutData();
+     void aboutQt();
+     void aboutTrolltech();
+
+ private:
+     struct Datum {
+         double value;
+         QString label;
+     };
+     QList<Datum> data;
+     void processData(QTextStream &in);
+
+     QMenu *menu;
+     QStatusBar *statusbar;
+     QAction *pie, *bar;
+
+     int pieRotation;
+     int pieTimer;
+     GraphStyle m_style;
+
+     int lastReqId, lastConfId;
+     QString lastConfUrl;
+     Reason lastConfReason;
+ };
+
+ Graph::Graph(QWidget *parent)
+ : QWidget(parent), pieRotation(0), pieTimer(0)
+ {
+     menu = new QMenu(this);
+     QMenu *styles = menu->addMenu("&Styles");
+
+     pie = styles->addAction("&Pie",this,SLOT(stylePie()));
+     pie->setShortcut(QString("Ctrl+P"));
+     pie->setCheckable(true);
+
+     bar = styles->addAction("&Bar", this, SLOT(styleBar()));
+     bar->setShortcut(QString("Ctrl+B"));
+     bar->setCheckable(true);
+
+     QActionGroup *group = new QActionGroup(this);
+     group->setExclusive(true);
+
+     group->addAction(pie);
+     group->addAction(bar);
+
+     QMenu* help = menu->addMenu("&Help");
+     help->addAction("About &plugin...", this, SLOT(aboutPlugin()))->setShortcut(QString("Ctrl+A"));
+     help->addAction("About &data...", this, SLOT(aboutData()));
+     help->addAction("About &Qt...", this, SLOT(aboutQt()));
+     help->addAction("About &Trolltech...", this, SLOT(aboutTrolltech()));
+
+     QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+F5"), this);
+     connect(shortcut, SIGNAL(activated()), this, SLOT(aboutQt()));
+
+     statusbar = new QStatusBar(this);
+
+     setFocusPolicy(Qt::StrongFocus);
+     setGraphStyle(Pie);
+
+     QPalette pal = palette();
+     pal.setColor(QPalette::Window,Qt::white);
+     setPalette(pal);
+
+     lastReqId = 0;
+     lastConfId = 0;
+     lastConfReason = ReasonUnknown;
+ }
+
+ Graph::~Graph()
+ {
+ }
+
+ void Graph::setGraphStyle(GraphStyle style)
+ {
+     if (style==m_style)
+         return;
+
+     if (pieTimer)
+         killTimer(pieTimer);
+
+     m_style = style;
+     switch(m_style) {
+     case Pie:
+         pieTimer = startTimer(50);
+         pie->setChecked(true);
+         break;
+     case Bar:
+         bar->setChecked(true);
+         break;
+     }
+
+     repaint();
+ }
+
+ Graph::GraphStyle Graph::graphStyle() const
+ {
+     return m_style;
+ }
+
+ void Graph::aboutPlugin()
+ {
+     openUrl("http://www.trolltech.com/products/solutions/catalog/4/Utilities/qtbrowserplugin/");
+ }
+
+ void Graph::aboutData()
+ {
+     QString page = parameters().value("datapage").toString();
+     if (!page.isEmpty()) {
+         openUrl(page);
+     } else {
+         QByteArray table("<b>This data has been loaded with streammode = '");
+         table += parameters().contains("streammode") ? parameters().value("streammode").toByteArray() : QByteArray("Default");
+         table += "'</b>\n";
+         table += "<table>\n";
+         for (int i = 0; i < data.count(); ++i) {
+             Datum datum = data.at(i);
+             table += "<tr><td>" + datum.label + "</td><td>" + QString::number(datum.value) + "</td></tr>\n";
+         }
+         table += "</table>\n";
+
+         table += "<p>Last OpenURL request id: " + QString::number(lastReqId);
+         table += "<br>Last confirmation id: " + QString::number(lastConfId);
+         table += " Reason: " + QString::number((int)lastConfReason);
+         table += "<br>URL: " + lastConfUrl;
+         QMessageBox::information(this, "Data information", QLatin1String(table));
+     }
+ }
+
+ void Graph::transferComplete(const QString &url, int id, Reason r)
+ {
+     lastConfId = id;
+     lastConfUrl = url;
+     lastConfReason = r;
+ }
+
+ void Graph::aboutQt()
+ {
+     QMessageBox::aboutQt(this);
+ }
+
+ void Graph::aboutTrolltech()
+ {
+     lastReqId = openUrl("http://www.trolltech.com");
+ }
+
+ void Graph::stylePie()
+ {
+     setGraphStyle(Pie);
+ }
+
+ void Graph::styleBar()
+ {
+     setGraphStyle(Bar);
+ }
+
+ bool Graph::readData(QIODevice *source, const QString &/*format*/)
+ {
+     if (!source->open(QIODevice::ReadOnly|QIODevice::Text))
+         return false;
+
+     QTextStream in(source);
+     processData(in);
+
+     update();
+     return true;
+ }
+
+ void Graph::processData(QTextStream &in)
+ {
+     while (!in.atEnd()) {
+         Datum datum;
+         QString value;
+         in >> value;
+         in >> datum.label;
+         bool ok;
+         datum.value = value.toDouble(&ok);
+         if (ok)
+             data += datum;
+     }
+ }
+
+ bool Graph::writeData(QIODevice *target)
+ {
+     if (!target->open(QIODevice::WriteOnly|QIODevice::Text))
+         return false;
+
+     QTextStream out(target);
+     foreach(Datum datum, data) {
+         out << datum.value << "\t" << datum.label << endl;
+     }
+
+     return true;
+ }
+
+ void Graph::timerEvent(QTimerEvent *e)
+ {
+     if (e->timerId() == pieTimer) {
+         pieRotation = (pieRotation + 1) % 360;
+         update();
+     }
+     QWidget::timerEvent(e);
+ }
+
+ void Graph::enterEvent(QEvent *)
+ {
+     statusbar->showMessage(QString("Qt Grapher plugin [%1]").arg(mimeType()));
+ }
+
+ void Graph::leaveEvent(QEvent *)
+ {
+     if (!QApplication::activePopupWidget()) {
+         statusbar->clearMessage();
+     }
+ }
+
+ void Graph::paintEvent(QPaintEvent* event)
+ {
+     if (!data.count()) {
+         paintWait();
+     } else {
+         switch (m_style) {
+         case Pie:
+             paintPie(event);
+             break;
+         default:
+             paintBar(event);
+             break;
+         }
+     }
+ }
+
+ void Graph::mousePressEvent(QMouseEvent *me)
+ {
+     menu->exec(me->globalPos());
+ }
+
+ void Graph::paintWait()
+ {
+     QPainter p(this);
+     p.drawText(rect(), Qt::AlignCenter, "Loading...");
+ }
+
+ void Graph::paintBar(QPaintEvent* event)
+ {
+     const int count = data.count();
+     double max = 0.0;
+     for (int i = 0; i < count; ++i) {
+         double value = data.at(i).value;
+         if (value > max)
+             max = value;
+     }
+
+     QPainter painter(this);
+     painter.setClipRect(event->rect());
+     painter.save();
+     painter.setWindow(0, qRound(max), count * 20, qRound(-max));
+     painter.setViewport(20, 5, width() - 40, height() - 40);
+
+     for (int i = 0; i < count; ++i) {
+         double value = data.at(i).value;
+         QColor c;
+         c.setHsv((i * 255)/count, 255, 255);// rainbow effect
+         painter.setBrush(c);
+
+         painter.drawRect(i * 20, 0, 20, qRound(value));
+     }
+     painter.restore();
+     painter.setClipRect(QRect());
+ }
+
+ void Graph::paintPie(QPaintEvent* event)
+ {
+     const int count = data.count();
+     double total = 0.0;
+
+     for (int i = 0; i < count; ++i) {
+         double value = data.at(i).value;
+         total += value;
+     }
+
+     int apos = (pieRotation-90)*16;
+
+     QPainter painter(this);
+     painter.setRenderHint(QPainter::Antialiasing);
+     painter.setClipRect(event->rect());
+     QRect r(rect());
+     r.adjust(10, 10, -10, -10);
+
+     for (int i = 0; i < count; ++i) {
+         double value = data.at(i).value;
+         QColor c;
+         c.setHsv((i * 255)/count, 255, 255);// rainbow effect
+         painter.setBrush( c );
+
+         int a = int((value * 360.0) / total * 16.0 + 0.5);
+         painter.drawPie(r, -apos, -a);
+         apos += a;
+     }
+ }
+
+ #include "grapher.moc"
+
+ QTNPFACTORY_BEGIN("Qt-based Graph Plugin", "A Qt-based LiveConnected plug-in that graphs numeric data");
+     QTNPCLASS(Graph)
+ QTNPFACTORY_END()
+
+ #ifdef QAXSERVER
+ #include <ActiveQt/QAxFactory>
+ QAXFACTORY_BEGIN("{89ab08da-df8c-4bd0-8327-72f73741c1a6}", "{082bd921-0832-4ca7-ab5a-ec06ca7f3350}")
+     QAXCLASS(Graph)
+ QAXFACTORY_END()
+ #endif
+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-scripting.html b/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-scripting.html new file mode 100644 index 0000000..a6032d7 --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-scripting.html @@ -0,0 +1,174 @@ + + + + + + Scripting Example + + + + + + + +
  Home

Scripting Example
+

+

This example demonstrates the combination of Javascript and a trivial plugin, and the use of a plugin in combination with a form.

+

If the browser supports scripting plugins, and everything is set up correctly, the plugin below should react to mouse clicks and drags by changing its text. The About... button should pop up an About Qt dialog. The second plugin instance, below the horizontal line, should display the word QtBrowserPlugin, and pressing the Go! button should navigate the browser to a search for this word at trolltech.com.

+ + + + + + + +
+ +
+ +
+
+ Search at Trolltech: + + +
+

Implementation:

+
 /****************************************************************************
+ **
+ ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved.
+ **
+ ** This file is part of a Qt Solutions component.
+ **
+ ** This file may be used under the terms of the GNU General Public
+ ** License version 2.0 as published by the Free Software Foundation
+ ** and appearing in the file LICENSE.GPL included in the packaging of
+ ** this file.  Please review the following information to ensure GNU
+ ** General Public Licensing requirements will be met:
+ ** http://www.trolltech.com/products/qt/opensource.html
+ **
+ ** If you are unsure which license is appropriate for your use, please
+ ** review the following information:
+ ** http://www.trolltech.com/products/qt/licensing.html or contact the
+ ** Trolltech sales department at sales@trolltech.com.
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+ #include <QtGui>
+ #include <qtbrowserplugin.h>
+
+ class Trivial : public QWidget
+ {
+     Q_OBJECT
+     Q_PROPERTY(QString text READ text WRITE setText)
+
+     Q_CLASSINFO("ClassID", "{5a22176d-118f-4185-9653-9f98958a6df8}")
+     Q_CLASSINFO("InterfaceID", "{2df735ba-da4f-4fb7-8f35-b8dfbf8cfd9a}")
+     Q_CLASSINFO("EventsID", "{449de213-f8bd-4d2e-a2cf-eab407c03245}")
+
+     Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless")
+     Q_CLASSINFO("ToSuperClass", "Trivial")
+     Q_CLASSINFO("DefaultProperty", "text")
+
+ public:
+     Trivial(QWidget *parent = 0)
+         : QWidget(parent)
+     {
+         m_text = QString::fromLatin1("Empty");
+     }
+
+     void mousePressEvent(QMouseEvent *)
+     {
+         mouseDown();
+     }
+     void mouseMoveEvent(QMouseEvent *e)
+     {
+         mouseMove(e->x(), e->y());
+     }
+     void mouseReleaseEvent(QMouseEvent*)
+     {
+         mouseUp();
+     }
+     QString text() const
+     {
+         return m_text;
+     }
+
+ public slots:
+     void about()
+     {
+         QMessageBox::aboutQt(this);
+     }
+     void setText(const QString &text)
+     {
+         m_text = text;
+         update();
+     }
+
+ signals:
+     void mouseDown();
+     void mouseMove(int x, int y);
+     void mouseUp();
+
+ protected:
+     void paintEvent(QPaintEvent*)
+     {
+         QPainter p(this);
+         QRect r(rect());
+         r.adjust(0, 0, -1, -1);
+
+         p.drawRect(r);
+         p.drawText(r, Qt::AlignCenter, m_text);
+     }
+
+ private:
+     QString m_text;
+ };
+
+ #include "trivial.moc"
+
+ QTNPFACTORY_BEGIN("Trivial Qt-based Plugin", "A Qt-based LiveConnected plug-in that does nothing")
+     QTNPCLASS(Trivial)
+ QTNPFACTORY_END()
+
+ #ifdef QAXSERVER
+ #include <ActiveQt/QAxFactory>
+ QAXFACTORY_BEGIN("{aa3216bf-7e20-482c-84c6-06167bacb616}", "{08538ca5-eb7a-4f24-a3c4-a120c6e04dc4}")
+     QAXCLASS(Trivial)
+ QAXFACTORY_END()
+ #endif
+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-trivial.html b/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-trivial.html new file mode 100644 index 0000000..810e47e --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtbrowserplugin-example-trivial.html @@ -0,0 +1,132 @@ + + + + + + Trivial Example + + + + + + + +
  Home

Trivial Example
+

+

This example is trivial, and thus useful for investigating problems you might have installing plugins. If everything works correctly, the trivial plugin should appear below as a rectangular field below with some text in it:

+ + +

Implementation:

+
 /****************************************************************************
+ **
+ ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved.
+ **
+ ** This file is part of a Qt Solutions component.
+ **
+ ** This file may be used under the terms of the GNU General Public
+ ** License version 2.0 as published by the Free Software Foundation
+ ** and appearing in the file LICENSE.GPL included in the packaging of
+ ** this file.  Please review the following information to ensure GNU
+ ** General Public Licensing requirements will be met:
+ ** http://www.trolltech.com/products/qt/opensource.html
+ **
+ ** If you are unsure which license is appropriate for your use, please
+ ** review the following information:
+ ** http://www.trolltech.com/products/qt/licensing.html or contact the
+ ** Trolltech sales department at sales@trolltech.com.
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+ #include <QtGui>
+ #include <qtbrowserplugin.h>
+
+ class Trivial : public QWidget
+ {
+     Q_OBJECT
+     Q_PROPERTY(QString text READ text WRITE setText)
+
+     Q_CLASSINFO("ClassID", "{5a22176d-118f-4185-9653-9f98958a6df8}")
+     Q_CLASSINFO("InterfaceID", "{2df735ba-da4f-4fb7-8f35-b8dfbf8cfd9a}")
+     Q_CLASSINFO("EventsID", "{449de213-f8bd-4d2e-a2cf-eab407c03245}")
+
+     Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless")
+     Q_CLASSINFO("ToSuperClass", "Trivial")
+     Q_CLASSINFO("DefaultProperty", "text")
+
+ public:
+     Trivial(QWidget *parent = 0)
+         : QWidget(parent)
+     {
+         m_text = QString::fromLatin1("Empty");
+     }
+
+     void mousePressEvent(QMouseEvent *)
+     {
+         mouseDown();
+     }
+     void mouseMoveEvent(QMouseEvent *e)
+     {
+         mouseMove(e->x(), e->y());
+     }
+     void mouseReleaseEvent(QMouseEvent*)
+     {
+         mouseUp();
+     }
+     QString text() const
+     {
+         return m_text;
+     }
+
+ public slots:
+     void about()
+     {
+         QMessageBox::aboutQt(this);
+     }
+     void setText(const QString &text)
+     {
+         m_text = text;
+         update();
+     }
+
+ signals:
+     void mouseDown();
+     void mouseMove(int x, int y);
+     void mouseUp();
+
+ protected:
+     void paintEvent(QPaintEvent*)
+     {
+         QPainter p(this);
+         QRect r(rect());
+         r.adjust(0, 0, -1, -1);
+
+         p.drawRect(r);
+         p.drawText(r, Qt::AlignCenter, m_text);
+     }
+
+ private:
+     QString m_text;
+ };
+
+ #include "trivial.moc"
+
+ QTNPFACTORY_BEGIN("Trivial Qt-based Plugin", "A Qt-based LiveConnected plug-in that does nothing")
+     QTNPCLASS(Trivial)
+ QTNPFACTORY_END()
+
+ #ifdef QAXSERVER
+ #include <ActiveQt/QAxFactory>
+ QAXFACTORY_BEGIN("{aa3216bf-7e20-482c-84c6-06167bacb616}", "{08538ca5-eb7a-4f24-a3c4-a120c6e04dc4}")
+     QAXCLASS(Trivial)
+ QAXFACTORY_END()
+ #endif
+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/qtbrowserplugin.dcf b/lib/browserplugin-solution/doc/html/qtbrowserplugin.dcf new file mode 100644 index 0000000..08e7fc5 --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtbrowserplugin.dcf @@ -0,0 +1,55 @@ + + +
+
+ QtNPBindable + DisplayMode + QtNPBindable::Embedded + QtNPBindable::Fullpage + Reason + QtNPBindable::ReasonError + QtNPBindable::ReasonBreak + QtNPBindable::ReasonUnknown + QtNPBindable::ReasonDone + displayMode + getBrowserVersion + getNppVersion + instance + mimeType + openUrl + parameters + readData + transferComplete + uploadData + uploadFile + userAgent +
+
+
+ QtNPFactory + createObject + mimeTypes + pluginDescription + pluginName +
+
+
+
+
+ Browser Plugin +
+
+ Developing Plugins +
+
+ Grapher Plugin +
+
+ Scripting Example +
+
+ Trivial Example +
+
+
+ diff --git a/lib/browserplugin-solution/doc/html/qtbrowserplugin.index b/lib/browserplugin-solution/doc/html/qtbrowserplugin.index new file mode 100644 index 0000000..fe7d932 --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtbrowserplugin.index @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/browserplugin-solution/doc/html/qtbrowserplugin.qch b/lib/browserplugin-solution/doc/html/qtbrowserplugin.qch new file mode 100644 index 0000000..975fbf8 Binary files /dev/null and b/lib/browserplugin-solution/doc/html/qtbrowserplugin.qch differ diff --git a/lib/browserplugin-solution/doc/html/qtbrowserplugin.qhp b/lib/browserplugin-solution/doc/html/qtbrowserplugin.qhp new file mode 100644 index 0000000..789f6e9 --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtbrowserplugin.qhp @@ -0,0 +1,71 @@ + + + com.trolltech.qtsolutions.qtbrowserplugin_2.3 + qdoc + + qt + qtbrowserplugin + solutions + + + qt + qtbrowserplugin + solutions + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + index.html + qtbrowserplugin-example-grapher.html + qtbrowserplugin-example-scripting.html + qtnpbindable.html + qtbrowserplugin-example-trivial.html + qtnpfactory.html + developingplugins.html + images/trolltech-logo.png + classic.css + images/qt-logo.png + +
+
diff --git a/lib/browserplugin-solution/doc/html/qtnpbindable-members.html b/lib/browserplugin-solution/doc/html/qtnpbindable-members.html new file mode 100644 index 0000000..3456f0f --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtnpbindable-members.html @@ -0,0 +1,45 @@ + + + + + + List of All Members for QtNPBindable + + + + + + + +
  Home

List of All Members for QtNPBindable

+

This is the complete list of members for QtNPBindable, including inherited members.

+

+ +
    +
  • mimeType () const : QString
  • +
  • openUrl ( const QString &, const QString & ) : int
  • +
  • parameters () const : QMap<QByteArray, QVariant>
  • +
  • readData ( QIODevice *, const QString & ) : bool
  • +
  • transferComplete ( const QString &, int, Reason )
  • +
  • uploadData ( const QString &, const QString &, const QByteArray & ) : int
  • +
  • uploadFile ( const QString &, const QString &, const QString & ) : int
  • +
  • userAgent () const : QString
  • +
+

+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/qtnpbindable.html b/lib/browserplugin-solution/doc/html/qtnpbindable.html new file mode 100644 index 0000000..9bdf7cd --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtnpbindable.html @@ -0,0 +1,148 @@ + + + + + + QtNPBindable Class Reference + + + + + + + +
  Home

QtNPBindable Class Reference

+

The QtNPBindable class provides an interface between a widget and the web browser. More...

+
 #include <QtNPBindable>
+ +

Public Types

+
    +
  • enum DisplayMode { Embedded, Fullpage }
  • +
  • enum Reason { ReasonDone, ReasonBreak, ReasonError, ReasonUnknown }
  • +
+ +

Public Functions

+
    +
  • DisplayMode displayMode () const
  • +
  • void getBrowserVersion ( int * major, int * minor ) const
  • +
  • void getNppVersion ( int * major, int * minor ) const
  • +
  • NPP instance () const
  • +
  • QString mimeType () const
  • +
  • int openUrl ( const QString & url, const QString & window = QString() )
  • +
  • QMap<QByteArray, QVariant> parameters () const
  • +
  • virtual bool readData ( QIODevice * source, const QString & format )
  • +
  • virtual void transferComplete ( const QString & url, int id, Reason reason )
  • +
  • int uploadData ( const QString & url, const QString & window, const QByteArray & data )
  • +
  • int uploadFile ( const QString & url, const QString & window, const QString & filename )
  • +
  • QString userAgent () const
  • +
+ +

Protected Functions

+ + +
+

Detailed Description

+

The QtNPBindable class provides an interface between a widget and the web browser.

+

Inherit your plugin widget class from both QWidget (or QObject) and QtNPBindable to be able to call the functions of this class, and to reimplement the virtual functions. The meta-object compiler requires you to inherit from the QObject subclass first.

+
 class PluginWidget : public QWidget, public QtNPBindable
+ {
+     Q_OBJECT
+ public:
+     PluginWidget(QWidget *parent = 0)
+     {
+     }
+
+     //...
+ };
+
+

Member Type Documentation

+

enum QtNPBindable::DisplayMode

+

This enum specifies the different display modes of a plugin

+

+ + + +
ConstantValueDescription
QtNPBindable::Embedded1The plugin widget is embedded in a web page, usually with the <EMBED> or the <OBJECT> tag.
QtNPBindable::Fullpage2The plugin widget is the primary content of the web browser, which is usually the case when the web browser displays a file the plugin supports.

+

enum QtNPBindable::Reason

+

This enum specifies how an URL operation was completed

+

+ + + + + +
ConstantValue
QtNPBindable::ReasonDone0
QtNPBindable::ReasonBreak1
QtNPBindable::ReasonError2
QtNPBindable::ReasonUnknown-1

+
+

Member Function Documentation

+

QtNPBindable::QtNPBindable ()   [protected]

+

Constructs a QtNPBindable object.

+

This can only happen when the plugin object is created.

+

QtNPBindable::~QtNPBindable ()   [virtual protected]

+

Destroys the object.

+

This can only happen when the plugin object is destroyed.

+

DisplayMode QtNPBindable::displayMode () const

+

Returns the display mode of the plugin.

+

void QtNPBindable::getBrowserVersion ( int * major, int * minor ) const

+

Extracts the version of the browser into major and minor.

+

See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ for an explanation of those values.

+

See also getNppVersion() and userAgent().

+

void QtNPBindable::getNppVersion ( int * major, int * minor ) const

+

Extracts the version of the plugin API used by this plugin into major and minor.

+

See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ for an explanation of those values.

+

See also getBrowserVersion() and userAgent().

+

NPP QtNPBindable::instance () const

+

Returns the browser's plugin instance associated with this plugin object. The instance is required to call functions in the Netscape Plugin API, i.e. NPN_GetJavaPeer().

+

The instance returned is only valid as long as this object is.

+

See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ for documentation of the NPP type.

+

QString QtNPBindable::mimeType () const

+

Returns the mime type this plugin has been instantiated for.

+

int QtNPBindable::openUrl ( const QString & url, const QString & window = QString() )

+

Requests that the url be retrieved and sent to the named window (or a new window if window is empty), and returns the ID of the request that is delivered to transferComplete() when the get-operation has finished. Returns 0 when the browser or the system doesn't support notification, or -1 when an error occured.

+
 void MyPlugin::aboutTrolltech()
+ {
+     openUrl("http://www.trolltech.com");
+ }
+

See Netscape's JavaScript documentation for an explanation of window names.

+

See also transferComplete(), uploadData(), and uploadFile().

+

QMap<QByteArray, QVariant> QtNPBindable::parameters () const

+

Returns the parameters passed to the plugin instance.

+

The framework sets the properties of the plugin to the corresponding parameters when the plugin object has been created, but you can use this function to process additional parameters.

+

Note that the SGML specification does not permit multiple arguments with the same name.

+

bool QtNPBindable::readData ( QIODevice * source, const QString & format )   [virtual]

+

Reimplement this function to read data from source provided with mime type format. The data is the one specified in the src or data attribute of the <EMBED> or <OBJECT> tag of in HTML page. This function is called once for every stream the browser creates for the plugin.

+

Return true to indicate successfull processing of the data, otherwise return false. The default implementation does nothing and returns false.

+

void QtNPBindable::transferComplete ( const QString & url, int id, Reason reason )   [virtual]

+

Called as a result of a call to openUrl, uploadData or uploadFile. url corresponds to the respective parameter, and id to value returned by the call. reason indicates how the transfer was completed.

+

int QtNPBindable::uploadData ( const QString & url, const QString & window, const QByteArray & data )

+

Posts data to url, and displays the result in window. Returns the ID of the request that is delivered to transferComplete() when the post-operation has finished. Returns 0 when the browser or the system doesn't support notification, or -1 when an error occured.

+
 void MyPlugin::sendMail()
+ {
+     uploadData("mailto:fred@somewhere.com", QString(), "There is a new file for you!");
+ }
+

See Netscape's JavaScript documentation for an explanation of window names.

+

See also transferComplete(), openUrl(), and uploadFile().

+

int QtNPBindable::uploadFile ( const QString & url, const QString & window, const QString & filename )

+

Posts filename to url, and displays the result in window. Returns the ID of the request that is delivered to transferComplete() when the post-operation has finished. Returns 0 when the browser or the system doesn't support notification, or -1 when an error occured.

+
 void MyPlugin::uploadFile()
+ {
+     uploadFile("ftp://ftp.somewhere.com/incoming", "response", "c:\\temp\\file.txt");
+ }
+

See Netscape's JavaScript documentation for an explanation of window names.

+

See also transferComplete(), uploadData(), and openUrl().

+

QString QtNPBindable::userAgent () const

+

Returns the user agent (browser name) containing this plugin.

+

This is a wrapper around NPN_UserAgent.

+

See also getBrowserVersion().

+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/qtnpfactory-members.html b/lib/browserplugin-solution/doc/html/qtnpfactory-members.html new file mode 100644 index 0000000..878ed5b --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtnpfactory-members.html @@ -0,0 +1,31 @@ + + + + + + List of All Members for QtNPFactory + + + + + + + +
  Home

List of All Members for QtNPFactory

+

This is the complete list of members for QtNPFactory, including inherited members.

+ +


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/html/qtnpfactory.html b/lib/browserplugin-solution/doc/html/qtnpfactory.html new file mode 100644 index 0000000..4b359f7 --- /dev/null +++ b/lib/browserplugin-solution/doc/html/qtnpfactory.html @@ -0,0 +1,79 @@ + + + + + + QtNPFactory Class Reference + + + + + + + +
  Home

QtNPFactory Class Reference

+

The QtNPFactory class provides the factory for plugin objects. More...

+
 #include <QtNPFactory>
+ +

Public Functions

+ + +
+

Detailed Description

+

The QtNPFactory class provides the factory for plugin objects.

+

Implement this factory once in your plugin project to provide information about the plugin and to create the plugin objects. Subclass QtNPFactory and implement the pure virtual functions, and export the factory using the QTNPFACTORY_EXPORT() macro.

+

If you use the Q_CLASSINFO macro in your object classes you can use the QTNPFACTORY_BEGIN(), QTNPCLASS() and QTNPFACTORY_END() macros to generate a factory implementation:

+
 class Widget : public QWidget
+ {
+     Q_OBJECT
+     Q_CLASSINFO("MIME", "application/x-graphable:g1n:Graphable data")
+ public:
+     ...
+ };
+
+ QTNPFACTORY_BEGIN("Plugin name", "Plugin description")
+     QTNPCLASS(WidgetClass)
+ QTNPFACTORY_END()
+

The classes exposed must provide a constructor.

+

If Qt is linked to the plugin as a dynamic library, only one instance of QApplication will exist across all plugins that have been made with Qt. So, your plugin should tread lightly on global settings. Do not, for example, use QApplication::setFont() - that will change the font in every widget of every Qt-based plugin currently loaded!

+
+

Member Function Documentation

+

QtNPFactory::QtNPFactory ()

+

Creates a QtNPFactory.

+

QtNPFactory::~QtNPFactory ()   [virtual]

+

Destroys the QtNPFactory.

+

This is called by the plugin binding code just before the plugin is about to be unloaded from memory. If createObject() has been called, a QApplication will still exist at this time, but will be deleted shortly after, just before the plugin is deleted.

+

QObject * QtNPFactory::createObject ( const QString & type )   [pure virtual]

+

Reimplement this function to return the QObject or QWidget subclass supporting the mime type type, or 0 if the factory doesn't support the type requested.

+

type will be in the same form as the leftmost (mime) part of the string(s) returned by mimeTypes(), e.g. "image/png".

+

QStringList QtNPFactory::mimeTypes () const   [pure virtual]

+

Reimplement this function to return the MIME types of the data formats supported by your plugin. The format of each string is mime:extension(s):description:

+
 QStringList mimeTypes() const
+ {
+     QStringList list;
+     list << "image/x-png:png:PNG Image"
+          << "image/png:png:PNG Image"
+          << "image/jpeg:jpg,jpeg:JPEG Image";
+     return list;
+ }
+

QString QtNPFactory::pluginDescription () const   [pure virtual]

+

Reimplement this function to return the description of the plugin.

+

QString QtNPFactory::pluginName () const   [pure virtual]

+

Reimplement this function to return the name of the plugin.

+


+ + + + +
Copyright © 2008 TrolltechTrademarks
Qt Solutions
+ diff --git a/lib/browserplugin-solution/doc/images/qt-logo.png b/lib/browserplugin-solution/doc/images/qt-logo.png new file mode 100644 index 0000000..fa3c518 Binary files /dev/null and b/lib/browserplugin-solution/doc/images/qt-logo.png differ diff --git a/lib/browserplugin-solution/doc/images/trolltech-logo.png b/lib/browserplugin-solution/doc/images/trolltech-logo.png new file mode 100644 index 0000000..7b119aa Binary files /dev/null and b/lib/browserplugin-solution/doc/images/trolltech-logo.png differ diff --git a/lib/browserplugin-solution/doc/index.qdoc b/lib/browserplugin-solution/doc/index.qdoc new file mode 100644 index 0000000..2209833 --- /dev/null +++ b/lib/browserplugin-solution/doc/index.qdoc @@ -0,0 +1,51 @@ +/*! + \page index.html + \title Browser Plugin + + \section1 Description + + The QtBrowserPlugin solution is useful for implementing plugins for + web browser. + + + + The project provides a framework that makes it simple to export + widgets and objects as plugins for web browsers supporting the Netscape + LiveConnect APIs. + + Supported web browsers are Netscape, Mozilla FireFox and Opera. + Internet Explorer is supported when the plugin supports ActiveX via ActiveQt. + + + This Qt Solutions component is for Qt 4. For Qt 3 Solutions, please + visit \l{http://www.trolltech.com/products/qt/addon/solutions/catalog/3/}{the Qt 3 Solutions Catalog}. + + + \section1 Guidelines + \list + \i \link developingplugins.html Developing Plugins \endlink \endlist + + \section1 Classes + \list + \i QtNPBindable \i QtNPFactory\endlist + + \section1 Examples + \list + \i \link qtbrowserplugin-example-trivial.html A trivial "Hello, World" plugin. \endlink \i \link qtbrowserplugin-example-scripting.html A webpage that combines javascript and the trivial plugin. \endlink \i \link qtbrowserplugin-example-grapher.html A plugin widget displaying a data file as a graph. \endlink \endlist + + + + + + + \section1 Tested platforms + \list + \i Qt 4.3, 4.4 / Windows XP, Vista / MSVC.NET 2005 + \i [experimental] Qt 4.3, 4.4 / Linux / gcc + \i [experimental] Qt 4.3, 4.4 / MacOS X / gcc + \endlist + + + + + */ \ No newline at end of file diff --git a/lib/browserplugin-solution/doc/qtbrowserplugin.qdoc b/lib/browserplugin-solution/doc/qtbrowserplugin.qdoc new file mode 100644 index 0000000..91a41ef --- /dev/null +++ b/lib/browserplugin-solution/doc/qtbrowserplugin.qdoc @@ -0,0 +1,296 @@ +/*! + +\page developingplugins.html +\title Developing Plugins + +The QtBrowserPlugin solution makes it easy to write browser plugins +that can be used in Netscape, Mozilla FireFox, Opera, and any other +web browser supporting the "npruntime" API: + +http://www.mozilla.org/projects/plugins/ +http://www.mozilla.org/projects/plugins/npruntime.html + +Current versions of Microsoft Internet Explorer do not support this +API. However, you can use the ActiveQt framework to compile a +single plugin library that works with all web browsers. + +\tableofcontents + +\section1 Implementing plugins + +Since any QWidget or QObject subclass can be turned into a plugin with +little effort it is usually easiest to do the development as a +stand-alone Qt application - debugging plugins is cumbersome. + +Make sure that the subclasses you want to export use the Q_OBJECT macro +and provide a default constructor. Use the Q_CLASSINFO macro to specify +a list of MIME types each of your classes supports, and export the +classes through the QtNPFactory macros: + +\quotefromfile grapher.cpp +\skipto QTNPFACTORY_BEGIN +\printuntil QTNPFACTORY_END() + +Include the \c qtbrowserplugin.pri in your .pro file, and regenerate +the makefile with qmake. The resulting makefile will generate a shared +library with a file name starting with \c{"np"} - this is required +by all browsers to recognize the library as a plugin. + +\section2 Windows specific notes + +On Windows it is required to link a version resource into the plugin +library. To do that, create an .rc file (a plain-text file) and add +it to the \c RC_FILE variable of your project. The .rc file needs to +contain a version description like here: + +\quotefromfile grapher.rc +\skipto VERSION +\printuntil VarFileInfo +\printuntil END +\printuntil END + +\section3 Enabling ActiveX support + +To build a plugin project with ActiveX support, use ActiveQt's QAxServer +module by adding the following line to your project: + +CONFIG += qaxserver + +Also, add the following line to your resource file + +\c{1 TYPELIB "thisfile.rc"} + +In your plugin code, use Q_CLASSINFO and the QAxFactory macros as usual. + +When you build the plugin, then ActiveQt will perform the build steps +required to turn the plugin library into an ActiveX control server +which provides your plugin classes not only to browsers supporting the +npruntime API, but also to browsers supporting ActiveX controls +(i.e. Internet Explorer). + +However, not that calling QtNPBindable APIs will not do anything when +the browser does not support the npruntime API. In some cases, QAxBindable +provides equivalent APIs (i.e. for reading incoming data). + +\section2 Unix specific notes + +On Unix/Linux, QtBrowserPlugin uses the XEmbed protocol. This is a +fairly recent addition to the NPP plugin API. At the time of writing, +it is not supported by the Opera and Konqueror browsers. Firefox and +other Mozilla/Gecko-based browsers do support it. + +Update: Opera version 9.50 will support the XEmbed +protocol. QtBrowserPlugin is tested successfully with the beta release +of Opera 9.50. One known issue: Opera does not automatically register +the extension part of the MIME description. If required, work around +by adding it manually in the \c{Preferences->Advanced->Download} +dialog. (e.g. add "g1n" to "application/x-graphable" to make the +grapher example work). + + +\section3 Known Issues on Unix/Linux + +There are two known issues that may cause the plugin to crash on +initialization, possibly taking the browser down with it: + +\list +\o Double initialization of glib/threading. This is fixed in Qt 4.3.1 and +later. + +\o Symbol clash with other instances of the Qt libraries. Although +Firefox/Gecko itself does not use Qt, it is not uncommon on Linux that +another plugin or style engine is present that will load the Qt +dynamic libraries. When another plugin based on the Qt 4 dynamically +libraries are added, some symbol clashes between the different Qt +instances will occur, leading to a crash. With Qt 4.4 and later, this +is easily worked around by configuring your Qt build to use a separate +namespace. Just add the \c{-qtnamespace=SomeNamespace} option to \c +configure. For Qt 4.3, it is possible to work around this by +building the Qt 4 library statically, and link them into +the plugin executable with a special linker option. See \c +qtbrowserplugin.pri for details. +\endlist + +In addition, Firefox may emit this warning when initializing the +plugin: \c{_XEMBED_INFO property has wrong type}. This is fixed in Qt +4.3.1 and later. + +\section2 Mac OSX specific notes + +To build a browser plugin on Mac, two plain-text resource files are +needed: an \c Info.plist file and a \c .r file. To create these files, +it is easiest to use the ones provided with the QtBrowserPlugin +examples as templates, editing as necessary. Then add them to your +project (\c .pro file) like this: + +\quotefromfile grapher.pro +\skipto QMAKE_INFO_PLIST +\printuntil QMAKE_BUNDLE_DATA + +\section3 Known Issues on Mac + +\list +\o After navigating away from the webpage with the plugin, and then back +again, the plugin no longer shows up or runs. No workaround currently +known. + +\o Some painting issues. Fixed in Qt 4.3.1 and later. +\endlist + +\section1 Installing and using Plugins + +Most browsers provide a UI to display all loaded plugins. Use this +functionality to diagnose problems. + +The plugin will need to load the Qt libraries at runtime (unless they +are statically linked into the plugin). Hence, the required Qt dynamic +libraries (at least QtCore, QtGui, and QtNetwork) must be located in a +directory which the system searches for DLLs. This may or may not +include the directory where the plugin itself is located, depending on +the OS and browser. + +Windows, Netscape-style browsers: To install the plugin, copy the +plugin library in the "plugins" directory of the browser. See +\c{src/qtbrowserplugin.pri} for some typical paths. + +Windows, Internet Explorer: The Makefile generated by qmake by default +runs the necessary commands to register the plugin as an ActiveX +server (if \c CONFIG includes \c qaxserver). To unregister, use the +following command: + +\code +c:\Qt-x.y.z\bin\idc.exe path\to\myplugin.dll /unregserver +\endcode + +Mac: The build will result in a directory called \c +myplugin.plugin. To install, copy this directory with all contents to +\c{/Library/Internet Plugins}. + +Unix: Copy the file \c myplugin.so to the browser or system plugin +directory, typically \c /usr/lib/browser-plugins. The path to the Qt +libraries may be set in the LD_LIBRARY_PATH environment variable of +the browser process. + +\section2 Using the plugin in HTML + +Different browser support different embedding tags, but the following +should work with Netscape, FireFox, Opera and Internet Explorer (if the +plugin has been compiled as an ActiveX server as well). + +\section3 Object with data: + +Objects can be initialized with a data file, which will be delivered to +the plugin at some point after plugin creation to the plugin through the +QtNPBindable::readData() virtual function. +\footnote +If files viewed by a plugin are provided by an HTTP server +(using a \c{http://...} URL) then the server must be configured to send +the correct MIME type for the file, e.g. by editing Apache's +\c{mime.types} file. If the files are viewed via a \c{file://...} URL, +then the browser will use the filename extension to decide the file type +(and hence the plugin to load) - the user may need to set the filename +extension in the Helpers or Applications section of their browser preferences. +\endfootnote + +\code + +Plugin not installed! + +\endcode + +\code + +Plugin not installed! + +\endcode + +Note that some browsers will not display or immediately unload the plugin +if the data file does not exist, while other browsers will display the plugin +without ever calling readData(). + +\section3 Objects without data: + +\code + +\endcode + +\section3 Not working with all browsers + +\list +\o \c{} Internet Explorer does not receive data +\o \c{} Opera does not display plugin without \c data attribute +\o \c{} FireFox and Netscape don't display +\o \c{} Internet Explorer does not receive data +\endlist + +For additional information, see http://devedge-temp.mozilla.org/library/manuals + +\section2 Scripting + +Plugins embedded into browsers that support the respecive NPAPI extensions as +well as ActiveX controls can be accessed from JavaScript in the HTML page. + +\quotefromfile ../examples/trivial/scripting.qdoc +\skipto + +Assign a function to a property of the object with the same name as the signal. Overloads +(i.e. two signal with the same name, but different parameters) are not possible. + +\printuntil + +Internet Explorer requires a special syntax that is not compatible with other browsers, +but the IE-specific function can just call the other functions. + +\section3 Using plugins in forms + +Plugin objects can be embedded as form elements. To specify which property value +the plugin should report to the form upon submission, specify the name of the +property as the DefaultProperty using a Q_CLASSINFO entry: + +\code +Q_OBJECT +Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless") +Q_CLASSINFO("DefaultProperty", "text") +\endcode + +In the HTML page, embed the object as usual: + +\code +
+ + + + + + +
Search:
+
+\endcode + +Clicking the button will make the browser request a URL + +\c http://www.server.com/search.asp?text=[value from object] + +The property type needs to be convertible to a string. +*/ diff --git a/lib/browserplugin-solution/examples/examples.pro b/lib/browserplugin-solution/examples/examples.pro new file mode 100644 index 0000000..76ae00c --- /dev/null +++ b/lib/browserplugin-solution/examples/examples.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = trivial grapher diff --git a/lib/browserplugin-solution/examples/grapher/Info.plist b/lib/browserplugin-solution/examples/grapher/Info.plist new file mode 100644 index 0000000..a57f735 --- /dev/null +++ b/lib/browserplugin-solution/examples/grapher/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + grapher + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BRPL + CFBundleSignature + TEST + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + WebPluginDescription + A graphing plug-in + WebPluginMIMETypes + + application/x-graphable + + WebPluginExtensions + + g1n + + WebPluginTypeDescription + Very graphing mimetype + + + WebPluginName + Qt graphing test plug-in + + diff --git a/lib/browserplugin-solution/examples/grapher/debug/npgrapher.lib b/lib/browserplugin-solution/examples/grapher/debug/npgrapher.lib new file mode 100644 index 0000000..082ba1c Binary files /dev/null and b/lib/browserplugin-solution/examples/grapher/debug/npgrapher.lib differ diff --git a/lib/browserplugin-solution/examples/grapher/graph.g1n b/lib/browserplugin-solution/examples/grapher/graph.g1n new file mode 100644 index 0000000..d366327 --- /dev/null +++ b/lib/browserplugin-solution/examples/grapher/graph.g1n @@ -0,0 +1,8 @@ +num label +10 A +24 B +12 C +7 D +34 E +15 F +19 G diff --git a/lib/browserplugin-solution/examples/grapher/grapher.cpp b/lib/browserplugin-solution/examples/grapher/grapher.cpp new file mode 100644 index 0000000..bfe5912 --- /dev/null +++ b/lib/browserplugin-solution/examples/grapher/grapher.cpp @@ -0,0 +1,388 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include +#include + +#ifdef QAXSERVER +#include +#endif + +class Graph : public QWidget, public QtNPBindable +#ifdef QAXSERVER + , public QAxBindable +#endif +{ + Q_OBJECT + Q_ENUMS(GraphStyle) + Q_PROPERTY(GraphStyle graphStyle READ graphStyle WRITE setGraphStyle) + + Q_CLASSINFO("ClassID", "{2e5b2715-46b2-4831-ba9b-6a3b195d5ec8}") + Q_CLASSINFO("InterfaceID", "{94581136-3c0c-46cc-97a1-066061356d43}") + Q_CLASSINFO("EventsID", "{8c191b77-1894-45c7-9d6b-201dede95410}") + + Q_CLASSINFO("MIME", "application/x-graphable:g1n:Graphable ASCII numeric data") +public: + Graph(QWidget *parent = 0); + ~Graph(); + + enum GraphStyle + { + Pie, + Bar + }; + void setGraphStyle(GraphStyle style); + GraphStyle graphStyle() const; + + bool readData(QIODevice *source, const QString &format); + bool writeData(QIODevice *sink); + + void transferComplete(const QString &url, int id, Reason r); + +protected: + void timerEvent(QTimerEvent*); + void enterEvent(QEvent *); + void leaveEvent(QEvent *); + void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent *me); + + void paintWait(); + void paintBar(QPaintEvent*); + void paintPie(QPaintEvent*); + +private slots: + void stylePie(); + void styleBar(); + void aboutPlugin(); + void aboutData(); + void aboutQt(); + void aboutTrolltech(); + +private: + struct Datum { + double value; + QString label; + }; + QList data; + void processData(QTextStream &in); + + QMenu *menu; + QStatusBar *statusbar; + QAction *pie, *bar; + + int pieRotation; + int pieTimer; + GraphStyle m_style; + + int lastReqId, lastConfId; + QString lastConfUrl; + Reason lastConfReason; +}; + + +Graph::Graph(QWidget *parent) +: QWidget(parent), pieRotation(0), pieTimer(0) +{ + menu = new QMenu(this); + QMenu *styles = menu->addMenu("&Styles"); + + pie = styles->addAction("&Pie",this,SLOT(stylePie())); + pie->setShortcut(QString("Ctrl+P")); + pie->setCheckable(true); + + bar = styles->addAction("&Bar", this, SLOT(styleBar())); + bar->setShortcut(QString("Ctrl+B")); + bar->setCheckable(true); + + QActionGroup *group = new QActionGroup(this); + group->setExclusive(true); + + group->addAction(pie); + group->addAction(bar); + + QMenu* help = menu->addMenu("&Help"); + help->addAction("About &plugin...", this, SLOT(aboutPlugin()))->setShortcut(QString("Ctrl+A")); + help->addAction("About &data...", this, SLOT(aboutData())); + help->addAction("About &Qt...", this, SLOT(aboutQt())); + help->addAction("About &Trolltech...", this, SLOT(aboutTrolltech())); + + QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+F5"), this); + connect(shortcut, SIGNAL(activated()), this, SLOT(aboutQt())); + + statusbar = new QStatusBar(this); + + setFocusPolicy(Qt::StrongFocus); + setGraphStyle(Pie); + + QPalette pal = palette(); + pal.setColor(QPalette::Window,Qt::white); + setPalette(pal); + + lastReqId = 0; + lastConfId = 0; + lastConfReason = ReasonUnknown; +} + +Graph::~Graph() +{ +} + +void Graph::setGraphStyle(GraphStyle style) +{ + if (style==m_style) + return; + + if (pieTimer) + killTimer(pieTimer); + + m_style = style; + switch(m_style) { + case Pie: + pieTimer = startTimer(50); + pie->setChecked(true); + break; + case Bar: + bar->setChecked(true); + break; + } + + repaint(); +} + +Graph::GraphStyle Graph::graphStyle() const +{ + return m_style; +} + +void Graph::aboutPlugin() +{ + openUrl("http://www.trolltech.com/products/solutions/catalog/4/Utilities/qtbrowserplugin/"); +} + +void Graph::aboutData() +{ + QString page = parameters().value("datapage").toString(); + if (!page.isEmpty()) { + openUrl(page); + } else { + QByteArray table("This data has been loaded with streammode = '"); + table += parameters().contains("streammode") ? parameters().value("streammode").toByteArray() : QByteArray("Default"); + table += "'\n"; + table += "\n"; + for (int i = 0; i < data.count(); ++i) { + Datum datum = data.at(i); + table += "\n"; + } + table += "
" + datum.label + "" + QString::number(datum.value) + "
\n"; + + table += "

Last OpenURL request id: " + QString::number(lastReqId); + table += "
Last confirmation id: " + QString::number(lastConfId); + table += " Reason: " + QString::number((int)lastConfReason); + table += "
URL: " + lastConfUrl; + QMessageBox::information(this, "Data information", QLatin1String(table)); + } +} + +void Graph::transferComplete(const QString &url, int id, Reason r) +{ + lastConfId = id; + lastConfUrl = url; + lastConfReason = r; +} + +void Graph::aboutQt() +{ + QMessageBox::aboutQt(this); +} + +void Graph::aboutTrolltech() +{ + lastReqId = openUrl("http://www.trolltech.com"); +} + +void Graph::stylePie() +{ + setGraphStyle(Pie); +} + +void Graph::styleBar() +{ + setGraphStyle(Bar); +} + +bool Graph::readData(QIODevice *source, const QString &/*format*/) +{ + if (!source->open(QIODevice::ReadOnly|QIODevice::Text)) + return false; + + QTextStream in(source); + processData(in); + + update(); + return true; +} + +void Graph::processData(QTextStream &in) +{ + while (!in.atEnd()) { + Datum datum; + QString value; + in >> value; + in >> datum.label; + bool ok; + datum.value = value.toDouble(&ok); + if (ok) + data += datum; + } +} + +bool Graph::writeData(QIODevice *target) +{ + if (!target->open(QIODevice::WriteOnly|QIODevice::Text)) + return false; + + QTextStream out(target); + foreach(Datum datum, data) { + out << datum.value << "\t" << datum.label << endl; + } + + return true; +} + +void Graph::timerEvent(QTimerEvent *e) +{ + if (e->timerId() == pieTimer) { + pieRotation = (pieRotation + 1) % 360; + update(); + } + QWidget::timerEvent(e); +} + +void Graph::enterEvent(QEvent *) +{ + statusbar->showMessage(QString("Qt Grapher plugin [%1]").arg(mimeType())); +} + +void Graph::leaveEvent(QEvent *) +{ + if (!QApplication::activePopupWidget()) { + statusbar->clearMessage(); + } +} + +void Graph::paintEvent(QPaintEvent* event) +{ + if (!data.count()) { + paintWait(); + } else { + switch (m_style) { + case Pie: + paintPie(event); + break; + default: + paintBar(event); + break; + } + } +} + +void Graph::mousePressEvent(QMouseEvent *me) +{ + menu->exec(me->globalPos()); +} + +void Graph::paintWait() +{ + QPainter p(this); + p.drawText(rect(), Qt::AlignCenter, "Loading..."); +} + +void Graph::paintBar(QPaintEvent* event) +{ + const int count = data.count(); + double max = 0.0; + for (int i = 0; i < count; ++i) { + double value = data.at(i).value; + if (value > max) + max = value; + } + + QPainter painter(this); + painter.setClipRect(event->rect()); + painter.save(); + painter.setWindow(0, qRound(max), count * 20, qRound(-max)); + painter.setViewport(20, 5, width() - 40, height() - 40); + + for (int i = 0; i < count; ++i) { + double value = data.at(i).value; + QColor c; + c.setHsv((i * 255)/count, 255, 255);// rainbow effect + painter.setBrush(c); + + painter.drawRect(i * 20, 0, 20, qRound(value)); + } + painter.restore(); + painter.setClipRect(QRect()); +} + +void Graph::paintPie(QPaintEvent* event) +{ + const int count = data.count(); + double total = 0.0; + + for (int i = 0; i < count; ++i) { + double value = data.at(i).value; + total += value; + } + + int apos = (pieRotation-90)*16; + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.setClipRect(event->rect()); + QRect r(rect()); + r.adjust(10, 10, -10, -10); + + for (int i = 0; i < count; ++i) { + double value = data.at(i).value; + QColor c; + c.setHsv((i * 255)/count, 255, 255);// rainbow effect + painter.setBrush( c ); + + int a = int((value * 360.0) / total * 16.0 + 0.5); + painter.drawPie(r, -apos, -a); + apos += a; + } +} + +#include "grapher.moc" + +QTNPFACTORY_BEGIN("Qt-based Graph Plugin", "A Qt-based LiveConnected plug-in that graphs numeric data"); + QTNPCLASS(Graph) +QTNPFACTORY_END() + +#ifdef QAXSERVER +#include +QAXFACTORY_BEGIN("{89ab08da-df8c-4bd0-8327-72f73741c1a6}", "{082bd921-0832-4ca7-ab5a-ec06ca7f3350}") + QAXCLASS(Graph) +QAXFACTORY_END() +#endif diff --git a/lib/browserplugin-solution/examples/grapher/grapher.pro b/lib/browserplugin-solution/examples/grapher/grapher.pro new file mode 100644 index 0000000..13f76ca --- /dev/null +++ b/lib/browserplugin-solution/examples/grapher/grapher.pro @@ -0,0 +1,19 @@ +TARGET = grapher + +SOURCES = grapher.cpp + +# On Windows, uncomment the following line to build a plugin that can +# be used also in Internet Explorer, through ActiveX. +# CONFIG += qaxserver + +win32 { + RC_FILE = grapher.rc +} else:mac { + QMAKE_INFO_PLIST = Info.plist + REZ_FILES += grapher.r + rsrc_files.files = grapher.rsrc + rsrc_files.path = Contents/Resources + QMAKE_BUNDLE_DATA += rsrc_files +} + +include(../../src/qtbrowserplugin.pri) diff --git a/lib/browserplugin-solution/examples/grapher/grapher.qdoc b/lib/browserplugin-solution/examples/grapher/grapher.qdoc new file mode 100644 index 0000000..83098db --- /dev/null +++ b/lib/browserplugin-solution/examples/grapher/grapher.qdoc @@ -0,0 +1,12 @@ +/*! \page qtbrowserplugin-example-grapher.html + + \title Grapher Plugin + + \raw HTML + + \endraw + + Implementation: + + \quotefile grapher/grapher.cpp +*/ diff --git a/lib/browserplugin-solution/examples/grapher/grapher.r b/lib/browserplugin-solution/examples/grapher/grapher.r new file mode 100644 index 0000000..42b29ba --- /dev/null +++ b/lib/browserplugin-solution/examples/grapher/grapher.r @@ -0,0 +1,19 @@ +#define SystemSevenOrLater 1 + +#include + +resource 'STR#' (127) +{{ +"A graphing plugin!" +}}; + +resource 'STR#' (128) +{{ +"application/x-graphable", +"" +}}; + +resource 'STR#' (126) +{{ +"Plugin for demonstration" +}}; diff --git a/lib/browserplugin-solution/examples/grapher/grapher.rc b/lib/browserplugin-solution/examples/grapher/grapher.rc new file mode 100644 index 0000000..4baba59 --- /dev/null +++ b/lib/browserplugin-solution/examples/grapher/grapher.rc @@ -0,0 +1,41 @@ +1 TYPELIB "grapher.rc" + +1 VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Trolltech\0" + VALUE "FileDescription", "grapher\0" + VALUE "FileExtents", "g1n\0" + VALUE "FileOpenName", "Graphable data (*.g1n)\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "grapher\0" + VALUE "LegalCopyright", "Copyright © 1997 Trolltech ASA\0" + VALUE "LegalTrademarks", "\0" + VALUE "MIMEType", "application/x-graphable\0" + VALUE "OriginalFilename", "grapher.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Trolltech grapher\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/lib/browserplugin-solution/examples/grapher/release/npgrapher.lib b/lib/browserplugin-solution/examples/grapher/release/npgrapher.lib new file mode 100644 index 0000000..47fb241 Binary files /dev/null and b/lib/browserplugin-solution/examples/grapher/release/npgrapher.lib differ diff --git a/lib/browserplugin-solution/examples/trivial/Info.plist b/lib/browserplugin-solution/examples/trivial/Info.plist new file mode 100644 index 0000000..3d34a4a --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + trivial + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BRPL + CFBundleSignature + TEST + CFBundleVersion + 0.0.1d1 + CSResourcesFileMapped + + WebPluginDescription + A very trivial plug-in + WebPluginMIMETypes + + trivial/very + + WebPluginTypeDescription + Very trivial mimetype + + + WebPluginName + Qt trivial test plug-in + + diff --git a/lib/browserplugin-solution/examples/trivial/debug/nptrivial.lib b/lib/browserplugin-solution/examples/trivial/debug/nptrivial.lib new file mode 100644 index 0000000..47c237c Binary files /dev/null and b/lib/browserplugin-solution/examples/trivial/debug/nptrivial.lib differ diff --git a/lib/browserplugin-solution/examples/trivial/release/nptrivial.lib b/lib/browserplugin-solution/examples/trivial/release/nptrivial.lib new file mode 100644 index 0000000..af7ca32 Binary files /dev/null and b/lib/browserplugin-solution/examples/trivial/release/nptrivial.lib differ diff --git a/lib/browserplugin-solution/examples/trivial/scripting.qdoc b/lib/browserplugin-solution/examples/trivial/scripting.qdoc new file mode 100644 index 0000000..6413771 --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/scripting.qdoc @@ -0,0 +1,65 @@ +/*! \page qtbrowserplugin-example-scripting.html + + \title Scripting Example + + This example demonstrates the combination of Javascript and a + trivial plugin, and the use of a plugin in combination with a form. + + If the browser supports scripting plugins, and everything is set up + correctly, the plugin below should react to mouse clicks and drags + by changing its text. The \c About... button should pop up an + \c{About Qt} dialog. The second plugin instance, below the + horizontal line, should display the word \c QtBrowserPlugin, and + pressing the \c Go! button should navigate the browser to a search + for this word at trolltech.com. + + \raw HTML + + + + + + + +

+ +
+ +
+
+ Search at Trolltech: + + +
+ \endraw + + Implementation: + + \quotefile trivial/trivial.cpp +*/ diff --git a/lib/browserplugin-solution/examples/trivial/trivial.cpp b/lib/browserplugin-solution/examples/trivial/trivial.cpp new file mode 100644 index 0000000..1ddd28b --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/trivial.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include +#include + +class Trivial : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + + Q_CLASSINFO("ClassID", "{5a22176d-118f-4185-9653-9f98958a6df8}") + Q_CLASSINFO("InterfaceID", "{2df735ba-da4f-4fb7-8f35-b8dfbf8cfd9a}") + Q_CLASSINFO("EventsID", "{449de213-f8bd-4d2e-a2cf-eab407c03245}") + + Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless") + Q_CLASSINFO("ToSuperClass", "Trivial") + Q_CLASSINFO("DefaultProperty", "text") + +public: + Trivial(QWidget *parent = 0) + : QWidget(parent) + { + m_text = QString::fromLatin1("Empty"); + } + + void mousePressEvent(QMouseEvent *) + { + mouseDown(); + } + void mouseMoveEvent(QMouseEvent *e) + { + mouseMove(e->x(), e->y()); + } + void mouseReleaseEvent(QMouseEvent*) + { + mouseUp(); + } + QString text() const + { + return m_text; + } + +public slots: + void about() + { + QMessageBox::aboutQt(this); + } + void setText(const QString &text) + { + m_text = text; + update(); + } + +signals: + void mouseDown(); + void mouseMove(int x, int y); + void mouseUp(); + +protected: + void paintEvent(QPaintEvent*) + { + QPainter p(this); + QRect r(rect()); + r.adjust(0, 0, -1, -1); + + p.drawRect(r); + p.drawText(r, Qt::AlignCenter, m_text); + } + +private: + QString m_text; +}; + +#include "trivial.moc" + +QTNPFACTORY_BEGIN("Trivial Qt-based Plugin", "A Qt-based LiveConnected plug-in that does nothing") + QTNPCLASS(Trivial) +QTNPFACTORY_END() + +#ifdef QAXSERVER +#include +QAXFACTORY_BEGIN("{aa3216bf-7e20-482c-84c6-06167bacb616}", "{08538ca5-eb7a-4f24-a3c4-a120c6e04dc4}") + QAXCLASS(Trivial) +QAXFACTORY_END() +#endif diff --git a/lib/browserplugin-solution/examples/trivial/trivial.pro b/lib/browserplugin-solution/examples/trivial/trivial.pro new file mode 100644 index 0000000..42941bc --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/trivial.pro @@ -0,0 +1,15 @@ +TARGET = trivial + +SOURCES = trivial.cpp + +win32 { + RC_FILE = trivial.rc +} else:mac { + QMAKE_INFO_PLIST = Info.plist + REZ_FILES += trivial.r + rsrc_files.files = trivial.rsrc + rsrc_files.path = Contents/Resources + QMAKE_BUNDLE_DATA += rsrc_files +} + +include(../../src/qtbrowserplugin.pri) diff --git a/lib/browserplugin-solution/examples/trivial/trivial.pro.user b/lib/browserplugin-solution/examples/trivial/trivial.pro.user new file mode 100644 index 0000000..002e3dc --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/trivial.pro.user @@ -0,0 +1,132 @@ + + + + RunConfiguration0-Arguments + + + + RunConfiguration0-Executable + + + + RunConfiguration0-RunConfiguration.name + Custom Executable + + + RunConfiguration0-WorkingDirectory + $BUILDDIR + + + RunConfiguration0-type + ProjectExplorer.CustomExecutableRunConfiguration + + + activeRunConfiguration + 0 + + + activebuildconfiguration + Debug + + + buildConfiguration-Debug + + Debug + 2 + D:\_C\aniplayer\plugin-solution\examples\trivial + + + + buildconfiguration-Debug-buildstep0 + + Debug + + + + buildconfiguration-Debug-buildstep1 + + Debug + 2 + + + + buildconfiguration-Debug-buildstep2 + + Debug + + + + buildconfiguration-Debug-cleanstep0 + + Debug + + + + buildconfiguration-Debug-cleanstep1 + + Debug + + + + buildconfigurations + + Debug + + + + buildstep0 + + + + + + buildstep1 + + + + + + + buildstep2 + + + + + + buildsteps + + trolltech.qt4projectmanager.gdbmaros + trolltech.qt4projectmanager.qmake + trolltech.qt4projectmanager.make + + + + cleanstep0 + + + true + + + + cleanstep1 + + + true + + + + cleansteps + + trolltech.qt4projectmanager.gdbmaros + trolltech.qt4projectmanager.make + + + + defaultFileEncoding + System + + + project + + + diff --git a/lib/browserplugin-solution/examples/trivial/trivial.qdoc b/lib/browserplugin-solution/examples/trivial/trivial.qdoc new file mode 100644 index 0000000..94aa1a6 --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/trivial.qdoc @@ -0,0 +1,18 @@ +/*! \page qtbrowserplugin-example-trivial.html + + \title Trivial Example + + This example is trivial, and thus useful for investigating problems + you might have installing plugins. If everything works correctly, + the \c trivial plugin should appear below as a rectangular field + below with some text in it: + + \raw HTML + + + \endraw + + Implementation: + + \quotefile trivial/trivial.cpp +*/ diff --git a/lib/browserplugin-solution/examples/trivial/trivial.r b/lib/browserplugin-solution/examples/trivial/trivial.r new file mode 100644 index 0000000..925bcee --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/trivial.r @@ -0,0 +1,19 @@ +#define SystemSevenOrLater 1 + +#include + +resource 'STR#' (127) +{{ +"A trivial Example plugin!" +}}; + +resource 'STR#' (128) +{{ +"trivial/very", +"" +}}; + +resource 'STR#' (126) +{{ +"Plugin for trivial uses" +}}; diff --git a/lib/browserplugin-solution/examples/trivial/trivial.rc b/lib/browserplugin-solution/examples/trivial/trivial.rc new file mode 100644 index 0000000..6113ae9 --- /dev/null +++ b/lib/browserplugin-solution/examples/trivial/trivial.rc @@ -0,0 +1,37 @@ +1 TYPELIB "trivial.rc" + +1 VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Trolltech\0" + VALUE "FileDescription", "trivial\0" + VALUE "FileExtents", "xxx\0" + VALUE "FileOpenName", "Nothing (*.xxx)\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "trivial\0" + VALUE "LegalCopyright", "Copyright © 1997 Trolltech AS\0" + VALUE "MIMEType", "trivial/very\0" + VALUE "OriginalFilename", "trivial.dll\0" + VALUE "ProductName", "Trolltech trivial\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/lib/browserplugin-solution/qtbrowserplugin.pro b/lib/browserplugin-solution/qtbrowserplugin.pro new file mode 100644 index 0000000..613343c --- /dev/null +++ b/lib/browserplugin-solution/qtbrowserplugin.pro @@ -0,0 +1,8 @@ +win32 { + !system(util\licensecheck.bat):error( "You are not licensed to use this software." ) +} else { + !system(util/licensecheck.sh):error( "You are not licensed to use this software." ) +} + +TEMPLATE = subdirs +SUBDIRS += examples diff --git a/lib/browserplugin-solution/src/qtbrowserplugin.cpp b/lib/browserplugin-solution/src/qtbrowserplugin.cpp new file mode 100644 index 0000000..ee07d6d --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin.cpp @@ -0,0 +1,1682 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include + +#include "qtnpapi.h" + +#include "qtbrowserplugin.h" +#include "qtbrowserplugin_p.h" + +#ifndef WINAPI +# ifdef Q_WS_WIN +# define WINAPI __stdcall +# else +# define WINAPI +# endif +#endif + +#ifdef Q_WS_X11 +# ifdef Bool +# undef Bool +# endif + +/* +static void debuginfo(const QString &str) +{ + static bool inited = false; + QFile file("/tmp/qnsdebug.txt"); + if (file.open(QFile::WriteOnly | QFile::Append)) { + if (!inited) { + file.write("\n\n*** New run started ***\n"); + inited = true; + } + file.write(qtNPFactory()->pluginName().toLatin1() + ": " + str.toLatin1() + '\n'); + file.close(); + } +} +*/ + +#endif + +static QtNPFactory *qNP = 0; +static NPNetscapeFuncs *qNetscapeFuncs = 0; + +// The single global plugin +QtNPFactory *qtNPFactory() +{ + extern QtNPFactory *qtns_instantiate(); + + if (!qNP) { + qNP = qtns_instantiate(); + } + + return qNP; +} + +// NPN functions, forwarding to function pointers provided by browser +void NPN_Version(int* plugin_major, int* plugin_minor, int* netscape_major, int* netscape_minor) +{ + Q_ASSERT(qNetscapeFuncs); + *plugin_major = NP_VERSION_MAJOR; + *plugin_minor = NP_VERSION_MINOR; + *netscape_major = qNetscapeFuncs->version >> 8; // Major version is in high byte + *netscape_minor = qNetscapeFuncs->version & 0xFF; // Minor version is in low byte +} + +#define NPN_Prolog(x) \ + Q_ASSERT(qNetscapeFuncs); \ + Q_ASSERT(qNetscapeFuncs->x); \ + + +const char *NPN_UserAgent(NPP instance) +{ + NPN_Prolog(uagent); + return FIND_FUNCTION_POINTER(NPN_UserAgentFP, qNetscapeFuncs->uagent)(instance); +} + +void NPN_Status(NPP instance, const char* message) +{ + NPN_Prolog(status); + FIND_FUNCTION_POINTER(NPN_StatusFP, qNetscapeFuncs->status)(instance, message); +} + +NPError NPN_GetURL(NPP instance, const char* url, const char* window) +{ + NPN_Prolog(geturl); + return FIND_FUNCTION_POINTER(NPN_GetURLFP, qNetscapeFuncs->geturl)(instance, url, window); +} + +NPError NPN_GetURLNotify(NPP instance, const char* url, const char* window, void* notifyData) +{ + if ((qNetscapeFuncs->version & 0xFF) < NPVERS_HAS_NOTIFICATION) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + NPN_Prolog(geturlnotify); + return FIND_FUNCTION_POINTER(NPN_GetURLNotifyFP, qNetscapeFuncs->geturlnotify)(instance, url, window, notifyData); +} + +NPError NPN_PostURLNotify(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData) +{ + if ((qNetscapeFuncs->version & 0xFF) < NPVERS_HAS_NOTIFICATION) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + NPN_Prolog(posturlnotify); + return FIND_FUNCTION_POINTER(NPN_PostURLNotifyFP, qNetscapeFuncs->posturlnotify)(instance, url, window, len, buf, file, notifyData); +} + +void* NPN_MemAlloc(uint32 size) +{ + NPN_Prolog(memalloc); + return FIND_FUNCTION_POINTER(NPN_MemAllocFP, qNetscapeFuncs->memalloc)(size); +} + +void NPN_MemFree(void* ptr) +{ + NPN_Prolog(memfree); + FIND_FUNCTION_POINTER(NPN_MemFreeFP, qNetscapeFuncs->memfree)(ptr); +} + +uint32 NPN_MemFlush(uint32 size) +{ + NPN_Prolog(memflush); + return FIND_FUNCTION_POINTER(NPN_MemFlushFP, qNetscapeFuncs->memflush)(size); +} + +NPError NPN_GetValue(NPP instance, NPNVariable variable, void *ret_value) +{ + NPN_Prolog(getvalue); + return FIND_FUNCTION_POINTER(NPN_GetValueFP, qNetscapeFuncs->getvalue)(instance, variable, ret_value); +} + +NPError NPN_SetValue(NPP instance, NPPVariable variable, void *ret_value) +{ + NPN_Prolog(setvalue); + return FIND_FUNCTION_POINTER(NPN_SetValueFP, qNetscapeFuncs->setvalue)(instance, variable, ret_value); +} + +NPIdentifier NPN_GetStringIdentifier(const char* name) +{ + NPN_Prolog(getstringidentifier); + return FIND_FUNCTION_POINTER(NPN_GetStringIdentifierFP, qNetscapeFuncs->getstringidentifier)(name); +} + +void NPN_GetStringIdentifiers(const char** names, int32 nameCount, NPIdentifier* identifiers) +{ + NPN_Prolog(getstringidentifiers); + FIND_FUNCTION_POINTER(NPN_GetStringIdentifiersFP, qNetscapeFuncs->getstringidentifiers)(names, nameCount, identifiers); +} + +NPIdentifier NPN_GetIntIdentifier(int32 intid) +{ + NPN_Prolog(getintidentifier); + return FIND_FUNCTION_POINTER(NPN_GetIntIdentifierFP, qNetscapeFuncs->getintidentifier)(intid); +} + +bool NPN_IdentifierIsString(NPIdentifier identifier) +{ + NPN_Prolog(identifierisstring); + return FIND_FUNCTION_POINTER(NPN_IdentifierIsStringFP, qNetscapeFuncs->identifierisstring)(identifier); +} + +char* NPN_UTF8FromIdentifier(NPIdentifier identifier) +{ + NPN_Prolog(utf8fromidentifier); + return FIND_FUNCTION_POINTER(NPN_UTF8FromIdentifierFP, qNetscapeFuncs->utf8fromidentifier)(identifier); +} + +int32 NPN_IntFromIdentifier(NPIdentifier identifier) +{ + NPN_Prolog(intfromidentifier); + return FIND_FUNCTION_POINTER(NPN_IntFromIdentifierFP, qNetscapeFuncs->intfromidentifier)(identifier); +} + +NPObject* NPN_CreateObject(NPP npp, NPClass *aClass) +{ + NPN_Prolog(createobject); + return FIND_FUNCTION_POINTER(NPN_CreateObjectFP, qNetscapeFuncs->createobject)(npp, aClass); +} + +NPObject* NPN_RetainObject(NPObject *obj) +{ + NPN_Prolog(retainobject); + return FIND_FUNCTION_POINTER(NPN_RetainObjectFP, qNetscapeFuncs->retainobject)(obj); +} + +void NPN_ReleaseObject(NPObject *obj) +{ + NPN_Prolog(releaseobject); + FIND_FUNCTION_POINTER(NPN_ReleaseObjectFP, qNetscapeFuncs->releaseobject)(obj); +} + +// Scripting implementation (QObject calling JavaScript in browser) - we don't use those +bool NPN_Invoke(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, int32 argCount, NPVariant *result) +{ + NPN_Prolog(invoke); + return FIND_FUNCTION_POINTER(NPN_InvokeFP, qNetscapeFuncs->invoke)(npp, obj, methodName, args, argCount, result); +} + +bool NPN_InvokeDefault(NPP npp, NPObject* obj, const NPVariant *args, int32 argCount, NPVariant *result) +{ + NPN_Prolog(invokedefault); + return FIND_FUNCTION_POINTER(NPN_InvokeDefaultFP, qNetscapeFuncs->invokedefault)(npp, obj, args, argCount, result); +} + +bool NPN_Evaluate(NPP npp, NPObject *obj, NPString *script, NPVariant *result) +{ + NPN_Prolog(evaluate); + return FIND_FUNCTION_POINTER(NPN_EvaluateFP, qNetscapeFuncs->evaluate)(npp, obj, script, result); +} + +bool NPN_GetProperty(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result) +{ + NPN_Prolog(getproperty); + return FIND_FUNCTION_POINTER(NPN_GetPropertyFP, qNetscapeFuncs->getproperty)(npp, obj, propertyName, result); +} + +bool NPN_SetProperty(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value) +{ + NPN_Prolog(setproperty); + return FIND_FUNCTION_POINTER(NPN_SetPropertyFP, qNetscapeFuncs->setproperty)(npp, obj, propertyName, value); +} + +bool NPN_RemoveProperty(NPP npp, NPObject *obj, NPIdentifier propertyName) +{ + NPN_Prolog(removeproperty); + return FIND_FUNCTION_POINTER(NPN_RemovePropertyFP, qNetscapeFuncs->removeproperty)(npp, obj, propertyName); +} + +bool NPN_HasProperty(NPP npp, NPObject *obj, NPIdentifier propertyName) +{ + NPN_Prolog(hasproperty); + return FIND_FUNCTION_POINTER(NPN_HasPropertyFP, qNetscapeFuncs->hasproperty)(npp, obj, propertyName); +} + +bool NPN_HasMethod(NPP npp, NPObject *obj, NPIdentifier methodName) +{ + NPN_Prolog(hasmethod); + return FIND_FUNCTION_POINTER(NPN_HasMethodFP, qNetscapeFuncs->hasmethod)(npp, obj, methodName); +} + +void NPN_ReleaseVariantValue(NPVariant *variant) +{ + NPN_Prolog(releasevariantvalue); + FIND_FUNCTION_POINTER(NPN_ReleaseVariantValueFP, qNetscapeFuncs->releasevariantvalue)(variant); +} + +void NPN_SetException(NPObject *obj, const char *message) +{ + qDebug("NPN_SetException: %s", message); + NPN_Prolog(setexception); + FIND_FUNCTION_POINTER(NPN_SetExceptionFP, qNetscapeFuncs->setexception)(obj, message); +} + +// Scripting implementation (JavaScript calling QObject) +#define NPClass_Prolog \ + if (!npobj->_class) return false; \ + if (!npobj->_class->qtnp) return false; \ + QtNPInstance *This = npobj->_class->qtnp; \ + if (!This->qt.object) return false; \ + QObject *qobject = This->qt.object \ + + +static NPObject *NPAllocate(NPP npp, NPClass *aClass) +{ + Q_UNUSED(npp); + Q_UNUSED(aClass); + + Q_ASSERT(false); + return 0; +} + +static void NPDeallocate(NPObject *npobj) +{ + Q_UNUSED(npobj); + + Q_ASSERT(false); + return; +} + +static void NPInvalidate(NPObject *npobj) +{ + if (npobj) + delete npobj->_class; + npobj->_class = 0; +} + +enum MetaOffset { MetaProperty, MetaMethod }; + +static int metaOffset(const QMetaObject *metaObject, MetaOffset offsetType) +{ + int classInfoIndex = metaObject->indexOfClassInfo("ToSuperClass"); + if (classInfoIndex == -1) + return 0; + QByteArray ToSuperClass = metaObject->classInfo(classInfoIndex).value(); + int offset = offsetType == MetaProperty ? metaObject->propertyOffset() + : metaObject->methodOffset(); + + while (ToSuperClass != metaObject->className()) { + metaObject = metaObject->superClass(); + if (!metaObject) + break; + offset -= offsetType == MetaProperty ? metaObject->propertyCount() + : metaObject->methodCount(); + } + return offset; +} + +static int publicMethodIndex(NPObject *npobj, const QByteArray &slotName, int argCount = -1) +{ + NPClass_Prolog; + const QMetaObject *metaObject = qobject->metaObject(); + for (int slotIndex = metaOffset(metaObject, MetaMethod); slotIndex < metaObject->methodCount(); ++slotIndex) { + const QMetaMethod slot = qobject->metaObject()->method(slotIndex); + if (slot.access() != QMetaMethod::Public || slot.methodType() == QMetaMethod::Signal) + continue; + QByteArray signature = slot.signature(); + if (signature.left(signature.indexOf('(')) == slotName) { + if (argCount == -1 || slot.parameterTypes().count() == argCount) + return slotIndex; + } + } + return -1; +} + +static bool NPClass_HasMethod(NPObject *npobj, NPIdentifier name) +{ + NPClass_Prolog; + Q_UNUSED(qobject); + return publicMethodIndex(npobj, NPN_UTF8FromIdentifier(name)) != -1; +} + +static bool NPClass_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32 argCount, NPVariant *result) +{ + NPClass_Prolog; + const QByteArray slotName = NPN_UTF8FromIdentifier(name); + int slotIndex = publicMethodIndex(npobj, slotName, static_cast(argCount)); + if (slotIndex == -1) { + NPN_SetException(npobj, QByteArray("No method '" + slotName + "' with " + QByteArray::number(argCount) + " parameters").constData()); + return false; + } + + const QMetaMethod slot = qobject->metaObject()->method(slotIndex); + QList parameterTypes = slot.parameterTypes(); + if (parameterTypes.count() != static_cast(argCount)) { + NPN_SetException(npobj, QByteArray("Wrong parameter count for method " + slotName).constData()); + return false; + } + + QVariant returnVariant(QVariant::nameToType(slot.typeName()), (void*)0); + QVector variants(parameterTypes.count()); // keep data alive + QVector metacallArgs(parameterTypes.count() + 1); // arguments for qt_metacall + metacallArgs[0] = returnVariant.data(); // args[0] == return value + + for (int p = 0; p < parameterTypes.count(); ++p) { + QVariant::Type type = QVariant::nameToType(parameterTypes.at(p)); + if (type == QVariant::Invalid && parameterTypes.at(p) != "QVariant") { + NPN_SetException(npobj, QString("Parameter %1 in method '%2' has invalid type") + .arg(p).arg(QString::fromUtf8(slotName)).toAscii().constData()); + return false; + } + QVariant qvar = args[p]; + if (type != QVariant::Invalid && !qvar.convert(type)) { + NPN_SetException(npobj, QString("Parameter %1 to method '%2' needs to be convertable to '%3'") + .arg(p).arg(QString::fromUtf8(slotName)).arg(QString::fromAscii(parameterTypes.at(p))).toAscii().constData()); + return false; + } + + variants[p] = qvar; + if (type == QVariant::Invalid) + metacallArgs[p + 1] = &variants.at(p); + else + metacallArgs[p + 1] = variants.at(p).constData(); // must not detach! + } + + qobject->qt_metacall(QMetaObject::InvokeMetaMethod, slotIndex, const_cast(metacallArgs.data())); + if (returnVariant.isValid() && result) + *result = NPVariant::fromQVariant(This, returnVariant); + + return true; +} + +static bool NPClass_InvokeDefault(NPObject * /*npobj*/, const NPVariant * /*args*/, uint32 /*argCount*/, NPVariant * /*result*/) +{ + return false; +} + +static bool NPClass_HasProperty(NPObject *npobj, NPIdentifier name) +{ + NPClass_Prolog; + const QByteArray qname = NPN_UTF8FromIdentifier(name); + const QMetaObject *metaObject = qobject->metaObject(); + int propertyIndex = metaObject->indexOfProperty(qname); + if (propertyIndex == -1 || propertyIndex < metaOffset(metaObject, MetaProperty)) + return false; + QMetaProperty property = qobject->metaObject()->property(propertyIndex); + if (!property.isScriptable()) + return false; + + return true; +} + +static bool NPClass_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) +{ + NPClass_Prolog; + const QByteArray qname = NPN_UTF8FromIdentifier(name); + QVariant qvar = qobject->property(qname); + if (!qvar.isValid()) { + NPN_SetException(npobj, QByteArray("Failed to get value for property " + qname).constData()); + return false; + } + *result = NPVariant::fromQVariant(This, qvar); + return true; +} + +static bool NPClass_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *result) +{ + NPClass_Prolog; + const QByteArray qname = NPN_UTF8FromIdentifier(name); + QVariant qvar = *result; + return qobject->setProperty(qname, qvar); +} + +static bool NPClass_RemoveProperty(NPObject * /*npobj*/, NPIdentifier /*name*/) +{ + return false; +} + +NPClass::NPClass(QtNPInstance *This) +{ + structVersion = NP_CLASS_STRUCT_VERSION; + allocate = 0; + deallocate = 0; + invalidate = NPInvalidate; + hasMethod = NPClass_HasMethod; + invoke = NPClass_Invoke; + invokeDefault = NPClass_InvokeDefault; + hasProperty = NPClass_HasProperty; + getProperty = NPClass_GetProperty; + setProperty = NPClass_SetProperty; + removeProperty = NPClass_RemoveProperty; + qtnp = This; + delete_qtnp = false; +} + +NPClass::~NPClass() +{ + if (delete_qtnp) + delete qtnp; +} + +// Type conversions +NPString NPString::fromQString(const QString &qstr) +{ + NPString npstring; + const QByteArray qutf8 = qstr.toUtf8(); + + npstring.utf8length = qutf8.length(); + npstring.utf8characters = (char*)NPN_MemAlloc(npstring.utf8length); + memcpy((char*)npstring.utf8characters, qutf8.constData(), npstring.utf8length); + + return npstring; +} + +NPString::operator QString() const +{ + return QString::fromUtf8(utf8characters, utf8length); +} + +NPVariant NPVariant::fromQVariant(QtNPInstance *This, const QVariant &qvariant) +{ + Q_ASSERT(This); + NPVariant npvar; + npvar.type = Null; + + QVariant qvar(qvariant); + switch(qvariant.type()) { + case QVariant::Bool: + npvar.value.boolValue = qvar.toBool(); + npvar.type = Boolean; + break; + case QVariant::Int: + npvar.value.intValue = qvar.toInt(); + npvar.type = Int32; + break; + case QVariant::Double: + npvar.value.doubleValue = qvar.toDouble(); + npvar.type = Double; + break; + case QVariant::UserType: + { + QByteArray userType = qvariant.typeName(); + if (userType.endsWith('*')) { + QtNPInstance *that = new QtNPInstance; + that->npp = This->npp; + that->qt.object = *(QObject**)qvariant.constData(); + NPClass *npclass = new NPClass(that); + npclass->delete_qtnp = true; + npvar.value.objectValue = NPN_CreateObject(This->npp, npclass); + npvar.type = Object; + } + } + break; + default: // including QVariant::String + if (!qvar.convert(QVariant::String)) + break; + npvar.type = String; + npvar.value.stringValue = NPString::fromQString(qvar.toString()); + break; + } + + return npvar; +} + +NPVariant::operator QVariant() const +{ + switch(type) { + case Void: + case Null: + return QVariant(); + case Object: + { + if (!value.objectValue || !value.objectValue->_class) + break; + NPClass *aClass = value.objectValue->_class; + // not one of ours? + if (aClass->invoke != NPClass_Invoke) + break; + // or just empty for some reason + QObject *qobject = aClass->qtnp->qt.object; + if (!qobject) + break; + QByteArray typeName = qobject->metaObject()->className(); + int userType = QMetaType::type(typeName + "*"); + if (userType == QVariant::Invalid) + break; + QVariant result(userType, &aClass->qtnp->qt.object); + // sanity check + Q_ASSERT(*(QObject**)result.constData() == aClass->qtnp->qt.object); + return result; + } + case Boolean: + return value.boolValue; + case Int32: + return value.intValue; + case Double: + return value.doubleValue; + case String: + return QString(value.stringValue); + default: + break; + } + return QVariant(); +} + +// Helper class for handling incoming data +class QtNPStream +{ +public: + QtNPStream(NPP instance, NPStream *st); + virtual ~QtNPStream() + { + } + + QString url() const; + bool finish(QtNPBindable *bindable); + + QByteArray buffer; + QFile file; + QString mime; + + NPError reason; + + NPP npp; + NPStream* stream; + +protected: + qint64 readData(char *, qint64); + qint64 writeData(const char *, qint64); +}; + +QtNPStream::QtNPStream(NPP instance, NPStream *st) + : reason(NPRES_DONE), npp(instance), stream(st) +{ +} + +/*! + Returns the URL from which the stream was created, or the empty string + for write-only streams. +*/ +QString QtNPStream::url() const +{ + if (!stream) + return QString(); + return QString::fromLocal8Bit(stream->url); +} + +class ErrorBuffer : public QBuffer +{ + friend class QtNPStream; +}; + +bool QtNPStream::finish(QtNPBindable *bindable) +{ + if (!bindable) + return false; + + bool res = false; + if (bindable) { + switch(reason) { + case NPRES_DONE: + // no data at all? url is probably local file (Opera) + if (buffer.isEmpty() && file.fileName().isEmpty()) { + QUrl u = QUrl::fromEncoded(stream->url); + QString lfn = u.toLocalFile(); + if (lfn.startsWith("//localhost/")) + lfn = lfn.mid(12); + file.setFileName(lfn); + } + + if (file.exists()) { + file.setObjectName(url()); + res = bindable->readData(&file, mime); + } else { + QBuffer io(&buffer); + io.setObjectName(url()); + res = bindable->readData(&io, mime); + } + break; + case NPRES_USER_BREAK: + { + ErrorBuffer empty; + empty.setObjectName(url()); + empty.setErrorString("User cancelled operation."), + res = bindable->readData(&empty, mime); + } + break; + case NPRES_NETWORK_ERR: + { + ErrorBuffer empty; + empty.setObjectName(url()); + empty.setErrorString("Network error during download."), + res = bindable->readData(&empty, mime); + } + break; + default: + break; + } + } + stream->pdata = 0; + delete this; + return res; +} + +// Helper class for forwarding signal emissions to the respective JavaScript +class QtSignalForwarder : public QObject +{ +public: + QtSignalForwarder(QtNPInstance *that) + : This(that), domNode(0) + { + } + + ~QtSignalForwarder() + { + if (domNode) + NPN_ReleaseObject(domNode); + } + + int qt_metacall(QMetaObject::Call call, int index, void **args); + +private: + QtNPInstance *This; + NPObject *domNode; +}; + +int QtSignalForwarder::qt_metacall(QMetaObject::Call call, int index, void **args) +{ + // no support for QObject method/properties etc! + if (!This || !This->npp || call != QMetaObject::InvokeMetaMethod + || !This->qt.object) + return index; + + switch (index) { + case -1: + { + QString msg = *(QString*)args[1]; + NPN_Status(This->npp, msg.toLocal8Bit().constData()); + } + break; + default: + { + QObject *qobject = This->qt.object; + if (!domNode) + NPN_GetValue(This->npp, NPNVPluginElementNPObject, &domNode); + if (!domNode) + break; + const QMetaObject *metaObject = qobject->metaObject(); + if (index < metaOffset(metaObject, MetaMethod)) + break; + + const QMetaMethod method = metaObject->method(index); + Q_ASSERT(method.methodType() == QMetaMethod::Signal); + + QByteArray signalSignature = method.signature(); + QByteArray scriptFunction = signalSignature.left(signalSignature.indexOf('(')); + NPIdentifier id = NPN_GetStringIdentifier(scriptFunction.constData()); + if (NPN_HasMethod(This->npp, domNode, id)) { + QList parameterTypes = method.parameterTypes(); + QVector parameters; + NPVariant result; + bool error = false; + for (int p = 0; p < parameterTypes.count(); ++p) { + QVariant::Type type = QVariant::nameToType(parameterTypes.at(p)); + if (type == QVariant::Invalid) { + NPN_SetException(domNode, QByteArray("Unsupported parameter type in ") + scriptFunction); + error = true; + break; + } + QVariant qvar(type, args[p + 1]); + NPVariant npvar = NPVariant::fromQVariant(This, qvar); + if (npvar.type == NPVariant::Null || npvar.type == NPVariant::Void) { + NPN_SetException(domNode, QByteArray("Unsupported parameter value in ") + scriptFunction); + error =true; + break; + } + parameters += npvar; + } + if (error) + break; + + NPError nperror = NPN_Invoke(This->npp, domNode, id, parameters.constData(), parameters.count(), &result); + if (nperror != NPERR_NO_ERROR && false) { // disabled, as NPN_Invoke seems to always return GENERICERROR + NPN_SetException(domNode, QByteArray("Error invoking event handler ") + scriptFunction); + } + // ### TODO: update return value (args[0]) (out-parameters not supported anyway) + NPN_ReleaseVariantValue(&result); + } + } + break; + } + + return index; +} + + +// Plugin functions +extern "C" NPError +NPP_GetValue(NPP instance, NPPVariable variable, void *value) +{ + if (!instance || !instance->pdata) + return NPERR_INVALID_INSTANCE_ERROR; + + QtNPInstance* This = (QtNPInstance*) instance->pdata; + + switch (variable) { + case NPPVpluginNameString: + { + static QByteArray name = qtNPFactory()->pluginName().toLocal8Bit(); + *(const char**)value = name.constData(); + } + break; + case NPPVpluginDescriptionString: + { + static QByteArray description = qtNPFactory()->pluginDescription().toLocal8Bit(); + *(const char**)value = description.constData(); + } + break; + +#ifdef Q_WS_X11 + case NPPVpluginNeedsXEmbed: + *(int*)value = true; // PRBool = int + break; +#endif + + case NPPVpluginScriptableNPObject: + { + NPObject *object = NPN_CreateObject(instance, new NPClass(This)); + *(NPObject**)value = object; + } + break; + case NPPVformValue: + { + QObject *object = This->qt.object; + const QMetaObject *metaObject = object->metaObject(); + int defaultIndex = metaObject->indexOfClassInfo("DefaultProperty"); + if (defaultIndex == -1) + return NPERR_GENERIC_ERROR; + QByteArray defaultProperty = metaObject->classInfo(defaultIndex).value(); + if (defaultProperty.isEmpty()) + return NPERR_GENERIC_ERROR; + QVariant defaultValue = object->property(defaultProperty); + if (!defaultValue.isValid()) + return NPERR_GENERIC_ERROR; + defaultProperty = defaultValue.toString().toUtf8(); + int size = defaultProperty.size(); + char *utf8 = (char*)NPN_MemAlloc(size + 1); + memcpy(utf8, defaultProperty.constData(), size); + utf8[size] = 0; // null-terminator + *(void**)value = utf8; + } + break; + default: + return NPERR_GENERIC_ERROR; + } + + return NPERR_NO_ERROR; +} + +extern "C" NPError +NPP_SetValue(NPP instance, NPPVariable variable, void *value) +{ + Q_UNUSED(variable); + Q_UNUSED(value); + + if (!instance || !instance->pdata) + return NPERR_INVALID_INSTANCE_ERROR; + + /* + switch(variable) { + default: + return NPERR_GENERIC_ERROR; + } + */ + return NPERR_NO_ERROR; +} + +extern "C" int16 NPP_Event(NPP instance, NPEvent* event) +{ + if (!instance || !instance->pdata) + return NPERR_INVALID_INSTANCE_ERROR; + + QtNPInstance* This = (QtNPInstance*) instance->pdata; + extern bool qtns_event(QtNPInstance *, NPEvent *); + return qtns_event(This, event) ? 1 : 0; +} + +#ifdef Q_WS_X11 +// Instance state information about the plugin. +extern "C" char* +NP_GetMIMEDescription(void) +{ + static QByteArray mime = qtNPFactory()->mimeTypes().join(";").toLocal8Bit(); + return (char*)mime.constData(); +} + +extern "C" NPError +NP_GetValue(void*, NPPVariable aVariable, void *aValue) +{ + NPError err = NPERR_NO_ERROR; + + static QByteArray name = qtNPFactory()->pluginName().toLocal8Bit(); + static QByteArray descr = qtNPFactory()->pluginDescription().toLocal8Bit(); + + switch (aVariable) { + case NPPVpluginNameString: + *static_cast (aValue) = name.constData(); + break; + case NPPVpluginDescriptionString: + *static_cast(aValue) = descr.constData(); + break; + case NPPVpluginNeedsXEmbed: + *static_cast(aValue) = true; + break; + case NPPVpluginTimerInterval: + case NPPVpluginKeepLibraryInMemory: + default: + err = NPERR_INVALID_PARAM; + break; + } + return err; +} +#endif + +/* +** NPP_New is called when your plugin is instantiated (i.e. when an EMBED +** tag appears on a page). +*/ +extern "C" NPError +NPP_New(NPMIMEType pluginType, + NPP instance, + uint16 mode, + int16 argc, + char* argn[], + char* argv[], + NPSavedData* /*saved*/) +{ + if (!instance) + return NPERR_INVALID_INSTANCE_ERROR; + + QtNPInstance* This = new QtNPInstance; + if (!This) + return NPERR_OUT_OF_MEMORY_ERROR; + + instance->pdata = This; + This->filter = 0; + This->bindable = 0; + This->npp = instance; + This->fMode = mode; // NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h) + This->window = 0; + This->qt.object = 0; +#ifdef Q_WS_MAC + This->rootWidget = 0; +#endif + This->pendingStream = 0; // stream might be created before instance + This->mimetype = QString::fromLatin1(pluginType); + This->notificationSeqNum = 0; + + for (int i = 0; i < argc; i++) { + QByteArray name = QByteArray(argn[i]).toLower(); + if (name == "id") + This->htmlID = argv[i]; + This->parameters[name] = QVariant(argv[i]); + } + + return NPERR_NO_ERROR; +} + +extern "C" NPError +NPP_Destroy(NPP instance, NPSavedData** /*save*/) +{ + if (!instance || !instance->pdata) + return NPERR_INVALID_INSTANCE_ERROR; + + QtNPInstance* This = (QtNPInstance*) instance->pdata; + +#ifdef Q_WS_X11 + //This->widget->destroy(false, false); // X has destroyed all windows +#endif + delete This->qt.object; + This->qt.object = 0; + delete This->filter; + This->filter = 0; + extern void qtns_destroy(QtNPInstance *This); + qtns_destroy(This); + delete This; + instance->pdata = 0; + + return NPERR_NO_ERROR; +} + +static QtNPInstance *next_pi = 0; // helper to connect to QtNPBindable + +extern "C" NPError +NPP_SetWindow(NPP instance, NPWindow* window) +{ + if (!instance) + return NPERR_INVALID_INSTANCE_ERROR; + + QtNPInstance* This = (QtNPInstance*) instance->pdata; + extern void qtns_setGeometry(QtNPInstance*, const QRect &, const QRect &); + + const QRect clipRect(window->clipRect.left, window->clipRect.top, + window->clipRect.right - window->clipRect.left, + window->clipRect.bottom - window->clipRect.top); + if (window) + This->geometry = QRect(window->x, window->y, window->width, window->height); + + // take a shortcut if all that was changed is the geometry + if (qobject_cast(This->qt.object) && window && This->window == (QtNPInstance::Widget)window->window) { + qtns_setGeometry(This, This->geometry, clipRect); + return NPERR_NO_ERROR; + } + + delete This->qt.object; + This->qt.object = 0; + extern void qtns_destroy(QtNPInstance *This); + qtns_destroy(This); + + if (!window) { + This->window = 0; + return NPERR_NO_ERROR; + } + + This->window = (QtNPInstance::Widget)window->window; +#ifdef Q_WS_X11 + //This->display = ((NPSetWindowCallbackStruct *)window->ws_info)->display; +#endif + + extern void qtns_initialize(QtNPInstance*); + qtns_initialize(This); + + next_pi = This; + This->qt.object = qtNPFactory()->createObject(This->mimetype); + next_pi = 0; + + if (!This->qt.object) + return NPERR_NO_ERROR; + + if (!This->htmlID.isEmpty()) + This->qt.object->setObjectName(QLatin1String(This->htmlID)); + + This->filter = new QtSignalForwarder(This); + QStatusBar *statusbar = qFindChild(This->qt.object); + if (statusbar) { + int statusSignal = statusbar->metaObject()->indexOfSignal("messageChanged(QString)"); + if (statusSignal != -1) { + QMetaObject::connect(statusbar, statusSignal, This->filter, -1); + statusbar->hide(); + } + } + + const QMetaObject *mo = This->qt.object->metaObject(); + for (int p = 0; p < mo->propertyCount(); ++p) { + const QMetaProperty property = mo->property(p); + QByteArray name(property.name()); + QVariant value = This->parameters.value(name.toLower()); + if (value.isValid()) + property.write(This->qt.object, value); + } + for (int methodIndex = 0; methodIndex < mo->methodCount(); ++methodIndex) { + const QMetaMethod method = mo->method(methodIndex); + if (method.methodType() == QMetaMethod::Signal) + QMetaObject::connect(This->qt.object, methodIndex, This->filter, methodIndex); + } + + if (This->pendingStream) { + This->pendingStream->finish(This->bindable); + This->pendingStream = 0; + } + + if (!qobject_cast(This->qt.object)) + return NPERR_NO_ERROR; + + extern void qtns_embed(QtNPInstance*); + qtns_embed(This); + + QEvent e(QEvent::EmbeddingControl); + QApplication::sendEvent(This->qt.widget, &e); + + if (!This->qt.widget->testAttribute(Qt::WA_PaintOnScreen)) + This->qt.widget->setAutoFillBackground(true); + This->qt.widget->raise(); + qtns_setGeometry(This, This->geometry, clipRect); + This->qt.widget->show(); + + return NPERR_NO_ERROR; +} + +extern "C" NPError +NPP_NewStream(NPP instance, + NPMIMEType type, + NPStream *stream, + NPBool /*seekable*/, + uint16 *stype) +{ + if (!instance) + return NPERR_INVALID_INSTANCE_ERROR; + + QtNPInstance* This = (QtNPInstance*) instance->pdata; + if (!This) + return NPERR_NO_ERROR; + + QtNPStream *qstream = new QtNPStream(instance, stream); + qstream->mime = QString::fromLocal8Bit(type); + stream->pdata = qstream; + + *stype = NP_ASFILEONLY; + + return NPERR_NO_ERROR; +} + +extern "C" int32 +NPP_WriteReady(NPP, NPStream *stream) +{ + if (stream->pdata) + return 0x0FFFFFFF; + return 0; +} + +// Both Netscape and FireFox call this for OnDemand streams as well... +extern "C" int32 +NPP_Write(NPP instance, NPStream *stream, int32 /*offset*/, int32 len, void *buffer) +{ + if (!instance || !stream || !stream->pdata) + return NPERR_INVALID_INSTANCE_ERROR; + + // this should not be called, as we always demand a download + QtNPStream *qstream = (QtNPStream*)stream->pdata; + QByteArray data((const char*)buffer, len); // make deep copy + qstream->buffer += data; + + return len; +} + +// Opera calls this for OnDemand streams without calling NPP_Write first +extern "C" NPError +NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) +{ + if (!instance || !instance->pdata || !stream || !stream->pdata) + return NPERR_INVALID_INSTANCE_ERROR; + + QtNPInstance *This = (QtNPInstance*)instance->pdata; + QtNPStream *qstream = (QtNPStream*)stream->pdata; + qstream->reason = reason; + + if (!This->qt.object) { // not yet initialized + This->pendingStream = qstream; + return NPERR_NO_ERROR; + } + + This->pendingStream = 0; + qstream->finish(This->bindable); + + return NPERR_NO_ERROR; +} + +extern "C" void +NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) +{ + if (!instance || !stream || !stream->pdata) + return; + + QString path = QString::fromLocal8Bit(fname); +#ifdef Q_WS_MAC + path = "/" + path.section(':', 1).replace(':', '/'); +#endif + + QtNPStream *qstream = (QtNPStream*)stream->pdata; + qstream->file.setFileName(path); +} + +extern "C" void +NPP_URLNotify(NPP instance, + const char* url, + NPReason reason, + void* notifyData) +{ + if (!instance) + return; + QtNPInstance* This = (QtNPInstance*) instance->pdata; + if (!This->bindable) + return; + + QtNPBindable::Reason r; + switch (reason) { + case NPRES_DONE: + r = QtNPBindable::ReasonDone; + break; + case NPRES_USER_BREAK: + r = QtNPBindable::ReasonBreak; + break; + case NPRES_NETWORK_ERR: + r = QtNPBindable::ReasonError; + break; + default: + r = QtNPBindable::ReasonUnknown; + break; + } + + qint32 id = static_cast(reinterpret_cast(notifyData)); + if (id < 0) // Sanity check + id = 0; + + This->bindable->transferComplete(QString::fromLocal8Bit(url), id, r); +} + +extern "C" void +NPP_Print(NPP instance, NPPrint* printInfo) +{ + if(!printInfo || !instance) + return; + + QtNPInstance* This = (QtNPInstance*) instance->pdata; + if (!This->bindable) + return; + +/* + if (printInfo->mode == NP_FULL) { + printInfo->print.fullPrint.pluginPrinted = This->bindable->printFullPage(); + } else if (printInfo->mode == NP_EMBED) { + extern void qtns_print(QtNPInstance*, NPPrint*); + qtns_print(This, printInfo); + } +*/ +} + +// Plug-in entrypoints - these are called by the browser + +// Fills in functiontable used by browser to call entry points in plugin. +extern "C" NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pFuncs) +{ + if(!pFuncs) + return NPERR_INVALID_FUNCTABLE_ERROR; + if(!pFuncs->size) + pFuncs->size = sizeof(NPPluginFuncs); + else if (pFuncs->size < sizeof(NPPluginFuncs)) + return NPERR_INVALID_FUNCTABLE_ERROR; + + pFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; + pFuncs->newp = MAKE_FUNCTION_POINTER(NPP_New); + pFuncs->destroy = MAKE_FUNCTION_POINTER(NPP_Destroy); + pFuncs->setwindow = MAKE_FUNCTION_POINTER(NPP_SetWindow); + pFuncs->newstream = MAKE_FUNCTION_POINTER(NPP_NewStream); + pFuncs->destroystream = MAKE_FUNCTION_POINTER(NPP_DestroyStream); + pFuncs->asfile = MAKE_FUNCTION_POINTER(NPP_StreamAsFile); + pFuncs->writeready = MAKE_FUNCTION_POINTER(NPP_WriteReady); + pFuncs->write = MAKE_FUNCTION_POINTER(NPP_Write); + pFuncs->print = MAKE_FUNCTION_POINTER(NPP_Print); + pFuncs->event = MAKE_FUNCTION_POINTER(NPP_Event); + pFuncs->urlnotify = MAKE_FUNCTION_POINTER(NPP_URLNotify); + pFuncs->javaClass = 0; + pFuncs->getvalue = MAKE_FUNCTION_POINTER(NPP_GetValue); + pFuncs->setvalue = MAKE_FUNCTION_POINTER(NPP_SetValue); + return NPERR_NO_ERROR; +} + +enum NPNToolkitType +{ + NPNVGtk12 = 1, + NPNVGtk2 +}; + +#ifndef Q_WS_X11 +extern "C" NPError WINAPI NP_Initialize(NPNetscapeFuncs* pFuncs) +{ + if(!pFuncs) + return NPERR_INVALID_FUNCTABLE_ERROR; + + qNetscapeFuncs = pFuncs; + int navMajorVers = qNetscapeFuncs->version >> 8; + + // if the plugin's major version is lower than the Navigator's, + // then they are incompatible, and should return an error + if(navMajorVers > NP_VERSION_MAJOR) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + return NPERR_NO_ERROR; +} +#else +extern "C" NPError WINAPI NP_Initialize(NPNetscapeFuncs* nFuncs, NPPluginFuncs* pFuncs) +{ + if(!nFuncs) + return NPERR_INVALID_FUNCTABLE_ERROR; + + qNetscapeFuncs = nFuncs; + int navMajorVers = qNetscapeFuncs->version >> 8; + + // if the plugin's major version is lower than the Navigator's, + // then they are incompatible, and should return an error + if(navMajorVers > NP_VERSION_MAJOR) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + // check if the Browser supports the XEmbed protocol + int supportsXEmbed = 0; + NPError err = NPN_GetValue(0, NPNVSupportsXEmbedBool, (void *)&supportsXEmbed); + if (err != NPERR_NO_ERROR ||!supportsXEmbed) + return NPERR_INCOMPATIBLE_VERSION_ERROR; + + return NP_GetEntryPoints(pFuncs); +} +#endif + +extern "C" NPError WINAPI NP_Shutdown() +{ + delete qNP; + qNP = 0; + + extern void qtns_shutdown(); + qtns_shutdown(); + + qNetscapeFuncs = 0; + return NPERR_NO_ERROR; +} + + +/*! + \class QtNPBindable qtnetscape.h + \brief The QtNPBindable class provides an interface between a widget and the web browser. + + Inherit your plugin widget class from both QWidget (or QObject) and QtNPBindable + to be able to call the functions of this class, and to reimplement the virtual + functions. The \l{moc}{meta-object compiler} requires you to inherit from the + QObject subclass first. + + \code + class PluginWidget : public QWidget, public QtNPBindable + { + Q_OBJECT + public: + PluginWidget(QWidget *parent = 0) + { + } + + //... + }; + \endcode +*/ + +/*! + \enum QtNPBindable::DisplayMode + + \brief This enum specifies the different display modes of a plugin + + \value Embedded The plugin widget is embedded in a web page, usually + with the or the tag. + \value Fullpage The plugin widget is the primary content of the web browser, which + is usually the case when the web browser displays a file the plugin supports. +*/ + +/*! + \enum QtNPBindable::Reason + + \brief This enum specifies how an URL operation was completed + + \value ReasonDone + \value ReasonBreak + \value ReasonError + \value ReasonUnknown +*/ + +/*! + Constructs a QtNPBindable object. + + This can only happen when the plugin object is created. +*/ +QtNPBindable::QtNPBindable() +: pi(next_pi) +{ + if (pi) + pi->bindable = this; + next_pi = 0; +} + +/*! + Destroys the object. + + This can only happen when the plugin object is destroyed. +*/ +QtNPBindable::~QtNPBindable() +{ +} + +/*! + Returns the parameters passed to the plugin instance. + + The framework sets the properties of the plugin to the corresponding + parameters when the plugin object has been created, but you can + use this function to process additional parameters. + + Note that the SGML specification does not permit multiple + arguments with the same name. +*/ +QMap QtNPBindable::parameters() const +{ + if (!pi) + return QMap(); + return pi->parameters; +} + +/*! + Returns the user agent (browser name) containing this plugin. + + This is a wrapper around NPN_UserAgent. + + \sa getBrowserVersion() +*/ +QString QtNPBindable::userAgent() const +{ + if (!pi) + return QString(); + return QString::fromLocal8Bit(NPN_UserAgent(pi->npp)); +} + +/*! + Extracts the version of the plugin API used by this plugin into \a major + and \a minor. + + See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ + for an explanation of those values. + + \sa getBrowserVersion() userAgent() +*/ +void QtNPBindable::getNppVersion(int *major, int *minor) const +{ + int dummy = 0; + if (pi) + NPN_Version(major, minor, &dummy, &dummy); +} + +/*! + Extracts the version of the browser into \a major and \a minor. + + See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ + for an explanation of those values. + + \sa getNppVersion() userAgent() +*/ +void QtNPBindable::getBrowserVersion(int *major, int *minor) const +{ + int dummy = 0; + if (pi) + NPN_Version(&dummy, &dummy, major, minor); +} + +/*! + Returns the display mode of the plugin. +*/ +QtNPBindable::DisplayMode QtNPBindable::displayMode() const +{ + if (!pi) + return Embedded; + return (QtNPBindable::DisplayMode)pi->fMode; +} + +/*! + Returns the mime type this plugin has been instantiated for. +*/ +QString QtNPBindable::mimeType() const +{ + if (!pi) + return QString(); + return pi->mimetype; +} + +/*! + Returns the browser's plugin instance associated with this plugin object. + The instance is required to call functions in the Netscape Plugin API, + i.e. NPN_GetJavaPeer(). + + The instance returned is only valid as long as this object is. + + See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ + for documentation of the \c NPP type. +*/ +NPP QtNPBindable::instance() const +{ + if (!pi) + return 0; + return pi->npp; +} + +/*! + Reimplement this function to read data from \a source provided with + mime type \a format. The data is the one specified in the \c src or + \c data attribute of the \c{} or \c{} tag of in + HTML page. This function is called once for every stream the browser + creates for the plugin. + + Return true to indicate successfull processing of the data, otherwise + return false. The default implementation does nothing and returns false. +*/ + +bool QtNPBindable::readData(QIODevice *source, const QString &format) +{ + Q_UNUSED(source); + Q_UNUSED(format); + return false; +} + +/*! + Requests that the \a url be retrieved and sent to the named \a window (or + a new window if \a window is empty), and returns the ID of the request that is + delivered to transferComplete() when the get-operation has finished. Returns 0 when + the browser or the system doesn't support notification, or -1 when an error occured. + + \code + void MyPlugin::aboutTrolltech() + { + openUrl("http://www.trolltech.com"); + } + \endcode + + See Netscape's JavaScript documentation for an explanation of window names. + + \sa transferComplete() uploadData() uploadFile() +*/ +int QtNPBindable::openUrl(const QString &url, const QString &window) +{ + if (!pi) + return -1; + QString wnd = window; + if (wnd.isEmpty()) + wnd = "_blank"; + + qint32 id = pi->getNotificationSeqNum(); + NPError err = NPN_GetURLNotify(pi->npp, url.toLocal8Bit().constData(), wnd.toLocal8Bit().constData(), reinterpret_cast(id)); + if (err != NPERR_NO_ERROR) + id = -1; + + if (err == NPERR_INCOMPATIBLE_VERSION_ERROR) { + err = NPN_GetURL(pi->npp, url.toLocal8Bit().constData(), wnd.toLocal8Bit().constData()); + if (NPERR_NO_ERROR == err) + id = 0; + else + id = -1; + } + return id; +} + +/*! + Posts \a data to \a url, and displays the result in \a window. Returns the ID of the request + that is delivered to transferComplete() when the post-operation has finished. Returns 0 when + the browser or the system doesn't support notification, or -1 when an error occured. + + \code + void MyPlugin::sendMail() + { + uploadData("mailto:fred@somewhere.com", QString(), "There is a new file for you!"); + } + \endcode + + See Netscape's JavaScript documentation for an explanation of window names. + + \sa transferComplete() openUrl() uploadFile() +*/ +int QtNPBindable::uploadData(const QString &url, const QString &window, const QByteArray &data) +{ + if (!pi) + return -1; + + int id = pi->getNotificationSeqNum(); + if (NPERR_NO_ERROR != NPN_PostURLNotify(pi->npp, url.toLocal8Bit().constData(), window.isEmpty() ? 0 : window.toLocal8Bit().constData(), data.size(), data.constData(), false, reinterpret_cast(id))) + id = -1; + + return id; +} + +/*! + Posts \a filename to \a url, and displays the result in \a window. Returns the ID of + the request that is delivered to transferComplete() when the post-operation has finished. + Returns 0 when the browser or the system doesn't support notification, or -1 when an + error occured. + + \code + void MyPlugin::uploadFile() + { + uploadFile("ftp://ftp.somewhere.com/incoming", "response", "c:\\temp\\file.txt"); + } + \endcode + + See Netscape's JavaScript documentation for an explanation of window names. + + \sa transferComplete() uploadData() openUrl() +*/ + +int QtNPBindable::uploadFile(const QString &url, const QString &window, const QString &filename) +{ + if (!pi) + return -1; + + QByteArray data = filename.toLocal8Bit(); + int id = pi->getNotificationSeqNum(); + if (NPERR_NO_ERROR != NPN_PostURLNotify(pi->npp, url.toLocal8Bit().constData(), window.isEmpty() ? 0 : window.toLocal8Bit().constData(), data.size(), data.constData(), true, reinterpret_cast(id))) + id = -1; + + return id; +} + +/*! + Called as a result of a call to openUrl, uploadData or uploadFile. + \a url corresponds to the respective parameter, and \a id to value returned + by the call. \a reason indicates how the transfer was completed. +*/ +void QtNPBindable::transferComplete(const QString &url, int id, Reason reason) +{ + Q_UNUSED(url) + Q_UNUSED(id) + Q_UNUSED(reason) +} + + +/****************************************************************************** + * The plugin itself - only one ever exists, created by QtNPFactory::create() + *****************************************************************************/ + + +/*! + \class QtNPFactory qtbrowserplugin.h + \brief The QtNPFactory class provides the factory for plugin objects. + + Implement this factory once in your plugin project to provide information + about the plugin and to create the plugin objects. Subclass QtNPFactory and + implement the pure virtual functions, and export the factory using the + \c QTNPFACTORY_EXPORT() macro. + + If you use the Q_CLASSINFO macro in your object classes you can use the + \c QTNPFACTORY_BEGIN(), \c QTNPCLASS() and \c QTNPFACTORY_END() macros to + generate a factory implementation: + + \code + class Widget : public QWidget + { + Q_OBJECT + Q_CLASSINFO("MIME", "application/x-graphable:g1n:Graphable data") + public: + ... + }; + + QTNPFACTORY_BEGIN("Plugin name", "Plugin description") + QTNPCLASS(WidgetClass) + QTNPFACTORY_END() + \endcode + + The classes exposed must provide a constructor. + + If Qt is linked to the plugin as a dynamic library, only one instance of + QApplication will exist \e{across all plugins that have been made with Qt}. + So, your plugin should tread lightly on global settings. Do not, for example, + use QApplication::setFont() - that will change the font in every widget of + every Qt-based plugin currently loaded! +*/ + +/*! + Creates a QtNPFactory. +*/ +QtNPFactory::QtNPFactory() +{ +} + +/*! + Destroys the QtNPFactory. + + This is called by the plugin binding code just before the plugin is + about to be unloaded from memory. If createObject() has been called, + a QApplication will still exist at this time, but will be deleted + shortly after, just before the plugin is deleted. +*/ +QtNPFactory::~QtNPFactory() +{ +} + + +/*! + \fn QStringList QtNPFactory::mimeTypes() const + + Reimplement this function to return the MIME types of the data formats + supported by your plugin. The format of each string is + mime:extension(s):description: + + \code + QStringList mimeTypes() const + { + QStringList list; + list << "image/x-png:png:PNG Image" + << "image/png:png:PNG Image" + << "image/jpeg:jpg,jpeg:JPEG Image"; + return list; + } + \endcode +*/ + +/*! + \fn QObject *QtNPFactory::createObject(const QString &type) + + Reimplement this function to return the QObject or QWidget subclass + supporting the mime type \a type, or 0 if the factory doesn't support + the type requested. + + \a type will be in the same form as the leftmost (mime) part of + the string(s) returned by mimeTypes(), e.g. "image/png". +*/ + +/*! + \fn QString QtNPFactory::pluginName() const + + Reimplement this function to return the name of the plugin. +*/ + +/*! + \fn QString QtNPFactory::pluginDescription() const + + Reimplement this function to return the description of the plugin. +*/ diff --git a/lib/browserplugin-solution/src/qtbrowserplugin.def b/lib/browserplugin-solution/src/qtbrowserplugin.def new file mode 100644 index 0000000..ce7f119 --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin.def @@ -0,0 +1,4 @@ +EXPORTS + NP_GetEntryPoints @1 + NP_Initialize @2 + NP_Shutdown @3 diff --git a/lib/browserplugin-solution/src/qtbrowserplugin.h b/lib/browserplugin-solution/src/qtbrowserplugin.h new file mode 100644 index 0000000..eb0f3b5 --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#ifndef QTNETSCAPE_H +#define QTNETSCAPE_H + +#include +#include +#include +#include + + +struct QtNPInstance; +class QtNPBindable; +class QtNPStreamPrivate; + +struct NPP_t; +typedef NPP_t* NPP; + +class QtNPBindable +{ + friend class QtNPStream; +public: + enum Reason { + ReasonDone = 0, + ReasonBreak = 1, + ReasonError = 2, + ReasonUnknown = -1 + }; + enum DisplayMode + { + Embedded = 1, + Fullpage = 2 + }; + + QMap parameters() const; + DisplayMode displayMode() const; + QString mimeType() const; + + QString userAgent() const; + void getNppVersion(int *major, int *minor) const; + void getBrowserVersion(int *major, int *minor) const; + + // incoming streams (SRC=... tag) + virtual bool readData(QIODevice *source, const QString &format); + + // URL stuff + int openUrl(const QString &url, const QString &window = QString()); + int uploadData(const QString &url, const QString &window, const QByteArray &data); + int uploadFile(const QString &url, const QString &window, const QString &filename); + virtual void transferComplete(const QString &url, int id, Reason r); + + NPP instance() const; + +protected: + QtNPBindable(); + virtual ~QtNPBindable(); + +private: + QtNPInstance* pi; +}; + +class QtNPFactory { +public: + QtNPFactory(); + virtual ~QtNPFactory(); + + virtual QStringList mimeTypes() const = 0; + virtual QObject* createObject(const QString &type) = 0; + + virtual QString pluginName() const = 0; + virtual QString pluginDescription() const = 0; +}; + +extern QtNPFactory *qtNPFactory(); + +template +class QtNPClass : public QtNPFactory +{ +public: + QtNPClass() {} + + QObject *createObject(const QString &key) + { + foreach (QString mime, mimeTypes()) { + if (mime.left(mime.indexOf(':')) == key) + return new T; + } + return 0; + } + + QStringList mimeTypes() const + { + const QMetaObject &mo = T::staticMetaObject; + return QString::fromLatin1(mo.classInfo(mo.indexOfClassInfo("MIME")).value()).split(';'); + } + + QString pluginName() const { return QString(); } + QString pluginDescription() const { return QString(); } +}; + +#define QTNPFACTORY_BEGIN(Name, Description) \ +class QtNPClassList : public QtNPFactory \ +{ \ + QHash factories; \ + QStringList mimeStrings; \ + QString m_name, m_description; \ +public: \ + QtNPClassList() \ + : m_name(Name), m_description(Description) \ + { \ + QtNPFactory *factory = 0; \ + QStringList keys; \ + +#define QTNPCLASS(Class) \ + { \ + factory = new QtNPClass; \ + keys = factory->mimeTypes(); \ + foreach (QString key, keys) { \ + mimeStrings.append(key); \ + factories.insert(key.left(key.indexOf(':')), factory); \ + } \ + } \ + +#define QTNPFACTORY_END() \ + } \ + ~QtNPClassList() { /*crashes? qDeleteAll(factories);*/ } \ + QObject *createObject(const QString &mime) { \ + QtNPFactory *factory = factories.value(mime); \ + return factory ? factory->createObject(mime) : 0; \ + } \ + QStringList mimeTypes() const { return mimeStrings; } \ + QString pluginName() const { return m_name; } \ + QString pluginDescription() const { return m_description; } \ +}; \ +QtNPFactory *qtns_instantiate() { return new QtNPClassList; } \ + +#define QTNPFACTORY_EXPORT(Class) \ +QtNPFactory *qtns_instantiate() { return new Class; } + +#endif // QTNETSCAPE_H diff --git a/lib/browserplugin-solution/src/qtbrowserplugin.pri b/lib/browserplugin-solution/src/qtbrowserplugin.pri new file mode 100644 index 0000000..a429d34 --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin.pri @@ -0,0 +1,74 @@ +TEMPLATE = lib +CONFIG += dll +win32 { + # Uncomment the following line to build a plugin that can be used also in + # Internet Explorer, through ActiveX. + # CONFIG += qaxserver +} else { + CONFIG += plugin +} + +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + +SOURCES += $$PWD/qtbrowserplugin.cpp +HEADERS += $$PWD/qtbrowserplugin.h qtnpapi.h + +win32 { + SOURCES += $$PWD/qtbrowserplugin_win.cpp + !isEmpty(TARGET) { + TARGET = np$$TARGET + } + LIBS += -luser32 + + qaxserver { + DEF_FILE += $$PWD/qtbrowserpluginax.def + } else { + DEF_FILE += $$PWD/qtbrowserplugin.def + } + + firefox { + exists("c:/program files/mozilla firefox/plugins") { + DLLDESTDIR += "c:/program files/mozilla firefox/plugins" + } else { + message("Firefox not found at default location") + } + } + opera { + exists("c:/program files/opera/program/plugins") { + DLLDESTDIR += "c:/program files/opera/program/plugins" + } else { + message("Opera not found at default location") + } + } + netscape { + exists("c:/program files/netscape/netscape browser/plugins") { + DLLDESTDIR += "c:/program files/netscape/netscape browser/plugins" + } else { + message("Netscape not found at default location") + } + } +} else:mac { + CONFIG += plugin_bundle + SOURCES += $$PWD/qtbrowserplugin_mac.cpp + #target.path = /Library/Internet\ Plugins + #INSTALLS += target +} else { + SOURCES += $$PWD/qtbrowserplugin_x11.cpp + INCLUDEPATH += /usr/X11R6/include + + # Avoiding symbol clash with other instances of the Qt library + # (ref. developingplugins.html in the doc.): + # + # For Qt 4.4 and later, just configure Qt to use a separate namespace: + # configure -qtnamespace SomeNamespace + # + # For Qt 4.3: Uncomment the line below. + # It makes the dynamic linker prefer our own Qt symbols for the plugin, + # provided that our Qt is statically built and linked into the + # plugin. Note that to force the linker to prefer the static Qt + # libraries (.a files), the dynamic libraries (.so) files must not + # be present in the lib directory. + # + # QMAKE_LFLAGS += -Wl,-Bsymbolic +} diff --git a/lib/browserplugin-solution/src/qtbrowserplugin_mac.cpp b/lib/browserplugin-solution/src/qtbrowserplugin_mac.cpp new file mode 100644 index 0000000..00bce29 --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin_mac.cpp @@ -0,0 +1,544 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "qtnpapi.h" + +#include "qtbrowserplugin.h" +#include "qtbrowserplugin_p.h" + +static bool ownsqapp = false; +extern void qt_mac_set_native_menubar(bool b); +const UInt32 kWidgetCreatorQt = 'cute'; +enum { + kWidgetPropertyQWidget = 'QWId' //QWidget * +}; + +class +QMacBrowserRoot : public QWidget +{ + Q_OBJECT +public: + QMacBrowserRoot(HIViewRef root) : QWidget() + { + // make sure we're not registered with Qt before create + WindowRef window = HIViewGetWindow(root); + QWidget *oldwindow=0; + OSErr err; + err = GetWindowProperty(window, + kWidgetCreatorQt, + kWidgetPropertyQWidget, + sizeof(oldwindow), + 0, + &oldwindow); + if (err == noErr) + RemoveWindowProperty(window, kWidgetCreatorQt, kWidgetPropertyQWidget); + + create((WId)root); + + // re-register the root window with Qt + err = SetWindowProperty(window, + kWidgetCreatorQt, + kWidgetPropertyQWidget, + sizeof(oldwindow), + &oldwindow); + if (err != noErr) { + qWarning("Error, couldn't register Window with Qt: (%s:%d:%d)", __FILE__, __LINE__, err); + } + + QPalette pal = palette(); + pal.setColor(QPalette::Window,Qt::transparent); + setPalette(pal); + + setAttribute(Qt::WA_WState_Polished); + } + + ~QMacBrowserRoot() { } +}; +#include "qtbrowserplugin_mac.moc" + +struct key_sym +{ + int mac_code; + int qt_code; + const char *desc; +}; + +static key_sym modifier_syms[] = { +{ shiftKey, Qt::ShiftModifier, "Qt::ShiftModifier" }, +{ controlKey, Qt::MetaModifier, "Qt::MetaModifier" }, +{ rightControlKey, Qt::MetaModifier, "Qt::MetaModifier" }, +{ optionKey, Qt::AltModifier, "Qt::AltModifier" }, +{ rightOptionKey, Qt::AltModifier, "Qt::AltModifier" }, +{ cmdKey, Qt::ControlModifier, "Qt::ControlModifier" }, +{ 0, 0, NULL } +}; +static Qt::KeyboardModifiers get_modifiers(int key) +{ + Qt::KeyboardModifiers ret = 0; + for(int i = 0; modifier_syms[i].desc; i++) { + if(key & modifier_syms[i].mac_code) { + ret |= Qt::KeyboardModifier(modifier_syms[i].qt_code); + } + } + return ret; +} + +static key_sym key_syms[] = { +{ kHomeCharCode, Qt::Key_Home, "Qt::Home" }, +{ kEnterCharCode, Qt::Key_Enter, "Qt::Key_Enter" }, +{ kEndCharCode, Qt::Key_End, "Qt::Key_End" }, +{ kBackspaceCharCode, Qt::Key_Backspace, "Qt::Backspace" }, +{ kTabCharCode, Qt::Key_Tab, "Qt::Tab" }, +{ kPageUpCharCode, Qt::Key_PageUp, "Qt::PageUp" }, +{ kPageDownCharCode, Qt::Key_PageDown, "Qt::PageDown" }, +{ kReturnCharCode, Qt::Key_Return, "Qt::Key_Return" }, +//function keys? +{ kEscapeCharCode, Qt::Key_Escape, "Qt::Key_Escape" }, +{ kLeftArrowCharCode, Qt::Key_Left, "Qt::Key_Left" }, +{ kRightArrowCharCode, Qt::Key_Right, "Qt::Key_Right" }, +{ kUpArrowCharCode, Qt::Key_Up, "Qt::Key_Up" }, +{ kDownArrowCharCode, Qt::Key_Down, "Qt::Key_Down" }, +{ kDeleteCharCode, Qt::Key_Delete, "Qt::Key_Delete" } +}; +static int get_key(int key) +{ + for(int i = 0; key_syms[i].desc; i++) { + if(key_syms[i].mac_code == key) { + return key_syms[i].qt_code; + } + } + return key; +} + +struct qt_last_mouse_down_struct { + unsigned int when; + int x, y; +} qt_last_mouse_down = { 0, 0, 0 }; + +//nasty, copied code - +static void qt_dispatchEnterLeave(QWidget* enter, QWidget* leave) { +#if 0 + if(leave) { + QEvent e(QEvent::Leave); + QApplication::sendEvent(leave, & e); + } + if(enter) { + QEvent e(QEvent::Enter); + QApplication::sendEvent(enter, & e); + } + return; +#endif + + QWidget* w ; + if(!enter && !leave) + return; + QWidgetList leaveList; + QWidgetList enterList; + + bool sameWindow = leave && enter && leave->window() == enter->window(); + if(leave && !sameWindow) { + w = leave; + do { + leaveList.append(w); + } while(!w->isWindow() && (w = w->parentWidget())); + } + if(enter && !sameWindow) { + w = enter; + do { + enterList.prepend(w); + } while(!w->isWindow() && (w = w->parentWidget())); + } + if(sameWindow) { + int enterDepth = 0; + int leaveDepth = 0; + w = enter; + while(!w->isWindow() && (w = w->parentWidget())) + enterDepth++; + w = leave; + while(!w->isWindow() && (w = w->parentWidget())) + leaveDepth++; + QWidget* wenter = enter; + QWidget* wleave = leave; + while(enterDepth > leaveDepth) { + wenter = wenter->parentWidget(); + enterDepth--; + } + while(leaveDepth > enterDepth) { + wleave = wleave->parentWidget(); + leaveDepth--; + } + while(!wenter->isWindow() && wenter != wleave) { + wenter = wenter->parentWidget(); + wleave = wleave->parentWidget(); + } + + w = leave; + while(w != wleave) { + leaveList.append(w); + w = w->parentWidget(); + } + w = enter; + while(w != wenter) { + enterList.prepend(w); + w = w->parentWidget(); + } + } + + QEvent leaveEvent(QEvent::Leave); + for (int i = 0; i < leaveList.size(); ++i) { + w = leaveList.at(i); + QApplication::sendEvent(w, &leaveEvent); +#if 0 + if(w->testAttribute(Qt::WA_Hover)) { + Q_ASSERT(instance()); + QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), + w->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos)); + QApplication::sendEvent(w, &he); + } +#endif + } + QPoint posEnter = QCursor::pos(); + QEvent enterEvent(QEvent::Enter); + for (int i = 0; i < enterList.size(); ++i) { + w = enterList.at(i); + QApplication::sendEvent(w, &enterEvent); + if(w->testAttribute(Qt::WA_Hover)) { + QHoverEvent he(QEvent::HoverEnter, w->mapFromGlobal(posEnter), QPoint(-1, -1)); + QApplication::sendEvent(w, &he); + } + } +} + + +extern "C" bool qtns_event(QtNPInstance *This, NPEvent *event) +{ + static QPointer lastWidget; + static QPointer qt_button_down; + static Point lastPosition = { 0, 0 }; + if(event->what == nullEvent || event->what == adjustCursorEvent) { + if(event->what == nullEvent) { + qApp->processEvents(); + QApplication::sendPostedEvents(); + } + + //watch for mouse moves + Point currentPosition; + GetMouse(¤tPosition); + LocalToGlobal(¤tPosition); + if(currentPosition.h != lastPosition.h || currentPosition.v != lastPosition.v) { + lastPosition = currentPosition; + + WindowPtr wp; + FindWindow(currentPosition, &wp); + QWidget *widget = 0; + if(wp == GetWindowFromPort((CGrafPtr)This->window->port)) + widget = This->rootWidget->childAt(This->rootWidget->mapFromGlobal(QPoint(event->where.h, event->where.v))); + else + widget = QApplication::widgetAt(event->where.h, event->where.v); + if(widget != lastWidget) { + qt_dispatchEnterLeave(widget, lastWidget); + lastWidget = widget; + } + if(widget) { + QPoint p(currentPosition.h, currentPosition.v); + QPoint plocal(widget->mapFromGlobal(p)); + QMouseEvent qme(QEvent::MouseMove, plocal, p, Button() ? Qt::LeftButton : Qt::NoButton, + 0, get_modifiers(GetCurrentKeyModifiers())); + QApplication::sendEvent(widget, &qme); + } + } + return true; + } else if(QWidget *widget = qobject_cast(This->qt.object)) { + if(event->what == updateEvt) { + widget->repaint(); + return true; + } else if(event->what == keyUp || event->what == keyDown) { + QWidget *widget = 0; + if(QWidget::keyboardGrabber()) + widget = QWidget::keyboardGrabber(); + else if(QApplication::focusWidget()) + widget = QApplication::focusWidget(); + else //last ditch effort + widget = QApplication::widgetAt(event->where.h, event->where.v); + + if(widget) { +#if 0 + if(app_do_modal && !qt_try_modal(widget, er)) + return 1; +#endif + + int mychar=get_key(event->message & charCodeMask); + QEvent::Type etype = event->what == keyUp ? QEvent::KeyRelease : QEvent::KeyPress; + QKeyEvent ke(etype, mychar, get_modifiers(event->modifiers), QString(QChar(mychar))); + QApplication::sendEvent(widget,&ke); + return true; + } + } else if(event->what == mouseDown || event->what == mouseUp) { + QEvent::Type etype = QEvent::None; + Qt::KeyboardModifiers keys = get_modifiers(event->modifiers); + Qt::MouseButton button = Qt::LeftButton; + + if(event->what == mouseDown) { + if (lastWidget) + qt_button_down = lastWidget; + //check if this is the second click, there must be a way to make the + //mac do this for us, FIXME!! + if(qt_last_mouse_down.when && + (event->when - qt_last_mouse_down.when <= (uint)QApplication::doubleClickInterval())) { + int x = event->where.h, y = event->where.v; + if(x >= (qt_last_mouse_down.x-2) && x <= (qt_last_mouse_down.x+4) && + y >= (qt_last_mouse_down.y-2) && y <= (qt_last_mouse_down.y+4)) { + etype = QEvent::MouseButtonDblClick; + qt_last_mouse_down.when = 0; + } + } + + if(etype == QEvent::None) { //guess it's just a press + etype = QEvent::MouseButtonPress; + qt_last_mouse_down.when = event->when; + qt_last_mouse_down.x = event->where.h; + qt_last_mouse_down.y = event->where.v; + } + } else { + etype = QEvent::MouseButtonRelease; + } + + WindowPtr wp; + FindWindow(event->where, &wp); + + //handle popup's first + QWidget *popupwidget = NULL; + if(QApplication::activePopupWidget()) { + if(wp) { + QWidget *clt=QWidget::find((WId)wp); + if(clt && clt->windowType() == Qt::Popup) + popupwidget = clt; + } + if(!popupwidget) + popupwidget = QApplication::activePopupWidget(); + if(QWidget *child = popupwidget->childAt(popupwidget->mapFromGlobal(QPoint(event->where.h, event->where.v)))) + popupwidget = child; + + QPoint p(event->where.h, event->where.v); + QPoint plocal(popupwidget->mapFromGlobal(p)); + QMouseEvent qme(etype, plocal, p, button, 0, keys); + QApplication::sendEvent(popupwidget, &qme); + } + + { + QWidget *widget = 0; //figure out which widget to send it to + if(event->what == mouseUp && qt_button_down) + widget = qt_button_down; + else if(QWidget::mouseGrabber()) + widget = QWidget::mouseGrabber(); + else if(wp == GetWindowFromPort((CGrafPtr)This->window->port)) + widget = This->rootWidget->childAt(This->rootWidget->mapFromGlobal(QPoint(event->where.h, event->where.v))); + else + widget = QApplication::widgetAt(event->where.h, event->where.v); + + //setup the saved widget + qt_button_down = event->what == mouseDown ? widget : 0; + + //finally send the event to the widget if its not the popup + if(widget && widget != popupwidget) { +#if 0 + if(app_do_modal && !qt_try_modal(widget, er)) + return 1; +#endif + if(event->what == mouseDown) { + QWidget* w = widget; + while(w->focusProxy()) + w = w->focusProxy(); + if(w->focusPolicy() & Qt::ClickFocus) + w->setFocus(Qt::MouseFocusReason); + if(QWidget *tlw = widget->topLevelWidget()) { + tlw->raise(); + if(tlw->isTopLevel() && tlw->windowType() != Qt::Popup && + (tlw->isModal() || tlw->windowType() != Qt::Dialog)) + QApplication::setActiveWindow(tlw); + } + } + + QPoint p(event->where.h, event->where.v); + QPoint plocal(widget->mapFromGlobal( p )); + QMouseEvent qme(etype, plocal, p, button, 0, keys); + QApplication::sendEvent(widget, &qme); + return true; + } + } + } else { + //qDebug("%d", event->what); + } + } + return false; +} + +#ifdef QTBROWSER_USE_CFM +static bool qtbrowser_use_cfm = false; +static UInt32 gGlueTemplate[6] = { 0x3D800000, 0x618C0000, 0x800C0000, + 0x804C0004, 0x7C0903A6, 0x4E800420 }; +struct TVector_rec +{ + ProcPtr fProcPtr; + void *fTOC; +}; + +void *CFMFunctionPointerForMachOFunctionPointer(void *inMachProcPtr) +{ + if(!qtbrowser_use_cfm) + return inMachProcPtr; + TVector_rec *vTVector = (TVector_rec*)malloc(sizeof(TVector_rec)); + if(MemError() == noErr && vTVector != 0) { + vTVector->fProcPtr = (ProcPtr)inMachProcPtr; + vTVector->fTOC = 0; // ignored + } + return((void *)vTVector); +} + +void DisposeCFMFunctionPointer(void *inCfmProcPtr) +{ + if(!qtbrowser_use_cfm) + return; + if(inCfmProcPtr) + free(inCfmProcPtr); +} + +void* MachOFunctionPointerForCFMFunctionPointer(void* inCfmProcPtr) +{ + if(!qtbrowser_use_cfm) + return inCfmProcPtr; + UInt32 *vMachProcPtr = (UInt32*)NewPtr(sizeof(gGlueTemplate)); + vMachProcPtr[0] = gGlueTemplate[0] | ((UInt32)inCfmProcPtr >> 16); + vMachProcPtr[1] = gGlueTemplate[1] | ((UInt32)inCfmProcPtr & 0xFFFF); + vMachProcPtr[2] = gGlueTemplate[2]; + vMachProcPtr[3] = gGlueTemplate[3]; + vMachProcPtr[4] = gGlueTemplate[4]; + vMachProcPtr[5] = gGlueTemplate[5]; + MakeDataExecutable(vMachProcPtr, sizeof(gGlueTemplate)); + return(vMachProcPtr); +} +#endif + + +extern "C" void qtns_initialize(QtNPInstance *) +{ + qt_mac_set_native_menubar(false); + if(!qApp) { + ownsqapp = true; + static int argc=0; + static char **argv={ 0 }; + (void)new QApplication(argc, argv); + } +} + +extern "C" void qtns_destroy(QtNPInstance *This) +{ + delete This->rootWidget; + This->rootWidget = 0; +} + +extern "C" void qtns_shutdown() +{ + if(!ownsqapp) + return; + + // TODO: find out if other plugin DLL's still need qApp + delete qApp; + ownsqapp = false; +} + +extern "C" void qtns_embed(QtNPInstance *This) +{ + Q_ASSERT(qobject_cast(This->qt.object)); + + WindowPtr windowptr = GetWindowFromPort((CGrafPtr)This->window->port); + HIViewRef root = 0; + OSErr err; + err = GetRootControl(windowptr,&root); + if(!root) + root = HIViewGetRoot(windowptr); + if(!root) { + qDebug("No window composition!"); + } else { + This->rootWidget = new QMacBrowserRoot(root); + This->qt.widget->setParent(This->rootWidget); + } +} + +extern "C" void qtns_setGeometry(QtNPInstance *This, const QRect &rect, const QRect &clipRect) +{ + Q_ASSERT(qobject_cast(This->qt.object)); + + WindowPtr windowptr = GetWindowFromPort((CGrafPtr)This->window->port); + Rect content_r; + GetWindowBounds(windowptr, kWindowContentRgn, &content_r); + Rect structure_r; + GetWindowBounds(windowptr, kWindowStructureRgn, &structure_r); + + QRect geom(rect.translated(content_r.left-structure_r.left, content_r.top-structure_r.top)); + if(rect != clipRect) { + QRegion clipRegion(QRect(clipRect.x()-geom.x(), clipRect.y()-geom.y(), clipRect.width(), clipRect.height()) + .translated(content_r.left-structure_r.left, content_r.top-structure_r.top)); + if(clipRegion.isEmpty()) + clipRegion = QRegion(-1, -1, 1, 1); //eww ### FIXME + This->qt.widget->setMask(clipRegion); + } else { + This->qt.widget->clearMask(); + } + This->qt.widget->setGeometry(geom); +} + +typedef void (*NPP_ShutdownUPP)(void); + +extern "C" void NPP_MacShutdown() +{ + //extern NPError NP_Shutdown(); + //NP_Shutdown(); +} + +extern "C" int main(NPNetscapeFuncs *npn_funcs, NPPluginFuncs *np_funcs, NPP_ShutdownUPP *shutdown) +{ + qtbrowser_use_cfm = true; //quite the heuristic.. + + NPError ret; + extern NPError NP_Initialize(NPNetscapeFuncs*); + if((ret=NP_Initialize(npn_funcs)) != NPERR_NO_ERROR) + return ret; + extern NPError NP_GetEntryPoints(NPPluginFuncs*); + if((ret=NP_GetEntryPoints(np_funcs)) != NPERR_NO_ERROR) + return ret; + *shutdown = (NPP_ShutdownUPP)MAKE_FUNCTION_POINTER(NPP_MacShutdown); + return NPERR_NO_ERROR; +} diff --git a/lib/browserplugin-solution/src/qtbrowserplugin_p.h b/lib/browserplugin-solution/src/qtbrowserplugin_p.h new file mode 100644 index 0000000..767fa31 --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include +#include +#include + +#ifdef Q_WS_X11 +# include + +class QtNPStream; +class QtNPBindable; +#endif + +struct QtNPInstance +{ + NPP npp; + + short fMode; + +#ifdef Q_WS_WIN + typedef HWND Widget; +#endif +#ifdef Q_WS_X11 + typedef Window Widget; + Display *display; +#endif +#ifdef Q_WS_MAC + typedef NPPort* Widget; + QWidget *rootWidget; +#endif + + Widget window; + + QRect geometry; + QString mimetype; + QByteArray htmlID; + union { + QObject* object; + QWidget* widget; + } qt; + QtNPStream *pendingStream; + QtNPBindable* bindable; + QObject *filter; + + QMap parameters; + + qint32 notificationSeqNum; + QMutex seqNumMutex; + qint32 getNotificationSeqNum() + { + QMutexLocker locker(&seqNumMutex); + + if (++notificationSeqNum < 0) + notificationSeqNum = 1; + return notificationSeqNum; + } + +}; diff --git a/lib/browserplugin-solution/src/qtbrowserplugin_win.cpp b/lib/browserplugin-solution/src/qtbrowserplugin_win.cpp new file mode 100644 index 0000000..ad3e1fa --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin_win.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include + +#include "qtbrowserplugin.h" +#include "qtbrowserplugin_p.h" + +#include +#include "qtnpapi.h" + +static HHOOK hhook = 0; +static bool ownsqapp = false; +Q_GUI_EXPORT int qt_translateKeyCode(int); + +LRESULT CALLBACK FilterProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ + if (qApp) + qApp->sendPostedEvents(0, -1); + + if (nCode < 0 || !(wParam & PM_REMOVE)) + return CallNextHookEx(hhook, nCode, wParam, lParam); + + MSG *msg = (MSG*)lParam; + bool processed = false; + + // (some) support for key-sequences via QAction and QShortcut + if(msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN) { + QWidget *focusWidget = QWidget::find(msg->hwnd); + if (focusWidget) { + int key = msg->wParam; + if (!(key >= 'A' && key <= 'Z') && !(key >= '0' && key <= '9')) + key = qt_translateKeyCode(msg->wParam); + + Qt::KeyboardModifiers modifiers = 0; + int modifierKey = 0; + if (GetKeyState(VK_SHIFT) < 0) { + modifierKey |= Qt::SHIFT; + modifiers |= Qt::ShiftModifier; + } + if (GetKeyState(VK_CONTROL) < 0) { + modifierKey |= Qt::CTRL; + modifiers |= Qt::ControlModifier; + } + if (GetKeyState(VK_MENU) < 0) { + modifierKey |= Qt::ALT; + modifiers |= Qt::AltModifier; + } + QKeyEvent override(QEvent::ShortcutOverride, key, modifiers); + override.ignore(); + QApplication::sendEvent(focusWidget, &override); + processed = override.isAccepted(); + + QKeySequence shortcutKey(modifierKey + key); + if (!processed) { + QList actions = qFindChildren(focusWidget->window()); + for (int i = 0; i < actions.count() && !processed; ++i) { + QAction *action = actions.at(i); + if (!action->isEnabled() || action->shortcut() != shortcutKey) + continue; + QShortcutEvent event(shortcutKey, 0); + processed = QApplication::sendEvent(action, &event); + } + } + if (!processed) { + QList shortcuts = qFindChildren(focusWidget->window()); + for (int i = 0; i < shortcuts.count() && !processed; ++i) { + QShortcut *shortcut = shortcuts.at(i); + if (!shortcut->isEnabled() || shortcut->key() != shortcutKey) + continue; + QShortcutEvent event(shortcutKey, shortcut->id()); + processed = QApplication::sendEvent(shortcut, &event); + } + } + } + } + + return CallNextHookEx(hhook, nCode, wParam, lParam); +} + +extern "C" bool qtns_event(QtNPInstance *, NPEvent *) +{ + return false; +} + +extern Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str); + +extern "C" void qtns_initialize(QtNPInstance*) +{ + if (!qApp) { + qInstallMsgHandler(qWinMsgHandler); + ownsqapp = true; + static int argc=0; + static char **argv={ 0 }; + (void)new QApplication(argc, argv); + + QT_WA({ + hhook = SetWindowsHookExW( WH_GETMESSAGE, FilterProc, 0, GetCurrentThreadId() ); + }, { + hhook = SetWindowsHookExA( WH_GETMESSAGE, FilterProc, 0, GetCurrentThreadId() ); + }); + } +} + +extern "C" void qtns_destroy(QtNPInstance *) +{ +} + +extern "C" void qtns_shutdown() +{ + if (!ownsqapp) + return; + + // check if qApp still runs widgets (in other DLLs) + QWidgetList widgets = qApp->allWidgets(); + int count = widgets.count(); + for (int w = 0; w < widgets.count(); ++w) { + // ignore all Qt generated widgets + QWidget *widget = widgets.at(w); + if (widget->windowFlags() & Qt::Desktop) + count--; + } + if (count) // qApp still used + return; + + delete qApp; + ownsqapp = false; + if ( hhook ) + UnhookWindowsHookEx( hhook ); + hhook = 0; +} + +extern "C" void qtns_embed(QtNPInstance *This) +{ + Q_ASSERT(qobject_cast(This->qt.object)); + + LONG oldLong = GetWindowLong(This->window, GWL_STYLE); + ::SetWindowLong(This->window, GWL_STYLE, oldLong | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + ::SetWindowLong(This->qt.widget->winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + ::SetParent(This->qt.widget->winId(), This->window); +} + +extern "C" void qtns_setGeometry(QtNPInstance *This, const QRect &rect, const QRect &) +{ + Q_ASSERT(qobject_cast(This->qt.object)); + + This->qt.widget->setGeometry(QRect(0, 0, rect.width(), rect.height())); +} + +/* +extern "C" void qtns_print(QtNPInstance * This, NPPrint *printInfo) +{ + NPWindow* printWindow = &(printInfo->print.embedPrint.window); + void* platformPrint = printInfo->print.embedPrint.platformPrint; + // #### Nothing yet. +} +*/ diff --git a/lib/browserplugin-solution/src/qtbrowserplugin_x11.cpp b/lib/browserplugin-solution/src/qtbrowserplugin_x11.cpp new file mode 100644 index 0000000..059e217 --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserplugin_x11.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include +#include + +#include "qtbrowserplugin.h" +#include "qtbrowserplugin_p.h" + +#include "qtnpapi.h" + +#include + +static bool ownsqapp = false; +static QMap clients; + +extern "C" bool qtns_event(QtNPInstance *, NPEvent *) +{ + return false; +} + +extern "C" void qtns_initialize(QtNPInstance* This) +{ + if (!qApp) { + ownsqapp = true; + static int argc = 0; + static char **argv = {0}; + + // Workaround to avoid re-initilaziation of glib + char* envvar = qstrdup("QT_NO_THREADED_GLIB=1"); + // Unavoidable memory leak; the variable must survive plugin unloading + ::putenv(envvar); + + (void)new QApplication(argc, argv); + } + if (!clients.contains(This)) { + QX11EmbedWidget* client = new QX11EmbedWidget; + QHBoxLayout* layout = new QHBoxLayout(client); + layout->setMargin(0); + clients.insert(This, client); + } +} + +extern "C" void qtns_destroy(QtNPInstance* This) +{ + QMap::iterator it = clients.find(This); + if (it == clients.end()) + return; + delete it.value(); + clients.erase(it); +} + +extern "C" void qtns_shutdown() +{ + if (clients.count() > 0) { + QMap::iterator it = clients.begin(); + while (it != clients.end()) { + delete it.value(); + ++it; + } + clients.clear(); + } + + if (!ownsqapp) + return; + + // check if qApp still runs widgets (in other DLLs) + QWidgetList widgets = qApp->allWidgets(); + int count = widgets.count(); + for (int w = 0; w < widgets.count(); ++w) { + // ignore all Qt generated widgets + QWidget *widget = widgets.at(w); + if (widget->windowFlags() & Qt::Desktop) + count--; + } + if (count) // qApp still used + return; + + delete qApp; + ownsqapp = false; +} + +extern "C" void qtns_embed(QtNPInstance *This) +{ + Q_ASSERT(qobject_cast(This->qt.object)); + + QMap::iterator it = clients.find(This); + if (it == clients.end()) + return; + QX11EmbedWidget* client = it.value(); + This->qt.widget->setParent(client); + client->layout()->addWidget(This->qt.widget); + client->embedInto(This->window); + client->show(); +} + +extern "C" void qtns_setGeometry(QtNPInstance *This, const QRect &rect, const QRect &) +{ + Q_ASSERT(qobject_cast(This->qt.object)); + + QMap::iterator it = clients.find(This); + if (it == clients.end()) + return; + QX11EmbedWidget* client = it.value(); + client->setGeometry(QRect(0, 0, rect.width(), rect.height())); +} + +/* +extern "C" void qtns_print(QtNPInstance * This, NPPrint *printInfo) +{ + NPWindow* printWindow = &(printInfo->print.embedPrint.window); + void* platformPrint = printInfo->print.embedPrint.platformPrint; + // #### Nothing yet. +} +*/ diff --git a/lib/browserplugin-solution/src/qtbrowserpluginax.def b/lib/browserplugin-solution/src/qtbrowserpluginax.def new file mode 100644 index 0000000..df2dedb --- /dev/null +++ b/lib/browserplugin-solution/src/qtbrowserpluginax.def @@ -0,0 +1,9 @@ +EXPORTS + NP_GetEntryPoints @1 + NP_Initialize @2 + NP_Shutdown @3 + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DumpIDL PRIVATE diff --git a/lib/browserplugin-solution/src/qtnpapi.h b/lib/browserplugin-solution/src/qtnpapi.h new file mode 100644 index 0000000..63fe8f4 --- /dev/null +++ b/lib/browserplugin-solution/src/qtnpapi.h @@ -0,0 +1,539 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved. +** +** This file is part of a Qt Solutions component. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** Trolltech sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +// see http://www.mozilla.org/projects/plugins/ for details regarding the structs and API prototypes + +#ifndef QTNPAPI_H +#define QTNPAPI_H + +// Plugin API version +#define NP_VERSION_MAJOR 0 +#define NP_VERSION_MINOR 17 + +// basic types +typedef unsigned short uint16; +typedef short int16; +typedef unsigned int uint32; +typedef int int32; + +typedef unsigned char NPBool; +typedef int16 NPError; +typedef int16 NPReason; +typedef char* NPMIMEType; + +typedef void *NPRegion; +typedef void *NPIdentifier; + +// Java stuff +typedef void* jref; +typedef void* JRIGlobalRef; +typedef void* JRIEnv; // ### not quite correct, but we don't use it anyway + +// NP-types +struct NPP_t +{ + void* pdata; // plug-in private data + void* ndata; // browser private data +}; +typedef NPP_t* NPP; + +struct NPRect +{ + uint16 top; + uint16 left; + uint16 bottom; + uint16 right; +}; + +#ifdef Q_WS_WIN +struct NPEvent +{ + uint16 event; + uint32 wParam; + uint32 lParam; +}; +#elif defined(Q_WS_X11) +# include +typedef XEvent NPEvent; +#elif defined (Q_WS_MAC) +typedef struct EventRecord NPEvent; +#endif + +// Variable names for NPP_GetValue +enum NPPVariable { + NPPVpluginNameString = 1, + NPPVpluginDescriptionString, + NPPVpluginWindowBool, + NPPVpluginTransparentBool, + NPPVjavaClass, + NPPVpluginWindowSize, + NPPVpluginTimerInterval, + + NPPVpluginScriptableInstance = 10, + NPPVpluginScriptableIID = 11, + + // Introduced in Mozilla 0.9.9 + NPPVjavascriptPushCallerBool = 12, + + // Introduced in Mozilla 1.0 + NPPVpluginKeepLibraryInMemory = 13, + NPPVpluginNeedsXEmbed = 14, + + // Introduced in Firefox 1.0 + NPPVpluginScriptableNPObject = 15, + NPPVformValue = 16 +} ; + +// Variable names for NPN_GetValue +enum NPNVariable { + NPNVxDisplay = 1, + NPNVxtAppContext, + NPNVnetscapeWindow, + NPNVjavascriptEnabledBool, + NPNVasdEnabledBool, + NPNVisOfflineBool, + + // Introduced in Mozilla 0.9.4 + NPNVserviceManager = 10, + NPNVDOMElement = 11, + // Introduced in Mozilla 1.2 + NPNVDOMWindow = 12, + NPNVToolkit = 13, + NPNVSupportsXEmbedBool = 14, + + NPNVWindowNPObject = 15, + NPNVPluginElementNPObject = 16 +}; + + +enum NPWindowType { + NPWindowTypeWindow = 1, // Windowed plug-in. The window field holds a platform-specific handle to a window. + NPWindowTypeDrawable // Windows: HDC; Mac OS: pointer to NP_Port structure. +}; + +struct NPWindow +{ + // Platform-specific handle to a native window element in the browser's window hierarchy + // XEmbed: "In the NPP_SetWindow call, the window parameter will be the XID of the hosting + // XEmbed window. As an implementation note, this is really the XID of a GtkSocket window." + void* window; + // The x and y coordinates for the top left corner of the plug-in relative to the page + // (and thus relative to the origin of the drawable) + uint32 x, y; + // The height and width of the plug-in area. Should not be modified by the plug-in. + uint32 width, height; + // Used by MAC only (Clipping rectangle in port coordinates) + NPRect clipRect; +#ifdef Q_WS_X11 + // Contains information about the plug-in's Unix window environment + // points to an NPSetWindowCallbackStruct + void* ws_info; // probably obsolete with XEmbed +#endif + // The type field indicates the NPWindow type of the target area + NPWindowType type; +}; + +struct NPPort +{ + void *port; + int32 portx; + int32 porty; +}; + +struct NPFullPrint +{ + NPBool pluginPrinted; // true if plugin handled fullscreen printing + NPBool printOne; // true if plugin should print one copy to default printer + void* platformPrint; // Platform-specific printing info +}; + +struct NPEmbedPrint +{ + NPWindow window; + void* platformPrint; // Platform-specific printing info +}; + +struct NPPrint +{ + uint16 mode; // NP_FULL or NP_EMBED + union { + NPFullPrint fullPrint; + NPEmbedPrint embedPrint; + } print; +}; + +struct NPSavedData +{ + int32 len; + void* buf; +}; + +struct NPStream +{ + void* pdata; + void* ndata; + const char* url; + uint32 end; + uint32 lastmodified; + void* notifyData; +}; + +struct NPByteRange +{ + int32 offset; // negative offset means from the end + uint32 length; + NPByteRange* next; +}; + +// Values for mode passed to NPP_New: +#define NP_EMBED 1 +#define NP_FULL 2 + +// Values for stream type passed to NPP_NewStream: +#define NP_NORMAL 1 +#define NP_SEEK 2 +#define NP_ASFILE 3 +#define NP_ASFILEONLY 4 + +#define NP_MAXREADY (((unsigned)(~0)<<1)>>1) + +// Values of type NPError: +#define NPERR_NO_ERROR 0 +#define NPERR_GENERIC_ERROR 1 +#define NPERR_INVALID_INSTANCE_ERROR 2 +#define NPERR_INVALID_FUNCTABLE_ERROR 3 +#define NPERR_MODULE_LOAD_FAILED_ERROR 4 +#define NPERR_OUT_OF_MEMORY_ERROR 5 +#define NPERR_INVALID_PLUGIN_ERROR 6 +#define NPERR_INVALID_PLUGIN_DIR_ERROR 7 +#define NPERR_INCOMPATIBLE_VERSION_ERROR 8 +#define NPERR_INVALID_PARAM 9 +#define NPERR_INVALID_URL 10 +#define NPERR_FILE_NOT_FOUND 11 +#define NPERR_NO_DATA 12 +#define NPERR_STREAM_NOT_SEEKABLE 13 + +// Values of type NPReason: +#define NPRES_DONE 0 +#define NPRES_NETWORK_ERR 1 +#define NPRES_USER_BREAK 2 + +// Version feature information +#define NPVERS_HAS_STREAMOUTPUT 8 +#define NPVERS_HAS_NOTIFICATION 9 +#define NPVERS_HAS_LIVECONNECT 9 +#define NPVERS_WIN16_HAS_LIVECONNECT 10 + +// Mac specifics +#ifdef Q_WS_MAC +# define getFocusEvent (osEvt + 16) +# define loseFocusEvent (osEvt + 17) +# define adjustCursorEvent (osEvt + 18) +# define QTBROWSER_USE_CFM +#endif + +#ifdef QTBROWSER_USE_CFM + extern void *CFMFunctionPointerForMachOFunctionPointer(void*); + extern void DisposeCFMFunctionPointer(void *); + extern void* MachOFunctionPointerForCFMFunctionPointer(void*); +# define FUNCTION_POINTER(t) void* +# define MAKE_FUNCTION_POINTER(f) CFMFunctionPointerForMachOFunctionPointer((void*)f) +# define DESTROY_FUNCTION_POINTER(n) DisposeCFMFunctionPointer(n) +# define FIND_FUNCTION_POINTER(t, n) (*(t)MachOFunctionPointerForCFMFunctionPointer(n)) +#else +# define FUNCTION_POINTER(t) t +# define MAKE_FUNCTION_POINTER(f) f +# define DESTROY_FUNCTION_POINTER(n) +# define FIND_FUNCTION_POINTER(t, n) (*n) +#endif + +// Plugin function prototypes +typedef NPError (*NPP_NewFP)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); +typedef NPError (*NPP_DestroyFP)(NPP instance, NPSavedData** save); +typedef NPError (*NPP_SetWindowFP)(NPP instance, NPWindow* window); +typedef NPError (*NPP_NewStreamFP)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); +typedef NPError (*NPP_DestroyStreamFP)(NPP instance, NPStream* stream, NPReason reason); +typedef void (*NPP_StreamAsFileFP)(NPP instance, NPStream* stream, const char* fname); +typedef int32 (*NPP_WriteReadyFP)(NPP instance, NPStream* stream); +typedef int32 (*NPP_WriteFP)(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer); +typedef void (*NPP_PrintFP)(NPP instance, NPPrint* platformPrint); +typedef int16 (*NPP_HandleEventFP)(NPP instance, NPEvent* event); +typedef void (*NPP_URLNotifyFP)(NPP instance, const char* url, NPReason reason, void* notifyData); +typedef NPError (*NPP_GetValueFP)(NPP instance, NPPVariable variable, void *value); +typedef NPError (*NPP_SetValueFP)(NPP instance, NPPVariable variable, void *value); + +// table of functions implemented by the plugin +struct NPPluginFuncs { + uint16 size; + uint16 version; + FUNCTION_POINTER(NPP_NewFP) newp; + FUNCTION_POINTER(NPP_DestroyFP) destroy; + FUNCTION_POINTER(NPP_SetWindowFP) setwindow; + FUNCTION_POINTER(NPP_NewStreamFP) newstream; + FUNCTION_POINTER(NPP_DestroyStreamFP) destroystream; + FUNCTION_POINTER(NPP_StreamAsFileFP) asfile; + FUNCTION_POINTER(NPP_WriteReadyFP) writeready; + FUNCTION_POINTER(NPP_WriteFP) write; + FUNCTION_POINTER(NPP_PrintFP) print; + FUNCTION_POINTER(NPP_HandleEventFP) event; + FUNCTION_POINTER(NPP_URLNotifyFP) urlnotify; + JRIGlobalRef javaClass; + FUNCTION_POINTER(NPP_GetValueFP) getvalue; + FUNCTION_POINTER(NPP_SetValueFP) setvalue; +} ; + + +// forward declarations +struct NPObject; +struct NPClass; +struct NPVariant; +struct NPString; +struct QtNPInstance; + +// NPObject is the type used to express objects exposed by either +// the plugin or by the browser. Implementation specific (i.e. plugin +// specific, or browser specific) members can come after the struct. +// In our case, the plugin specific member (aka QObject) lives in NPClass. +struct NPObject +{ + NPClass *_class; + uint32 refCount; +}; + +// NPClass is what virtual function tables would look like if +// there was no C++... +typedef NPObject *(*NPAllocateFP)(NPP npp, NPClass *aClass); +typedef void (*NPDeallocateFP)(NPObject *npobj); +typedef void (*NPInvalidateFP)(NPObject *npobj); +typedef bool (*NPHasMethodFP)(NPObject *npobj, NPIdentifier name); +typedef bool (*NPInvokeFP)(NPObject *npobj, NPIdentifier name,const NPVariant *args, uint32 argCount,NPVariant *result); +typedef bool (*NPInvokeDefaultFP)(NPObject *npobj,const NPVariant *args,uint32 argCount,NPVariant *result); +typedef bool (*NPHasPropertyFP)(NPObject *npobj, NPIdentifier name); +typedef bool (*NPGetPropertyFP)(NPObject *npobj, NPIdentifier name, NPVariant *result); +typedef bool (*NPSetPropertyFP)(NPObject *npobj, NPIdentifier name, const NPVariant *value); +typedef bool (*NPRemovePropertyFP)(NPObject *npobj, NPIdentifier name); + +#define NP_CLASS_STRUCT_VERSION 1 + +struct NPClass +{ + NPClass(QtNPInstance *qtnp); + ~NPClass(); + + // NP API + uint32 structVersion; + NPAllocateFP allocate; + NPDeallocateFP deallocate; + NPInvalidateFP invalidate; + NPHasMethodFP hasMethod; + NPInvokeFP invoke; + NPInvokeDefaultFP invokeDefault; + NPHasPropertyFP hasProperty; + NPGetPropertyFP getProperty; + NPSetPropertyFP setProperty; + NPRemovePropertyFP removeProperty; + + // User data lives here + QtNPInstance *qtnp; + bool delete_qtnp; +}; + +struct NPString { + const char *utf8characters; + uint32 utf8length; + + // Qt specific conversion routines + // (no c'tor as it would be misleading that there is no d'tor in spite of memory allocation) + static NPString fromQString(const QString &qstr); + operator QString() const; +}; + +struct NPVariant { + enum Type { + Void, + Null, + Boolean, + Int32, + Double, + String, + Object + }; + Type type; + union { + bool boolValue; + uint32 intValue; + double doubleValue; + NPString stringValue; + NPObject *objectValue; + } value; + + NPVariant() + : type(Null) + {} + + // Qt specific conversion routines + // (no c'tor as the NPP instance is required) + static NPVariant fromQVariant(QtNPInstance *This, const QVariant &qvariant); + operator QVariant() const; + +private: +}; + +#ifdef Q_WS_X11 +extern "C" { +#endif + +// Browser function prototypes +typedef NPError (*NPN_GetURLFP)(NPP instance, const char* url, const char* window); +typedef NPError (*NPN_PostURLFP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file); +typedef NPError (*NPN_RequestReadFP)(NPStream* stream, NPByteRange* rangeList); +typedef NPError (*NPN_NewStreamFP)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); +typedef int32 (*NPN_WriteFP)(NPP instance, NPStream* stream, int32 len, void* buffer); +typedef NPError (*NPN_DestroyStreamFP)(NPP instance, NPStream* stream, NPReason reason); +typedef void (*NPN_StatusFP)(NPP instance, const char* message); +typedef const char* (*NPN_UserAgentFP)(NPP instance); +typedef void* (*NPN_MemAllocFP)(uint32 size); +typedef void (*NPN_MemFreeFP)(void* ptr); +typedef uint32 (*NPN_MemFlushFP)(uint32 size); +typedef void (*NPN_ReloadPluginsFP)(NPBool reloadPages); +typedef JRIEnv* (*NPN_GetJavaEnvFP)(void); +typedef jref (*NPN_GetJavaPeerFP)(NPP instance); +typedef NPError (*NPN_GetURLNotifyFP)(NPP instance, const char* url, const char* window, void* notifyData); +typedef NPError (*NPN_PostURLNotifyFP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData); +typedef NPError (*NPN_GetValueFP)(NPP instance, NPNVariable variable, void *ret_value); +typedef NPError (*NPN_SetValueFP)(NPP instance, NPPVariable variable, void *ret_value); +typedef void (*NPN_InvalidateRectFP)(NPP instance, NPRect *rect); +typedef void (*NPN_InvalidateRegionFP)(NPP instance, NPRegion *region); +typedef void (*NPN_ForceRedrawFP)(NPP instance); +typedef NPIdentifier (*NPN_GetStringIdentifierFP)(const char* name); +typedef void (*NPN_GetStringIdentifiersFP)(const char** names, int32 nameCount, NPIdentifier* identifiers); +typedef NPIdentifier (*NPN_GetIntIdentifierFP)(int32 intid); +typedef bool (*NPN_IdentifierIsStringFP)(NPIdentifier identifier); +typedef char* (*NPN_UTF8FromIdentifierFP)(NPIdentifier identifier); +typedef int32 (*NPN_IntFromIdentifierFP)(NPIdentifier identifier); +typedef NPObject* (*NPN_CreateObjectFP)(NPP npp, NPClass *aClass); +typedef NPObject* (*NPN_RetainObjectFP)(NPObject *obj); +typedef void (*NPN_ReleaseObjectFP)(NPObject *obj); +typedef bool (*NPN_InvokeFP)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, int32 argCount, NPVariant *result); +typedef bool (*NPN_InvokeDefaultFP)(NPP npp, NPObject* obj, const NPVariant *args, int32 argCount, NPVariant *result); +typedef bool (*NPN_EvaluateFP)(NPP npp, NPObject *obj, NPString *script, NPVariant *result); +typedef bool (*NPN_GetPropertyFP)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); +typedef bool (*NPN_SetPropertyFP)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); +typedef bool (*NPN_RemovePropertyFP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +typedef bool (*NPN_HasPropertyFP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +typedef bool (*NPN_HasMethodFP)(NPP npp, NPObject *obj, NPIdentifier methodName); +typedef void (*NPN_ReleaseVariantValueFP)(NPVariant *variant); +typedef void (*NPN_SetExceptionFP)(NPObject *obj, const char *message); + +// function declarations +NPError NPN_GetURL(NPP instance, const char* url, const char* window); +NPError NPN_PostURL(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file); +NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList); +NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* window, NPStream** stream); +int32 NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer); +NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason); +void NPN_Status(NPP instance, const char* message); +const char* NPN_UserAgent(NPP instance); +void* NPN_MemAlloc(uint32 size); +void NPN_MemFree(void* ptr); +uint32 NPN_MemFlush(uint32 size); +void NPN_ReloadPlugins(NPBool reloadPages); +JRIEnv* NPN_GetJavaEnv(void); +jref NPN_GetJavaPeer(NPP instance); +NPError NPN_GetURLNotify(NPP instance, const char* url, const char* window, void* notifyData); +NPError NPN_PostURLNotify(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData); +NPError NPN_GetValue(NPP instance, NPNVariable variable, void *ret_value); +NPError NPN_SetValue(NPP instance, NPPVariable variable, void *ret_value); +void NPN_InvalidateRect(NPP instance, NPRect *rect); +void NPN_InvalidateRegion(NPP instance, NPRegion *region); +void NPN_ForceRedraw(NPP instance); +NPIdentifier NPN_GetStringIdentifier(const char* name); +void NPN_GetStringIdentifiers(const char** names, int32 nameCount, NPIdentifier* identifiers); +NPIdentifier NPN_GetIntIdentifier(int32 intid); +bool NPN_IdentifierIsString(NPIdentifier identifier); +char* NPN_UTF8FromIdentifier(NPIdentifier identifier); +int32 NPN_IntFromIdentifier(NPIdentifier identifier); +NPObject* NPN_CreateObject(NPP npp, NPClass *aClass); +NPObject* NPN_RetainObject(NPObject *obj); +void NPN_ReleaseObject(NPObject *obj); +bool NPN_Invoke(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, int32 argCount, NPVariant *result); +bool NPN_InvokeDefault(NPP npp, NPObject* obj, const NPVariant *args, int32 argCount, NPVariant *result); +bool NPN_Evaluate(NPP npp, NPObject *obj, NPString *script, NPVariant *result); +bool NPN_GetProperty(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); +bool NPN_SetProperty(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); +bool NPN_RemoveProperty(NPP npp, NPObject *obj, NPIdentifier propertyName); +bool NPN_HasProperty(NPP npp, NPObject *obj, NPIdentifier propertyName); +bool NPN_HasMethod(NPP npp, NPObject *obj, NPIdentifier methodName); +void NPN_ReleaseVariantValue(NPVariant *variant); +void NPN_SetException(NPObject *obj, const char *message); + +// table of function implemented by the browser +struct NPNetscapeFuncs { + uint16 size; + uint16 version; + FUNCTION_POINTER(NPN_GetURLFP) geturl; + FUNCTION_POINTER(NPN_PostURLFP) posturl; + FUNCTION_POINTER(NPN_RequestReadFP) requestread; + FUNCTION_POINTER(NPN_NewStreamFP) newstream; + FUNCTION_POINTER(NPN_WriteFP) write; + FUNCTION_POINTER(NPN_DestroyStreamFP) destroystream; + FUNCTION_POINTER(NPN_StatusFP) status; + FUNCTION_POINTER(NPN_UserAgentFP) uagent; + FUNCTION_POINTER(NPN_MemAllocFP) memalloc; + FUNCTION_POINTER(NPN_MemFreeFP) memfree; + FUNCTION_POINTER(NPN_MemFlushFP) memflush; + FUNCTION_POINTER(NPN_ReloadPluginsFP) reloadplugins; + FUNCTION_POINTER(NPN_GetJavaEnvFP) getJavaEnv; + FUNCTION_POINTER(NPN_GetJavaPeerFP) getJavaPeer; + FUNCTION_POINTER(NPN_GetURLNotifyFP) geturlnotify; + FUNCTION_POINTER(NPN_PostURLNotifyFP) posturlnotify; + FUNCTION_POINTER(NPN_GetValueFP) getvalue; + FUNCTION_POINTER(NPN_SetValueFP) setvalue; + FUNCTION_POINTER(NPN_InvalidateRectFP) invalidaterect; + FUNCTION_POINTER(NPN_InvalidateRegionFP) invalidateregion; + FUNCTION_POINTER(NPN_ForceRedrawFP) forceredraw; + FUNCTION_POINTER(NPN_GetStringIdentifierFP) getstringidentifier; + FUNCTION_POINTER(NPN_GetStringIdentifiersFP) getstringidentifiers; + FUNCTION_POINTER(NPN_GetIntIdentifierFP) getintidentifier; + FUNCTION_POINTER(NPN_IdentifierIsStringFP) identifierisstring; + FUNCTION_POINTER(NPN_UTF8FromIdentifierFP) utf8fromidentifier; + FUNCTION_POINTER(NPN_IntFromIdentifierFP) intfromidentifier; + FUNCTION_POINTER(NPN_CreateObjectFP) createobject; + FUNCTION_POINTER(NPN_RetainObjectFP) retainobject; + FUNCTION_POINTER(NPN_ReleaseObjectFP) releaseobject; + FUNCTION_POINTER(NPN_InvokeFP) invoke; + FUNCTION_POINTER(NPN_InvokeDefaultFP) invokedefault; + FUNCTION_POINTER(NPN_EvaluateFP) evaluate; + FUNCTION_POINTER(NPN_GetPropertyFP) getproperty; + FUNCTION_POINTER(NPN_SetPropertyFP) setproperty; + FUNCTION_POINTER(NPN_RemovePropertyFP) removeproperty; + FUNCTION_POINTER(NPN_HasPropertyFP) hasproperty; + FUNCTION_POINTER(NPN_HasMethodFP) hasmethod; + FUNCTION_POINTER(NPN_ReleaseVariantValueFP) releasevariantvalue; + FUNCTION_POINTER(NPN_SetExceptionFP) setexception; +}; + +#ifdef Q_WS_X11 +} +#endif + +#endif diff --git a/lib/browserplugin-solution/util/licenseAccepted b/lib/browserplugin-solution/util/licenseAccepted new file mode 100644 index 0000000..d788f0d --- /dev/null +++ b/lib/browserplugin-solution/util/licenseAccepted @@ -0,0 +1 @@ +license accepted diff --git a/lib/browserplugin-solution/util/licensecheck.bat b/lib/browserplugin-solution/util/licensecheck.bat new file mode 100644 index 0000000..edbeed8 --- /dev/null +++ b/lib/browserplugin-solution/util/licensecheck.bat @@ -0,0 +1,87 @@ +@echo off + +rem +rem "Main" +rem + +rem only ask to accept the license text once +if exist util\licenseAccepted goto EOF + +rem determine if free or commercial package +set edition=commercial +if exist LICENSE.GPL. set edition=free + +if %edition%==free ( + goto HandleFree +) else ( + goto RegionLoop + :ReturnRegionLoop + goto HandleCommercial +) + +goto EOF + +rem +rem "Loops" +rem + +:RegionLoop + echo . + echo Please choose your region. + echo . + echo Type 1 for North or South America. + echo Type 2 for anywhere outside North and South America. + echo . + set /p region=Select: + if %region%==1 ( + set licenseFile=LICENSE.US + goto ReturnRegionLoop + ) + if %region%==2 ( + set licenseFile=LICENSE.NO + goto ReturnRegionLoop + ) +goto RegionLoop + +:HandleFree + echo . + echo You are licensed to use this software under the terms of + echo the GNU General Public License (GPL). + echo . + echo Type 'G' to view the GNU General Plublic License. + echo Type 'yes' to accept this license offer. + echo Type 'no' to decline this license offer. + echo . + set /p answer=Do you accept the terms of this license? + + if %answer%==no exit 1 + if %answer%==yes ( + echo license accepted > util\licenseAccepted + goto EOF + ) + if %answer%==g more LICENSE.GPL + if %answer%==G more LICENSE.GPL +goto HandleFree + +:HandleCommercial + echo . + echo License Agreement + echo . + echo Type '?' to view the Qt Solutions Commercial License. + echo Type 'yes' to accept this license offer. + echo Type 'no' to decline this license offer. + echo . + set /p answer=Do you accept the terms of this license? + + if %answer%==no exit 1 + if %answer%==yes ( + echo license accepted > util\licenseAccepted + copy %licenseFile% LICENSE + del LICENSE.US + del LICENSE.NO + goto EOF + ) + if %answer%==? more %licenseFile% +goto HandleCommercial + +:EOF diff --git a/lib/browserplugin-solution/util/licensecheck.sh b/lib/browserplugin-solution/util/licensecheck.sh new file mode 100644 index 0000000..f393a59 --- /dev/null +++ b/lib/browserplugin-solution/util/licensecheck.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +# only ask to accept the license text once +if [ -f util/licenseAccepted ]; then + exit 0 +fi + +# determine if free or commercial package +if [ -f LICENSE.GPL ]; then + # free edition + while true; do + echo + echo "You are licensed to use this software under the terms of" + echo "the GNU General Public License (GPL)." + echo + echo "Type 'G' to view the GNU General Plublic License." + echo "Type 'yes' to accept this license offer." + echo "Type 'no' to decline this license offer." + echo + echo "Do you accept the terms of this license? " + read answer + + if [ "x$answer" = "xno" ]; then + exit 1 + elif [ "x$answer" = "xyes" ]; then + echo license accepted > util/licenseAccepted + exit 0 + elif [ "x$answer" = "xg" -o "x$answer" = "xG" ]; then + more LICENSE.GPL + fi + done +else + while true; do + echo + echo "Please choose your region." + echo + echo "Type 1 for North or South America." + echo "Type 2 for anywhere outside North and South America." + echo + echo "Select: " + read region + if [ "x$region" = "x1" ]; then + licenseFile=LICENSE.US + break; + elif [ "x$region" = "x2" ]; then + licenseFile=LICENSE.NO + break; + fi + done + while true; do + echo + echo "License Agreement" + echo + echo "Type '?' to view the Qt Solutions Commercial License." + echo "Type 'yes' to accept this license offer." + echo "Type 'no' to decline this license offer." + echo + echo "Do you accept the terms of this license? " + read answer + + if [ "x$answer" = "xno" ]; then + exit 1 + elif [ "x$answer" = "xyes" ]; then + echo license accepted > util/licenseAccepted + cp "$licenseFile" LICENSE + rm LICENSE.US + rm LICENSE.NO + exit 0 + elif [ "x$answer" = "x?" ]; then + more "$licenseFile" + fi + done +fi diff --git a/lib/lib.pro b/lib/lib.pro new file mode 100644 index 0000000..5e2246b --- /dev/null +++ b/lib/lib.pro @@ -0,0 +1,8 @@ +CONFIG += ordered +TEMPLATE = subdirs + +SUBDIRS += anidbudpclient + +browserplugin { +# SUBDIRS += browserplugin-solution +} diff --git a/src/abstractplaylist.h b/src/abstractplaylist.h new file mode 100644 index 0000000..4736be4 --- /dev/null +++ b/src/abstractplaylist.h @@ -0,0 +1,28 @@ +#ifndef ABSTRACTPLAYLIST_H +#define ABSTRACTPLAYLIST_H + +#include + +class AbstractPlaylist : public QObject +{ + Q_OBJECT + +public: + AbstractPlaylist(QObject *parent = 0) : QObject(parent) {} + virtual ~AbstractPlaylist() {} + + virtual bool isEmpty() const = 0; + virtual int count() const = 0; + virtual int currentIndex() const = 0; + +public slots: + virtual void next() = 0; + virtual void previous() = 0; + virtual void setCurrent(int index) = 0; + +signals: + virtual void currentChanged(int index) = 0; + virtual void currentChanged(const QString &newCurrent) = 0; +}; + +#endif // ABSTRACTPLAYLIST_H diff --git a/src/anidbconfigdialog.cpp b/src/anidbconfigdialog.cpp new file mode 100644 index 0000000..2b726d5 --- /dev/null +++ b/src/anidbconfigdialog.cpp @@ -0,0 +1,74 @@ +#include "anidbconfigdialog.h" +#include "ui_anidbconfigdialog.h" + +AniDBConfigDialog::AniDBConfigDialog(QWidget *parent) : + QDialog(parent), + m_ui(new Ui::AniDBConfigDialog) +{ + m_ui->setupUi(this); +} + +QString AniDBConfigDialog::host() const +{ + return m_ui->host->text(); +} + +void AniDBConfigDialog::setHost(const QString &host) +{ + m_ui->host->setText(host); +} + +quint16 AniDBConfigDialog::hostPort() const +{ + return m_ui->hostPort->value(); +} +void AniDBConfigDialog::setHostPort(quint16 port) +{ + m_ui->hostPort->setValue(port); +} + +quint16 AniDBConfigDialog::localPort() const +{ + return m_ui->localPort->value(); +} + +void AniDBConfigDialog::setLocalPort(quint16 port) +{ + m_ui->localPort->setValue(port); +} + +QString AniDBConfigDialog::user() const +{ + return m_ui->user->text(); +} + +void AniDBConfigDialog::setUser(const QString &user) +{ + m_ui->user->setText(user); +} + +QString AniDBConfigDialog::pass() const +{ + return m_ui->pass->text(); +} + +void AniDBConfigDialog::setPass(const QString &pass) +{ + m_ui->pass->setText(pass); +} + +AniDBConfigDialog::~AniDBConfigDialog() +{ + delete m_ui; +} + +void AniDBConfigDialog::changeEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::LanguageChange: + m_ui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/src/anidbconfigdialog.h b/src/anidbconfigdialog.h new file mode 100644 index 0000000..c1fbb1e --- /dev/null +++ b/src/anidbconfigdialog.h @@ -0,0 +1,46 @@ +#ifndef ANIDBCONFIGDIALOG_H +#define ANIDBCONFIGDIALOG_H + +#include + +namespace Ui { + class AniDBConfigDialog; +} + +class AniDBConfigDialog : public QDialog { + Q_OBJECT + Q_DISABLE_COPY(AniDBConfigDialog) +public: + explicit AniDBConfigDialog(QWidget *parent = 0); + virtual ~AniDBConfigDialog(); + + QString host() const; + void setHost(const QString &host); + + quint16 hostPort() const; + void setHostPort(quint16 port); + + quint16 localPort() const; + void setLocalPort(quint16 port); + + QString user() const; + void setUser(const QString &user); + + QString pass() const; + void setPass(const QString &pass); + +protected: + virtual void changeEvent(QEvent *e); + +private: + Ui::AniDBConfigDialog *m_ui; + + QString m_user; + QString m_pass; + QString m_host; + quint16 m_hostPort; + quint16 m_localPort; + +}; + +#endif // ANIDBCONFIGDIALOG_H diff --git a/src/anidbconfigdialog.ui b/src/anidbconfigdialog.ui new file mode 100644 index 0000000..97664af --- /dev/null +++ b/src/anidbconfigdialog.ui @@ -0,0 +1,147 @@ + + + AniDBConfigDialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + AniDB Connection Settings + + + + + + Host: + + + + + + + + + + Port: + + + + + + + 1024 + + + 65536 + + + 9000 + + + + + + + Local Port: + + + + + + + 1024 + + + 65536 + + + 9001 + + + + + + + User: + + + + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + AniDBConfigDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AniDBConfigDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/aniplayer.cpp b/src/aniplayer.cpp new file mode 100644 index 0000000..c462239 --- /dev/null +++ b/src/aniplayer.cpp @@ -0,0 +1,16 @@ +#include "aniplayer.h" + +#include + +AniPlayer::AniPlayer(int &argc, char *argv[]) : QApplication(argc, argv) +{ + m_instance = this; + QSettings::setDefaultFormat(QSettings::IniFormat); +} + +AniPlayer::~AniPlayer() +{ + m_instance = 0; +} + +AniPlayer *AniPlayer::m_instance = 0; diff --git a/src/aniplayer.h b/src/aniplayer.h new file mode 100644 index 0000000..2900499 --- /dev/null +++ b/src/aniplayer.h @@ -0,0 +1,24 @@ +#ifndef ANIPLAYER_H +#define ANIPLAYER_H + +#include + +#ifdef qApp +# undef qApp +# define qApp (AniPlayer::instance()) +#endif + +class AniPlayer : public QApplication +{ + Q_OBJECT + +public: + AniPlayer(int &argc, char *argv[]); + virtual ~AniPlayer(); + + inline static const AniPlayer *instance() { return m_instance;} +private: + static AniPlayer *m_instance; +}; + +#endif // ANIPLAYER_H diff --git a/src/aniplayer.rc b/src/aniplayer.rc new file mode 100644 index 0000000..0a882be --- /dev/null +++ b/src/aniplayer.rc @@ -0,0 +1,37 @@ +1 TYPELIB "aniplayer.rc" + +1 VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "APTX\0" + VALUE "FileDescription", "aniplayer\0" + VALUE "FileExtents", "xxx\0" + VALUE "FileOpenName", "Video Files (*.*)\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "aniplayer\0" + VALUE "LegalCopyright", "Copyright © 2009 APTX\0" + VALUE "MIMEType", "application/x-aniplayer\0" + VALUE "OriginalFilename", "aniplayer.dll\0" + VALUE "ProductName", "AniPlayer\0" + VALUE "ProductVersion", "0, 1, 0, 0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/src/directoryplaylist.cpp b/src/directoryplaylist.cpp new file mode 100644 index 0000000..450da39 --- /dev/null +++ b/src/directoryplaylist.cpp @@ -0,0 +1,78 @@ +#include "directoryplaylist.h" + +DirectoryPlaylist::DirectoryPlaylist(QObject *parent) + : AbstractPlaylist(parent), m_currentIndex(-1) +{ +} + +DirectoryPlaylist::DirectoryPlaylist(QDir directory, QObject *parent) + : AbstractPlaylist(parent), m_currentIndex(-1) +{ + setDirectory(directory); +} + +DirectoryPlaylist::~DirectoryPlaylist() +{ +} + +void DirectoryPlaylist::setDirectory(QDir directory) +{ + m_directory = directory; + m_currentIndex = 2; + emit currentChanged(m_currentIndex - 2); + emit currentChanged(m_directory[m_currentIndex]); +} + +int DirectoryPlaylist::indexOfFile(const QString &file) const +{ + return m_directory.entryList().indexOf(file); +} + +bool DirectoryPlaylist::isEmpty() const +{ + return m_directory.count() == 2; +} + +int DirectoryPlaylist::count() const +{ + return m_directory.count() - 2; +} + +int DirectoryPlaylist::currentIndex() const +{ + return m_currentIndex; +} + +void DirectoryPlaylist::next() +{ + ++m_currentIndex; + if (m_currentIndex == count()) + m_currentIndex = 2; + + emit currentChanged(m_currentIndex - 2); + emit currentChanged(m_directory[m_currentIndex]); +} + +void DirectoryPlaylist::previous() +{ + --m_currentIndex; + if (m_currentIndex == 1) + m_currentIndex = m_directory.count() - 1; + + emit currentChanged(m_currentIndex - 2); + emit currentChanged(m_directory[m_currentIndex]); +} + +void DirectoryPlaylist::setCurrent(int index) +{ + if (index == m_currentIndex) + return; + + if (index < 0 || index > count() - 2) + return; + + m_currentIndex = index + 2; + + emit currentChanged(m_currentIndex - 2); + emit currentChanged(m_directory[m_currentIndex]); +} diff --git a/src/directoryplaylist.h b/src/directoryplaylist.h new file mode 100644 index 0000000..aa501e1 --- /dev/null +++ b/src/directoryplaylist.h @@ -0,0 +1,40 @@ +#ifndef DIRECTORYPLAYLIST_H +#define DIRECTORYPLAYLIST_H + +#include "abstractplaylist.h" +#include + +class DirectoryPlaylist : public AbstractPlaylist +{ + Q_OBJECT + +public: + DirectoryPlaylist(QObject *parent = 0); + DirectoryPlaylist(QDir directory, QObject *parent = 0); + + virtual ~DirectoryPlaylist(); + + void setDirectory(QDir directory); + const QDir &directory() const {return m_directory;} + + int indexOfFile(const QString &file) const; + + virtual bool isEmpty() const; + virtual int count() const; + virtual int currentIndex() const; + +public slots: + virtual void next(); + virtual void previous(); + virtual void setCurrent(int index); + +signals: + virtual void currentChanged(int index); + virtual void currentChanged(const QString &newCurrent); + +private: + QDir m_directory; + int m_currentIndex; +}; + +#endif // DIRECTORYPLAYLIST_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..be24830 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,87 @@ +#include "aniplayer.h" +#include "videowindow.h" + +#ifndef BROWSERPLUGIN_BUILD + +#ifdef STATIC_BUILD +#include +Q_IMPORT_PLUGIN(phonon_ds9) +#endif + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + AniPlayer::setApplicationName("AniPlayer"); + AniPlayer::setOrganizationName("APTX"); + AniPlayer::setApplicationVersion("1.0.0A1"); + + qsrand(QTime().msecsTo(QTime::currentTime())); + + AniPlayer a(argc, argv); + + VideoWindow w; + w.show(); + + if (a.argc() >= 2) + { + w.play(QDir::fromNativeSeparators(a.arguments()[1]), true); + } + return a.exec(); +} +#else + +#include + + +class AniPlayerNPFactory : public QtNPFactory +{ + virtual ~AniPlayerNPFactory() {} + + virtual QObject *createObject(const QString &type) + { + Q_UNUSED(type); + return new VideoWindow(0); + } + + virtual QStringList mimeTypes() const + { + QStringList mime; + mime + << "video/x-matroska:mkv:Matroska File" + << "application/ogg:ogg,ogv:Ogg File" + << "video/ogg:ogg,ogv:Ogg File" + << "video/x-msvideo:avi:Avi File" + << "video/x-ms-wmv:wmv:Windows Media File" + << "video/mp4:mp4:Mp4 File" + << "application/x-aniplayer:xxx:AniPlayer mime type"; + return mime; + } + + virtual QString pluginDescription() const + { + return "AniPlayer Browser Plugin"; + } + + virtual QString pluginName() const + { + return "AniPlayer"; + } +}; + +QTNPFACTORY_EXPORT(AniPlayerNPFactory) + +#ifdef QAXSERVER +#include +QAXFACTORY_BEGIN( + "{1968B727-E990-4751-AE1A-8F0E6404339E}", + "{BAB56E8F-1782-429c-9003-25C7D29841EF}" +) + QAXCLASS(VideoWindow) +QAXFACTORY_END() +#endif + +#endif diff --git a/src/menu.cpp b/src/menu.cpp new file mode 100644 index 0000000..4337680 --- /dev/null +++ b/src/menu.cpp @@ -0,0 +1,132 @@ +#include "menu.h" +#include "ui_menu.h" + +#ifdef KDE_PHONON +# include +# include +#else +# include +#endif + +#include +#include +#include +#include + +Menu::Menu(QWidget *parent) + : QMainWindow(parent), ui(new Ui::MenuClass), dragged(false) +{ +#ifdef Q_WS_X11 + setWindowFlags(Qt::Tool | Qt::X11BypassWindowManagerHint); +#else + setWindowFlags(Qt::Tool); +#endif + setAttribute(Qt::WA_QuitOnClose); + + ui->setupUi(this); + + QWidget *playBarContents = new QWidget(ui->playBar); + + m_seekSlider = new Phonon::SeekSlider(playBarContents); + m_volumeSlider = new Phonon::VolumeSlider(playBarContents); + + m_seekSlider->setMinimumWidth(100); + m_volumeSlider->setMinimumWidth(50); + + timeLabel = new QLabel("0", this); + + QHBoxLayout *layout = new QHBoxLayout(playBarContents); + layout->addWidget(m_seekSlider, 5); + layout->addWidget(timeLabel, 1); + layout->addWidget(m_volumeSlider, 2); + ui->playBar->addWidget(playBarContents); + + setWindowTitle(tr("%1 Control Panel").arg(qApp->applicationName())); + + totalTime = " / " + QTime(0, 0, 0, 0).toString("h:mm:ss"); +} + +Menu::~Menu() +{ + delete ui; +} + +void Menu::addActions(QList actions) +{ + ui->mainToolBar->addActions(actions); +} + +Phonon::SeekSlider *Menu::seekSlider() const +{ + return m_seekSlider; +} + +Phonon::VolumeSlider *Menu::volumeSlider() const +{ + return m_volumeSlider; +} + + +void Menu::showMessage(const QString &message) +{ + ui->statusBar->showMessage(message); +} + +void Menu::tick(qint64 pos) +{ + int sec = pos/1000; + int min = sec/60; + int hour = min/60; + int msec = pos; + timeLabel->setText(QTime(hour, min % 60, sec % 60, msec % 1000).toString("h:mm:ss") + totalTime); +} + +void Menu::setTotalTime(qint64 pos) +{ + int sec = pos/1000; + int min = sec/60; + int hour = min/60; + int msec = pos; + totalTime = " / " + QTime(hour, min % 60, sec % 60, msec % 1000).toString("h:mm:ss"); +} + +void Menu::moveEvent(QMoveEvent *event) +{ + QMainWindow::moveEvent(event); + emit positionChanged(); +} + +void Menu::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + { + dragPosition = event->globalPos() - frameGeometry().topLeft(); + dragged = true; + event->accept(); + } +} + +void Menu::mouseMoveEvent(QMouseEvent *event) +{ + if (!dragged) + return; + + if (event->buttons() & Qt::LeftButton) + { + move(event->globalPos() - dragPosition); + event->accept(); + } +} + +void Menu::mouseReleaseEvent(QMouseEvent * /*event*/) +{ + if (!dragged) + return; + dragged = false; +} + +void Menu::resizeEvent(QResizeEvent *event) +{ + QMainWindow::resizeEvent(event); + emit positionChanged(); +} diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 0000000..c22ef97 --- /dev/null +++ b/src/menu.h @@ -0,0 +1,62 @@ +#ifndef MENU_H +#define MENU_H + +#include +#include + +namespace Ui +{ + class MenuClass; +} + +namespace Phonon +{ + class SeekSlider; + class VolumeSlider; +} + +class QMouseEvent; +class QLabel; + +class Menu : public QMainWindow +{ + Q_OBJECT + +public: + Menu(QWidget *parent = 0); + ~Menu(); + + void addActions(QList actions); + + Phonon::SeekSlider *seekSlider() const; + Phonon::VolumeSlider *volumeSlider() const; + +public slots: + void showMessage(const QString &message); + void tick(qint64 msec); + void setTotalTime(qint64 msec); + +signals: + void positionChanged(); + +protected: + virtual void moveEvent(QMoveEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void resizeEvent(QResizeEvent *event); + +private: + Ui::MenuClass *ui; + Phonon::SeekSlider *m_seekSlider; + Phonon::VolumeSlider *m_volumeSlider; + + + QLabel *timeLabel; + QString totalTime; + + QPoint dragPosition; + bool dragged; +}; + +#endif // MENU_H diff --git a/src/menu.ui b/src/menu.ui new file mode 100644 index 0000000..907dfaf --- /dev/null +++ b/src/menu.ui @@ -0,0 +1,85 @@ + + + MenuClass + + + + 0 + 0 + 395 + 67 + + + + + 0 + 0 + + + + Menu + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 0 + + + + background-color:red; + + + + + + 0 + 0 + 395 + 22 + + + + + 16777215 + 16777215 + + + + + + TopToolBarArea + + + false + + + + + + toolBar + + + TopToolBarArea + + + true + + + + + + + diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 0000000..c00f4ee --- /dev/null +++ b/src/src.pro @@ -0,0 +1,61 @@ +# ------------------------------------------------- +# Project created by QtCreator 2009-02-11T10:09:59 +# ------------------------------------------------- +QT += phonon + +# CONFIG += static +unix { + message(Using system (KDE?) Phonon) + QT -= phonon + LIBS += -lphonon + DEFINES += KDE_PHONON +} +DESTDIR = ../build/ + +# DEFINES += GRAPHICS_VIEW_VIDEO +TARGET = aniplayer +TEMPLATE = app +SOURCES += main.cpp \ + menu.cpp \ + videowindow.cpp \ + videowidget.cpp \ + aniplayer.cpp \ + directoryplaylist.cpp \ + anidbconfigdialog.cpp +HEADERS += menu.h \ + videowindow.h \ + videowidget.h \ + aniplayer.h \ + abstractplaylist.h \ + directoryplaylist.h \ + anidbconfigdialog.h +FORMS += menu.ui \ + anidbconfigdialog.ui +win32:RC_FILE += aniplayer.rc +browserplugin { + win32: + + # CONFIG += qaxserver + include(../lib/browserplugin-solution/src/qtbrowserplugin.pri) + DESTDIR = ../browserplugin_build/ + DEFINES += BROWSERPLUGIN_BUILD +} +static { + win32 { + # LIBS += -L"$(DXSDK_DIR)\Lib\x86" + LIBS += -L"C:\Program Files (x86)\Microsoft DirectX SDK (November 2008)\Lib\x86" + QTPLUGIN += phonon_ds9 + LIBS += -lphonon_ds9 \ + -lstrmiids \ + -ldmoguids \ + -lmsdmo \ + -lole32 \ + -loleaut32 \ + -luuid \ + -lgdi32 \ + $$QMAKE_LIBS_OPENGL + } + DEFINES += STATIC_BUILD + DESTDIR = ../build-static/ +} +include(../lib/anidbudpclient/anidbudpclient.pri) diff --git a/src/videowidget.cpp b/src/videowidget.cpp new file mode 100644 index 0000000..96bcd8f --- /dev/null +++ b/src/videowidget.cpp @@ -0,0 +1,55 @@ +#include "videowidget.h" + +#include +#include + +#include + +VideoWidget::VideoWidget(QWidget *parent) : Phonon::VideoWidget(parent) +{ +} + +void VideoWidget::toggleFullScreen() +{ + setFullScreen(!isFullScreen()); + emit menuToggleRequested(); + emit menuToggleRequested(); +} + +void VideoWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + emit menuToggleRequested(); +#ifndef GRAPHICS_VIEW_VIDEO + else if (event->button() == Qt::RightButton) + toggleFullScreen(); +#endif + else + Phonon::VideoWidget::mousePressEvent(event); +} + +void VideoWidget::wheelEvent(QWheelEvent *event) +{ + // Wheel Up + if (event->delta() > 0) + emit volumeChangeRequested(5); + // Wheel Down + else + emit volumeChangeRequested(-5); + + Phonon::VideoWidget::wheelEvent(event); +} + +void VideoWidget::closeEvent(QCloseEvent *event) +{ + // As per the manual, the fullscreen vidowidget is not "the same". + // It's a top level window. We want to exit fullscreen mode + // (or the entire app) when the users closes this window. + if (isFullScreen()) + { + toggleFullScreen(); + event->ignore(); + return; + } + Phonon::VideoWidget::closeEvent(event); +} diff --git a/src/videowidget.h b/src/videowidget.h new file mode 100644 index 0000000..337adad --- /dev/null +++ b/src/videowidget.h @@ -0,0 +1,30 @@ +#ifndef VIDEOWIDGET_H +#define VIDEOWIDGET_H + +#ifdef KDE_PHONON +# include +#else +# include +#endif + +class VideoWidget : public Phonon::VideoWidget +{ +Q_OBJECT; + +public: + VideoWidget(QWidget *parent = 0); + +public slots: + void toggleFullScreen(); + +signals: + void menuToggleRequested(); + void volumeChangeRequested(int by); + +protected: + void mousePressEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + void closeEvent(QCloseEvent *event); +}; + +#endif // VIDEOWIDGET_H diff --git a/src/videowindow.cpp b/src/videowindow.cpp new file mode 100644 index 0000000..110ce38 --- /dev/null +++ b/src/videowindow.cpp @@ -0,0 +1,717 @@ +#include "videowindow.h" + +#include +#include +#include +#include +#ifdef Q_WS_X11 +# include +#endif +#include +#include +#include +#include + +#include "menu.h" +#include "videowidget.h" +#include "aniplayer.h" +#include "directoryplaylist.h" +#include "anidbconfigdialog.h" + +#include +#include +#include + +#include + +VideoWindow::VideoWindow(QWidget *parent) : QMainWindow(parent) +#ifdef BROWSERPLUGIN_BUILD + , QtNPBindable() +#endif +{ + anidb = new AniDBUdpClient(this); + + +#ifdef Q_WS_X11 + setFocusPolicy(Qt::StrongFocus); +#endif + resize(640, 480); + + addCommand = 0; + destroyed = menuMoving = windowMoving = m_closeOnStop = false; + m_currentFile = ""; + + + mediaObject = new Phonon::MediaObject(this); + mediaController = new Phonon::MediaController(mediaObject); + +#ifdef GRAPHICS_VIEW_VIDEO + videoWidget = new VideoWidget(); +#else + videoWidget = new VideoWidget(this); +#endif + audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this); + + Phonon::createPath(mediaObject, videoWidget); + Phonon::createPath(mediaObject, audioOutput); + +#ifdef GRAPHICS_VIEW_VIDEO + videoScene = new QGraphicsScene(this); + + videoWidgetProxy = videoScene->addWidget(videoWidget); + videoWidgetProxy->setPos(0, 0); + videoScene->setSceneRect(videoWidgetProxy->rect()); + + videoView = new QGraphicsView(videoScene, this); + videoView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + videoView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + videoView->centerOn(videoWidgetProxy); + + setCentralWidget(videoView); +// videoView->resize(size()); + +#else + setCentralWidget(videoWidget); +#endif + + playlist = new DirectoryPlaylist(this); + + + addAction("open", "&Open...", QKeySequence::Open); + addAction("play", "Play", QKeySequence("P")); + addAction("pause", "Pause", QKeySequence("W")); + addAction("stop", "Stop", QKeySequence("X")); +// addAction("next", "Next", QKeySequence(".")); +// addAction("previous", "Previous", QKeySequence(",")); +#ifndef BROWSERPLUGIN_BUILD + addAction("togglePinMenu", "Pin Menu", QKeySequence(), true); + addAction("toggleStayOnTop", "Stay on top", QKeySequence("T"), true); + + m_actions["togglePinMenu"]->setChecked(true); + m_actions["toggleStayOnTop"]->setChecked(false); +#endif + addAction("markWatched", "Mark Watched", QKeySequence("CTRL+M")); + addAction("settings", "Settings", QKeySequence("F7")); + + menu = new Menu(this); + menu->addActions(QWidget::actions()); + +#ifdef GRAPHICS_VIEW_VIDEO + videoSceneMenu = new Menu(); + videoSceneMenu->addActions(QWidget::actions()); + menuProxy = videoScene->addWidget(videoSceneMenu); + menuProxy->hide(); +#endif + + addAction("togglePlay", "Play/Pause", QKeySequence(" ")); + addAction("volUp", "Volume Up", QKeySequence("+")); + addAction("volDown", "Volume Down", QKeySequence("-")); + + addAction("skip85sec", "Skip 1:25", QKeySequence("/")); + + videoWidget->addActions(actions()); + + connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(handleStateChange(Phonon::State,Phonon::State))); + connect(mediaController, SIGNAL(availableSubtitlesChanged()), this, SLOT(updateSubtitles())); + + connect(m_actions["markWatched"], SIGNAL(triggered()), this, SLOT(markWatched())); + connect(m_actions["settings"], SIGNAL(triggered()), this, SLOT(anidbSettings())); + + connect(m_actions["open"], SIGNAL(triggered()), this, SLOT(open())); + connect(m_actions["play"], SIGNAL(triggered()), this, SLOT(play())); +#ifndef BROWSERPLUGIN_BUILD + connect(m_actions["togglePlay"], SIGNAL(triggered()), this, SLOT(togglePlay())); + connect(m_actions["togglePinMenu"], SIGNAL(toggled(bool)), this, SLOT(setPinMenu(bool))); + connect(m_actions["toggleStayOnTop"], SIGNAL(toggled(bool)), this, SLOT(toggleStayOnTop())); +#endif + connect(m_actions["pause"], SIGNAL(triggered()), this, SLOT(pause())); + connect(m_actions["stop"], SIGNAL(triggered()), this, SLOT(stop())); + + connect(m_actions["volUp"], SIGNAL(triggered()), this, SLOT(volumeUp())); + connect(m_actions["volDown"], SIGNAL(triggered()), this, SLOT(volumeDown())); + + connect(m_actions["skip85sec"], SIGNAL(triggered()), this, SLOT(skip())); + + connect(videoWidget, SIGNAL(menuToggleRequested()), this, SLOT(toggleMenu())); + connect(videoWidget, SIGNAL(volumeChangeRequested(int)), this, SLOT(changeVolume(int))); + +// connect(m_actions["next"], SIGNAL(triggered()), playlist, SLOT(next())); +// connect(m_actions["previous"], SIGNAL(triggered()), playlist, SLOT(previous())); +// connect(playlist, SIGNAL(currentChanged(QString)), this, SLOT(play(QString))); +#ifndef BROWSERPLUGIN_BUILD + connect(menu, SIGNAL(positionChanged()), this, SLOT(moveWithMenu())); +#endif + connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), menu, SLOT(setTotalTime(qint64))); + connect(mediaObject, SIGNAL(tick(qint64)), menu, SLOT(tick(qint64))); + + menu->seekSlider()->setMediaObject(mediaObject); + menu->volumeSlider()->setAudioOutput(audioOutput); +#ifdef GRAPHICS_VIEW_VIDEO + videoSceneMenu->seekSlider()->setMediaObject(mediaObject); + videoSceneMenu->volumeSlider()->setAudioOutput(audioOutput); +#endif + + menu->show(); +#ifndef BROWSERPLUGIN_BUILD + move(50, 50); +#endif + setWindowTitle(qApp->applicationName() + " v" + qApp->applicationVersion()); + + loadSettings(); + + anidb->setCompression(true); + anidb->setIdlePolicy(AniDBUdpClient::LogoutIdlePolicy); + + open(m_currentFile); +} + +VideoWindow::~VideoWindow() +{ + saveSettings(); + + destroyed = true; + // HAX + mediaObject->setCurrentSource(Phonon::MediaSource()); +} + +void VideoWindow::toggleMenu() +{ +#ifdef GRAPHICS_VIEW_VIDEO + if (isFullScreen()) + videoSceneMenu->setVisible(!videoSceneMenu->isVisible()); + else +#endif + menu->setVisible(!menu->isVisible()); +} + +void VideoWindow::setMenuVisible(bool visible) +{ + menu->setVisible(visible); +} + +void VideoWindow::open(bool closeOnStop) +{ + QString dir; + QFileInfo fileInfo(m_currentFile); + if (fileInfo.exists()) + { + dir = fileInfo.absolutePath(); + } + else + { + dir = QDesktopServices::storageLocation(QDesktopServices::MoviesLocation); + } + + QString file = QFileDialog::getOpenFileName( + this, + tr("Open media"), + dir, + tr("Video files (*.mkv *.mp4 *.ogg *.ogm *.wmv *.avi);;All files (*)") + ); + + if (file == "") + return; + +// open(file, closeOnStop); + play(file, closeOnStop); +} + +void VideoWindow::open(const QString &file, bool closeOnStop) +{ + if (file == "") + return; + + QFileInfo fileInfo(file); + if (!fileInfo.exists()) + { + menu->showMessage(tr("File %1 does not exist").arg(file)); + return; + } + m_currentFile = file; + m_currentUrl = ""; + + playlist->setDirectory(fileInfo.absoluteDir()); + playlist->setCurrent(playlist->indexOfFile(file)); + + menu->showMessage(tr("Opening: %1").arg(file)); + + Phonon::MediaSource mediaSource(file); + mediaObject->setCurrentSource(mediaSource); + + m_closeOnStop = closeOnStop; +} + +void VideoWindow::openUrl(const QString &urlstr) +{ + QUrl url(urlstr); + if (!url.isValid()) + return; + + menu->showMessage(tr("Opening: %1").arg(url.toString(QUrl::RemovePassword))); + Phonon::MediaSource mediaSource(url); + mediaObject->setCurrentSource(mediaSource); + m_currentUrl = url; + m_closeOnStop = false; + + play(m_closeOnStop); +} + +void VideoWindow::play(bool closeOnStop) +{ + if ((m_currentFile == "" && !m_currentUrl.isValid()) || mediaObject->currentSource().type() == Phonon::MediaSource::Invalid) + { + open(closeOnStop); + } + + mediaObject->play(); +} + +void VideoWindow::play(const QString &file, bool closeOnStop) +{ + open(file, closeOnStop); + play(closeOnStop); +} + +void play(const QString &file); + +void VideoWindow::togglePlay() +{ + Phonon::State state = mediaObject->state(); + + switch(state) + { + case Phonon::PlayingState: + mediaObject->pause(); + break; + case Phonon::LoadingState: + case Phonon::PausedState: + case Phonon::StoppedState: + play(); + break; + default: + break; + } +} + +void VideoWindow::pause() +{ + mediaObject->pause(); +} + +void VideoWindow::stop() +{ + mediaObject->stop(); +} + +void VideoWindow::volumeUp(int by) +{ + qreal volume = qBound(qreal(0), audioOutput->volume() + qreal(by) * 0.01, qreal(1.0)); + audioOutput->setVolume(volume); +} + +void VideoWindow::volumeDown(int by) +{ + qreal volume = qBound(qreal(0), audioOutput->volume() - qreal(by) * 0.01, qreal(1.0)); + audioOutput->setVolume(volume); +} + +void VideoWindow::changeVolume(int by) +{ + qreal volume = qBound(qreal(0), audioOutput->volume() + qreal(by) * 0.01, qreal(1.0)); + audioOutput->setVolume(volume); +} + +void VideoWindow::resizeToVideo() +{ +#ifdef GRAPHICS_VIEW_VIDEO + videoWidget->resize(videoWidget->sizeHint()); + videoScene->setSceneRect(videoWidget->rect()); + videoView->centerOn(videoWidgetProxy); +#endif + resize(videoWidget->sizeHint()); +} + +void VideoWindow::setPinMenu(bool pinned) +{ + setMenuPinned(pinned); + if (pinned) + moveWithMenu(); +} + +void VideoWindow::toggleStayOnTop() +{ + if (windowFlags() & Qt::WindowStaysOnTopHint) + setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + else + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + show(); +} + +void VideoWindow::skip(int msec) +{ + mediaObject->seek(mediaObject->currentTime() + msec); +} + +void VideoWindow::handleStateChange(Phonon::State newstate, Phonon::State oldstate) +{ +qDebug() << "Media changed state from" << oldstate << "to" << newstate; + if (destroyed) + return; + + switch(newstate) + { + case Phonon::ErrorState: + //QMessageBox::warning(this, tr("Phonon error"), mediaObject->errorString()); + menu->showMessage(mediaObject->errorString()); + m_currentFile = ""; + + m_actions["play"]->setDisabled(false); + m_actions["pause"]->setDisabled(true); + m_actions["stop"]->setDisabled(true); +#ifdef BROWSERPLUGIN_BUILD + m_endBrowserStreamRead = true; +#endif + return; + case Phonon::StoppedState: + if (m_closeOnStop) + qApp->quit(); + + m_actions["play"]->setDisabled(false); + m_actions["pause"]->setDisabled(true); + m_actions["stop"]->setDisabled(true); + + break; + case Phonon::PlayingState: + m_actions["play"]->setDisabled(true); + m_actions["pause"]->setDisabled(false); + m_actions["stop"]->setDisabled(false); + break; + case Phonon::PausedState: + m_actions["play"]->setDisabled(false); + m_actions["pause"]->setDisabled(true); + m_actions["stop"]->setDisabled(false); + break; +#ifdef BROWSERPLUGIN_BUILD + case Phonon::LoadingState: + m_endBrowserStreamRead = true; + break; +#endif + default: + break; + } + switch (oldstate) + { + case Phonon::LoadingState: +#ifndef BROWSERPLUGIN_BUILD + if (!isFullScreen()) + resizeToVideo(); +#endif + if (addCommand) + addCommand->deleteLater(); + + addCommand = new MylistAddCommand(m_currentFile, this); + break; + case Phonon::PlayingState: + if (newstate == Phonon::PausedState && mediaObject->remainingTime() == 0) + mediaObject->stop(); + default: + break; + } +} + +void VideoWindow::updateChapters() +{ + +} + +void VideoWindow::updateSubtitles() +{ + QList subtitles = mediaController->availableSubtitles(); + + foreach (const Phonon::SubtitleDescription &subtitle, subtitles) + { + qDebug() << subtitle; + } +} + +void VideoWindow::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + { + toggleMenu(); + event->accept(); + } + else if (event->button() == Qt::RightButton) + { +#ifdef GRAPHICS_VIEW_VIDEO + if (isFullScreen()) + { + showNormal(); + menu->setVisible(videoSceneMenu->isVisible()); + videoSceneMenu->hide(); + + bool pinned = isMenuPinned(); + setMenuPinned(true); + updateMenuPosition(); + setMenuPinned(pinned); + } + else + { + showFullScreen(); + videoSceneMenu->setVisible(menu->isVisible()); + menu->hide(); + } +#else + videoWidget->toggleFullScreen(); + event->accept(); +#endif + } + else + { + QMainWindow::mousePressEvent(event); + } +} + +void VideoWindow::moveEvent(QMoveEvent *event) +{ + QMainWindow::moveEvent(event); + windowMoving = true; + updateMenuPosition(); + windowMoving = false; +} + +void VideoWindow::resizeEvent(QResizeEvent *event) +{ + QMainWindow::resizeEvent(event); +#ifdef GRAPHICS_VIEW_VIDEO + videoWidget->resize(size()); + videoScene->setSceneRect(videoWidget->rect()); + videoView->centerOn(videoWidgetProxy); +#endif + windowMoving = true; + updateMenuPosition(); + windowMoving = false; +} + +#ifdef Q_WS_X11 +void VideoWindow::focusInEvent(QFocusEvent *event) +{ + if (event->gotFocus() && videoWidget->isFullScreen()) + { + menu->setVisible(menuVisible); + event->accept(); + return; + } + QMainWindow::focusInEvent(event); +} + +void VideoWindow::focusOutEvent(QFocusEvent *event) +{ + if (event->lostFocus() && videoWidget->isFullScreen()) + { + menuVisible = menu->isVisible(); + menu->hide(); + event->accept(); + return; + } + QMainWindow::focusOutEvent(event); +} +#endif + +void VideoWindow::wheelEvent(QWheelEvent *event) +{ + // Wheel Up + if (event->delta() > 0) + changeVolume(5); + // Wheel Down + else + changeVolume(-5); + + event->accept(); +} + +void VideoWindow::updateMenuPosition() +{ + if (menuMoving || !isMenuPinned() || isFullScreen()) + return; + + QPoint p(x() + frameGeometry().width() / 2 - menu->frameGeometry().width() / 2, y() + frameGeometry().height()); + menu->move(p); +} + +void VideoWindow::moveWithMenu() +{ + if (windowMoving || !isMenuPinned()) + return; + + QPoint p(menu->x() + menu->frameGeometry().width() / 2 - frameGeometry().width() / 2, menu->y() - frameGeometry().height()); + menuMoving = true; + move(p); + menuMoving = false; +} + +void VideoWindow::markWatched() +{ + if (!addCommand) + { + menu->showMessage("File already Marked"); + return; + } + connect(addCommand, SIGNAL(hashComplete()), this, SLOT(doMarkWatched())); + addCommand->setMarkWatched(true); +qDebug() << "hashing file..."; + addCommand->hash(); + addCommand = 0; +} + +void VideoWindow::doMarkWatched() +{ + MylistAddCommand *cmd = qobject_cast(sender()); + if (!cmd) + return; + + connect(cmd, SIGNAL(replyReady()), cmd, SLOT(deleteLater())); + anidb->send(cmd); + +} + +void VideoWindow::anidbSettings() +{ + AniDBConfigDialog dialog; + + dialog.setHost(anidb->host()); + dialog.setHostPort(anidb->hostPort()); + dialog.setLocalPort(anidb->localPort()); + dialog.setUser(anidb->user()); + dialog.setPass(anidb->pass()); + + if (!dialog.exec()) + { + return; + } + + anidb->disconnect(); + + anidb->setHost(dialog.host()); + anidb->setHostPort(dialog.hostPort()); + anidb->setLocalPort(dialog.localPort()); + anidb->setUser(dialog.user()); + anidb->setPass(dialog.pass()); + + anidb->connect(); +} + +void VideoWindow::addAction(const QString &name, const QString &text, const QKeySequence &shortcut, bool checkable) +{ + QAction *action = new QAction(text, this); + action->setShortcut(shortcut); + action->setCheckable(checkable); + QWidget::addAction(action); + m_actions[name] = action; +} + +bool VideoWindow::isMenuPinned() const +{ +#ifndef BROWSERPLUGIN_BUILD + return m_actions["togglePinMenu"]->isChecked(); +#else + return false; +#endif +} + +void VideoWindow::setMenuPinned(bool pinned) +{ +#ifndef BROWSERPLUGIN_BUILD + m_actions["togglePinMenu"]->setChecked(pinned); +#else + Q_UNUSED(pinned); +#endif +} + +void VideoWindow::saveSettings() +{ +#ifndef BROWSERPLUGIN_BUILD + QSettings settings; + + settings.beginGroup("settings"); + settings.setValue("isMenuPinned", isMenuPinned()); + settings.setValue("currentFile", m_currentFile); + settings.setValue("volume", audioOutput->volume()); + settings.endGroup(); + settings.beginGroup("videoWindow"); + settings.setValue("geometry", saveGeometry()); + settings.endGroup(); + settings.beginGroup("menu"); + settings.setValue("geometry", menu->saveGeometry()); + settings.setValue("state", menu->saveState()); + settings.setValue("isVisible", menu->isVisible()); + settings.endGroup(); + + settings.beginGroup("anidbudpapiclient"); + settings.setValue("host", anidb->host()); + settings.setValue("hostPort", anidb->hostPort()); + settings.setValue("localPort", anidb->localPort()); + settings.setValue("user", anidb->user()); + settings.setValue("pass", anidb->pass()); + settings.endGroup(); +#endif +} + +void VideoWindow::loadSettings() +{ +#ifndef BROWSERPLUGIN_BUILD + QSettings settings; + settings.beginGroup("settings"); + m_actions["togglePinMenu"]->setChecked(settings.value("isMenuPinned", true).toBool()); + if (!m_closeOnStop) + m_currentFile = settings.value("currentFile", "").toString(); + audioOutput->setVolume(settings.value("volume", qreal(1.0)).toDouble()); + settings.endGroup(); + settings.beginGroup("videoWindow"); + restoreGeometry(settings.value("geometry", saveGeometry()).toByteArray()); + settings.endGroup(); + settings.beginGroup("menu"); + menu->restoreGeometry(settings.value("geometry", menu->saveGeometry()).toByteArray()); + menu->restoreState(settings.value("state", menu->saveState()).toByteArray()); + menu->setVisible(settings.value("isVisible", true).toBool()); + settings.endGroup(); + + settings.beginGroup("anidbudpapiclient"); + anidb->setHost(settings.value("host", "api.anidb.info").toString()); + anidb->setHostPort(settings.value("hostPort", 9000).toInt()); + anidb->setLocalPort(settings.value("localPort", 9001).toInt()); + anidb->setUser(settings.value("user").toString()); + anidb->setPass(settings.value("pass").toString()); + settings.endGroup(); + QFileInfo file(m_currentFile); + if (!file.exists()) + { + m_currentFile = ""; + } +#endif +} + +#ifdef BROWSERPLUGIN_BUILD +bool VideoWindow::readData(QIODevice *source, const QString &format) +{ + if (!source->open(QIODevice::ReadOnly)) + return false; + + QMap params = parameters(); + + if (!params.contains("src")) + { + return false; + } + + m_currentUrl = params.value("src").toString(); + + QUrl url(m_currentUrl); + Phonon::MediaSource mediaSource(url); + mediaObject->setCurrentSource(mediaSource); + mediaObject->play(); + + return true; +} +#endif diff --git a/src/videowindow.h b/src/videowindow.h new file mode 100644 index 0000000..0361346 --- /dev/null +++ b/src/videowindow.h @@ -0,0 +1,168 @@ +#ifndef VIDEOWINDOW_H +#define VIDEOWINDOW_H + +#ifdef KDE_PHONON +# include +# include +# include + +# include +# include +#else +# include +#endif + +#ifdef GRAPHICS_VIEW_VIDEO +# include +# include +#endif + +#include +#include +#include +#include + +#ifdef BROWSERPLUGIN_BUILD +# include +# include + +# ifdef QAXSERVER +# include +# endif +#endif + +class VideoWidget; +class Menu; +class DirectoryPlaylist; +class AniDBUdpClient; +class MylistAddCommand; + +class VideoWindow : public QMainWindow +#ifdef BROWSERPLUGIN_BUILD + , public QtNPBindable +# ifdef QAXSERVER + , public QAxBindable +# endif +#endif +{ + Q_OBJECT + + Q_CLASSINFO("MIME", "application/x-aniplayer:xxx:AniPlayer") + + Q_CLASSINFO("ClassID", "{EB98FA4A-E5EA-40d2-84B7-5EAA37DCD6AC}") + Q_CLASSINFO("InterfaceID", "{9A321D1E-6808-4a91-B261-B638D056AFC7}") + Q_CLASSINFO("EventsID", "{43598003-CD16-40d0-BD41-1B574A3496BB}") + +public: + VideoWindow(QWidget *parent = 0); + virtual ~VideoWindow(); + + inline const QString ¤tFile() const { return m_currentFile;} + + +public slots: + void toggleMenu(); + void setMenuVisible(bool visible); + + void open(bool closeOnStop = false); + void open(const QString &file, bool closeOnStop = false); + void openUrl(const QString &url); + void play(bool closeOnStop = false); + void play(const QString &file, bool closeOnStop = false); + void togglePlay(); + void pause(); + void stop(); + + void volumeUp(int by = 5); + void volumeDown(int by = 5); + void changeVolume(int by = 5); + + void resizeToVideo(); + + void setPinMenu(bool pinned); + + void toggleStayOnTop(); + + void skip(int msec = 85000); + +protected: + + virtual void mousePressEvent(QMouseEvent *event); + + virtual void moveEvent(QMoveEvent *event); + virtual void resizeEvent(QResizeEvent *event); +#ifdef Q_WS_X11 + virtual void focusInEvent(QFocusEvent *event); + virtual void focusOutEvent(QFocusEvent *event); +#endif + virtual void wheelEvent(QWheelEvent *event); + + void updateMenuPosition(); + +protected slots: + void moveWithMenu(); + +private slots: + void handleStateChange(Phonon::State newstate, Phonon::State oldstate); + + void updateChapters(); + void updateSubtitles(); + + void markWatched(); + void doMarkWatched(); + + void anidbSettings(); + +private: + void addAction(const QString &name, const QString &text, const QKeySequence &shortcut = QKeySequence(), bool checkable = false); + + bool isMenuPinned() const; + void setMenuPinned(bool pinned); + + void saveSettings(); + void loadSettings(); + + Menu *menu; +#ifdef GRAPHICS_VIEW_VIDEO + Menu *videoSceneMenu; +#endif + + Phonon::MediaObject *mediaObject; + Phonon::MediaController *mediaController; + VideoWidget *videoWidget; + +#ifdef GRAPHICS_VIEW_VIDEO + QGraphicsScene *videoScene; + QGraphicsView *videoView; + QGraphicsProxyWidget *videoWidgetProxy; + QGraphicsProxyWidget *menuProxy; +#endif + Phonon::AudioOutput *audioOutput; + + QMap m_actions; + QList chapterActions; + QList subtitleActions; + + QString m_currentFile; + QUrl m_currentUrl; + + bool destroyed; + bool windowMoving; + bool menuMoving; +#ifdef Q_WS_X11 + bool menuVisible; +#endif + + bool m_closeOnStop; + + DirectoryPlaylist *playlist; + AniDBUdpClient *anidb; + MylistAddCommand *addCommand; + +#ifdef BROWSERPLUGIN_BUILD + virtual bool readData( QIODevice *source, const QString &format); + bool m_endBrowserStreamRead; +#endif +}; + +#endif // VIDEOWINDOW_H