Codebase list mozc / upstream/2.23.2815.102 src / gui / character_pad / hand_writing.cc
upstream/2.23.2815.102

Tree @upstream/2.23.2815.102 (Download .tar.gz)

hand_writing.cc @upstream/2.23.2815.102raw · history · blame

// Copyright 2010-2018, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "gui/character_pad/hand_writing.h"

#ifdef ENABLE_CLOUD_HANDWRITING
#include <QtGui/QGuiApplication>
#endif  // ENABLE_CLOUD_HANDWRITING

#include <QtGui/QtGui>
#include <QtWidgets/QMessageBox>

#ifdef OS_WIN
#include <windows.h>
#include <windowsx.h>
#endif

#ifdef ENABLE_CLOUD_HANDWRITING
#include "config/config_handler.h"
#include "handwriting/cloud_handwriting.h"
#include "protocol/config.pb.h"
#endif  // ENABLE_CLOUD_HANDWRITING

#include "base/logging.h"
#include "client/client.h"
#include "config/stats_config_util.h"
#include "gui/base/win_util.h"
#include "handwriting/handwriting_manager.h"
#include "handwriting/zinnia_handwriting.h"
#include "protocol/commands.pb.h"

namespace mozc {

namespace {
enum HandwritingSourceId {
  kZinniaHandwriting = 0,
#ifdef ENABLE_CLOUD_HANDWRITING
  kCloudHandwriting = 1,
#endif  // ENABLE_CLOUD_HANDWRITING
};

#ifdef ENABLE_CLOUD_HANDWRITING
bool SetConfig(client::ClientInterface *client,
               const config::Config &config) {
  if (!client->CheckVersionOrRestartServer()) {
    LOG(ERROR) << "CheckVersionOrRestartServer failed";
    return false;
  }

  if (!client->SetConfig(config)) {
    LOG(ERROR) << "SetConfig failed";
    return false;
  }

  return true;
}

bool GetConfig(client::ClientInterface *client,
               config::Config *config) {
  if (!client->CheckVersionOrRestartServer()) {
    LOG(ERROR) << "CheckVersionOrRestartServer failed";
    return false;
  }

  if (!client->GetConfig(config)) {
    LOG(ERROR) << "GetConfig failed";
    return false;
  }

  return true;
}

bool IsCloudHandwritingAllowed(client::ClientInterface *client) {
  config::Config config;
  if (!GetConfig(client, &config)) {
    return false;
  }

  // Note that |allow_cloud_handwriting| has default value 'false'.
  return config.allow_cloud_handwriting();
}
#endif  // ENABLE_CLOUD_HANDWRITING

}  // namespace

namespace gui {

HandWriting::HandWriting(QWidget *parent)
    : QMainWindow(parent),
      usage_stats_enabled_(mozc::config::StatsConfigUtil::IsEnabled()),
#ifdef ENABLE_CLOUD_HANDWRITING
      cloud_handwriting_(new mozc::handwriting::CloudHandwriting),
#endif  // ENABLE_CLOUD_HANDWRITING
      zinnia_handwriting_(new mozc::handwriting::ZinniaHandwriting(
          mozc::handwriting::ZinniaHandwriting::GetModelFileName())) {
  // To reduce the disk IO of reading the stats config, we load it only when the
  // class is initialized. There is no problem because the config dialog (on
  // Mac) and the administrator dialog (on Windows) say that the usage stats
  // setting changes will take effect after the re-login.

#ifdef ENABLE_CLOUD_HANDWRITING
  client_.reset(client::ClientFactory::NewClient());
#else
  if (usage_stats_enabled_) {
    client_.reset(client::ClientFactory::NewClient());
  }
#endif  // ENABLE_CLOUD_HANDWRITING
  setupUi(this);

  handWritingCanvas->setListWidget(resultListWidget);

  fontComboBox->setWritingSystem
      (static_cast<QFontDatabase::WritingSystem>
       (QFontDatabase::Any));
  fontComboBox->setEditable(false);
  fontComboBox->setCurrentFont(resultListWidget->font());

  QObject::connect(resultListWidget,
                   SIGNAL(itemSelected(const QListWidgetItem*)),
                   this,
                   SLOT(itemSelected(const QListWidgetItem*)));

  QObject::connect(fontComboBox,
                   SIGNAL(currentFontChanged(const QFont &)),
                   this, SLOT(updateFont(const QFont &)));

  QObject::connect(sizeComboBox,
                   SIGNAL(currentIndexChanged(int)),
                   this, SLOT(updateFontSize(int)));

#ifdef ENABLE_CLOUD_HANDWRITING
  QObject::connect(handwritingSourceComboBox,
                   SIGNAL(currentIndexChanged(int)),
                   this, SLOT(tryToUpdateHandwritingSource(int)));
#else
  // When cloud handwriting is configured to be disabled, hide the combo box.
  handwritingSourceComboBox->setVisible(false);
#endif  // ENABLE_CLOUD_HANDWRITING

  QObject::connect(clearButton,
                   SIGNAL(clicked()),
                   this, SLOT(clear()));

  QObject::connect(revertButton,
                   SIGNAL(clicked()),
                   this, SLOT(revert()));

  QObject::connect(handWritingCanvas,
                   SIGNAL(canvasUpdated()),
                   this, SLOT(updateUIStatus()));

  // "4" means smallest.
  sizeComboBox->setCurrentIndex(4);
  fontComboBox->setCurrentFont(resultListWidget->font());

  int default_handwriting_method = kZinniaHandwriting;
#ifdef ENABLE_CLOUD_HANDWRITING
  if (IsCloudHandwritingAllowed(client_.get())) {
    // If cloud handwriting is enabled, use it by default.
    // TODO(team): Consider the case where network access is not available.
    default_handwriting_method = kCloudHandwriting;
  }
#endif  // ENABLE_CLOUD_HANDWRITING
  handwritingSourceComboBox->setCurrentIndex(default_handwriting_method);

  if (usage_stats_enabled_) {
    CHECK(client_.get());
    // Sends the usage stats event (HANDWRITING_OPEN_EVENT) to mozc converter.
    commands::SessionCommand command;
    command.set_type(commands::SessionCommand::USAGE_STATS_EVENT);
    command.set_usage_stats_event(
        commands::SessionCommand::HANDWRITING_OPEN_EVENT);
    commands::Output dummy_output;
    client_->SendCommand(command, &dummy_output);
  }

  updateUIStatus();
  repaint();
  update();
}

HandWriting::~HandWriting() {}

void HandWriting::updateFont(const QFont &font) {
  resultListWidget->updateFont(font);
}

void HandWriting::updateFontSize(int index) {
  resultListWidget->updateFontSize(index);
}

void HandWriting::tryToUpdateHandwritingSource(int index) {
  switch (index) {
    case kZinniaHandwriting:
      updateHandwritingSource(kZinniaHandwriting);
      break;
#ifdef ENABLE_CLOUD_HANDWRITING
    case kCloudHandwriting:
      if (TryToEnableCloudHandwriting()) {
        updateHandwritingSource(kCloudHandwriting);
      } else {
        // When user refused to use cloud handwriting, change the
        // combobox to Zinnia.
        handwritingSourceComboBox->setCurrentIndex(kZinniaHandwriting);
        updateHandwritingSource(kZinniaHandwriting);
      }
      break;
#endif  // ENABLE_CLOUD_HANDWRITING
    default:
      DLOG(INFO) << "Unknown index = " << index;
      break;
  }
}

void HandWriting::updateHandwritingSource(int index) {
  switch (index) {
    case kZinniaHandwriting:
      mozc::handwriting::HandwritingManager::SetHandwritingModule(
          zinnia_handwriting_.get());
      break;
#ifdef ENABLE_CLOUD_HANDWRITING
    case kCloudHandwriting:
      mozc::handwriting::HandwritingManager::SetHandwritingModule(
          cloud_handwriting_.get());
      break;
#endif  // ENABLE_CLOUD_HANDWRITING
    default:
      DLOG(INFO) << "Unknown index = " << index;
      break;
  }
  resultListWidget->clear();
  handWritingCanvas->restartRecognition();
}

void HandWriting::resizeEvent(QResizeEvent *event) {
  resultListWidget->update();
}

void HandWriting::clear() {
  resultListWidget->clear();
  handWritingCanvas->clear();
  updateUIStatus();
}

void HandWriting::revert() {
  resultListWidget->clear();
  handWritingCanvas->revert();
  updateUIStatus();
}

void HandWriting::updateUIStatus() {
#ifdef OS_MACOSX
  // Due to a bug of Qt?, the appearance of these buttons
  // doesn't change on Mac. To fix this issue, always set
  // true on Mac.
  clearButton->setEnabled(true);
  revertButton->setEnabled(true);
#else
  const bool enabled = handWritingCanvas->strokes_size() > 0;
  clearButton->setEnabled(enabled);
  revertButton->setEnabled(enabled);
#endif
}

void HandWriting::itemSelected(const QListWidgetItem *item) {
  if (!usage_stats_enabled_) {
    return;
  }
  CHECK(client_.get());
  // Sends the usage stats event (HANDWRITING_COMMIT_EVENT) to mozc converter.
  commands::SessionCommand command;
  command.set_type(commands::SessionCommand::USAGE_STATS_EVENT);
  command.set_usage_stats_event(
      commands::SessionCommand::HANDWRITING_COMMIT_EVENT);
  commands::Output dummy_output;
  client_->SendCommand(command, &dummy_output);
}

#ifdef ENABLE_CLOUD_HANDWRITING
bool HandWriting::TryToEnableCloudHandwriting() {
  if (IsCloudHandwritingAllowed(client_.get())) {
    // Already allowed. Do nothing.
    return true;
  }

  // Currently custom style sheet is used only on Windows.
#ifdef OS_WIN
  // When a custom style sheet is applied, temporarily disable it to
  // show a message box with default theme. See b/5949615.
  // Mysteriously, a message box launched from dictionary tool does
  // not have this issue even when a custom style sheet is applied.
  // This implies that we might be able to fix this issue in a more
  // appropriate way.
  // TODO(yukawa): Investigate why this does not happen on the
  //     dictionary tool and remove this workaround code if possible.
  //     See b/5974593.
  const QString custom_style_sheet = qApp->styleSheet();
  if (!custom_style_sheet.isEmpty()) {
    qApp->setStyleSheet("");
  }
#endif  // OS_WIN

  // When cloud handwriting is not allowed, ask the user to enable it.
  const QMessageBox::StandardButton result =
      QMessageBox::question(
          this,
          tr("Cloud handwriting recognition"),
          // TODO(yukawa, peria): Update the warning message and have
          //     native check. b/5943541.
          tr("This feature improve the accuracy of handwriting recognition "
             "by using a Google web service. To do so, your handwriting "
             "strokes will be securely sent to Google. Do you want to use "
             "Cloud handwriting?"),
          QMessageBox::Yes | QMessageBox::No, QMessageBox::No);

  // Currently custom style sheet is used only on Windows.
#ifdef OS_WIN
  // Restore the custom style sheet if necessary.
  if (!custom_style_sheet.isEmpty()) {
    qApp->setStyleSheet(custom_style_sheet);
  }
#endif  // OS_WIN

  if (result == QMessageBox::No) {
    // User refused.
    return false;
  }

  // The user allowed to enable the cloud handwriting. Store this info
  // for later use.
  config::Config config;
  if (GetConfig(client_.get(), &config)) {
    config.set_allow_cloud_handwriting(true);
    SetConfig(client_.get(), config);
  }

  return true;
}
#endif  // ENABLE_CLOUD_HANDWRITING

}  // namespace gui
}  // namespace mozc