diff --git a/LxBTSC/template/Emotes.js b/LxBTSC/template/Emotes.js index 42dee97..ac494a9 100644 --- a/LxBTSC/template/Emotes.js +++ b/LxBTSC/template/Emotes.js @@ -55,7 +55,7 @@ var Emotes = { alt: emote.code, 'data-key': emote.code }).click(function(e) { - emoteClicked($(this).data('key')); + emoteClicked($(this).data('key'), e.shiftKey); }); emote_container.append(emote_img); }); diff --git a/LxBTSC/template/xbbcode.js b/LxBTSC/template/xbbcode.js index e0197d7..864539b 100644 --- a/LxBTSC/template/xbbcode.js +++ b/LxBTSC/template/xbbcode.js @@ -37,7 +37,7 @@ var XBBCODE = (function() { // ----------------------------------------------------------------------------- var me = {}, - urlPattern = /^(?:https?|file|c):(?:\/{1,3}|\\{1})[-a-zA-Z0-9:;,@#%&()~_?\+=\/\\\.]*$/, + urlPattern = /^(?:https?|ts3file|file|c):(?:\/{1,3}|\\{1})[-a-zA-Z0-9:;,@#%&()~_?\+=\/\\\.]*$/, colorNamePattern = /^(?:aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen)$/, colorCodePattern = /^#?[a-fA-F0-9]{6}$/, emailPattern = /[^\s@]+@[^\s@]+\.[^\s@]+/, diff --git a/QtLxBTSC/ChatWidget.cpp b/QtLxBTSC/ChatWidget.cpp index d996781..31aff3d 100644 --- a/QtLxBTSC/ChatWidget.cpp +++ b/QtLxBTSC/ChatWidget.cpp @@ -67,6 +67,11 @@ void ChatWidget::linkHovered(const QUrl &u) currentHoveredUrl = u; } +void ChatWidget::onFileUrlClicked(const QUrl & url) +{ + emit fileUrlClicked(url); +} + void ChatWidget::copyActivated() { QGuiApplication::clipboard()->setText(view->selectedText(), QClipboard::Clipboard); @@ -110,8 +115,8 @@ void ChatWidget::createPage() page->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); page->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); page->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); - QObject::connect(page, &TsWebEnginePage::linkHovered, this, &ChatWidget::linkHovered); + QObject::connect(page, &TsWebEnginePage::fileUrlClicked, this, &ChatWidget::onFileUrlClicked); page->setUrl(QUrl(pathToPage)); channel = new QWebChannel(page); diff --git a/QtLxBTSC/ChatWidget.h b/QtLxBTSC/ChatWidget.h index 905ce64..3b66593 100644 --- a/QtLxBTSC/ChatWidget.h +++ b/QtLxBTSC/ChatWidget.h @@ -39,11 +39,15 @@ class ChatWidget : public QFrame QWebEngineView *view; TsWebObject *wObject; + signals: + void fileUrlClicked(const QUrl &url); + private slots: void copyActivated(); void copyUrlActivated(); void showContextMenu(const QPoint &); void linkHovered(const QUrl &); + void onFileUrlClicked(const QUrl &url); private: TsWebEnginePage *page; diff --git a/QtLxBTSC/QtLxBTSC.vcxproj b/QtLxBTSC/QtLxBTSC.vcxproj index 875da6e..d580ff7 100644 --- a/QtLxBTSC/QtLxBTSC.vcxproj +++ b/QtLxBTSC/QtLxBTSC.vcxproj @@ -35,6 +35,7 @@ DynamicLibrary v140 + NotSet DynamicLibrary @@ -163,7 +164,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing TsWebObject.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL -D_UNICODE "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" $(QTDIR)\bin\moc.exe;%(FullPath) @@ -180,7 +181,7 @@ Moc%27ing TsWebEnginePage.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL -D_UNICODE "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" @@ -198,7 +199,7 @@ Moc%27ing QtGuiClass.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL -D_UNICODE "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_QUICKWIDGETS_LIB -DQT_WIDGETS_LIB -DQTLXBTSC_LIB -D_WINDLL "-I.\..\ts_plugin\include" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtQuickWidgets" "-I$(QTDIR)\include\QtWidgets" diff --git a/QtLxBTSC/TsWebEnginePage.h b/QtLxBTSC/TsWebEnginePage.h index c272db8..0609bd7 100644 --- a/QtLxBTSC/TsWebEnginePage.h +++ b/QtLxBTSC/TsWebEnginePage.h @@ -10,6 +10,7 @@ #include #include #include +#include class TsWebEnginePage : public QWebEnginePage { @@ -24,9 +25,20 @@ class TsWebEnginePage : public QWebEnginePage { if (type == NavigationTypeLinkClicked && isMainFrame == true) { - QDesktopServices::openUrl(url); - return false; + if (url.scheme() == "ts3file") + { + emit fileUrlClicked(url); + return false; + } + else + { + QDesktopServices::openUrl(url); + return false; + } } return true; } + + signals: + void fileUrlClicked(const QUrl url); }; diff --git a/QtLxBTSC/client.h b/QtLxBTSC/client.h index 921c2db..9784d45 100644 --- a/QtLxBTSC/client.h +++ b/QtLxBTSC/client.h @@ -10,7 +10,7 @@ class Client { this->nickname_ = nickname; this->uid_ = uid; - this->safe_uid_ = uid.replace(QRegExp("[+/=]"), "0"); + this->safe_uid_ = uid.replace(QRegExp("[+/=]"), "00"); } ~Client(){} diff --git a/QtLxBTSC/plugin.cpp b/QtLxBTSC/plugin.cpp index ba00c68..8c1ca95 100644 --- a/QtLxBTSC/plugin.cpp +++ b/QtLxBTSC/plugin.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -145,7 +146,6 @@ static void receiveTabChange(int i) } else { - //const QString id = servers[currentServerID].get_client_safe_uid_by_nickname(chatTabWidget->tabText(i)); const QString id = servers[currentServerID].get_client_by_nickname(chatTabWidget->tabText(i)).safe_uid(); tabName = QString("tab-%1-private-%2").arg(servers[currentServerID].safe_uid()).arg(id); } @@ -173,7 +173,6 @@ static void recheckSelectedTab() } else { - //const QString id = servers[currentServerID].get_client_safe_uid_by_nickname(chatTabWidget->tabText(i)); const QString id = servers[currentServerID].get_client_by_nickname(chatTabWidget->tabText(i)).safe_uid(); tabName = QString("tab-%1-private-%2").arg(servers[currentServerID].safe_uid()).arg(id); } @@ -198,6 +197,50 @@ static void receiveEmoticonButtonClick(bool c) chat->openCloseEmoteMenu(); } +static void receiveFileUrlClick(const QUrl &url) +{ + if (url.hasQuery()) + { + QMessageBox::information(0, "Nope", "Use filelinks from default chat, /lxb toggle", QMessageBox::Ok); + + + // CHECK FOR PASSWORD REQUIREMENT + /*QMessageBox::information(0, "debug", QString("tabchange_trigger: %1").arg("yey"), QMessageBox::Ok); + QUrlQuery query; + query.setQuery(url.query()); + QString server_uid = query.queryItemValue("serverUID", QUrl::FullyDecoded); + QString channel_id = query.queryItemValue("channel", QUrl::FullyDecoded); + QString is_dir = query.queryItemValue("isDir", QUrl::FullyDecoded); + QString file_path = query.queryItemValue("path", QUrl::FullyDecoded); + QString filename = query.queryItemValue("filename", QUrl::FullyDecoded); + + QString full_path; + if (file_path == "/") + { + full_path = QString("/%1").arg(filename); + } + else + { + full_path = QString("%1/%2").arg(file_path, filename); + } + std::string std_filepath = full_path.toStdString(); + + QString download_path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DownloadLocation); + std::string std_download_path = download_path.toStdString(); + + anyID res; + const char ret = '1'; + for each(const Server & server in servers) + { + if (server.uid() == server_uid) + { + QMessageBox::information(0, "debug", QString("%1 %2, %3 %4").arg(full_path).arg(download_path).arg(channel_id).arg(server.server_connection_handler_id()), QMessageBox::Ok); + ts3Functions.requestFile(server.server_connection_handler_id(), channel_id.toULongLong(), "", std_filepath.c_str(), 1, 0, std_download_path.c_str(), &res, &ret); + } + }*/ + } +} + static void receiveEmoticonAppend(QString e) { if (!chatLineEdit->document()->isModified()) @@ -253,10 +296,10 @@ void findEmoticonButton() { if (list[i]->objectName() == "EmoticonButton") { - emoticonButton = static_cast(list[i]); // the one with no tooltip is the correct one :/ - if (emoticonButton->toolTip().isEmpty()) + if (list[i]->toolTip().isEmpty()) { + emoticonButton = static_cast(list[i]); emoticonButton->disconnect(); e = QObject::connect(emoticonButton, &QToolButton::clicked, receiveEmoticonButtonClick); break; @@ -297,6 +340,7 @@ int ts3plugin_init() { pathToPlugin = QString(pluginPath); utils::checkEmoteSets(pathToPlugin); chat = new ChatWidget(pathToPlugin); + QObject::connect(chat, &ChatWidget::fileUrlClicked, receiveFileUrlClick); chat->setStyleSheet("border: 1px solid gray"); return 0; /* 0 = success, 1 = failure, -2 = failure but client will not show a "failed to load" warning */ @@ -357,7 +401,7 @@ void ts3plugin_registerPluginID(const char* id) { /* Plugin command keyword. Return NULL or "" if not used. */ const char* ts3plugin_commandKeyword() { - return "lxbtsc"; + return "lxb"; //return ""; } @@ -409,12 +453,14 @@ Client getClient(uint64 serverConnectionHandlerID, anyID id) if (ts3Functions.getClientDisplayName(serverConnectionHandlerID, id, res, TS3_MAX_SIZE_CLIENT_NICKNAME) == ERROR_ok) { } + QString uniqueid; char *uid; if (ts3Functions.getClientVariableAsString(serverConnectionHandlerID, id, CLIENT_UNIQUE_IDENTIFIER, &uid) == ERROR_ok) { + uniqueid = uid; ts3plugin_freeMemory(uid); } - return Client(res, uid); + return Client(res, uniqueid); } // cache all connected clients @@ -448,7 +494,7 @@ void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int char *res; if (ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_UNIQUE_IDENTIFIER, &res) == ERROR_ok) { - const Server server(res, getAllClientNicks(serverConnectionHandlerID)); + const Server server(serverConnectionHandlerID, res, getAllClientNicks(serverConnectionHandlerID)); chat->addServer(server.safe_uid()); char *msg; if (!servers.values().contains(server)) diff --git a/QtLxBTSC/server.h b/QtLxBTSC/server.h index b3054fb..c270bdf 100644 --- a/QtLxBTSC/server.h +++ b/QtLxBTSC/server.h @@ -6,11 +6,12 @@ class Server { public: - Server(QString uid, QMap clients) + Server(uint64 serverid, QString uid, QMap clients) { this->clients_ = clients; + this->server_connection_handler_id_ = serverid; this->uid_ = uid; - this->safe_uid_ = uid.replace(QRegExp("[+/=]"), "0"); + this->safe_uid_ = uid.replace(QRegExp("[+/=]"), "00"); } Server() : uid_("") {} ~Server() {} @@ -37,6 +38,11 @@ class Server return safe_uid_; } + uint64 Server::server_connection_handler_id() const + { + return server_connection_handler_id_; + } + Client Server::get_client(anyID clientID) const { return clients_.value(clientID); @@ -61,6 +67,7 @@ class Server private: QMap clients_; + uint64 server_connection_handler_id_; QString uid_; QString safe_uid_; }; diff --git a/QtLxBTSC/utils.cpp b/QtLxBTSC/utils.cpp index d0f005b..8ededf6 100644 --- a/QtLxBTSC/utils.cpp +++ b/QtLxBTSC/utils.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include namespace utils { @@ -22,6 +22,7 @@ namespace utils // escape single quotes original.replace("'", "\\'"); + original.replace("\\", "\\\\"); return original; } @@ -49,4 +50,81 @@ namespace utils stream << json << endl; } } + + // helper function to print some object info + void printObjectDetails(QObject *object, QTextStream &stream) + { + stream << "objectname: " << object->objectName() << endl; + const QMetaObject *mo = object->metaObject(); + stream << "classname: " << mo->className() << endl; + stream << "-------properties-----------" << endl; + for (size_t j = 0; j < mo->propertyCount(); ++j) + { + QMetaProperty p = mo->property(j); + + QVariant v = object->property(p.name()); + stream << QString("%1: %2").arg(p.name()).arg(v.toString()) << endl; + } + stream << "-------dynamics-----------" << endl; + QList by = object->dynamicPropertyNames(); + + for each (QByteArray var in by) + { + stream << var << endl; + } + stream << "-----------methods-----------" << endl; + for (int k = mo->methodOffset(); k < mo->methodCount(); ++k) + { + int return_type = mo->method(k).returnType(); + QMetaMethod::Access access = mo->method(k).access(); + QMetaMethod::MethodType method_type = mo->method(k).methodType(); + QList param_names = mo->method(k).parameterNames(); + stream << QMetaType::typeName(return_type) << " "; + stream << QString::fromLatin1(mo->method(k).methodSignature()); + for (int h = 0; h < param_names.count(); ++h) + { + stream << param_names[h] << " "; + } + switch (access) + { + case QMetaMethod::Private: + stream << "private"; + break; + + case QMetaMethod::Protected: + stream << "protected"; + break; + + case QMetaMethod::Public: + stream << "public"; + break; + } + stream << " "; + switch (method_type) + { + case QMetaMethod::Constructor: + stream << "constructor"; + break; + + case QMetaMethod::Method: + stream << "method"; + break; + + case QMetaMethod::Signal: + stream << "signal"; + break; + + case QMetaMethod::Slot: + stream << "slot"; + break; + } + stream << endl; + } + stream << endl; + QObjectList list = object->children(); + for (int v = 0; v < list.count(); ++v) + { + printObjectDetails(list[v], stream); + } + } } diff --git a/QtLxBTSC/utils.h b/QtLxBTSC/utils.h index 1d71ad5..9d9130a 100644 --- a/QtLxBTSC/utils.h +++ b/QtLxBTSC/utils.h @@ -1,9 +1,11 @@ #pragma once #include +#include namespace utils { QString direction(bool direction); QString format(QString original); void checkEmoteSets(const QString &path); + void printObjectDetails(QObject *object, QTextStream &stream); }