OSDN Git Service

ソケットの終了処理追加。
authorwordring <kouichi_pm@users.osdn.me>
Sat, 15 Aug 2015 22:26:59 +0000 (07:26 +0900)
committerwordring <kouichi_pm@users.osdn.me>
Sat, 15 Aug 2015 22:26:59 +0000 (07:26 +0900)
23 files changed:
html/htmlparser.cpp
html/htmlparser.h
languages/english/english.cpp
languages/english/english.h
languages/japanese/japanese.cpp
languages/japanese/japanese.h
languages/language/language.h
proxy/main.cpp
proxy/mainwindow.cpp
proxy/mainwindow.h
proxy/tm.js
proxy/tmdatabase.cpp
proxy/tmdatabase.h
proxy/tmeditorwidget.cpp
proxy/tmeditorwidget.h
proxy/tmhttp.cpp
proxy/tmhttp.h
proxy/tmservice.cpp
proxy/tmservice.h
proxy/tmsocket.cpp
proxy/tmsocket.h
utility/text.cpp
utility/text.h

index 51e14fc..78fb378 100644 (file)
@@ -120,8 +120,7 @@ bool HtmlHandler::comment(QString const &ch)
 
 bool HtmlHandler::fatalError(const QXmlParseException & exception)
 {
-       //m_document->m_error_message = exception.message();
-       qDebug() << exception.message();
+       qCritical() << exception.message();
        return false;
 }
 
@@ -135,11 +134,27 @@ bool HtmlHandler::fatalError(const QXmlParseException & exception)
 // bool HtmlHandler::ignorableWhitespace(QString const &ch) { return true; }
 // bool HtmlHandler::internalEntityDecl(QString const &name, QString const &value) { return true; }
 // bool HtmlHandler::processingInstruction(QString const &target, QString const &data) { return true; }
-// bool HtmlHandler::resolveEntity(QString const &publicId, QString const &systemId, QXmlInputSource *& ret) { return true; }
+/*
+bool HtmlHandler::resolveEntity(QString const &publicId, QString const &systemId, QXmlInputSource *& ret)
+{
+       qDebug() << "HtmlHandler::resolveEntity:" << publicId << ", " << systemId;
+       ret = 0;
+       return true;
+}
+*/
 // void HtmlHandler::setDocumentLocator(QXmlLocator * locator) { return true; }
-// bool HtmlHandler::skippedEntity(QString const &name) { return true; }
+bool HtmlHandler::skippedEntity(QString const &name)
+{
+       if(name == "nbsp") return characters(" ");
+       return true;
+}
 // bool HtmlHandler::startCDATA() { return true; }
-
-// bool HtmlHandler::startEntity(QString const &name) { return true; }
+/*
+bool HtmlHandler::startEntity(QString const &name)
+{
+       qDebug() << "HtmlHandler::startEntity: " << name;
+       return true;
+}
+*/
 // bool HtmlHandler::startPrefixMapping(QString const &prefix, QString const &uri) { return true; }
 // bool HtmlHandler::warning(const QXmlParseException & exception) { return true; }
index eb238bf..2e697a4 100644 (file)
@@ -46,7 +46,7 @@ public:
        //      virtual bool attributeDecl(QString const &eName, QString const &aName,
                        //QString const &type, QString const &valueDefault, QString const &value);
 
-       virtual bool comment(string_type const &ch);
+       bool comment(string_type const &ch);
 //     virtual bool endCDATA();
 //     virtual bool endEntity(QString const &name);
 //     virtual bool endPrefixMapping(QString const &prefix);
@@ -57,12 +57,12 @@ public:
 //     virtual bool ignorableWhitespace(QString const &ch);
 //     virtual bool internalEntityDecl(QString const &name, QString const &value);
 //     virtual bool processingInstruction(QString const &target, QString const &data);
-//     virtual bool resolveEntity(QString const &publicId, QString const &systemId, QXmlInputSource *&ret);
+//     bool resolveEntity(QString const &publicId, QString const &systemId, QXmlInputSource *&ret);
 //     virtual void setDocumentLocator(QXmlLocator * locator);
-//     virtual bool skippedEntity(QString const &name);
+       bool skippedEntity(QString const &name);
 //     virtual bool startCDATA();
 
-//     virtual bool startEntity(QString const &name);
+//     bool startEntity(QString const &name);
 //     virtual bool startPrefixMapping(QString const &prefix, QString const &uri);
 //     virtual bool warning(QXmlParseException const &exception);
 
index 9836618..6f057ea 100644 (file)
@@ -50,9 +50,7 @@ Text::pointer EnglishPlugin::divide_into_sentences(QString string_)
                case 3:
                        if('A' <= c && c <= 'Z')
                        {
-                               Text::pointer s = Text::create(result, cstring);
-                               s->set_data(RangeData::create(begin_, tail_));
-                               result->append(s);
+                               stuff_sentence(result, cstring, begin_, tail_);
                                cstring.clear();
                                goto s0;
                        }
@@ -62,12 +60,7 @@ Text::pointer EnglishPlugin::divide_into_sentences(QString string_)
                tail_ = i;
                cstring.push_back(c);
        }
-       if(!cstring.isEmpty())
-       {
-               Text::pointer s = Text::create(result, cstring);
-               s->set_data(RangeData::create(begin_, tail_));
-               result->append(s);
-       }
+       if(!cstring.isEmpty()) stuff_sentence(result, cstring, begin_, tail_);
        return result;
 }
 
@@ -107,3 +100,30 @@ Text::pointer EnglishPlugin::divide_into_words(Text::pointer sentence)
        return result;
 }
 
+QString EnglishPlugin::normalize(QString string)
+{
+       return string.toLower();
+}
+
+void EnglishPlugin::stuff_sentence(Text::pointer parent, QString string,
+                                                                       int begin_, int tail_)
+{
+       // 先頭の空白文字を取り除く。
+       while(string.startsWith(' '))
+       {
+               string.remove(0, 1);
+               ++begin_;
+       }
+       // 後方の空白文字を取り除く。
+       while(string.endsWith(' '))
+       {
+               string.remove(string.size() - 1, 1);
+               --tail_;
+       }
+       if(string.isEmpty()) return; // 空白文字を取り除いた結果、空になった場合、ここで終わる。
+
+       // センテンス追加。
+       Text::pointer s = Text::create(parent, string);
+       s->set_data(RangeData::create(begin_, tail_));
+       parent->append(s);
+}
index fa45c05..a636fb7 100644 (file)
@@ -25,6 +25,12 @@ public:
        Text::pointer divide_into_sentences(QString string);
        Text::pointer divide_into_words(Text::pointer sentence);
 
+       QString normalize(QString string);
+
+private:
+       void stuff_sentence(Text::pointer parent, QString string,
+                                               int begin_, int tail_);
+
 private:
        Settings const *m_settings;
 };
index 296496c..c99745a 100644 (file)
@@ -80,7 +80,10 @@ Text::pointer JapanesePlugin::divide_into_words(Text::pointer sentence)
        return result;
 }
 
-
+QString JapanesePlugin::normalize(QString string)
+{
+       return string;
+}
 
 
 
index 1cb0097..18f53db 100644 (file)
@@ -28,6 +28,8 @@ public:
        Text::pointer divide_into_sentences(QString string);
        Text::pointer divide_into_words(Text::pointer sentence);
 
+       QString normalize(QString string);
+
 private:
        Settings const *m_settings;
 
index a2cff78..43576be 100644 (file)
@@ -65,6 +65,10 @@ public:
                return result;
        }
 
+       /*!
+        * \brief 引数として与えられた文字列を正規化して返します。
+        */
+       virtual QString normalize(QString string) = 0;
 };
 
 Q_DECLARE_INTERFACE(Language, "net.wordring.tm.language/1.0")
index 2591b69..f6f09e9 100644 (file)
@@ -49,6 +49,9 @@ int main(int argc, char *argv[])
        if(!settings.contains("SocketServer/port")) settings.setValue("SocketServer/port", 8081);
        // ProxyModule
        if(!settings.contains("ProxyModule/prefix")) settings.setValue("ProxyModule/prefix", "/?");
+       // ProxyHandler
+       if(!settings.contains("ProxyHandler/jscode"))
+               settings.setValue("ProxyHandler/jscode", "C:/Users/Kouichi/Documents/OSDN/wordring-tm/proxy/tm.js");
 
        // Database
        if(!settings.contains("Database/root"))
@@ -64,11 +67,12 @@ int main(int argc, char *argv[])
        service->load_languages(QApplication::applicationDirPath() + "/plugins");
 
        HttpServer *server = new HttpServer(&settings, &w);
+       w.set_http_port(server->port());
 
-       TM::SocketServer *socket = new TM::SocketServer(&settings, w.editor_widget(), &w);
+       TM::SocketServer *socket = new TM::SocketServer(&settings, service, w.editor_widget(), &w);
 
        server->install(new TM::ProxyModule(
-                                               "/tm?", server->port(), socket->port(), server));
+                                               &settings, server->port(), socket->port(), server));
 
        QObject::connect(&w, SIGNAL(closing()), socket, SLOT(abort()));
        w.show();
index cf0b6eb..e948868 100644 (file)
@@ -42,6 +42,11 @@ MainWindow::~MainWindow()
 
 TM::EditorWidget* MainWindow::editor_widget() { return m_editor_widget; }
 
+void MainWindow::set_http_port(quint16 http_port)
+{
+       editor_widget()->set_http_port(http_port);
+}
+
 void MainWindow::closeEvent(QCloseEvent *ev)
 {
        emit closing();
index 156f6ab..1d1d85b 100644 (file)
@@ -26,6 +26,7 @@ public:
        ~MainWindow();
 
        TM::EditorWidget* editor_widget();
+       void set_http_port(quint16 http_port);
 
 signals:
        void closing();
index 9330053..4869f50 100644 (file)
@@ -63,7 +63,8 @@ window.wordring = {
        },
        
        onerror: function(ev) {
-               document.location.href = 'http://www.yahoo.co.jp/';     },
+               //document.location.href = 'http://www.yahoo.co.jp/';
+       },
        
        onclose: function(ev) {
                //alert('接続が閉じられました');
index 93a55ea..731c5dd 100644 (file)
@@ -213,8 +213,7 @@ TM::SentenceDatabase::SentenceDatabase(Settings *settings, int site_id, QString
                "CREATE TABLE IF NOT EXISTS sentences("
                        "sentence_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
                        "crc INTEGER,"
-                       "source_id INTEGER,"
-                       "sentence TEXT,"
+                       "UNIQUE(source_id INTEGER, sentence TEXT),"
                        "json TEXT,"
                        "user_id INTEGER,"
                        "time TIMESTAMP);");
@@ -225,9 +224,11 @@ TM::SentenceDatabase::SentenceDatabase(Settings *settings, int site_id, QString
        q = m_database.exec("CREATE INDEX IF NOT EXISTS crc_index ON sentences(crc);");
        if(q.lastError().isValid())
                qFatal("An error occured while create index in SentenceDatabase().");
+
        q = m_database.exec("CREATE INDEX IF NOT EXISTS source_id_index ON sentences(source_id);");
        if(q.lastError().isValid())
                qFatal("An error occured while create index in SentenceDatabase().");
+
        q = m_database.exec("CREATE INDEX IF NOT EXISTS sentence_index ON sentences(sentence);");
        if(q.lastError().isValid())
                qFatal("An error occured while create index in SentenceDatabase().");
@@ -235,15 +236,21 @@ TM::SentenceDatabase::SentenceDatabase(Settings *settings, int site_id, QString
        // クエリ作成。
        m_find_sentence_id.reset(new QSqlQuery(m_database));
        ret = m_find_sentence_id->prepare("SELECT sentence_id FROM sentences WHERE sentence=?;");
-       if(!ret) qFatal("An error occured while prepare select statement in SentenceDatabase().");
+       if(!ret) qFatal("An error occured while prepare find_sentence_id statement in SentenceDatabase().");
+
+       m_find_sentence_by_crc.reset(new QSqlQuery(m_database));
+       ret = m_find_sentence->prepare("SELECT * FROM sentences WHERE crc=?;");
+       if(!ret) qFatal("An error occured while prepare find_sentence_by_crc statement in SentenceDatabase().");
+
+       m_find_sentence_by_source_id.reset(new QSqlQuery(m_database));
+       ret = m_find_sentence->prepare("SELECT * FROM sentences WHERE source_id=?;");
+       if(!ret) qFatal("An error occured while prepare select_by_crc statement in SentenceDatabase().");
 
        m_insert_sentence.reset(new QSqlQuery(m_database));
        ret = m_insert_sentence->prepare(
-               "INSERT INTO sentences(crc, source_id, sentence, json, user_id, time) "
+               "INSERT OR REPLACE INTO sentences(crc, source_id, sentence, json, user_id, time) "
                "VALUES(?, ?, ?, ?, ?, ?);");
        if(!ret) qFatal("An error occured while prepare insert statement in SentenceDatabase().");
-
-
 }
 
 TM::SentenceDatabase::~SentenceDatabase()
@@ -263,6 +270,12 @@ int TM::SentenceDatabase::sentence_id(QString sentence)
        return 0;
 }
 
+/*bool TM::SentenceDatabase::find_sentence(QString sentence,
+                               QString *tsentence, QJsonArray *json)
+{
+
+}
+*/
 void TM::SentenceDatabase::insert(int source_id, QString sentence, QString json, int user_id)
 {
        QSqlQuery *q = m_insert_sentence.get();
@@ -383,4 +396,19 @@ int TM::Database::find_sentence_id(int site_id, int code, QString sentence)
        return p->sentence_id(sentence);
 }
 
+bool TM::Database::find_sentence(int site_id, int scode, QString ssentence, int tcode,
+                                  QString *tsentence, QJsonArray *json)
+{
+       SentenceDatabase::pointer p = find_sentence_database(site_id, scode);
+       //p->;
+
+       return true;
+}
+
+void TM::Database::insert_sentence(int site_id, int code, int source_id,
+                                       QString sentence, QString json, int user_id)
+{
+
+}
+
 QString TM::Database::root_key() { return "Database/root"; }
index e1fdc70..b60165c 100644 (file)
@@ -96,6 +96,14 @@ public:
        ~SentenceDatabase();
 
        int sentence_id(QString sentence);
+
+//     bool find_sentence_by_source_sentence(
+//                     QString sentence, QString *tsentence, QJsonArray *json = nullptr);
+       bool find_sentence_by_crc(
+                       quint32 crc, QString *tsentence, QJsonArray *json = nullptr);
+       bool find_sentence_by_source_id(
+                       int source_id, QString *tsentence, QJsonArray *json = nullptr);
+
        void insert(int source_id, QString sentence, QString json, int user_id);
 
 private:
@@ -110,6 +118,9 @@ private:
        QSqlDatabase m_database;
 
        query_pointer m_find_sentence_id;
+       query_pointer m_find_sentence;
+       query_pointer m_find_sentence_by_crc;
+       query_pointer m_find_sentence_by_source_id;
        query_pointer m_insert_sentence;
 };
 
@@ -131,9 +142,14 @@ public:
 
        void open_word_database(int code, QString name);
        int find_word_id(int code, QString word);
-
+private:
        SentenceDatabase::pointer find_sentence_database(int site_id, int code);
+public:
        int find_sentence_id(int site_id, int code, QString sentence);
+       bool find_sentence(int site_id, int scode, QString ssentence, int tcode,
+                                          QString *tsentence, QJsonArray *json);
+       void insert_sentence(int site_id, int code, int source_id,
+                                               QString sentence, QString json, int user_id);
 
        static QString root_key();
 signals:
index b4c5daa..c281604 100644 (file)
@@ -37,6 +37,7 @@ TM::EditorWidget::EditorWidget(Settings *settings, Service *service, QWidget *pa
        , m_mutex(QMutex::Recursive)
        , m_service(service)
        , m_settings(settings)
+       , m_http_port(80)
        , m_socket(nullptr)
 {
        QVBoxLayout *vlayout = new QVBoxLayout(this);
@@ -111,6 +112,8 @@ void TM::EditorWidget::detach(SocketConnection *)
        m_socket = nullptr;
 }
 
+void TM::EditorWidget::set_http_port(quint16 http_port) { m_http_port = http_port; }
+
 /*!
  * \brief 編集モードを変更します。
  */
@@ -123,12 +126,18 @@ void TM::EditorWidget::set_edit_mode(bool mode)
        m_edit_mode->setChecked(mode);
 }
 
+/*!
+ * \brief 編集モードの場合trueを返します。
+ */
 bool TM::EditorWidget::edit_mode()
 {
        QMutexLocker lock(&m_mutex);
        return m_edit_mode->isChecked();
 }
 
+/*!
+ * \brief リンクモードを設定します。
+ */
 void TM::EditorWidget::set_link_mode(bool mode)
 {
        QMutexLocker lock(&m_mutex);
@@ -138,6 +147,9 @@ void TM::EditorWidget::set_link_mode(bool mode)
        m_link->setChecked(mode);
 }
 
+/*!
+ * \brief リンクモードの場合、trueを返します。
+ */
 bool TM::EditorWidget::link_mode()
 {
        QMutexLocker lock(&m_mutex);
@@ -155,12 +167,18 @@ void TM::EditorWidget::set_link_mode_disabled(bool disable)
        m_link->setDisabled(disable);
 }
 
+/*!
+ * \brief 原文の言語コードを返します。
+ */
 int TM::EditorWidget::source_language()
 {
        QMutexLocker lock(&m_mutex);
        return m_slang->data().toInt();
 }
 
+/*!
+ * \brief 訳文の言語コードを返します。
+ */
 int TM::EditorWidget::target_language()
 {
        QMutexLocker lock(&m_mutex);
@@ -182,6 +200,12 @@ void TM::EditorWidget::set_string(QString source_, QString target_)
        m_edit->set_sentences(result);
 }
 
+/*!
+ * \brief 言語プラグインが読み込まれるたびに呼び出されます。
+ * \param code 言語コード。
+ * \param name 言語名。
+ * \param icon 言語を表すアイコン。
+ */
 void TM::EditorWidget::onLanguageLoaded(int code, QString name, QIcon icon)
 {
        QString dslanguage = m_settings->value("Widget/defaultSourceLanguage", "English").toString();
@@ -204,6 +228,9 @@ void TM::EditorWidget::onLanguageLoaded(int code, QString name, QIcon icon)
        connect(taction, SIGNAL(triggered(bool)), this, SLOT(onTargetLanguageTriggered(bool)));
 }
 
+/*!
+ * \brief 編集アイコンがクリックされたとき呼び出されます。
+ */
 void TM::EditorWidget::onEditModeTriggered(bool)
 {
        QAction *edit_mode = qobject_cast<QAction*>(sender());
@@ -216,12 +243,18 @@ void TM::EditorWidget::onEditModeTriggered(bool)
        m_edit->set_edit_mode(checked);
 }
 
+/*!
+ * \brief リンクアイコンがクリックされたとき呼び出されます。
+ */
 void TM::EditorWidget::onLinkModeTriggered(bool checked)
 {
        //QAction *link_mode = qobject_cast<QAction*>(sender());
        m_edit->set_link_mode(checked);
 }
 
+/*!
+ * \brief アクションから原文言語が変更されたとき呼び出されます。
+ */
 void TM::EditorWidget::onSourceLanguageTriggered(bool)
 {
        QAction *saction = qobject_cast<QAction*>(sender());
@@ -230,18 +263,26 @@ void TM::EditorWidget::onSourceLanguageTriggered(bool)
        m_slang->setData(saction->data());
 }
 
+/*!
+ * \brief アクションから訳文言語が変更されたとき呼び出されます。
+ */
 void TM::EditorWidget::onTargetLanguageTriggered(bool)
 {
        QAction *taction = qobject_cast<QAction*>(sender());
        assert(taction);
        m_tlang->setIcon(taction->icon());
        m_tlang->setData(taction->data());
-
 }
 
+/*!
+ * \brief ブラウザ・アイコンがクリックされたとき呼び出されます。
+ */
 void TM::EditorWidget::onBrowserTriggered(bool)
 {
-       QDesktopServices::openUrl(QUrl("http://localhost/"));
+       QString url("http://localhost:");
+       url += QString::number(m_http_port) + "/";
+
+       QDesktopServices::openUrl(QUrl(url));
 }
 
 // EditorPanel ----------------------------------------------------------------
@@ -252,14 +293,23 @@ TM::EditorPanel::EditorPanel(QWidget *parent)
 {
 }
 
+/*!
+ * \brief 親となるエディタを設定します。
+ */
 void TM::EditorPanel::set_editor(Editor *editor)
 {
        assert(!m_editor);
        m_editor = editor;
 }
 
+/*!
+ * \brief 保持している文を返します。
+ */
 Text::pointer TM::EditorPanel::sentence() { return m_sentence; }
 
+/*!
+ * \brief 文を設定します。
+ */
 void TM::EditorPanel::set_sentence(Text::pointer sentence)
 {
        assert(sentence);
@@ -275,16 +325,14 @@ void TM::EditorPanel::set_sentence(Text::pointer sentence)
        }
 }
 
-bool TM::EditorPanel::is_empty() const
-{
-       qDebug() << document()->isEmpty();
-       return document()->isEmpty();
-       if(!m_sentence) return true;
-       for(Text::const_pointer p = m_sentence->begin(); p; p = p->next())
-               if(!p->string().isEmpty()) return true;
-       return false;
-}
+/*!
+ * \brief 内容が空の場合、trueを返します。
+ */
+bool TM::EditorPanel::is_empty() const { return document()->isEmpty(); }
 
+/*!
+ * \brief 引数として与えられた単語に該当する範囲を選択するカーソルを返します。
+ */
 QTextCursor TM::EditorPanel::select_cursor(Text::pointer word)
 {
        RangeData *rd = static_cast<RangeData*>(word->data().get());
@@ -297,6 +345,9 @@ QTextCursor TM::EditorPanel::select_cursor(Text::pointer word)
        return c;
 }
 
+/*!
+ * \brief 引数として与えられた位置にある単語を返します。
+ */
 Text::pointer TM::EditorPanel::select_word(QPoint const &pos)
 {
        QTextCursor c = cursorForPosition(pos);
@@ -373,6 +424,9 @@ TM::WordLinker* TM::SourcePanel::linker()
        return &m_linker;
 }
 
+/*!
+ * \brief 保持するリンクを色分け表示します。
+ */
 void TM::SourcePanel::ensure_highlight()
 {
        clear_highlight();
@@ -457,6 +511,7 @@ TM::TargetPanel::TargetPanel(QWidget *parent)
        : EditorPanel(parent)
        , m_source_panel(nullptr)
        , m_text_dirty(false)
+       , m_text_saved(true)
 {
        //setContextMenuPolicy(Qt::NoContextMenu);
 }
@@ -472,14 +527,42 @@ void TM::TargetPanel::set_sentence(Text::pointer sentence)
 {
        EditorPanel::set_sentence(sentence);
        set_text_dirty(false);
+       set_text_saved(false);
+}
+
+/*!
+ * \brief データベースへの登録が必要な場合、falseを返します。
+ *
+ * パネル内の文字列が編集された場合、trueを返します。
+ * 原文パネルがフォーカスを失うと、エディタがこのメンバを呼び出し、
+ * データベース登録の必要性を判定します。
+ * その後、エディタはデータベース登録を行い、フラグをクリアするので、
+ * 次に文字列が編集されるまでtrueを返し続けます。
+ */
+bool TM::TargetPanel::is_text_saved() const { return m_text_saved; }
+
+void TM::TargetPanel::set_text_saved(bool saved)
+{
+       m_text_saved = saved;
 }
 
+/*!
+ * \brief パネル内の文字列が編集された場合、trueを返します。
+ *
+ * エディタがリンクモードに入るとき、このメンバを呼び出し、
+ * 単語へ分割する必要があるか判定します。
+ * エディタはパネルの文字列を単語に分割した後、set_sentence()によって
+ * パネルに文を設定するため、次に文字列を編集するまでfalseを返すようになります。
+ */
 bool TM::TargetPanel::is_text_dirty() const { return m_text_dirty; }
 
+/*!
+ * \brief パネルの文字列が編集されたかを示すフラグを設定します。
+ */
 void TM::TargetPanel::set_text_dirty(bool dirty)
 {
        m_text_dirty = dirty;
-       if(dirty) m_editor->parent_widget()->set_link_mode_disabled(false);
+       if(dirty) m_editor->parent_editor_widget()->set_link_mode_disabled(false);
 }
 
 bool TM::TargetPanel::canInsertFromMimeData(QMimeData const *source) const
@@ -492,12 +575,17 @@ void TM::TargetPanel::insertFromMimeData(QMimeData const *source)
 {
        TextPanel::insertFromMimeData(source);
        set_text_dirty(true);
+       set_text_saved(false);
 }
 
 void TM::TargetPanel::inputMethodEvent(QInputMethodEvent *ev)
 {
        if(m_editor->link_mode()) ev->setCommitString("");
-       if(!ev->commitString().isEmpty()) set_text_dirty(true);
+       if(!ev->commitString().isEmpty())
+       {
+               set_text_dirty(true);
+               set_text_saved(false);
+       }
        QPlainTextEdit::inputMethodEvent(ev);
 }
 
@@ -507,7 +595,11 @@ void TM::TargetPanel::keyPressEvent(QKeyEvent *ev)
        else
        {
                TextPanel::keyPressEvent(ev);
-               if(!ev->text().isEmpty()) set_text_dirty(true);
+               if(!ev->text().isEmpty())
+               {
+                       set_text_dirty(true);
+                       set_text_saved(false);
+               }
        }
 }
 
@@ -585,7 +677,7 @@ void TM::Editor::clear()
        ta->clear();
        // リンクモードの解除。
        set_link_mode(false);
-       parent_widget()->set_link_mode_disabled(true);
+       parent_editor_widget()->set_link_mode_disabled(true);
 }
 
 /*!
@@ -623,7 +715,7 @@ void TM::Editor::set_link_mode(bool mode_)
        assert(!mode_ || can_link_mode()); // リンクモードに入るには、条件がある。
 
        m_link_mode = mode_;
-       parent_widget()->set_link_mode(mode_);
+       parent_editor_widget()->set_link_mode(mode_);
 
        if(mode_) do_link_mode_enter(m_current_source_panel);
        else if(m_current_source_panel) do_link_mode_leave(m_current_source_panel);
@@ -638,7 +730,7 @@ bool TM::Editor::can_link_mode() const
        return true;
 }
 
-TM::EditorWidget* TM::Editor::parent_widget()
+TM::EditorWidget* TM::Editor::parent_editor_widget()
 {
        EditorWidget* result = qobject_cast<EditorWidget*>(parentWidget());
        assert(result);
@@ -685,7 +777,7 @@ void TM::Editor::do_panel_enter(SourcePanel *panel)
        TargetPanel *tp = panel->target_panel();
        assert(tp);
        tp->show();
-       if(can_link_mode()) parent_widget()->set_link_mode_disabled(false);
+       if(can_link_mode()) parent_editor_widget()->set_link_mode_disabled(false);
 }
 
 /*!
@@ -698,9 +790,13 @@ void TM::Editor::do_panel_leave(SourcePanel *panel)
        tp->hide();
 
        set_link_mode(false);
-       parent_widget()->set_link_mode_disabled(true);
+       parent_editor_widget()->set_link_mode_disabled(true);
 
-       qDebug() << "focus out";
+       if(!tp->is_text_saved())
+       {
+               //qDebug() << m_service->si
+               tp->set_text_saved(true);
+       }
 }
 
 /*!
@@ -711,7 +807,7 @@ void TM::Editor::do_link_mode_enter(SourcePanel *panel)
        assert(panel);
        TargetPanel *tp = panel->target_panel();
        assert(tp);
-       int tcode = parent_widget()->target_language();
+       int tcode = parent_editor_widget()->target_language();
 
        if(tp->is_text_dirty())
        {
@@ -721,7 +817,7 @@ void TM::Editor::do_link_mode_enter(SourcePanel *panel)
                if(sentences->size())
                {
                        Text::pointer words = m_service->divide_into_words(tcode, sentences->begin());
-                       tp->set_sentence(words);
+                       tp->set_sentence(words); // ココで、text_dirtyがfalseになる。
                }
        }
 
@@ -736,7 +832,7 @@ void TM::Editor::do_link_mode_leave(SourcePanel *panel)
        qDebug() << m_current_source_panel->linker()->to_json_array();
        assert(panel);
        panel->commit_link();
-       panel->clear_highlight();
+       //panel->clear_highlight();
 }
 
 
index 4108335..ab4218b 100644 (file)
@@ -53,6 +53,8 @@ public:
        void attach(SocketConnection *socket);
        void detach(SocketConnection *socket);
 
+       void set_http_port(quint16 http_port);
+
        void set_edit_mode(bool mode);
        bool edit_mode();
        void set_link_mode(bool mode);
@@ -63,11 +65,15 @@ public:
        int target_language();
 
        void set_string(QString source_, QString target_);
+       void append_sentence();
+       void save_sentence();
 
 signals:
        void editModeChanged(bool mode_);
        void linkModeChanged(bool mode_);
 
+       void contentsEdited();
+
 public slots:
        void onLanguageLoaded(int code, QString name, QIcon icon);
        void onEditModeTriggered(bool);
@@ -80,6 +86,7 @@ private:
        QMutex m_mutex;
        Service *m_service;
        Settings *m_settings;
+       quint16 m_http_port;
        SocketConnection *m_socket;
 
        QToolBar *m_toolbar;
@@ -163,6 +170,9 @@ public:
 
        void set_sentence(Text::pointer sentence);
 
+       bool is_text_saved() const;
+       void set_text_saved(bool saved);
+
        bool is_text_dirty() const;
        void set_text_dirty(bool dirty);
 
@@ -184,22 +194,13 @@ protected:
 
 private:
        SourcePanel *m_source_panel;
-       bool m_text_dirty;
+       bool m_text_dirty; /*!< 内容の変更を示すフラグ */
+       bool m_text_saved; /*!< データベース登録の必要性を示すフラグ */
 };
 
 class Editor : public TextWidget
 {
        Q_OBJECT
-/*     enum : int
-       {
-               TextSourceSentence = QTextCharFormat::UserProperty,
-               TextSourceWord,
-               TextTargetSentence = QTextCharFormat::UserProperty + 10,
-               TextTargetWord,
-               TextCurrentBlock,
-               TextCurrentEditor,
-       };
-*/
 public:
        Editor(Settings *settings, Service *service, QWidget *parent);
 
@@ -213,7 +214,7 @@ public:
 
        bool can_link_mode() const;
 
-       EditorWidget* parent_widget();
+       EditorWidget* parent_editor_widget();
        TargetPanel* current_target_panel();
        TargetPanel const* current_target_panel() const;
 
index 64ada23..9f61937 100644 (file)
@@ -2,6 +2,7 @@
 #include "html.h"
 #include "htmlprivate.h"
 #include "tmservice.h"
+#include "settings.h"
 
 #include <QThread>
 
 
 // ProxyContext ---------------------------------------------------------------
 
-TM::ProxyContext::ProxyContext(QString prefix, quint16 http, quint16 socket)
+TM::ProxyContext::ProxyContext(Settings *settings, quint16 http, quint16 socket)
        : QObject(0)
+       , m_settings(settings)
        , m_manager(new QNetworkAccessManager(this))
        , m_cookie(new QNetworkCookieJar(this))
-       , m_prefix(prefix)
-       , m_http(http)
-       , m_socket(socket)
+       , m_http_port(http)
+       , m_socket_port(socket)
 {
        m_manager->setCookieJar(m_cookie);
+       assert(settings->contains("ProxyModule/prefix"));
+       m_prefix = settings->value("ProxyModule/prefix").toString();
+       assert(settings->contains("ProxyHandler/jscode"));
+       m_jscode = settings->value("ProxyHandler/jscode").toString();
 }
 
+QNetworkAccessManager* TM::ProxyContext::network_access_manager()
+{
+       return m_manager;
+}
+
+quint16 TM::ProxyContext::http_port() const { return m_http_port; }
+
+quint16 TM::ProxyContext::socket_port() const { return m_socket_port; }
+
+QString TM::ProxyContext::prefix() const { return m_prefix; }
+
+QString TM::ProxyContext::jscode() const { return m_jscode; }
+
 // ProxyModule ----------------------------------------------------------------
 
-TM::ProxyModule::ProxyModule(QString prefix, quint16 http, quint16 socket, QObject *parent)
+TM::ProxyModule::ProxyModule(Settings *settings, quint16 http, quint16 socket,
+                                                       QObject *parent)
        : HttpModule(parent)
        , m_thread(new QThread(this))
-       , m_context(new ProxyContext(prefix, http, socket))
-       , m_prefix(prefix)
-       , m_http(http)
+       , m_context(new ProxyContext(settings, http, socket))
 {
        m_context->moveToThread(m_thread);
        connect(m_thread, SIGNAL(finished()), m_context, SLOT(deleteLater()));
@@ -51,7 +68,7 @@ TM::ProxyModule::~ProxyModule()
 HttpHandler* TM::ProxyModule::create_handler(QByteArray method, QByteArray url)
 {
        if(method.toLower() != "get") return nullptr;
-       if(!url.toLower().startsWith(m_prefix.toUtf8())) return nullptr;
+       if(!url.toLower().startsWith(m_context->prefix().toUtf8())) return nullptr;
 
        HttpHandler *handler = new ProxyHandler(m_context);
        handler->moveToThread(m_thread);
@@ -80,9 +97,9 @@ TM::ProxyHandler::~ProxyHandler()
 int TM::ProxyHandler::run()
 {
        m_targetUrl = QUrl::fromUserInput(
-                       m_request->url().remove(0, m_context->m_prefix.toUtf8().length()));
+                       m_request->url().remove(0, m_context->prefix().toUtf8().length()));
        // HTML取得要求
-       m_reply = m_context->m_manager->get(QNetworkRequest(m_targetUrl));
+       m_reply = m_context->network_access_manager()->get(QNetworkRequest(m_targetUrl));
        connect(m_reply, SIGNAL(finished()), this, SLOT(onNetworkReplyFinished()));
        return 0;
 }
@@ -159,9 +176,8 @@ int TM::ProxyHandler::response()
        node = head.insert("style", head.end());
        node.insert_text(" .wordring-segment:hover{ color:#ff0000; } ", node.end());
        // JS書き込み
-       //QFile file("C:\\Users\\Kouichi\\Documents\\GitHub\\TM\\Proxy\\tm.js");
 
-       QFile file("tm.js");
+       QFile file(m_context->jscode());
        file.open(QIODevice::ReadOnly);
        QByteArray js = file.readAll();
        file.close();
@@ -170,7 +186,7 @@ int TM::ProxyHandler::response()
        //
        node = head.insert("script", head.end()).set_attribute("type", "text/javascript");
        QString str1 = "\nwindow.wordring.port=";
-       str1 += QString::number(m_context->m_socket) + ";\n";
+       str1 += QString::number(m_context->socket_port()) + ";\n";
        node.insert_comment(str1, node.end());
        // パラグラフ設定
        create_paragraph(body.lbegin(), body.ltail());
@@ -308,7 +324,7 @@ void TM::ProxyHandler::create_paragraph(Html::pointer begin_, Html::pointer tail
  */
 QString TM::ProxyHandler::host() const
 {
-       return  QString("http://localhost:") + QString::number(m_context->m_http);
+       return  QString("http://localhost:") + QString::number(m_context->http_port());
 }
 
 /*!
@@ -317,10 +333,7 @@ QString TM::ProxyHandler::host() const
  *
  * 例)/tm?
  */
-QString TM::ProxyHandler::prefix() const
-{
-       return m_context->m_prefix;
-}
+QString TM::ProxyHandler::prefix() const { return m_context->prefix(); }
 
 
 
index d90db5c..00a61fe 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <QObject>
 #include <QThread>
+#include <QMutex>
 #include <QUrl>
 
 QT_BEGIN_NAMESPACE
@@ -26,18 +27,26 @@ class ProxyHandler;
 class ProxyContext : public QObject
 {
        Q_OBJECT
-       friend class ProxyHandler;
 
 public:
-       ProxyContext(QString prefix, quint16 http, quint16 socket);
+       ProxyContext(Settings *settings, quint16 http, quint16 socket);
+
+       QNetworkAccessManager* network_access_manager();
+       quint16 http_port() const;
+       quint16 socket_port() const;
+       QString prefix() const;
+       QString jscode() const;
 
 private:
+       Settings *m_settings;
+
        QNetworkAccessManager *m_manager;
        QNetworkCookieJar *m_cookie;
 
+       quint16 m_http_port;
+       quint16 m_socket_port;
        QString m_prefix;
-       quint16 m_http;
-       quint16 m_socket;
+       QString m_jscode;
 };
 
 class ProxyModule : public HttpModule
@@ -45,7 +54,7 @@ class ProxyModule : public HttpModule
        Q_OBJECT
 
 public:
-       ProxyModule(QString prefix, quint16 http, quint16 socket, QObject *parent);
+       ProxyModule(Settings *settings, quint16 http, quint16 socket, QObject *parent);
        ~ProxyModule();
 
        virtual HttpHandler* create_handler(QByteArray method, QByteArray url);
@@ -54,9 +63,6 @@ public:
 private:
        QThread *m_thread;
        ProxyContext *m_context;
-
-       QString m_prefix;
-       quint16 m_http;
 };
 
 class ProxyHandler : public HttpHandler
index a6602f2..80418a1 100644 (file)
@@ -5,6 +5,7 @@
 #include "tmdatabase.h"
 
 #include <QDir>
+
 #include <QMutex>
 #include <QMutexLocker>
 
@@ -68,6 +69,46 @@ Text::pointer TM::Service::divide_into_words(int code, Text::pointer sentence)
        return m_languages[code]->divide_into_words(sentence);
 }
 
+/*!
+ * \brief 原文と訳文の対をデータベースへ登録します。
+ * \param site_id 翻訳対象サイトを表すID。
+ * \param scode 原文の言語コード。
+ * \param ssentence 原文の構造化テキスト。
+ * \param tcode 訳文の言語コード。
+ * \param tsentence 訳文の構造化テキスト。
+ * \param json 原文と訳文間の単語リンク。
+ */
+void TM::Service::insert_sentence(int site_id, int scode, Text::pointer ssentence,
+                               int tcode, Text::pointer tsentence, QJsonArray json)
+{
+       QMutexLocker lock(&m_mutex);
+
+       assert(m_languages.contains(scode));
+       assert(m_languages.contains(tcode));
+       Language *slanguage = m_languages[scode];
+       Language *tlanguage = m_languages[tcode];
+
+       QString sstring = slanguage->normalize(ssentence->to_string());
+       QString tstring = tlanguage->normalize(tsentence->to_string());
+
+       //m_database->
+}
+
+/*!
+ * \brief 原文から訳文を検索します。
+ * \param site_id 翻訳対象サイトを表すID。
+ * \param scode 原文の言語コード。
+ * \param ssentence 原文の構造化テキスト。
+ * \param tcode 訳文の言語コード。
+ * \param tsentence 訳文の構造化テキストを受け取るポインタ。
+ * \param json 原文と訳文間の単語リンクを受け取るポインタ。
+ * \return 訳文が検索できた場合、trueを返します。
+ */
+bool TM::Service::find_sentence(int site_id, int scode, Text::pointer ssentence, int tcode,
+                               Text::pointer *tsentence, QJsonArray *json)
+{
+       return true;
+}
 
 
 
index 07e52b9..32b749c 100644 (file)
@@ -4,8 +4,9 @@
 #include "language.h"
 
 #include <QObject>
-#include <QByteArray>
 #include <QString>
+#include <QByteArray>
+#include <QJsonArray>
 #include <QMap>
 
 #include <QIcon>
@@ -34,7 +35,10 @@ public:
        Text::pointer divide_into_sentences(int code, QString string);
        Text::pointer divide_into_words(int code, Text::pointer sentence);
 
-       //int find_source_id(int code, QString const &source);
+       void insert_sentence(int site_id, int scode, Text::pointer ssentence,
+                                       int tcode, Text::pointer tsentence, QJsonArray json);
+       bool find_sentence(int site_id, int scode, Text::pointer ssentence, int tcode,
+                                       Text::pointer *tsentence, QJsonArray *json);
 
 signals:
        /*!
index 2650e4a..b2850ae 100644 (file)
@@ -115,8 +115,11 @@ bool TM::TextConverter::is_white_space(QChar const &ch)
 
 // SocketConnection -----------------------------------------------------------
 
-TM::SocketConnection::SocketConnection(EditorWidget *editor_widget, QWebSocket *socket)
+TM::SocketConnection::SocketConnection(Settings *settings, Service *service,
+                                                                       EditorWidget *editor_widget, QWebSocket *socket)
        : QObject(socket)
+       , m_settings(settings)
+       , m_service(service)
        , m_editor_widget(editor_widget)
        , m_mutex(QMutex::Recursive)
        , m_edit_mode(false)
@@ -237,9 +240,11 @@ void TM::SocketConnection::onBinaryMessageReceived(QByteArray const &message)
 
 // SocketServer ---------------------------------------------------------------
 
-TM::SocketServer::SocketServer(Settings *settings, EditorWidget *editor_widget, QObject *parent)
+TM::SocketServer::SocketServer(Settings *settings, Service* service,
+                                                       EditorWidget *editor_widget, QObject *parent)
        : QObject(parent)
        , m_settings(settings)
+       , m_service(service)
        , m_server(new QWebSocketServer(QStringLiteral("wordring websocket"),
                                                                        QWebSocketServer::NonSecureMode, this))
        , m_editor_widget(editor_widget)
@@ -275,7 +280,7 @@ void TM::SocketServer::onNewConnection()
 {
        QWebSocket *socket = m_server->nextPendingConnection();
        connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
-       new SocketConnection(m_editor_widget, socket);
+       new SocketConnection(m_settings, m_service, m_editor_widget, socket);
        m_sockets.push_back(socket);
 }
 
index 912c607..48cdbbc 100644 (file)
@@ -8,7 +8,9 @@
 
 #include <QString>
 #include <QList>
+#include <QJsonArray>
 
+#include <QThread>
 #include <QMutex>
 
 #include <QWebSocket>
@@ -23,6 +25,7 @@ class Settings;
 namespace TM
 {
 
+class Service;
 class EditorWidget;
 
 class HtmlData : public RangeData
@@ -44,11 +47,12 @@ private:
        HtmlNode m_node;
 };
 
+/*!
+ * \brief HtmlRangeから構造化テキストに変換するためのクラスです。
+ */
 class TextConverter
 {
 public:
-       //TextConverter();
-
        Text::pointer to_text(HtmlRange range);
        Text::pointer stuff_text(Text::pointer parent, QString const &string);
 
@@ -60,12 +64,27 @@ private:
        int m_state;
 };
 
+class TextSentence
+{
+
+private:
+       Text::pointer m_source_sentence;
+       Text::pointer m_target_sentence;
+       QJsonArray m_link_data;
+};
+
+class TextSegment
+{
+
+};
+
 class SocketConnection : public QObject
 {
        Q_OBJECT
 
 public:
-       SocketConnection(EditorWidget *editor_widget, QWebSocket *socket);
+       SocketConnection(Settings *settings, Service *service,
+                                       EditorWidget *editor_widget, QWebSocket *socket);
        virtual ~SocketConnection();
 
        //quint16 port() const;
@@ -96,6 +115,9 @@ private slots:
        void onBinaryMessageReceived(QByteArray const &message);
 
 private:
+       Settings *m_settings;
+       Service *m_service;
+
        QMutex m_mutex;
 
        bool m_edit_mode;
@@ -113,7 +135,8 @@ class SocketServer : public QObject
 {
        Q_OBJECT
 public:
-       SocketServer(Settings *settings, EditorWidget *editor_widget, QObject *parent);
+       SocketServer(Settings *settings, Service* service,
+                               EditorWidget *editor_widget, QObject *parent);
        ~SocketServer();
 
        quint16 port() const;
@@ -132,9 +155,12 @@ signals:
 
 private:
        Settings *m_settings;
+       Service *m_service;
+
        QWebSocketServer *m_server;
-       EditorWidget *m_editor_widget;
        QList<QWebSocket*> m_sockets;
+
+       EditorWidget *m_editor_widget;
 };
 
 } // namespace TM
index 2f1346a..4bbe72c 100644 (file)
@@ -165,7 +165,14 @@ Text::pointer Text::insert_after(pointer position_, QString const &string_)
        return insert_after(position_, create(self(), string_));
 }
 
+Text::pointer Text::remove(pointer position_)
+{
+       assert(false); // 未実装
+       return position_;
+}
+
 QString& Text::string() { return m_string; }
+
 QString const& Text::string() const { return m_string; }
 
 Text& Text::set_string(QString const &string)
index 79eb9c6..42cb88d 100644 (file)
@@ -45,11 +45,14 @@ public:
 
        pointer append(pointer value_);
        pointer append(QString const &string_);
+
        pointer insert(pointer position_, pointer value_);
        pointer insert(pointer position_, QString const &string_);
        pointer insert_after(pointer position, pointer value);
        pointer insert_after(pointer position_, QString const &string_);
 
+       pointer remove(pointer position_);
+
        QString& string();
        QString const& string() const;
        Text& set_string(QString const &string);