From dc2d6c975e2efab88e8d46fbdbb45579ec0d01a6 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sat, 12 May 2012 00:40:53 +0000 Subject: [PATCH] - Moved HandleRichText from the folder "chat" to "util" and redesigned the source - Extended RsHtml::formatText to replace the RetroShare links with an image and enabled this for the certificate links in the system messages (friend recommendation and user request) - Added new ObjectPainter for painting a button on a pixmap git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@5160 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- retroshare-gui/src/RetroShare.pro | 6 +- retroshare-gui/src/gui/ForumsDialog.cpp | 3 +- retroshare-gui/src/gui/FriendsDialog.cpp | 15 +- retroshare-gui/src/gui/RetroShareLink.cpp | 16 +- retroshare-gui/src/gui/RetroShareLink.h | 4 +- retroshare-gui/src/gui/chat/ChatStyle.cpp | 19 +- retroshare-gui/src/gui/chat/ChatStyle.h | 11 +- retroshare-gui/src/gui/chat/ChatWidget.cpp | 15 +- retroshare-gui/src/gui/common/Emoticons.cpp | 23 +- retroshare-gui/src/gui/common/Emoticons.h | 5 +- retroshare-gui/src/gui/feeds/ChanMsgItem.cpp | 6 +- retroshare-gui/src/gui/feeds/ChatMsgItem.cpp | 4 +- retroshare-gui/src/gui/feeds/ForumMsgItem.cpp | 8 +- retroshare-gui/src/gui/feeds/MsgItem.cpp | 4 +- .../src/gui/im_history/ImHistoryBrowser.cpp | 9 +- .../src/gui/msgs/MessageComposer.cpp | 4 +- retroshare-gui/src/gui/msgs/MessageWidget.cpp | 35 ++- retroshare-gui/src/gui/settings/ChatPage.cpp | 12 +- .../src/gui/toaster/ChatLobbyToaster.cpp | 4 +- .../src/gui/toaster/ChatToaster.cpp | 4 +- .../src/gui/toaster/GroupChatToaster.cpp | 4 +- retroshare-gui/src/lang/retroshare_de.qm | Bin 421692 -> 421908 bytes retroshare-gui/src/lang/retroshare_de.ts | 34 ++- .../src/{gui/chat => util}/HandleRichText.cpp | 246 +++++++++++++++--- .../src/{gui/chat => util}/HandleRichText.h | 99 ++----- retroshare-gui/src/util/ObjectPainter.cpp | 62 +++++ retroshare-gui/src/util/ObjectPainter.h | 33 +++ 27 files changed, 470 insertions(+), 215 deletions(-) rename retroshare-gui/src/{gui/chat => util}/HandleRichText.cpp (66%) rename retroshare-gui/src/{gui/chat => util}/HandleRichText.h (50%) create mode 100644 retroshare-gui/src/util/ObjectPainter.cpp create mode 100644 retroshare-gui/src/util/ObjectPainter.h diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index e2c0d3f5b..919e1f833 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -263,6 +263,8 @@ HEADERS += rshare.h \ util/printpreview.h \ util/log.h \ util/misc.h \ + util/HandleRichText.h \ + util/ObjectPainter.h \ gui/bwgraph/bwgraph.h \ gui/profile/ProfileWidget.h \ gui/profile/StatusMessage.h \ @@ -274,7 +276,6 @@ HEADERS += rshare.h \ gui/ChatLobbyWidget.h \ gui/chat/ChatLobbyDialog.h \ gui/chat/CreateLobbyDialog.h \ - gui/chat/HandleRichText.h \ gui/chat/ChatStyle.h \ gui/channels/CreateChannel.h \ gui/channels/ChannelDetails.h \ @@ -545,6 +546,8 @@ SOURCES += main.cpp \ util/printpreview.cpp \ util/log.cpp \ util/misc.cpp \ + util/HandleRichText.cpp \ + util/ObjectPainter.cpp \ gui/bwgraph/bwgraph.cpp \ gui/profile/ProfileWidget.cpp \ gui/profile/StatusMessage.cpp \ @@ -561,7 +564,6 @@ SOURCES += main.cpp \ gui/ChatLobbyWidget.cpp \ gui/chat/ChatLobbyDialog.cpp \ gui/chat/CreateLobbyDialog.cpp \ - gui/chat/HandleRichText.cpp \ gui/chat/ChatStyle.cpp \ gui/connect/ConfCertDialog.cpp \ gui/connect/FriendRequest.cpp \ diff --git a/retroshare-gui/src/gui/ForumsDialog.cpp b/retroshare-gui/src/gui/ForumsDialog.cpp index c38c80c46..8741f4e95 100644 --- a/retroshare-gui/src/gui/ForumsDialog.cpp +++ b/retroshare-gui/src/gui/ForumsDialog.cpp @@ -39,6 +39,7 @@ #include "RetroShareLink.h" #include "channels/ShareKey.h" #include "notifyqt.h" +#include "util/HandleRichText.h" #include #include @@ -1165,7 +1166,7 @@ void ForumsDialog::insertPost() } } - QString extraTxt = RsHtml::formatText(messageFromInfo(msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); + QString extraTxt = RsHtml().formatText(ui.postText->document(), messageFromInfo(msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); ui.postText->setHtml(extraTxt); ui.threadTitle->setText(titleFromInfo(msg)); diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index acf1857a5..d7974f329 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include "retroshare/rsinit.h" #include "retroshare/rsnotify.h" @@ -55,6 +58,7 @@ #include "RetroShareLink.h" #include "settings/rsharesettings.h" #include "util/misc.h" +#include "util/HandleRichText.h" #include "chat/CreateLobbyDialog.h" #include "FriendRecommendDialog.h" @@ -373,11 +377,11 @@ void FriendsDialog::publicChatChanged(int type) void FriendsDialog::addChatMsg(bool incoming, bool history, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message) { - unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS | CHAT_FORMATMSG_OPTIMIZE; + unsigned int formatTextFlag = RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_OPTIMIZE; // embed smileys ? if (Settings->valueFromGroup("Chat", "Emoteicons_GroupChat", true).toBool()) { - formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS; + formatTextFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; } ChatStyle::enumFormatMessage type; @@ -394,10 +398,9 @@ void FriendsDialog::addChatMsg(bool incoming, bool history, const QString &name, type = ChatStyle::FORMATMSG_OUTGOING; } } - // Remove

's from older RetroShare versions before 31.01.2012 (can be removed later) - QString optimizedMessage = message; - RsHtml::optimizeHtml(optimizedMessage); - QString formatMsg = style.formatMessage(type, name, incoming ? recvTime : sendTime, optimizedMessage, formatFlag); + + QString formattedMessage = RsHtml().formatText(ui.msgText->document(), message, formatTextFlag); + QString formatMsg = style.formatMessage(type, name, incoming ? recvTime : sendTime, formattedMessage); ui.msgText->append(formatMsg); } diff --git a/retroshare-gui/src/gui/RetroShareLink.cpp b/retroshare-gui/src/gui/RetroShareLink.cpp index 68fc164bc..a2463c5ea 100644 --- a/retroshare-gui/src/gui/RetroShareLink.cpp +++ b/retroshare-gui/src/gui/RetroShareLink.cpp @@ -757,7 +757,7 @@ bool RetroShareLink::checkHash(const QString& hash) return true ; } -static void processList(QStringList &list, const QString &textSingular, const QString &textPlural, QString &result) +static void processList(const QStringList &list, const QString &textSingular, const QString &textPlural, QString &result) { if (list.size() == 0) { return; @@ -768,7 +768,7 @@ static void processList(QStringList &list, const QString &textSingular, const QS result += "" + textPlural + ":"; } result += "

"; - QStringList::iterator it; + QStringList::const_iterator it; for (it = list.begin(); it != list.end(); ++it) { if (it != list.begin()) { result += ", "; @@ -778,9 +778,9 @@ static void processList(QStringList &list, const QString &textSingular, const QS result += "

"; } -/*static*/ int RetroShareLink::process(QList &linksIn, uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/) +/*static*/ int RetroShareLink::process(const QList &linksIn, uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/) { - QList::iterator linkIt; + QList::const_iterator linkIt; /* filter dublicate links */ QList links; @@ -798,7 +798,7 @@ static void processList(QStringList &list, const QString &textSingular, const QS QStringList personAdd; for (linkIt = links.begin(); linkIt != links.end(); linkIt++) { - RetroShareLink &link = *linkIt; + const RetroShareLink &link = *linkIt; if (link.valid() == false) { continue; @@ -897,7 +897,7 @@ static void processList(QStringList &list, const QString &textSingular, const QS // not needed: forumFound, channelFound, messageStarted for (linkIt = links.begin(); linkIt != links.end(); linkIt++) { - RetroShareLink &link = *linkIt; + const RetroShareLink &link = *linkIt; if (link.valid() == false) { std::cerr << " RetroShareLink::process invalid request" << std::endl; @@ -1257,11 +1257,11 @@ static void processList(QStringList &list, const QString &textSingular, const QS return 0; } -/*static*/ int RetroShareLink::process(QStringList &urls, RetroShareLink::enumType type /* = RetroShareLink::TYPE_UNKNOWN*/, uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/) +/*static*/ int RetroShareLink::process(const QStringList &urls, RetroShareLink::enumType type /* = RetroShareLink::TYPE_UNKNOWN*/, uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/) { QList links; - for (QStringList::iterator it = urls.begin(); it != urls.end(); it++) { + for (QStringList::const_iterator it = urls.begin(); it != urls.end(); it++) { RetroShareLink link(*it); if (link.valid() && (type == RetroShareLink::TYPE_UNKNOWN || link.type() == type)) { links.append(link); diff --git a/retroshare-gui/src/gui/RetroShareLink.h b/retroshare-gui/src/gui/RetroShareLink.h index dfef45835..8756b5d48 100644 --- a/retroshare-gui/src/gui/RetroShareLink.h +++ b/retroshare-gui/src/gui/RetroShareLink.h @@ -101,8 +101,8 @@ class RetroShareLink bool operator==(const RetroShareLink& l) const { return _type == l._type && _hash == l._hash ; } - static int process(QStringList &urls, RetroShareLink::enumType type = RetroShareLink::TYPE_UNKNOWN, uint flag = RSLINK_PROCESS_NOTIFY_ALL); - static int process(QList &links, uint flag = RSLINK_PROCESS_NOTIFY_ALL); + static int process(const QStringList &urls, RetroShareLink::enumType type = RetroShareLink::TYPE_UNKNOWN, uint flag = RSLINK_PROCESS_NOTIFY_ALL); + static int process(const QList &links, uint flag = RSLINK_PROCESS_NOTIFY_ALL); private: void fromString(const QString &url); diff --git a/retroshare-gui/src/gui/chat/ChatStyle.cpp b/retroshare-gui/src/gui/chat/ChatStyle.cpp index ca007c897..2041ecf7c 100644 --- a/retroshare-gui/src/gui/chat/ChatStyle.cpp +++ b/retroshare-gui/src/gui/chat/ChatStyle.cpp @@ -101,11 +101,11 @@ #include #include +#include #include "ChatStyle.h" #include "gui/settings/rsharesettings.h" #include "gui/notifyqt.h" -#include "gui/common/Emoticons.h" #include @@ -301,19 +301,6 @@ QString ChatStyle::formatMessage(enumFormatMessage type, const QString &name, co m_style[type] = style; } - unsigned int formatFlag = 0; - if (flag & CHAT_FORMATMSG_EMBED_SMILEYS) { - formatFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; - } - if (flag & CHAT_FORMATMSG_EMBED_LINKS) { - formatFlag |= RSHTML_FORMATTEXT_EMBED_LINKS; - } - if (flag & CHAT_FORMATMSG_OPTIMIZE) { - formatFlag |= RSHTML_FORMATTEXT_OPTIMIZE; - } - - QString msg = RsHtml::formatText(message, formatFlag); - QColor color; #ifdef COLORED_NICKNAMES if (flag & CHAT_FORMATMSG_SYSTEM) { @@ -332,12 +319,14 @@ QString ChatStyle::formatMessage(enumFormatMessage type, const QString &name, co color.setHsv(hash, 255, 150); } +#else + Q_UNUSED(flag); #endif QString formatMsg = style.replace("%name%", name) .replace("%date%", timestamp.date().toString("dd.MM.yyyy")) .replace("%time%", timestamp.time().toString("hh:mm:ss")) - .replace("%message%", msg) + .replace("%message%", message) .replace("%color%", color.name()); return formatMsg; diff --git a/retroshare-gui/src/gui/chat/ChatStyle.h b/retroshare-gui/src/gui/chat/ChatStyle.h index 7dc8d28f0..25dab4654 100644 --- a/retroshare-gui/src/gui/chat/ChatStyle.h +++ b/retroshare-gui/src/gui/chat/ChatStyle.h @@ -30,14 +30,7 @@ #include /* Flags for ChatStyle::formatMessage */ -#define CHAT_FORMATMSG_EMBED_SMILEYS 1 -#define CHAT_FORMATMSG_EMBED_LINKS 2 -#define CHAT_FORMATMSG_SYSTEM 4 -#define CHAT_FORMATMSG_OPTIMIZE 8 - -/* Flags for ChatStyle::formatText */ -#define CHAT_FORMATTEXT_EMBED_SMILEYS 1 -#define CHAT_FORMATTEXT_EMBED_LINKS 2 +#define CHAT_FORMATMSG_SYSTEM 1 #define FORMATMSG_COUNT 6 @@ -89,7 +82,7 @@ public: bool setStylePath(const QString &stylePath, const QString &styleVariant); bool setStyleFromSettings(enumStyleType styleType); - QString formatMessage(enumFormatMessage type, const QString &name, const QDateTime ×tamp, const QString &message, unsigned int flag); + QString formatMessage(enumFormatMessage type, const QString &name, const QDateTime ×tamp, const QString &message, unsigned int flag = 0); static bool getAvailableStyles(enumStyleType styleType, QList &styles); static bool getAvailableVariants(const QString &stylePath, QStringList &variants); diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index cd8299de3..db0078c7f 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include #include "ChatWidget.h" #include "ui_ChatWidget.h" @@ -35,11 +38,11 @@ #include "gui/settings/rsharesettings.h" #include "gui/settings/RsharePeerSettings.h" #include "gui/im_history/ImHistoryBrowser.h" -#include "HandleRichText.h" #include "gui/common/StatusDefs.h" #include "gui/common/FilesDefs.h" #include "gui/common/Emoticons.h" #include "util/misc.h" +#include "util/HandleRichText.h" #include #include @@ -305,11 +308,12 @@ void ChatWidget::addChatMsg(bool incoming, const QString &name, const QDateTime std::cout << "ChatWidget::addChatMsg message : " << message.toStdString() << std::endl; #endif - unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS | CHAT_FORMATMSG_OPTIMIZE; + unsigned int formatTextFlag = RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_OPTIMIZE; + unsigned int formatFlag = 0; // embed smileys ? if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool()) { - formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS; + formatTextFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; } ChatStyle::enumFormatMessage type; @@ -327,7 +331,8 @@ void ChatWidget::addChatMsg(bool incoming, const QString &name, const QDateTime formatFlag |= CHAT_FORMATMSG_SYSTEM; } - QString formatMsg = chatStyle.formatMessage(type, name, incoming ? sendTime : recvTime, message, formatFlag); + QString formattedMessage = RsHtml().formatText(ui->textBrowser->document(), message, formatTextFlag); + QString formatMsg = chatStyle.formatMessage(type, name, incoming ? sendTime : recvTime, formattedMessage, formatFlag); ui->textBrowser->append(formatMsg); @@ -732,7 +737,7 @@ void ChatWidget::updatePeersCustomStateString(const QString& peer_id, const QStr ui->statusmessagelabel->hide(); } else { ui->statusmessagelabel->show(); - status_text = RsHtml::formatText(status_string, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); + status_text = RsHtml().formatText(NULL, status_string, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); ui->statusmessagelabel->setText(status_text); } } diff --git a/retroshare-gui/src/gui/common/Emoticons.cpp b/retroshare-gui/src/gui/common/Emoticons.cpp index f7ae097ca..997526d00 100644 --- a/retroshare-gui/src/gui/common/Emoticons.cpp +++ b/retroshare-gui/src/gui/common/Emoticons.cpp @@ -31,6 +31,7 @@ #include #include "Emoticons.h" +#include "util/HandleRichText.h" static QHash Smileys; @@ -118,7 +119,7 @@ void Emoticons::load() } // init embedder - RsHtml::defEmbedImg.InitFromAwkwardHash(Smileys); + RsHtml::initEmoticons(Smileys); } void Emoticons::showSmileyWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above) @@ -198,13 +199,13 @@ void Emoticons::showSmileyWidget(QWidget *parent, QWidget *button, const char *s smWidget->show(); } -void Emoticons::formatText(QString &text) -{ - QHashIterator i(Smileys); - while(i.hasNext()) { - i.next(); - foreach (QString code, i.key().split("|")) { - text.replace(code, ""); - } - } -} +//void Emoticons::formatText(QString &text) +//{ +// QHashIterator i(Smileys); +// while(i.hasNext()) { +// i.next(); +// foreach (QString code, i.key().split("|")) { +// text.replace(code, ""); +// } +// } +//} diff --git a/retroshare-gui/src/gui/common/Emoticons.h b/retroshare-gui/src/gui/common/Emoticons.h index d9c722d6b..713aec815 100644 --- a/retroshare-gui/src/gui/common/Emoticons.h +++ b/retroshare-gui/src/gui/common/Emoticons.h @@ -19,12 +19,9 @@ * Boston, MA 02110-1301, USA. ****************************************************************/ - #ifndef _EMOTICONS_H #define _EMOTICONS_H -#include "gui/chat/HandleRichText.h" - class QWidget; class QString; @@ -35,7 +32,7 @@ public: static void showSmileyWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above); - static void formatText(QString &text); +// static void formatText(QString &text); }; #endif diff --git a/retroshare-gui/src/gui/feeds/ChanMsgItem.cpp b/retroshare-gui/src/gui/feeds/ChanMsgItem.cpp index 6d926bedf..a1d9e61ed 100644 --- a/retroshare-gui/src/gui/feeds/ChanMsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/ChanMsgItem.cpp @@ -29,7 +29,7 @@ #include "gui/notifyqt.h" #include "util/misc.h" #include "gui/RetroShareLink.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #include @@ -123,7 +123,7 @@ void ChanMsgItem::updateItemStatic() { /* subject */ titleLabel->setText(QString::fromStdWString(cmi.subject)); - subjectLabel->setText(RsHtml::formatText(QString::fromStdWString(cmi.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + subjectLabel->setText(RsHtml().formatText(NULL, QString::fromStdWString(cmi.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); /* disable buttons: deletion facility not enabled with cache services yet */ clearButton->setEnabled(false); @@ -160,7 +160,7 @@ void ChanMsgItem::updateItemStatic() } } - msgLabel->setText(RsHtml::formatText(QString::fromStdWString(cmi.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + msgLabel->setText(RsHtml().formatText(NULL, QString::fromStdWString(cmi.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); msgWidget->setVisible(!cmi.msg.empty()); QDateTime qtime; diff --git a/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp b/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp index 316579cc9..9290cf2a5 100644 --- a/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp @@ -26,7 +26,7 @@ #include "FeedHolder.h" #include "retroshare-gui/RsAutoUpdatePage.h" #include "gui/msgs/MessageComposer.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #include "gui/common/AvatarDefs.h" #include "gui/settings/rsharesettings.h" @@ -155,7 +155,7 @@ void ChatMsgItem::insertChat(const std::string &message) formatFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; } - formatMsg = RsHtml::formatText(formatMsg, formatFlag); + formatMsg = RsHtml().formatText(NULL, formatMsg, formatFlag); chatTextlabel->setText(formatMsg); } diff --git a/retroshare-gui/src/gui/feeds/ForumMsgItem.cpp b/retroshare-gui/src/gui/feeds/ForumMsgItem.cpp index b8145fa03..eebab06ce 100644 --- a/retroshare-gui/src/gui/feeds/ForumMsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/ForumMsgItem.cpp @@ -31,7 +31,7 @@ #include #include "gui/forums/CreateForumMsg.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #include "gui/common/AvatarDefs.h" #include "gui/notifyqt.h" #include "gui/ForumsDialog.h" @@ -155,7 +155,7 @@ void ForumMsgItem::updateItemStatic() } prevSubLabel->setText(link.toHtml()); - prevMsgLabel->setText(RsHtml::formatText(ForumsDialog::messageFromInfo(msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + prevMsgLabel->setText(RsHtml().formatText(NULL, ForumsDialog::messageFromInfo(msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); QDateTime qtime; qtime.setTime_t(msg.ts); @@ -180,7 +180,7 @@ void ForumMsgItem::updateItemStatic() } nextSubLabel->setText(link.toHtml()); - nextMsgLabel->setText(RsHtml::formatText(ForumsDialog::messageFromInfo(msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + nextMsgLabel->setText(RsHtml().formatText(NULL, ForumsDialog::messageFromInfo(msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); QDateTime qtime; qtime.setTime_t(msg.ts); @@ -197,7 +197,7 @@ void ForumMsgItem::updateItemStatic() RetroShareLink linkParent; linkParent.createForum(msgParent.forumId, msgParent.msgId); prevSubLabel->setText(linkParent.toHtml()); - prevMsgLabel->setText(RsHtml::formatText(ForumsDialog::messageFromInfo(msgParent), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + prevMsgLabel->setText(RsHtml().formatText(NULL, ForumsDialog::messageFromInfo(msgParent), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); if (rsPeers->getPeerName(msgParent.srcId) !="") { diff --git a/retroshare-gui/src/gui/feeds/MsgItem.cpp b/retroshare-gui/src/gui/feeds/MsgItem.cpp index ef7f5b228..78c24edef 100644 --- a/retroshare-gui/src/gui/feeds/MsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/MsgItem.cpp @@ -26,7 +26,7 @@ #include "FeedHolder.h" #include "SubFileItem.h" #include "gui/msgs/MessageComposer.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #include "gui/common/AvatarDefs.h" #include "gui/notifyqt.h" @@ -131,7 +131,7 @@ void MsgItem::updateItemStatic() titleLabel->setText(title); subjectLabel->setText(QString::fromStdWString(mi.title)); - msgLabel->setText(RsHtml::formatText(QString::fromStdWString(mi.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + msgLabel->setText(RsHtml().formatText(NULL, QString::fromStdWString(mi.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); std::list::iterator it; for(it = mi.files.begin(); it != mi.files.end(); it++) diff --git a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp index 6efa02e74..c11afcb91 100644 --- a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp +++ b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp @@ -32,6 +32,7 @@ #include "ImHistoryBrowser.h" #include "IMHistoryItemDelegate.h" #include "IMHistoryItemPainter.h" +#include "util/HandleRichText.h" #include "rshare.h" #include @@ -254,10 +255,10 @@ void ImHistoryBrowser::historyChanged(uint msgId, int type) void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, HistoryMsg& msg) { - unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS; + unsigned int formatTextFlag = RSHTML_FORMATTEXT_EMBED_LINKS; if (embedSmileys) { - formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS; + formatTextFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; } ChatStyle::enumFormatMessage type; @@ -267,8 +268,8 @@ void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, HistoryMsg& msg) type = ChatStyle::FORMATMSG_OUTGOING; } - QString messageText = QString::fromUtf8(msg.message.c_str()); - QString formatMsg = style.formatMessage(type, QString::fromUtf8(msg.peerName.c_str()), QDateTime::fromTime_t(msg.sendTime), messageText, formatFlag); + QString messageText = RsHtml().formatText(NULL, QString::fromUtf8(msg.message.c_str()), formatTextFlag); + QString formatMsg = style.formatMessage(type, QString::fromUtf8(msg.peerName.c_str()), QDateTime::fromTime_t(msg.sendTime), messageText); itemWidget->setData(Qt::DisplayRole, qVariantFromValue(IMHistoryItemPainter(formatMsg))); itemWidget->setData(ROLE_MSGID, msg.msgId); diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.cpp b/retroshare-gui/src/gui/msgs/MessageComposer.cpp index a78ea4afb..3d37cef1e 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.cpp +++ b/retroshare-gui/src/gui/msgs/MessageComposer.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include @@ -55,7 +57,7 @@ #include "TagsMenu.h" #include "gui/common/TagDefs.h" #include "gui/connect/ConfCertDialog.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #define IMAGE_GROUP16 ":/images/user/group16.png" #define IMAGE_FRIENDINFO ":/images/peerdetails_16x16.png" diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.cpp b/retroshare-gui/src/gui/msgs/MessageWidget.cpp index d1da303f7..47f3c7d2d 100644 --- a/retroshare-gui/src/gui/msgs/MessageWidget.cpp +++ b/retroshare-gui/src/gui/msgs/MessageWidget.cpp @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include "gui/notifyqt.h" #include "gui/RetroShareLink.h" @@ -37,6 +40,7 @@ #include "MessageWindow.h" #include "util/misc.h" #include "util/printpreview.h" +#include "util/HandleRichText.h" #include #include @@ -51,6 +55,35 @@ #define COLUMN_FILE_HASH 2 #define COLUMN_FILE_COUNT 3 +class RsHtmlMsg : public RsHtml +{ +public: + RsHtmlMsg(uint msgFlags) : RsHtml() + { + this->msgFlags = msgFlags; + } + +protected: + virtual void anchorTextForImg(QDomDocument &doc, QDomElement &element, const RetroShareLink &link, QString &text) + { + if (link.type() == RetroShareLink::TYPE_CERTIFICATE) { + if (msgFlags & RS_MSG_USER_REQUEST) { + text = QApplication::translate("MessageWidget", "Confirm %1 as friend").arg(link.name()); + return; + } + if (msgFlags & RS_MSG_FRIEND_RECOMMENDATION) { + text = QApplication::translate("MessageWidget", "Add %1 as friend").arg(link.name()); + return; + } + } + + RsHtml::anchorTextForImg(doc, element, link, text); + } + +protected: + uint msgFlags; +}; + MessageWidget *MessageWidget::openMsg(const std::string &msgId, bool window) { if (msgId.empty()) { @@ -523,7 +556,7 @@ void MessageWidget::fill(const std::string &msgId) ui.subjectText->setText(QString::fromStdWString(msgInfo.title)); - text = RsHtml::formatText(QString::fromStdWString(msgInfo.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); + text = RsHtmlMsg(msgInfo.msgflags).formatText(ui.msgText->document(), QString::fromStdWString(msgInfo.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_REPLACE_LINKS); ui.msgText->setHtml(text); ui.filesText->setText(QString("(%1 %2)").arg(msgInfo.count).arg(msgInfo.count == 1 ? tr("File") : tr("Files"))); diff --git a/retroshare-gui/src/gui/settings/ChatPage.cpp b/retroshare-gui/src/gui/settings/ChatPage.cpp index 242a37ce7..4fa60cd15 100644 --- a/retroshare-gui/src/gui/settings/ChatPage.cpp +++ b/retroshare-gui/src/gui/settings/ChatPage.cpp @@ -206,12 +206,12 @@ void ChatPage::setPreviewMessages(QString &stylePath, QString styleVariant, QTex QString nameOutgoing = tr("Outgoing"); QDateTime timestmp = QDateTime::fromTime_t(time(NULL)); - textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_HINCOMING, nameIncoming, timestmp, tr("Incoming message in history"), CHAT_FORMATTEXT_EMBED_SMILEYS | CHAT_FORMATMSG_OPTIMIZE)); - textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_HOUTGOING, nameOutgoing, timestmp, tr("Outgoing message in history"), CHAT_FORMATTEXT_EMBED_SMILEYS | CHAT_FORMATMSG_OPTIMIZE)); - textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_INCOMING, nameIncoming, timestmp, tr("Incoming message"), CHAT_FORMATTEXT_EMBED_SMILEYS | CHAT_FORMATMSG_OPTIMIZE)); - textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_OUTGOING, nameOutgoing, timestmp, tr("Outgoing message"), CHAT_FORMATTEXT_EMBED_SMILEYS | CHAT_FORMATMSG_OPTIMIZE)); - textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_OOUTGOING, nameOutgoing, timestmp, tr("Outgoing offline message"), CHAT_FORMATTEXT_EMBED_SMILEYS | CHAT_FORMATMSG_OPTIMIZE)); - textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_SYSTEM, tr("System"), timestmp, tr("System message"), CHAT_FORMATTEXT_EMBED_SMILEYS | CHAT_FORMATMSG_OPTIMIZE)); + textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_HINCOMING, nameIncoming, timestmp, tr("Incoming message in history"))); + textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_HOUTGOING, nameOutgoing, timestmp, tr("Outgoing message in history"))); + textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_INCOMING, nameIncoming, timestmp, tr("Incoming message"))); + textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_OUTGOING, nameOutgoing, timestmp, tr("Outgoing message"))); + textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_OOUTGOING, nameOutgoing, timestmp, tr("Outgoing offline message"))); + textBrowser->append(style.formatMessage(ChatStyle::FORMATMSG_SYSTEM, tr("System"), timestmp, tr("System message"))); } void ChatPage::fillPreview(QListWidget *listWidget, QComboBox *comboBox, QTextBrowser *textBrowser) diff --git a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp index affbc17f1..9d38da20f 100644 --- a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp +++ b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp @@ -21,7 +21,7 @@ #include "ChatLobbyToaster.h" #include "gui/chat/ChatDialog.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #include @@ -36,7 +36,7 @@ ChatLobbyToaster::ChatLobbyToaster(const std::string &peerId, const QString &nam connect(ui.closeButton, SIGNAL(clicked()), SLOT(hide())); /* set informations */ - ui.messageLabel->setText(RsHtml::formatText(message, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_CLEANSTYLE)); + ui.messageLabel->setText(RsHtml().formatText(NULL, message, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_CLEANSTYLE)); ui.avatarWidget->setFrameType(AvatarWidget::NORMAL_FRAME); ui.avatarWidget->setDefaultAvatar(":images/user/agt_forum64.png"); diff --git a/retroshare-gui/src/gui/toaster/ChatToaster.cpp b/retroshare-gui/src/gui/toaster/ChatToaster.cpp index 333e312ef..0f03c4d23 100644 --- a/retroshare-gui/src/gui/toaster/ChatToaster.cpp +++ b/retroshare-gui/src/gui/toaster/ChatToaster.cpp @@ -21,7 +21,7 @@ #include "ChatToaster.h" #include "gui/chat/ChatDialog.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #include @@ -36,7 +36,7 @@ ChatToaster::ChatToaster(const std::string &peerId, const QString &message) : QW connect(ui.closeButton, SIGNAL(clicked()), SLOT(hide())); /* set informations */ - ui.messageLabel->setText(RsHtml::formatText(message, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_CLEANSTYLE)); + ui.messageLabel->setText(RsHtml().formatText(NULL, message, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_CLEANSTYLE)); ui.nameLabel->setText(QString::fromUtf8(rsPeers->getPeerName(peerId).c_str())); ui.avatarWidget->setFrameType(AvatarWidget::STATUS_FRAME); ui.avatarWidget->setId(peerId, false); diff --git a/retroshare-gui/src/gui/toaster/GroupChatToaster.cpp b/retroshare-gui/src/gui/toaster/GroupChatToaster.cpp index 63742d43a..df56a96c5 100644 --- a/retroshare-gui/src/gui/toaster/GroupChatToaster.cpp +++ b/retroshare-gui/src/gui/toaster/GroupChatToaster.cpp @@ -19,7 +19,7 @@ #include "GroupChatToaster.h" #include "gui/FriendsDialog.h" -#include "gui/chat/HandleRichText.h" +#include "util/HandleRichText.h" #include @@ -34,7 +34,7 @@ GroupChatToaster::GroupChatToaster(const std::string &peerId, const QString &mes connect(ui.closeButton, SIGNAL(clicked()), SLOT(hide())); /* set informations */ - ui.messageLabel->setText(RsHtml::formatText(message, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_CLEANSTYLE)); + ui.messageLabel->setText(RsHtml().formatText(NULL, message, RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS | RSHTML_FORMATTEXT_CLEANSTYLE)); ui.nameLabel->setText(QString::fromUtf8(rsPeers->getPeerName(peerId).c_str())); ui.avatarWidget->setFrameType(AvatarWidget::STATUS_FRAME); ui.avatarWidget->setDefaultAvatar(":/images/user/personal64.png"); diff --git a/retroshare-gui/src/lang/retroshare_de.qm b/retroshare-gui/src/lang/retroshare_de.qm index dbaa0a705c1d5252476df9cb4ba46ca5a8fd912d..d616362183e51bbad9ef5663765636dd3e191e1d 100644 GIT binary patch delta 12811 zcmZ9Sd00)|`^KNW*IxU~=R_F_r#WMxL8dYl>dl-|sH7;GsLVQEgfgXFn#?5g6v9hr zpiqY7HD*YrSEiKA-^V_G{I2WwhwHP?aXM%3wb#0z`?=RXTVtH|#5l!BcM1S3ff@5R zau6_QE0BYMaa<~rdp}YnZ<>M}2E3&XIRaUS^akE)19B$t)}{dLVBjq_0dN8k4?pBF z{GL5}`nM9vy^j;go1R482G}69?ecyz9)AMf^f3T!iGTA=Pyd-Bx%Zbu@@CQv)vjGm zFUD8>fEw@D)8d()`G1Mz&HErn0dKAmT$na3p5vV1n?4oJs1QqHV?SRodL#;0}!fkOfSPk z=<`B6fc$EJ@za53?*f>R48*T5z{D;tup@5a>jGfM z{NZh2$Nk|)VEvJnYGE_0wXh5ZZeiGEJB02HeALz#B<` zd$a(E7oOz{Z~WOx;9l9_`#q7F!0sv)Nk$at8RM+yFK?0D(?~s=@bvKW^w%Ze-u3`u ze^DfFhTr=>7oZK*v(qk-!WqukJ|_&>VpII&q|z0Nx+l2K&KS~xf2XDY!BX4Tc9(G zfL!0E=bcoMJpBN4b`n5ejYxXlN+i$Q0G)#~HaiXI8XVw0^F{LJfj~1$p&fK+BOVZc zYms!59O$M$LpM>d<$GD&*n}_LfO39FZ(x$LMUu(>dZq*liF_~JY#Gq)6v)3#dj5VY zl6y8p&!3$|^74^-8sO>X;Q*h+ugj|i5|FQF$e;J|^@78CZoq-u?+;|!0iY-Fy^F_y zUcd!41TP=S{Wbzxau{@Q>H*LftMLPGfN#V}Rnu1_H68~N98YHb43Iih1DjU@^7o&C zbRP+dca69@GeKF<1%UYh$}97MJ^B{Z2NnT&bsjW5z5?S=3kFpO07l70QU_x&326!B zvpJX)tpk?30qwIcPXaP4=Fb6;IUn_0?G4%%eSnrmfoXpYFgG57X-Y>R=?B5gaXt_m zf3RqZ2d0BRSp7NScn`4IOMvO04IMLZg*beJj(5fZFKrZBNk_?ULYERJpqBAMq_hq5 zSV)w*va#cYQmL!%Y!GyFs{^iann)Ts8+tO$!2RkYlFmE^4�Sx#t89e)-5?a1?nS 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 XE9L+HRGXDc3JCt=3YHYmvjzVH`swLx delta 12650 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 diff --git a/retroshare-gui/src/lang/retroshare_de.ts b/retroshare-gui/src/lang/retroshare_de.ts index 6f150bdb4..843c3a095 100644 --- a/retroshare-gui/src/lang/retroshare_de.ts +++ b/retroshare-gui/src/lang/retroshare_de.ts @@ -1502,7 +1502,7 @@ p, li { white-space: pre-wrap; } ChatStyle - + Standard style for group chat Standard Stil für den Gruppenchat @@ -1646,7 +1646,7 @@ p, li { white-space: pre-wrap; } Schriftart auf den Standard setzen - + Paste RetroShare Link RetroShare Link einfügen @@ -4606,7 +4606,7 @@ p, li { white-space: pre-wrap; } Du kannst einem anonymen Autor nicht antworten - + Your Forums Deine Foren @@ -4771,7 +4771,7 @@ p, li { white-space: pre-wrap; } Druckvorschau - + Start New Thread Erstelle neues Thema @@ -5602,7 +5602,7 @@ p, li { white-space: pre-wrap; } Löscht den gespeicherten und angezeigten Chat Verlauf - + Chat lobbies Chat Lobbies @@ -5740,7 +5740,7 @@ p, li { white-space: pre-wrap; } tippt... - + New group chat Neuer Gruppenchat @@ -7222,7 +7222,7 @@ p, li { white-space: pre-wrap; } - + Copy Kopieren @@ -7673,7 +7673,7 @@ Bitte gib etwas Speicher frei und drücke OK. MessageComposer - + Compose Verfassen @@ -8390,7 +8390,17 @@ p, li { white-space: pre-wrap; } Druckvorschau - + + Confirm %1 as friend + %1 als Freund bestätigen + + + + Add %1 as friend + %1 als Freund hinzufügen + + + No subject Kein Betreff @@ -10184,7 +10194,7 @@ p, li { white-space: pre-wrap; } Formular - + Status: Status: @@ -10194,7 +10204,7 @@ p, li { white-space: pre-wrap; } Datei Prüfsumme: - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -10207,7 +10217,7 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="more"><span style=" text-decoration: underline; color:#0000ff;">mehr...</span></a></p></body></html> - + File name: Dateiname: diff --git a/retroshare-gui/src/gui/chat/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp similarity index 66% rename from retroshare-gui/src/gui/chat/HandleRichText.cpp rename to retroshare-gui/src/util/HandleRichText.cpp index 2a835c59b..dc7e25f89 100644 --- a/retroshare-gui/src/gui/chat/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -20,16 +20,77 @@ ****************************************************************/ #include +#include + #include "HandleRichText.h" #include "gui/RetroShareLink.h" +#include "util/ObjectPainter.h" #include -namespace RsHtml { +/** + * The type of embedding we'd like to do + */ +enum EmbeddedType +{ + Ahref, ///< into + Img ///< into +}; -EmbedInHtmlImg defEmbedImg; +/** + * Base class for storing information about a given kind of embedding. + * + * Its only constructor is protected so it is impossible to instantiate it, and + * at the same time derived classes have to provide a type. + */ +class EmbedInHtml +{ +protected: + EmbedInHtml(EmbeddedType newType) : myType(newType) {} -void EmbedInHtmlImg::InitFromAwkwardHash(const QHash< QString, QString >& hash) +public: + const EmbeddedType myType; + QRegExp myRE; +}; + +/** + * This class is used to store information for embedding links into tags. + */ +class EmbedInHtmlAhref : public EmbedInHtml +{ +public: + EmbedInHtmlAhref() : EmbedInHtml(Ahref) + { + myRE.setPattern("(\\bretroshare://[^\\s]*)|(\\bhttps?://[^\\s]*)|(\\bfile://[^\\s]*)|(\\bwww\\.[^\\s]*)"); + } +}; + +/** + * This class is used to store information for embedding smileys into tags. + * + * By default the QRegExp the variables are empty, which means it must be + * filled at runtime, typically when the smileys set is loaded. It can be + * either done by hand or by using one of the helper methods available. + * + * Note: The QHash uses only *one* smiley per key (unlike soon-to-be-upgraded + * code out there). + */ +class EmbedInHtmlImg : public EmbedInHtml +{ +public: + EmbedInHtmlImg() : EmbedInHtml(Img) {} + + QHash smileys; +}; + +/* global instance for embedding emoticons */ +static EmbedInHtmlImg defEmbedImg; + +RsHtml::RsHtml() +{ +} + +void RsHtml::initEmoticons(const QHash< QString, QString >& hash) { QString newRE; for(QHash::const_iterator it = hash.begin(); it != hash.end(); ++it) @@ -37,11 +98,103 @@ void EmbedInHtmlImg::InitFromAwkwardHash(const QHash< QString, QString >& hash) if (smile.isEmpty()) { continue; } - smileys.insert(smile, it.value()); + defEmbedImg.smileys.insert(smile, it.value()); newRE += "(" + QRegExp::escape(smile) + ")|"; } newRE.chop(1); // remove last | - myRE.setPattern(newRE); + defEmbedImg.myRE.setPattern(newRE); +} + +bool RsHtml::canReplaceAnchor(QDomDocument &/*doc*/, QDomElement &/*element*/, const RetroShareLink &link) +{ + switch (link.type()) { + case RetroShareLink::TYPE_UNKNOWN: + case RetroShareLink::TYPE_FILE: + case RetroShareLink::TYPE_PERSON: + case RetroShareLink::TYPE_FORUM: + case RetroShareLink::TYPE_CHANNEL: + case RetroShareLink::TYPE_SEARCH: + case RetroShareLink::TYPE_MESSAGE: + // not yet implemented + break; + + case RetroShareLink::TYPE_CERTIFICATE: + return true; + } + + return false; +} + +void RsHtml::anchorTextForImg(QDomDocument &/*doc*/, QDomElement &/*element*/, const RetroShareLink &link, QString &text) +{ + text = link.niceName(); +} + +void RsHtml::anchorStylesheetForImg(QDomDocument &/*doc*/, QDomElement &/*element*/, const RetroShareLink &link, QString &styleSheet) +{ + switch (link.type()) { + case RetroShareLink::TYPE_UNKNOWN: + case RetroShareLink::TYPE_FILE: + case RetroShareLink::TYPE_PERSON: + case RetroShareLink::TYPE_FORUM: + case RetroShareLink::TYPE_CHANNEL: + case RetroShareLink::TYPE_SEARCH: + case RetroShareLink::TYPE_MESSAGE: + // not yet implemented + break; + + case RetroShareLink::TYPE_CERTIFICATE: + styleSheet = ""; + break; + } +} + +void RsHtml::replaceAnchorWithImg(QDomDocument &doc, QDomElement &element, QTextDocument *textDocument, const RetroShareLink &link) +{ + if (!textDocument) { + return; + } + + if (!link.valid()) { + return; + } + + if (element.childNodes().length() != 1) { + return; + } + + if (!canReplaceAnchor(doc, element, link)) { + return; + } + + QString imgText; + anchorTextForImg(doc, element, link, imgText); + + QString styleSheet; + anchorStylesheetForImg(doc, element, link, styleSheet); + + QDomNode childNode = element.firstChild(); + + + /* build resource name */ + QString resourceName = QString("%1_%2.png").arg(link.type()).arg(imgText); + + if (!textDocument->resource(QTextDocument::ImageResource, QUrl(resourceName)).isValid()) { + /* draw a button on a pixmap */ + QPixmap pixmap; + ObjectPainter::drawButton(imgText, styleSheet, pixmap); + + /* add the image to the resource cache of the text document */ + textDocument->addResource(QTextDocument::ImageResource, QUrl(resourceName), QVariant(pixmap)); + } + + element.removeChild(childNode); + + /* replace text of the anchor with */ + QDomElement img = doc.createElement("img"); + img.setAttribute("src", resourceName); + + element.appendChild(img); } /** @@ -61,7 +214,7 @@ void EmbedInHtmlImg::InitFromAwkwardHash(const QHash< QString, QString >& hash) * @param[in,out] currentElement The current node (which is of type Element) * @param[in] embedInfos The regular expression and the type of embedding to use */ -static void embedHtml(QDomDocument& doc, QDomElement& currentElement, EmbedInHtml& embedInfos) +void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomElement& currentElement, EmbedInHtml& embedInfos, ulong flag) { if(embedInfos.myRE.pattern().length() == 0) // we'll get stuck with an empty regexp return; @@ -75,16 +228,31 @@ static void embedHtml(QDomDocument& doc, QDomElement& currentElement, EmbedInHtm if(element.tagName().toLower() == "head") { // skip it } else if (element.tagName().toLower() == "a") { - // skip it, but add title if not available - if (element.attribute("title").isEmpty()) { - RetroShareLink link(element.attribute("href")); - QString title = link.title(); - if (!title.isEmpty()) { - element.setAttribute("title", title); + // skip it + if (embedInfos.myType == Ahref) { + // but add title if not available + if (element.attribute("title").isEmpty()) { + RetroShareLink link(element.attribute("href")); + if (link.valid()) { + QString title = link.title(); + if (!title.isEmpty()) { + element.setAttribute("title", title); + } + if (textDocument && (flag & RSHTML_FORMATTEXT_REPLACE_LINKS)) { + replaceAnchorWithImg(doc, element, textDocument, link); + } + } + } else { + if (textDocument && (flag & RSHTML_FORMATTEXT_REPLACE_LINKS)) { + RetroShareLink link(element.attribute("href")); + if (link.valid()) { + replaceAnchorWithImg(doc, element, textDocument, link); + } + } } } } else { - embedHtml(doc, element, embedInfos); + embedHtml(textDocument, doc, element, embedInfos, flag); } } else if(node.isText()) { @@ -109,16 +277,22 @@ static void embedHtml(QDomDocument& doc, QDomElement& currentElement, EmbedInHtm switch(embedInfos.myType) { case Ahref: { - insertedTag = doc.createElement("a"); - insertedTag.setAttribute("href", embedInfos.myRE.cap(0)); - RetroShareLink link(embedInfos.myRE.cap(0)); - QString title = link.title(); - if (!title.isEmpty()) { - insertedTag.setAttribute("title", title); - } + if (link.valid()) { + insertedTag = doc.createElement("a"); + insertedTag.setAttribute("href", embedInfos.myRE.cap(0)); - insertedTag.appendChild(doc.createTextNode(embedInfos.myRE.cap(0))); + QString title = link.title(); + if (!title.isEmpty()) { + insertedTag.setAttribute("title", title); + } + + insertedTag.appendChild(doc.createTextNode(embedInfos.myRE.cap(0))); + + if (textDocument && (flag & RSHTML_FORMATTEXT_REPLACE_LINKS)) { + replaceAnchorWithImg(doc, insertedTag, textDocument, link); + } + } } break; case Img: @@ -129,10 +303,13 @@ static void embedHtml(QDomDocument& doc, QDomElement& currentElement, EmbedInHtm } break; } - currentElement.insertBefore(insertedTag, node); + + if (!insertedTag.isNull()) { + currentElement.insertBefore(insertedTag, node); + index++; + } currentPos = nextPos + embedInfos.myRE.matchedLength(); - index++; } // text after the last link, only if there's one, don't touch the index @@ -149,7 +326,7 @@ static void embedHtml(QDomDocument& doc, QDomElement& currentElement, EmbedInHtm } } -QString formatText(const QString &text, unsigned int flag) +QString RsHtml::formatText(QTextDocument *textDocument, const QString &text, ulong flag) { if (flag == 0 || text.isEmpty()) { // nothing to do @@ -166,11 +343,11 @@ QString formatText(const QString &text, unsigned int flag) QDomElement body = doc.documentElement(); if (flag & RSHTML_FORMATTEXT_EMBED_SMILEYS) { - embedHtml(doc, body, defEmbedImg); + embedHtml(textDocument, doc, body, defEmbedImg, flag); } if (flag & RSHTML_FORMATTEXT_EMBED_LINKS) { EmbedInHtmlAhref defEmbedAhref; - embedHtml(doc, body, defEmbedAhref); + embedHtml(textDocument, doc, body, defEmbedAhref, flag); } QString formattedText = doc.toString(-1); // -1 removes any annoying carriage return misinterpreted by QTextEdit @@ -217,11 +394,14 @@ static void findElements(QDomDocument& doc, QDomElement& currentElement, const Q } } -bool findAnchors(const QString &text, QStringList& urls) +bool RsHtml::findAnchors(const QString &text, QStringList& urls) { QDomDocument doc; if (doc.setContent(text) == false) { - return false; + // convert text with QTextBrowser + QTextBrowser textBrowser; + textBrowser.setText(text); + doc.setContent(textBrowser.toHtml()); } QDomElement body = doc.documentElement(); @@ -404,7 +584,7 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne } } -void optimizeHtml(QTextEdit *textEdit, QString &text, unsigned int flag) +void RsHtml::optimizeHtml(QTextEdit *textEdit, QString &text, unsigned int flag) { if (textEdit->toHtml() == QTextDocument(textEdit->toPlainText()).toHtml()) { text = textEdit->toPlainText(); @@ -417,7 +597,7 @@ void optimizeHtml(QTextEdit *textEdit, QString &text, unsigned int flag) optimizeHtml(text, flag); } -void optimizeHtml(QString &text, unsigned int flag) +void RsHtml::optimizeHtml(QString &text, unsigned int flag) { int originalLength = text.length(); @@ -430,13 +610,13 @@ void optimizeHtml(QString &text, unsigned int flag) } QDomElement body = doc.documentElement(); - optimizeHtml(doc, body, flag); + ::optimizeHtml(doc, body, flag); text = doc.toString(-1); std::cerr << "Optimized text to " << text.length() << " bytes , instead of " << originalLength << std::endl; } -QString toHtml(QString text, bool realHtml) +QString RsHtml::toHtml(QString text, bool realHtml) { // replace "\n" from the optimized html with "
" text.replace("\n", "
"); @@ -448,5 +628,3 @@ QString toHtml(QString text, bool realHtml) doc.setHtml(text); return doc.toHtml(); } - -} // namespace RsHtml diff --git a/retroshare-gui/src/gui/chat/HandleRichText.h b/retroshare-gui/src/util/HandleRichText.h similarity index 50% rename from retroshare-gui/src/gui/chat/HandleRichText.h rename to retroshare-gui/src/util/HandleRichText.h index e98ae07dd..1994202b2 100644 --- a/retroshare-gui/src/gui/chat/HandleRichText.h +++ b/retroshare-gui/src/util/HandleRichText.h @@ -25,13 +25,10 @@ * messages, particularly embedding special information into HTML tags. */ - #ifndef HANDLE_RICH_TEXT_H_ #define HANDLE_RICH_TEXT_H_ - #include -#include /* Flags for RsHtml::formatText */ #define RSHTML_FORMATTEXT_EMBED_SMILEYS 1 @@ -40,92 +37,40 @@ #define RSHTML_FORMATTEXT_REMOVE_COLOR 8 #define RSHTML_FORMATTEXT_CLEANSTYLE (RSHTML_FORMATTEXT_REMOVE_FONT | RSHTML_FORMATTEXT_REMOVE_COLOR) #define RSHTML_FORMATTEXT_OPTIMIZE 16 +#define RSHTML_FORMATTEXT_REPLACE_LINKS 32 /* Flags for RsHtml::formatText */ #define RSHTML_OPTIMIZEHTML_REMOVE_FONT 2 #define RSHTML_OPTIMIZEHTML_REMOVE_COLOR 1 class QTextEdit; +class QTextDocument; +class QDomDocument; +class QDomElement; +class EmbedInHtml; +class RetroShareLink; -namespace RsHtml { - - -/** - * The type of embedding we'd like to do - */ -enum EmbeddedType +class RsHtml { - Ahref, ///< into - Img, ///< into -}; +public: + RsHtml(); + static void initEmoticons(const QHash< QString, QString >& hash); + + QString formatText(QTextDocument *textDocument, const QString &text, ulong flag); + static bool findAnchors(const QString &text, QStringList& urls); + + static void optimizeHtml(QTextEdit *textEdit, QString &text, unsigned int flag = 0); + static void optimizeHtml(QString &text, unsigned int flag = 0); + static QString toHtml(QString text, bool realHtml = true); -/** - * Base class for storing information about a given kind of embedding. - * - * Its only constructor is protected so it is impossible to instantiate it, and - * at the same time derived classes have to provide a type. - */ -class EmbedInHtml -{ protected: - EmbedInHtml(EmbeddedType newType) : - myType(newType) - {} + void embedHtml(QTextDocument *textDocument, QDomDocument &doc, QDomElement ¤tElement, EmbedInHtml& embedInfos, ulong flag); + void replaceAnchorWithImg(QDomDocument& doc, QDomElement &element, QTextDocument *textDocument, const RetroShareLink &link); -public: - const EmbeddedType myType; - QRegExp myRE; + virtual bool canReplaceAnchor(QDomDocument &doc, QDomElement &element, const RetroShareLink &link); + virtual void anchorTextForImg(QDomDocument &doc, QDomElement &element, const RetroShareLink &link, QString &text); + virtual void anchorStylesheetForImg(QDomDocument &doc, QDomElement &element, const RetroShareLink &link, QString &styleSheet); }; - -/** - * This class is used to store information for embedding links into tags. - */ -class EmbedInHtmlAhref : public EmbedInHtml -{ -public: - EmbedInHtmlAhref() : - EmbedInHtml(Ahref) - { - myRE.setPattern("(\\bretroshare://[^\\s]*)|(\\bhttps?://[^\\s]*)|(\\bfile://[^\\s]*)|(\\bwww\\.[^\\s]*)"); - } -}; - - - -/** - * This class is used to store information for embedding smileys into tags. - * - * By default the QRegExp the variables are empty, which means it must be - * filled at runtime, typically when the smileys set is loaded. It can be - * either done by hand or by using one of the helper methods available. - * - * Note: The QHash uses only *one* smiley per key (unlike soon-to-be-upgraded - * code out there). - */ -class EmbedInHtmlImg : public EmbedInHtml -{ -public: - EmbedInHtmlImg() : - EmbedInHtml(Img) - {} - - void InitFromAwkwardHash(const QHash& hash); - - QHash smileys; -}; - -extern EmbedInHtmlImg defEmbedImg; - -QString formatText(const QString &text, unsigned int flag); -bool findAnchors(const QString &text, QStringList& urls); - -void optimizeHtml(QTextEdit *textEdit, QString &text, unsigned int flag = 0); -void optimizeHtml(QString &text, unsigned int flag = 0); -QString toHtml(QString text, bool realHtml = true); - -} // namespace RsHtml - - #endif // HANDLE_RICH_TEXT_H_ diff --git a/retroshare-gui/src/util/ObjectPainter.cpp b/retroshare-gui/src/util/ObjectPainter.cpp new file mode 100644 index 000000000..8c79e16e8 --- /dev/null +++ b/retroshare-gui/src/util/ObjectPainter.cpp @@ -0,0 +1,62 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2012, RetroShare Team + * + * 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 Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include +#include +#include + +#include "ObjectPainter.h" + +namespace ObjectPainter +{ + +class DrawButton : public QPushButton +{ +public: + DrawButton(const QString &text) : QPushButton(text) {} + + void drawOnPixmap(QPixmap &pixmap) + { + // get a transparent pixmap + pixmap = QPixmap(size()); + pixmap.fill(Qt::transparent); + + // init options + QStyleOptionButton option; + initStyleOption(&option); + + // draw the button onto the pixmap + QStylePainter painter(&pixmap, this); + painter.drawControl(QStyle::CE_PushButton, option); + painter.end(); + } +}; + +void drawButton(const QString &text, const QString &styleSheet, QPixmap &pixmap) +{ + DrawButton button(text); + button.setStyleSheet(styleSheet); + QSize size = button.sizeHint(); + button.setGeometry(0, 0, size.width(), size.height()); + button.drawOnPixmap(pixmap); +} + +} diff --git a/retroshare-gui/src/util/ObjectPainter.h b/retroshare-gui/src/util/ObjectPainter.h new file mode 100644 index 000000000..c7148c663 --- /dev/null +++ b/retroshare-gui/src/util/ObjectPainter.h @@ -0,0 +1,33 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2012, RetroShare Team + * + * 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 Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#ifndef OBJECTPAINTER_H +#define OBJECTPAINTER_H + +class QString; +class QPixmap; + +namespace ObjectPainter +{ + void drawButton(const QString &text, const QString &styleSheet, QPixmap &pixmap); +} + +#endif //MOUSEEVENTFILTER_H