2 #include "tmeditorwidget.h"
9 #include <QMutexLocker>
11 #include <QJsonDocument>
12 #include <QJsonObject>
17 // HtmlData -------------------------------------------------------------------
19 TM::HtmlData::HtmlData(HtmlNode node_, int begin_, int tail_)
20 : RangeData(begin_, tail_)
25 int TM::HtmlData::type() const { return Type; }
27 TM::HtmlData::pointer TM::HtmlData::create(HtmlNode node_, int begin_, int tail_)
29 return pointer(new HtmlData(node_, begin_, tail_));
32 // TextConverter --------------------------------------------------------------
35 * \brief 引数として与えられたHtmlの範囲から構造化テキストを作成します。
37 Text::pointer TM::TextConverter::to_text(HtmlRange range)
40 Text::pointer result = Text::create();
43 for(HtmlNode const &node : range)
45 if(node.type() != HtmlNode::Text) continue;
46 Text::pointer p = stuff_text(result, node.value());
48 int num = p->string().size();
49 HtmlData::pointer hd = HtmlData::create(node, begin, begin + num - 1);
57 * \brief 引数として与えられたノードから構造化テキストを作成します。
60 * 無効なノードが与えられた場合、空の構造化テキストを返します。
62 Text::pointer TM::TextConverter::stuff_text(Text::pointer parent, QString const &string)
65 for(QChar const &ch : string)
67 if(is_ignorable_white_space(ch)) continue;
68 if(is_white_space(ch)) outstring.append(' ');
69 else outstring.append(ch);
71 if(outstring.isEmpty()) return Text::pointer();
73 Text::pointer result = Text::create(parent, outstring);
74 parent->append(result);
79 * \brief 連続する空白文字を検出します。
81 * 最初の空白文字、あるいは空白文字以外は、falseを返します。
82 * 連続する空白文字の二番目以降に対してのみtrueを返します。
84 bool TM::TextConverter::is_ignorable_white_space(const QChar &ch)
86 if(!is_white_space(ch))
100 * \brief 引数として与えられたchが空白文字の場合true、それ以外の場合falseを返します。
102 bool TM::TextConverter::is_white_space(QChar const &ch)
117 // TextSentence ---------------------------------------------------------------
119 TM::TextSentence::TextSentence(Text::pointer source_sentence)
120 : m_source_sentence(source_sentence)
124 Text::pointer TM::TextSentence::source_sentence() { return m_source_sentence; }
126 Text::pointer TM::TextSentence::target_sentence() { return m_target_sentence; }
128 void TM::TextSentence::set_terget_sentence(Text::pointer target_sentence)
130 m_target_sentence = target_sentence;
133 QJsonArray TM::TextSentence::link_data() { return m_link_data; }
135 void TM::TextSentence::set_link_data(QJsonArray json) { m_link_data = json; }
137 TM::TextSentence::pointer TM::TextSentence::create(Text::pointer source_sentence)
139 return pointer(new TextSentence(source_sentence));
142 // TextSegment ----------------------------------------------------------------
144 TM::TextSegment::TextSegment(
145 Service *service, int scode, int segment_id, QString source)
146 : m_segment_id(segment_id)
147 , m_document(source.toUtf8())
149 HtmlNode body = m_document.first("html").first("body");
151 m_text = tc.to_text(HtmlRange(body, body));
153 Text::pointer sentences = service->divide_into_sentences(scode, m_text->to_string());
154 for(Text::pointer s = sentences->begin(); s; s = s->next()) // s: sentence
156 Text::pointer words = service->divide_into_words(scode, s);
157 m_sentences.append(TextSentence::create(words));
161 int TM::TextSegment::segment_id() const { return m_segment_id; }
163 TM::TextSentence::pointer TM::TextSegment::at(int index)
165 return m_sentences.at(index);
168 TM::TextSegment::iterator TM::TextSegment::begin() { return m_sentences.begin(); }
170 TM::TextSegment::iterator TM::TextSegment::end() { return m_sentences.end(); }
172 TM::TextSegment::pointer TM::TextSegment::create(
173 Service *service, int scode, int segment_id, QString source)
175 return pointer(new TextSegment(service, scode, segment_id, source));
178 // SocketConnection -----------------------------------------------------------
180 TM::SocketConnection::SocketConnection(Settings *settings, Service *service,
181 EditorWidget *editor_widget, QWebSocket *socket)
183 , m_settings(settings)
185 , m_editor_widget(editor_widget)
186 , m_mutex(QMutex::Recursive)
189 connect(socket, SIGNAL(textMessageReceived(QString const&)),
190 this, SLOT(onTextMessageReceived(QString const&)));
191 connect(socket, SIGNAL(binaryMessageReceived(QByteArray const&)),
192 this, SLOT(onBinaryMessageReceived(QByteArray const&)));
195 TM::SocketConnection::~SocketConnection()
197 m_editor_widget->detach(this);
200 QWebSocket* TM::SocketConnection::socket()
202 QWebSocket * result = qobject_cast<QWebSocket*>(parent());
207 void TM::SocketConnection::send_message(QString const &message)
209 socket()->sendTextMessage(message);
212 void TM::SocketConnection::send_message(QJsonObject const &json)
216 send_message(doc.toJson().data());
219 void TM::SocketConnection::save_sentence(int segment_id, int index,
220 Text::pointer target_sentence, QJsonArray link)
222 segment_map_iterator it = m_segments.find(segment_id);
223 assert(it != m_segments.end());
224 TextSentence::pointer sentence = it.value()->at(index);
225 sentence->set_terget_sentence(target_sentence);
226 sentence->set_link_data(link);
229 void TM::SocketConnection::changeEditMode(bool edit_mode)
231 set_edit_mode(edit_mode);
234 void TM::SocketConnection::set_edit_mode(bool edit_mode)
236 if(edit_mode == m_edit_mode) return;
238 m_edit_mode = edit_mode;
240 json["cmd"] = "set_edit_mode";
241 json["edit_mode"] = edit_mode;
247 * \brief ウェブブラウザ上でクリックされ、editコマンドが発行されたときに呼び出されます。
249 void TM::SocketConnection::do_edit(QJsonObject const &json)
251 int scode = m_editor_widget->source_language();
253 assert(json.contains("segment_id"));
254 int segment_id = json["segment_id"].toString().toInt();
256 segment_map_iterator it = m_segments.find(segment_id);
257 if(it == m_segments.end())
259 assert(json.contains("source"));
260 QString source = json["source"].toString();
261 m_current_segment = TextSegment::create(m_service, scode, segment_id, source);
262 m_segments.insert(segment_id, m_current_segment);
264 else m_current_segment = it.value();
266 m_editor_widget->set_segment(m_current_segment);
270 * \brief ウェブブラウザ上でドキュメントがフォーカスを取得し、
271 * focusコマンドが発行されたときに呼び出されます。
273 void TM::SocketConnection::do_focus(QJsonObject const &json)
275 m_editor_widget->attach(this);
276 bool edit_mode = json["edit_mode"].toBool();
277 m_edit_mode = edit_mode;
278 m_editor_widget->set_edit_mode(edit_mode);
280 if(m_current_segment) m_editor_widget->set_segment(m_current_segment);
283 void TM::SocketConnection::do_blur(QJsonObject const &)
285 //m_widget->detach(this);
288 void TM::SocketConnection::do_load(const QJsonObject &json)
290 m_editor_widget->attach(this);
291 bool edit_mode = json["edit_mode"].toBool();
292 m_edit_mode = edit_mode;
293 m_editor_widget->set_edit_mode(edit_mode);
295 //set_edit_mode(m_widget->edit_mode());
298 void TM::SocketConnection::onTextMessageReceived(QString const &message)
300 QJsonObject json = QJsonDocument::fromJson(message.toUtf8()).object();
301 QString cmd = json["cmd"].toString();
302 if(cmd == "edit") do_edit(json);
303 else if(cmd == "focus") do_focus(json);
304 else if(cmd == "blur") do_blur(json);
305 else if(cmd == "load") do_load(json);
308 void TM::SocketConnection::onBinaryMessageReceived(QByteArray const &message)
313 // SocketServer ---------------------------------------------------------------
315 TM::SocketServer::SocketServer(Settings *settings, Service* service,
316 EditorWidget *editor_widget, QObject *parent)
318 , m_settings(settings)
320 , m_server(new QWebSocketServer(QStringLiteral("wordring websocket"),
321 QWebSocketServer::NonSecureMode, this))
322 , m_editor_widget(editor_widget)
324 connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
326 quint16 port = m_settings->value("SocketServer/port").toUInt();
327 bool result = m_server->listen(QHostAddress::LocalHost, port);
328 if(!result) result = m_server->listen(QHostAddress::LocalHost, 0);
329 if(!result) qFatal("An error occured in SocketServer().");
332 TM::SocketServer::~SocketServer()
336 quint16 TM::SocketServer::port() const
338 return m_server->serverPort();
341 void TM::SocketServer::abort()
343 for(QWebSocket *ws : m_sockets)
351 void TM::SocketServer::onNewConnection()
353 QWebSocket *socket = m_server->nextPendingConnection();
354 connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
355 new SocketConnection(m_settings, m_service, m_editor_widget, socket);
356 m_sockets.push_back(socket);
359 void TM::SocketServer::onDisconnected()
361 QWebSocket *socket = qobject_cast<QWebSocket*>(sender());
362 m_sockets.removeOne(socket);
363 socket->deleteLater();