2 #include "tmeditorwidget.h"
8 #include <QMutexLocker>
10 #include <QJsonDocument>
11 #include <QJsonObject>
16 // HtmlData -------------------------------------------------------------------
18 TM::HtmlData::HtmlData(HtmlNode node_, int begin_, int tail_)
19 : RangeData(begin_, tail_)
24 int TM::HtmlData::type() const { return Type; }
26 TM::HtmlData::pointer TM::HtmlData::create(HtmlNode node_, int begin_, int tail_)
28 return pointer(new HtmlData(node_, begin_, tail_));
31 // TextConverter --------------------------------------------------------------
34 * \brief 引数として与えられたHtmlの範囲から構造化テキストを作成します。
36 Text::pointer TM::TextConverter::to_text(HtmlRange range)
39 Text::pointer result = Text::create();
42 for(HtmlNode const &node : range)
44 if(node.type() != HtmlNode::Text) continue;
45 Text::pointer p = stuff_text(result, node.value());
47 int num = p->string().size();
48 HtmlData::pointer hd = HtmlData::create(node, begin, begin + num - 1);
56 * \brief 引数として与えられたノードから構造化テキストを作成します。
59 * 無効なノードが与えられた場合、空の構造化テキストを返します。
61 Text::pointer TM::TextConverter::stuff_text(Text::pointer parent, QString const &string)
64 for(QChar const &ch : string)
66 if(is_ignorable_white_space(ch)) continue;
67 if(is_white_space(ch)) outstring.append(' ');
68 else outstring.append(ch);
70 if(outstring.isEmpty()) return Text::pointer();
72 Text::pointer result = Text::create(parent, outstring);
73 parent->append(result);
78 * \brief 連続する空白文字を検出します。
80 * 最初の空白文字、あるいは空白文字以外は、falseを返します。
81 * 連続する空白文字の二番目以降に対してのみtrueを返します。
83 bool TM::TextConverter::is_ignorable_white_space(const QChar &ch)
85 if(!is_white_space(ch))
99 * \brief 引数として与えられたchが空白文字の場合true、それ以外の場合falseを返します。
101 bool TM::TextConverter::is_white_space(QChar const &ch)
116 // SocketConnection -----------------------------------------------------------
118 TM::SocketConnection::SocketConnection(EditorWidget *editor_widget, QWebSocket *socket)
120 , m_editor_widget(editor_widget)
121 , m_mutex(QMutex::Recursive)
124 connect(socket, SIGNAL(textMessageReceived(QString const&)),
125 this, SLOT(onTextMessageReceived(QString const&)));
126 connect(socket, SIGNAL(binaryMessageReceived(QByteArray const&)),
127 this, SLOT(onBinaryMessageReceived(QByteArray const&)));
130 TM::SocketConnection::~SocketConnection()
132 m_editor_widget->detach(this);
135 QWebSocket* TM::SocketConnection::socket()
137 QWebSocket * result = qobject_cast<QWebSocket*>(parent());
142 void TM::SocketConnection::send_message(QString const &message)
144 socket()->sendTextMessage(message);
147 void TM::SocketConnection::send_message(QJsonObject const &json)
151 send_message(doc.toJson().data());
154 void TM::SocketConnection::changeEditMode(bool edit_mode)
156 set_edit_mode(edit_mode);
159 void TM::SocketConnection::set_edit_mode(bool edit_mode)
161 if(edit_mode == m_edit_mode) return;
163 m_edit_mode = edit_mode;
165 json["cmd"] = "set_edit_mode";
166 json["edit_mode"] = edit_mode;
172 * \brief ウェブブラウザ上でクリックされ、editコマンドが発行されたときに呼び出されます。
174 void TM::SocketConnection::do_edit(QJsonObject const &json)
176 m_document.set_content(json["source"].toString().toUtf8());
177 HtmlNode body = m_document.first("html").first("body");
180 m_text = tc.to_text(HtmlRange(body, body));
181 m_editor_widget->set_string(m_text->to_string(), json["target"].toString());
182 //emit editCmd(json["id"].toInt(), m_document.to_string());
185 reply["cmd"] = "doedit";
186 reply["id"] = json["id"].toString();
187 reply["html"] = "test2";
189 doc.setObject(reply);
190 send_message(doc.toJson().data());
195 * \brief ウェブブラウザ上でドキュメントがフォーカスを取得し、
196 * focusコマンドが発行されたときに呼び出されます。
198 void TM::SocketConnection::do_focus(QJsonObject const &json)
200 m_editor_widget->attach(this);
201 bool edit_mode = json["edit_mode"].toBool();
202 m_edit_mode = edit_mode;
203 m_editor_widget->set_edit_mode(edit_mode);
205 if(m_text) m_editor_widget->set_string(m_text->to_string(), "");
208 void TM::SocketConnection::do_blur(QJsonObject const &)
210 //m_widget->detach(this);
213 void TM::SocketConnection::do_load(const QJsonObject &json)
215 m_editor_widget->attach(this);
216 bool edit_mode = json["edit_mode"].toBool();
217 m_edit_mode = edit_mode;
218 m_editor_widget->set_edit_mode(edit_mode);
220 //set_edit_mode(m_widget->edit_mode());
223 void TM::SocketConnection::onTextMessageReceived(QString const &message)
225 QJsonObject json = QJsonDocument::fromJson(message.toUtf8()).object();
226 QString cmd = json["cmd"].toString();
227 if(cmd == "edit") do_edit(json);
228 else if(cmd == "focus") do_focus(json);
229 else if(cmd == "blur") do_blur(json);
230 else if(cmd == "load") do_load(json);
233 void TM::SocketConnection::onBinaryMessageReceived(QByteArray const &message)
238 // SocketServer ---------------------------------------------------------------
240 TM::SocketServer::SocketServer(Settings *settings, EditorWidget *editor_widget, QObject *parent)
242 , m_settings(settings)
243 , m_server(new QWebSocketServer(QStringLiteral("wordring websocket"),
244 QWebSocketServer::NonSecureMode, this))
245 , m_editor_widget(editor_widget)
247 connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
249 quint16 port = m_settings->value("SocketServer/port").toUInt();
250 bool result = m_server->listen(QHostAddress::LocalHost, port);
251 if(!result) result = m_server->listen(QHostAddress::LocalHost, 0);
252 if(!result) qFatal("An error occured in SocketServer().");
255 TM::SocketServer::~SocketServer()
259 quint16 TM::SocketServer::port() const
261 return m_server->serverPort();
264 void TM::SocketServer::abort()
266 for(QWebSocket *ws : m_sockets)
274 void TM::SocketServer::onNewConnection()
276 QWebSocket *socket = m_server->nextPendingConnection();
277 connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
278 new SocketConnection(m_editor_widget, socket);
279 m_sockets.push_back(socket);
282 void TM::SocketServer::onDisconnected()
284 QWebSocket *socket = qobject_cast<QWebSocket*>(sender());
285 m_sockets.removeOne(socket);
286 socket->deleteLater();