📄 chattextwgt.cpp
字号:
/*************************************************************************** * Copyright (C) 2007 by Anistratov Oleg * * ower@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation; * * * * 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. * * * ***************************************************************************/#include "chattextwgt.h"// TODO remove "globals.h" from this header#include "globals.h"#include <QTextCursor>#include <QScrollBar>#include <QFile>#include <QDateTime>#include <QTextFrame>#include "message.h"#include "smileswgt.h"#include "smileswgt.h"#include "abstractchatcore.h"#include "animatedsmile.h"QList<Smile> ChatTextWgt::m_smiles;ChatTextWgt::ChatTextWgt(QWidget *parent) : QWidget(parent), m_smilesFromSender(0), m_keepAnimations(-1){ QGridLayout* grid = new QGridLayout(this); m_text = new TextBrowser(this); m_text->setOpenExternalLinks(true); grid->addWidget(m_text, 0, 0); grid->setMargin(0); m_text->verticalScrollBar()->setTracking(true); initSmiles(QChatSettings::settings()->smilesThemePath()); connect(m_text, SIGNAL(viewportChanged()) , this, SLOT(setAnimations())); connect(m_text, SIGNAL(viewportVisible(bool)), this, SLOT(playPauseAnimations(bool)));}ChatTextWgt::~ChatTextWgt(){ foreach(AnimatedSmile* sm, m_animatedSmiles) delete sm; qDebug("[ChatTextWgt::~ChatTextWgt]\n");}//\*****************************************************************************void ChatTextWgt::addSmile(const QStringList & smiles, const QString & name){ m_smiles.append(Smile(smiles, name));}//\*****************************************************************************void ChatTextWgt::initSmiles(const QString & path){ QFile file(path + "/emoticons.xml"); QDomDocument dom_document; QDomElement root; QDomElement child; QDomElement emoticon; QDomElement name; QDomNodeList elements; QDomNodeList elements_names; QStringList list; m_smiles.clear(); if(!file.open(QIODevice::ReadOnly)) { Globals::addError("Couldn't open " + path + "/emoticons.xml"); return; } if(!dom_document.setContent(&file, true)) { Globals::addError("Couldn't parse " + path + "/emoticons.xml"); return; } root = dom_document.documentElement(); elements = root.elementsByTagName("emoticon"); for(uint i = 0, len = elements.length(); i < len; i++) { emoticon = elements.item(i).toElement(); elements_names = emoticon.elementsByTagName("string"); list.clear(); for(uint j = 0, len = elements_names.length(); j < len; j++) { child = elements_names.item(j).toElement(); list.append(child.text()); } addSmile(list, emoticon.attribute("file")); }}//\*****************************************************************************void ChatTextWgt::addMsg(const Message* msg){ QTextDocument* doc = new QTextDocument; QTextCharFormat fmt; QTextBlockFormat bl_fmt; QDateTime date_time; QTextCursor cur_old = m_text->textCursor(); QTextCursor cur_new; QBrush brush(Qt::SolidPattern); int insert_begin; if(msg->isHtml()) doc->setHtml(msg->msg()); else doc->setPlainText(msg->msg()); // preparing msg header(user and time information) // ************************ date_time.setTime_t(msg->receiveTime()); if(isSystemMsg(msg->type())) brush.setColor(QChatSettings::settings()->sysColor()); else brush.setColor(msg->color()); fmt.setForeground(brush); QString msg_hdr(QChatSettings::settings()->strOption("DisplayMessagesFormat")); QString tm_fmt = msg_hdr.section(QString("%time%"), 1, 1); msg_hdr.replace(QRegExp("%time%([^<]*)%time%"), date_time.toString(tm_fmt)); msg_hdr.replace("%user", msg->userName()); msg_hdr.replace("%comp", msg->compName()); if(msg->requested()) msg_hdr.prepend(">"); // ************************ // setting cursor to the end of document and inserting msg header text with needed format cur_new = m_text->textCursor(); cur_new.clearSelection(); cur_new.setPosition(m_text->toPlainText().size()); cur_new.setCharFormat(fmt); cur_new.insertText(msg_hdr); // processing message and inserting smiles // ************************ int idx_end = 0; QString str; QString smile; QString msg_ = doc->toPlainText(); cur_new = doc->rootFrame()->firstCursorPosition(); smile = nextSmile (msg_); idx_end = msg_.indexOf(smile); for(; idx_end != -1 && !smile.isEmpty();) { str = msg_.left(idx_end); msg_ = msg_.right(msg_.size() - idx_end - smile.size()); cur_new = doc->find(smile, cur_new); if(!cur_new.isNull()) { while(cur_new.selectedText() != smile) { cur_new.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); if(cur_new.position() == doc->toPlainText().size()) break; } if(cur_new.selectedText() == smile) { // FIXME workarounding qt4.3 bug if(cur_new.currentList()) cur_new.insertText(" "); insertSmile(cur_new, smile); } if(cur_new.position() == doc->toPlainText().size()) break; } if((smile = nextSmile(msg_)).isEmpty()) break; idx_end = msg_.indexOf(smile); } // ************************ processLinks(doc); // inserting processed text in the end of the chat view cur_new = m_text->textCursor(); insert_begin = m_text->toPlainText().size(); cur_new.setPosition(insert_begin); cur_new.insertHtml(doc->toHtml());// cur_new.insertText(doc->toPlainText()); // coloring whole msg accordingly to settings if(!(isSystemMsg(msg->type()) && !QChatSettings::settings()->boolOption("ColorWholeSystemMessage") || (msg->type() == AbstractChatCore::MESSAGE && !QChatSettings::settings()->boolOption("ColorWholeMessage")))) { cur_new.setPosition (insert_begin); cur_new.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cur_new.mergeCharFormat(fmt); cur_new.clearSelection(); } // restoring selection m_text->setTextCursor(cur_old); playPauseAnimations(QChatSettings::settings()->boolOption("UseAnimatedSmiles")); // if animation is disabled we will show only the first frame except showing nothing if(!QChatSettings::settings()->boolOption("UseAnimatedSmiles")) foreach(AnimatedSmile* sm, m_animatedSmiles) { sm->setPaused(false); sm->nextFrame(); sm->setPaused(true); } cur_new.insertBlock(QTextBlockFormat()); // TODO add autoscroll settings// if(scrl_max) m_text->verticalScrollBar()->setValue(m_text->verticalScrollBar()->maximum()); setAnimations(); delete doc;}//\*****************************************************************************void ChatTextWgt::setMsg(const QString & msg ){ QTextCursor cur_new = m_text->textCursor(); cur_new.clearSelection(); // Obrabotka soobscheniya i vstavka smailov int idx_end = 0; QString str; QString smile; QString msg_ = msg; cur_new.beginEditBlock(); smile = nextSmile (msg_); idx_end = msg_.indexOf(smile); for(int i = 0; i < 10 && idx_end != -1 && !smile.isEmpty(); i++) { str = msg_.left(idx_end); msg_ = msg_.right(msg_.size() - idx_end - smile.size()); cur_new.insertText(str); insertSmile(cur_new, smile); if((smile = nextSmile(msg_)).isEmpty()) break; idx_end = msg_.indexOf(smile); } str = msg_; cur_new.insertText(str); cur_new.endEditBlock();}//\*****************************************************************************QString ChatTextWgt::nextSmile(const QString & str, Smile** smile_){ int i, j; int idx = -1, idx1; int smile = -1; int smile_pos = -1; int smile_size = 0; for(i = 0; i < m_smiles.size(); i++) for(j = 0; j < m_smiles[i].smiles.size(); j++) { idx1 = str.indexOf(m_smiles[i].smiles[j]); if(idx1 >= 0 && (idx1 <= idx || idx < 0)) { if(m_smiles[i].smiles[j].size() >= smile_size) { smile_size = m_smiles[i].smiles[j].size(); smile = i; smile_pos = j; idx = idx1; } } } if(smile >= 0 && smile_pos >= 0) { if(smile_) *smile_ = &m_smiles[smile]; return m_smiles[smile].smiles[smile_pos]; } else return QString("");}//\*****************************************************************************QString ChatTextWgt::nextSmile(const QString & str) const{ int i, j; int idx = -1, idx1; int smile = -1; int smile_pos = -1; int smile_size = 0; for(i = 0; i < m_smiles.size(); i++) for(j = 0; j < m_smiles[i].smiles.size(); j++) { idx1 = str.indexOf(m_smiles[i].smiles[j]); if(idx1 >= 0 && (idx1 < idx || idx < 0 || (idx1 == idx && m_smiles[i].smiles[j].size() >= smile_size))) { smile_size = m_smiles[i].smiles[j].size(); smile = i; smile_pos = j; idx = idx1; } } if(m_smilesFromSender) { for(i = 0; i < m_smilesFromSender->size(); i++) { idx1 = str.indexOf((*m_smilesFromSender)[i].smiles[0]); if(idx1 >= 0 && (idx1 <= idx || idx < 0)) { if((*m_smilesFromSender)[i].smiles[0].size() >= smile_size) { smile_size = (*m_smilesFromSender)[i].smiles[0].size(); smile = i; smile_pos = -1; idx = idx1; } } } } if(smile >= 0 && smile_pos >= 0) return m_smiles[smile].smiles[smile_pos]; else if(smile >= 0 && smile_pos == -1) return (*m_smilesFromSender)[smile].smiles[0]; return QString("");}//\*****************************************************************************void ChatTextWgt::insertSmile(QTextCursor cursor, const QString & smile){ switch(QChatSettings::settings()->smilesPolicy()) { case QChatSettings::NoSmiles : return; case QChatSettings::DontUseSmilesFromSender : insertSmileFromLocalTheme(cursor, smile); break; case QChatSettings::UseSmilesFromSender : if(!insertSmileFromLocalTheme(cursor, smile)) insertSmileFromSender(cursor, smile); break; case QChatSettings::AlwaysUseSmilesFromSender : if(!insertSmileFromSender(cursor, smile)) insertSmileFromLocalTheme(cursor, smile); break; }}//\*****************************************************************************void ChatTextWgt::setSmilesFromSender(QList<Smile> * smiles){ m_smilesFromSender = smiles;}void ChatTextWgt::processLinks(QTextDocument* doc){ QTextCursor cursor = doc->rootFrame()->firstCursorPosition(); for(;;) { cursor = doc->find(QRegExp("\\b(http|ftp|https)://[\\S]+"), cursor); if(!cursor.isNull()) cursor.insertHtml((QString("<a href=%1>%2</a>").arg(cursor.selectedText()).arg(cursor.selectedText()))); else break; }}void ChatTextWgt::setAnimations(){ int min = m_text->cursorForPosition(QPoint(0, 0)).position(); int max = m_text->cursorForPosition(QPoint(m_text->size().width(), m_text->size().height())).position(); foreach(AnimatedSmile* sm, m_animatedSmiles) sm->pauseIfHidden(min, max);}bool ChatTextWgt::insertSmileFromSender(QTextCursor cursor, const QString & smile){ int i; if(m_smilesFromSender) { for(i = 0; i < m_smilesFromSender->size(); i++) if((*m_smilesFromSender)[i].smiles[0] == smile) { if(QFile((*m_smilesFromSender)[i].name).exists()) { cursor.insertText(" "); AnimatedSmile* asmile = new AnimatedSmile; asmile->init(cursor.position() + m_text->toPlainText().size() - 1, (*m_smilesFromSender)[i].name, m_text->document()); m_animatedSmiles.append(asmile); return true; } m_smilesFromSender->clear(); break; } } return false;}bool ChatTextWgt::insertSmileFromLocalTheme(QTextCursor cursor, const QString & smile){ QString smiles_dir = QChatSettings::settings()->smilesThemePath(); int i, j; for(i = 0; i < m_smiles.size(); i++) for(j = 0; j < m_smiles[i].smiles.size(); j++) if(m_smiles[i].smiles[j] == smile) { if(QFile(smiles_dir + m_smiles[i].name).exists()) cursor.insertImage(smiles_dir + m_smiles[i].name); else if(QFile(smiles_dir + m_smiles[i].name + ".png").exists()) cursor.insertImage(smiles_dir + m_smiles[i].name + ".png"); else if(QFile(smiles_dir + m_smiles[i].name + ".jpg").exists()) cursor.insertImage(smiles_dir + m_smiles[i].name + ".jpg"); else if(QFile(smiles_dir + m_smiles[i].name + ".gif").exists()) { cursor.insertText(" "); AnimatedSmile* asmile = new AnimatedSmile; asmile->init(cursor.position() + m_text->toPlainText().size() - 1, (smiles_dir + m_smiles[i].name + ".gif"), m_text->document()); m_animatedSmiles.append(asmile); } else if(QFile(smiles_dir + m_smiles[i].name + ".mng").exists()) { cursor.insertText(" "); AnimatedSmile* asmile = new AnimatedSmile; asmile->init(cursor.position() + m_text->toPlainText().size() - 1, (smiles_dir + m_smiles[i].name + ".mng"), m_text->document()); m_animatedSmiles.append(asmile); } else cursor.insertText(m_smiles[i].smiles[j]); return true; } return false;}void ChatTextWgt::playPauseAnimations(bool play){ if(play && !QChatSettings::settings()->boolOption("UseAnimatedSmiles")) return; if(play && m_keepAnimations < 0) foreach(AnimatedSmile* sm, m_animatedSmiles) sm->start(); else if(!play) foreach(AnimatedSmile* sm, m_animatedSmiles) sm->stop(); else { int i, j; for(i = m_animatedSmiles.size() - 1, j = 0; i >= 0 && j < m_keepAnimations; i--) { if(m_animatedSmiles[i]->animated()) { m_animatedSmiles[i]->start(); j++; } } for(; i >= 0; i--) if(m_animatedSmiles[i]->animated()) m_animatedSmiles[i]->setPaused(true); } if(play) setAnimations();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -