<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/input_method/xkeyboard.h"

#include <algorithm>
#include <set>
#include <string>

#include <gtest/gtest.h>
#include <X11/Xlib.h>

#include "base/logging.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "ui/base/x/x11_util.h"

#if defined(TOUCH_UI)
// Since TOUCH_UI build only supports a few keyboard layouts, we skip the tests
// for now.
#define TestCreateFullXkbLayoutNameKeepAlt \
  DISABLED_TestCreateFullXkbLayoutNameKeepAlt
#define TestCreateFullXkbLayoutNameKeepCapsLock \
  DISABLED_TestCreateFullXkbLayoutNameKeepCapsLock
#endif  // TOUCH_UI

namespace chromeos {
namespace input_method {

namespace {

class TestableXKeyboard : public XKeyboard {
 public:
  explicit TestableXKeyboard(const InputMethodUtil& util) : XKeyboard(util) {
  }

  // Change access rights.
  using XKeyboard::CreateFullXkbLayoutName;
  using XKeyboard::ContainsModifierKeyAsReplacement;
};

class Testee {
 public:
  Testee() : util_(), xkey_(util_) {
  }

  InputMethodUtil util_;
  TestableXKeyboard xkey_;
};

// Returns a ModifierMap object that contains the following mapping:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
ModifierMap GetMap(ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap modifier_key;
  // Use the Search key as |search|.
  modifier_key.push_back(ModifierKeyPair(kSearchKey, search));
  modifier_key.push_back(ModifierKeyPair(kLeftControlKey, control));
  modifier_key.push_back(ModifierKeyPair(kLeftAltKey, alt));
  return modifier_key;
}

// Checks |modifier_map| and returns true if the following conditions are met:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
bool CheckMap(const ModifierMap& modifier_map,
              ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap::const_iterator begin = modifier_map.begin();
  ModifierMap::const_iterator end = modifier_map.end();
  if ((std::count(begin, end, ModifierKeyPair(kSearchKey, search)) == 1) &&
      (std::count(begin, end,
                  ModifierKeyPair(kLeftControlKey, control)) == 1) &&
      (std::count(begin, end, ModifierKeyPair(kLeftAltKey, alt)) == 1)) {
    return true;
  }
  return false;
}

// Returns true if X display is available.
bool DisplayAvailable() {
  return ui::GetXDisplay() ? true : false;
}

}  // namespace

// Tests CreateFullXkbLayoutName() function.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameBasic) {
  Testee testee;

  // CreateFullXkbLayoutName should not accept an empty |layout_name|.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept an empty ModifierMap.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us", ModifierMap()).c_str());

  // CreateFullXkbLayoutName should not accept an incomplete ModifierMap.
  ModifierMap tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.pop_back();
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept redundant ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kSearchKey, kVoidKey));  // two search maps
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftControlKey, kVoidKey));  // two ctrls
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftAltKey, kVoidKey));  // two alts.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept invalid ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kVoidKey, kSearchKey));  // can't remap void
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kCapsLockKey, kSearchKey));  // ditto
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName can remap Search/Ctrl/Alt to CapsLock.
  EXPECT_STREQ("us+chromeos(capslock_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kCapsLockKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_capslock_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kCapsLockKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_disabled_capslock)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kVoidKey, kCapsLockKey)).c_str());

  // CreateFullXkbLayoutName should not accept non-alphanumeric characters
  // except "()-_".
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us!", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us; /bin/sh", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("ab-c_12+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "ab-c_12",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept upper-case ascii characters.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "US", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should accept lower-case ascii characters.
  for (int c = 'a'; c <= 'z'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept numbers.
  for (int c = '0'; c <= '9'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept a layout with a variant name.
  EXPECT_STREQ("us(dvorak)+chromeos(disabled_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(dvorak)",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("gb(extd)+chromeos(disabled_disabled_disabled_keepralt),us",
                testee.xkey_.CreateFullXkbLayoutName(
                    "gb(extd)",
                    GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("jp+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "jp",  // does not use AltGr, therefore no _keepralt.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // When the layout name is not "us", the second layout should be added.
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us(dvorak)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "gb(extd)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "jp", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepCapsLock) {
  Testee testee;

  EXPECT_STREQ("us(colemak)+chromeos(search_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(colemak)",
                   // The 1st kVoidKey should be ignored.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("de(neo)+"
               "chromeos(search_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   // The 1st kLeftControlKey should be ignored.
                   "de(neo)", GetMap(kLeftControlKey,
                                     kLeftControlKey,
                                     kLeftControlKey)).c_str());
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepAlt) {
  Testee testee;

  EXPECT_STREQ("us(intl)+chromeos(disabled_disabled_disabled_keepralt)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(intl)", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("kr(kr104)+"
               "chromeos(leftcontrol_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "kr(kr104)", GetMap(kLeftControlKey,
                                       kLeftControlKey,
                                       kLeftControlKey)).c_str());
}

// Tests if CreateFullXkbLayoutName and ExtractLayoutNameFromFullXkbLayoutName
// functions could handle all combinations of modifier remapping.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameModifierKeys) {
  Testee testee;

  std::set<std::string> layouts;
  for (int i = 0; i < static_cast<int>(kNumModifierKeys); ++i) {
    for (int j = 0; j < static_cast<int>(kNumModifierKeys); ++j) {
      for (int k = 0; k < static_cast<int>(kNumModifierKeys); ++k) {
        const std::string layout = testee.xkey_.CreateFullXkbLayoutName(
            "us", GetMap(ModifierKey(i), ModifierKey(j), ModifierKey(k)));
        // CreateFullXkbLayoutName should succeed (i.e. should not return "".)
        EXPECT_STREQ("us+", layout.substr(0, 3).c_str())
            << "layout: " << layout;
        // All 4*3*3 layouts should be different.
        EXPECT_TRUE(layouts.insert(layout).second) << "layout: " << layout;
      }
    }
  }
}

TEST(XKeyboardTest, TestSetCapsLockIsEnabled) {
  if (!DisplayAvailable()) {
    return;
  }
  const bool initial_lock_state = XKeyboard::CapsLockIsEnabled();
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(initial_lock_state);
}

TEST(XKeyboardTest, TestContainsModifierKeyAsReplacement) {
  EXPECT_FALSE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kSearchKey, kVoidKey, kVoidKey), kSearchKey));
}

}  // namespace input_method
}  // namespace chromeos
<commit_msg>Fix unit_tests break on TOUCH_UI build.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/input_method/xkeyboard.h"

#include <algorithm>
#include <set>
#include <string>

#include <gtest/gtest.h>
#include <X11/Xlib.h>

#include "base/logging.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "ui/base/x/x11_util.h"

#if defined(TOUCH_UI)
// Since TOUCH_UI build only supports a few keyboard layouts, we skip the tests
// for now.
#define TestCreateFullXkbLayoutNameKeepAlt \
  DISABLED_TestCreateFullXkbLayoutNameKeepAlt
#define TestCreateFullXkbLayoutNameKeepCapsLock \
  DISABLED_TestCreateFullXkbLayoutNameKeepCapsLock
#endif  // TOUCH_UI

namespace chromeos {
namespace input_method {

namespace {

class TestableXKeyboard : public XKeyboard {
 public:
  explicit TestableXKeyboard(const InputMethodUtil& util) : XKeyboard(util) {
  }

  // Change access rights.
  using XKeyboard::CreateFullXkbLayoutName;
  using XKeyboard::ContainsModifierKeyAsReplacement;
};

class Testee {
 public:
  Testee() : util_(), xkey_(util_) {
  }

  InputMethodUtil util_;
  TestableXKeyboard xkey_;
};

// Returns a ModifierMap object that contains the following mapping:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
ModifierMap GetMap(ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap modifier_key;
  // Use the Search key as |search|.
  modifier_key.push_back(ModifierKeyPair(kSearchKey, search));
  modifier_key.push_back(ModifierKeyPair(kLeftControlKey, control));
  modifier_key.push_back(ModifierKeyPair(kLeftAltKey, alt));
  return modifier_key;
}

// Checks |modifier_map| and returns true if the following conditions are met:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
bool CheckMap(const ModifierMap& modifier_map,
              ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap::const_iterator begin = modifier_map.begin();
  ModifierMap::const_iterator end = modifier_map.end();
  if ((std::count(begin, end, ModifierKeyPair(kSearchKey, search)) == 1) &&
      (std::count(begin, end,
                  ModifierKeyPair(kLeftControlKey, control)) == 1) &&
      (std::count(begin, end, ModifierKeyPair(kLeftAltKey, alt)) == 1)) {
    return true;
  }
  return false;
}

// Returns true if X display is available.
bool DisplayAvailable() {
  return ui::GetXDisplay() ? true : false;
}

}  // namespace

// Tests CreateFullXkbLayoutName() function.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameBasic) {
  Testee testee;

  // CreateFullXkbLayoutName should not accept an empty |layout_name|.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept an empty ModifierMap.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us", ModifierMap()).c_str());

  // CreateFullXkbLayoutName should not accept an incomplete ModifierMap.
  ModifierMap tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.pop_back();
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept redundant ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kSearchKey, kVoidKey));  // two search maps
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftControlKey, kVoidKey));  // two ctrls
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftAltKey, kVoidKey));  // two alts.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept invalid ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kVoidKey, kSearchKey));  // can't remap void
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kCapsLockKey, kSearchKey));  // ditto
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName can remap Search/Ctrl/Alt to CapsLock.
  EXPECT_STREQ("us+chromeos(capslock_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kCapsLockKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_capslock_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kCapsLockKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_disabled_capslock)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kVoidKey, kCapsLockKey)).c_str());

  // CreateFullXkbLayoutName should not accept non-alphanumeric characters
  // except "()-_".
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us!", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us; /bin/sh", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("ab-c_12+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "ab-c_12",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept upper-case ascii characters.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "US", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should accept lower-case ascii characters.
  for (int c = 'a'; c <= 'z'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept numbers.
  for (int c = '0'; c <= '9'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept a layout with a variant name.
  EXPECT_STREQ("us(dvorak)+chromeos(disabled_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(dvorak)",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("jp+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "jp",  // does not use AltGr, therefore no _keepralt.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // When the layout name is not "us", the second layout should be added.
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us(dvorak)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "gb(extd)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "jp", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepCapsLock) {
  Testee testee;

  EXPECT_STREQ("us(colemak)+chromeos(search_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(colemak)",
                   // The 1st kVoidKey should be ignored.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("de(neo)+"
               "chromeos(search_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   // The 1st kLeftControlKey should be ignored.
                   "de(neo)", GetMap(kLeftControlKey,
                                     kLeftControlKey,
                                     kLeftControlKey)).c_str());
  EXPECT_STREQ("gb(extd)+chromeos(disabled_disabled_disabled_keepralt),us",
                testee.xkey_.CreateFullXkbLayoutName(
                    "gb(extd)",
                    GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepAlt) {
  Testee testee;

  EXPECT_STREQ("us(intl)+chromeos(disabled_disabled_disabled_keepralt)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(intl)", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("kr(kr104)+"
               "chromeos(leftcontrol_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "kr(kr104)", GetMap(kLeftControlKey,
                                       kLeftControlKey,
                                       kLeftControlKey)).c_str());
}

// Tests if CreateFullXkbLayoutName and ExtractLayoutNameFromFullXkbLayoutName
// functions could handle all combinations of modifier remapping.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameModifierKeys) {
  Testee testee;

  std::set<std::string> layouts;
  for (int i = 0; i < static_cast<int>(kNumModifierKeys); ++i) {
    for (int j = 0; j < static_cast<int>(kNumModifierKeys); ++j) {
      for (int k = 0; k < static_cast<int>(kNumModifierKeys); ++k) {
        const std::string layout = testee.xkey_.CreateFullXkbLayoutName(
            "us", GetMap(ModifierKey(i), ModifierKey(j), ModifierKey(k)));
        // CreateFullXkbLayoutName should succeed (i.e. should not return "".)
        EXPECT_STREQ("us+", layout.substr(0, 3).c_str())
            << "layout: " << layout;
        // All 4*3*3 layouts should be different.
        EXPECT_TRUE(layouts.insert(layout).second) << "layout: " << layout;
      }
    }
  }
}

TEST(XKeyboardTest, TestSetCapsLockIsEnabled) {
  if (!DisplayAvailable()) {
    return;
  }
  const bool initial_lock_state = XKeyboard::CapsLockIsEnabled();
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(initial_lock_state);
}

TEST(XKeyboardTest, TestContainsModifierKeyAsReplacement) {
  EXPECT_FALSE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kSearchKey, kVoidKey, kVoidKey), kSearchKey));
}

}  // namespace input_method
}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_locker_tester.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/window_gtk.h"

namespace {

// An object that wait for lock state and fullscreen state.
class Waiter : public NotificationObserver {
 public:
  explicit Waiter(Browser* browser)
      : browser_(browser),
        running_(false) {
    registrar_.Add(this,
                   NotificationType::SCREEN_LOCK_STATE_CHANGED,
                   NotificationService::AllSources());
    handler_id_ = g_signal_connect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        "window-state-event",
        G_CALLBACK(OnWindowStateEventThunk),
        this);
  }

  ~Waiter() {
    g_signal_handler_disconnect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        handler_id_);
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::SCREEN_LOCK_STATE_CHANGED);
    if (running_)
      MessageLoop::current()->Quit();
  }

  // Wait until the two conditions are met.
  void Wait(bool locker_state, bool fullscreen) {
    running_ = true;
    scoped_ptr<chromeos::test::ScreenLockerTester>
        tester(chromeos::ScreenLocker::GetTester());
    while (tester->IsLocked() != locker_state ||
           browser_->window()->IsFullscreen() != fullscreen) {
      ui_test_utils::RunMessageLoop();
    }
    // Make sure all pending tasks are executed.
    ui_test_utils::RunAllPendingInMessageLoop();
    running_ = false;
  }

  CHROMEGTK_CALLBACK_1(Waiter, gboolean, OnWindowStateEvent,
                       GdkEventWindowState*);

 private:
  Browser* browser_;
  gulong handler_id_;
  NotificationRegistrar registrar_;

  // Are we currently running the message loop?
  bool running_;

  DISALLOW_COPY_AND_ASSIGN(Waiter);
};

gboolean Waiter::OnWindowStateEvent(GtkWidget* widget,
                                    GdkEventWindowState* event) {
  MessageLoop::current()->Quit();
  return false;
}

}  // namespace

namespace chromeos {

class ScreenLockerTest : public CrosInProcessBrowserTest {
 public:
  ScreenLockerTest() : mock_screen_lock_library_(NULL),
                       mock_input_method_library_(NULL) {
  }

 protected:
  MockScreenLockLibrary *mock_screen_lock_library_;
  MockInputMethodLibrary *mock_input_method_library_;

  // Test the no password mode with different unlock scheme given by
  // |unlock| function.
  void TestNoPassword(void (unlock)(views::Widget*)) {
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    UserManager::Get()->OffTheRecordUserLoggedIn();
    ScreenLocker::Show();
    scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
    tester->EmulateWindowManagerReady();
    if (!chromeos::ScreenLocker::GetTester()->IsLocked())
      ui_test_utils::WaitForNotification(
          NotificationType::SCREEN_LOCK_STATE_CHANGED);
    EXPECT_TRUE(tester->IsLocked());
    tester->InjectMockAuthenticator("", "");

    unlock(tester->GetWidget());

    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_TRUE(tester->IsLocked());

    // Emulate LockScreen request from PowerManager (via SessionManager).
    ScreenLocker::Hide();
    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_FALSE(tester->IsLocked());
  }

 private:
  virtual void SetUpInProcessBrowserTestFixture() {
    cros_mock_->InitStatusAreaMocks();
    cros_mock_->InitMockScreenLockLibrary();
    mock_screen_lock_library_ = cros_mock_->mock_screen_lock_library();
    mock_input_method_library_ = cros_mock_->mock_input_method_library();
    EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_))
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    // Expectations for the status are on the screen lock window.
    cros_mock_->SetStatusAreaMocksExpectations();
    // Expectations for the status area on the browser window.
    cros_mock_->SetStatusAreaMocksExpectations();
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
    command_line->AppendSwitch(switches::kNoFirstRun);
  }

  DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest);
};

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestBasic) {
  EXPECT_CALL(*mock_input_method_library_, GetNumActiveInputMethods())
      .Times(1)
      .WillRepeatedly((testing::Return(0)))
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  if (!chromeos::ScreenLocker::GetTester()->IsLocked())
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);

  // Test to make sure that the widget is actually appearing and is of
  // reasonable size, preventing a regression of
  // http://code.google.com/p/chromium-os/issues/detail?id=5987
  gfx::Rect lock_bounds;
  tester->GetChildWidget()->GetBounds(&lock_bounds, true);
  EXPECT_GT(lock_bounds.width(), 10);
  EXPECT_GT(lock_bounds.height(), 10);

  tester->InjectMockAuthenticator("user", "pass");
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("fail");
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  // Successful authentication simply send a unlock request to PowerManager.
  EXPECT_TRUE(tester->IsLocked());

  // Emulate LockScreen request from PowerManager (via SessionManager).
  // TODO(oshima): Find out better way to handle this in mock.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestFullscreenExit) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  {
    Waiter waiter(browser());
    browser()->ToggleFullscreenMode();
    waiter.Wait(false /* not locked */, true /* full screen */);
    EXPECT_TRUE(browser()->window()->IsFullscreen());
    EXPECT_FALSE(tester->IsLocked());
  }
  {
    Waiter waiter(browser());
    UserManager::Get()->UserLoggedIn("user");
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    waiter.Wait(true /* locked */, false /* full screen */);
    EXPECT_FALSE(browser()->window()->IsFullscreen());
    EXPECT_TRUE(tester->IsLocked());
  }
  tester->InjectMockAuthenticator("user", "pass");
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

void MouseMove(views::Widget* widget) {
  ui_controls::SendMouseMove(10, 10);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseMove) {
  TestNoPassword(MouseMove);
}

void MouseClick(views::Widget* widget) {
  ui_controls::SendMouseClick(ui_controls::RIGHT);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseClick) {
  TestNoPassword(MouseClick);
}

void KeyPress(views::Widget* widget) {
  ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()),
                            app::VKEY_SPACE, false, false, false, false);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithKeyPress) {
  TestNoPassword(KeyPress);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestShowTwice) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(2)
      .RetiresOnSaturation();

  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  if (!chromeos::ScreenLocker::GetTester()->IsLocked())
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);
  EXPECT_TRUE(tester->IsLocked());

  // Calling Show again simply send LockCompleted signal.
  ScreenLocker::Show();
  EXPECT_TRUE(tester->IsLocked());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

}  // namespace chromeos
<commit_msg>Mark ScreenLockerTest.TestBasic flaky.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_locker_tester.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/window_gtk.h"

namespace {

// An object that wait for lock state and fullscreen state.
class Waiter : public NotificationObserver {
 public:
  explicit Waiter(Browser* browser)
      : browser_(browser),
        running_(false) {
    registrar_.Add(this,
                   NotificationType::SCREEN_LOCK_STATE_CHANGED,
                   NotificationService::AllSources());
    handler_id_ = g_signal_connect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        "window-state-event",
        G_CALLBACK(OnWindowStateEventThunk),
        this);
  }

  ~Waiter() {
    g_signal_handler_disconnect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        handler_id_);
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::SCREEN_LOCK_STATE_CHANGED);
    if (running_)
      MessageLoop::current()->Quit();
  }

  // Wait until the two conditions are met.
  void Wait(bool locker_state, bool fullscreen) {
    running_ = true;
    scoped_ptr<chromeos::test::ScreenLockerTester>
        tester(chromeos::ScreenLocker::GetTester());
    while (tester->IsLocked() != locker_state ||
           browser_->window()->IsFullscreen() != fullscreen) {
      ui_test_utils::RunMessageLoop();
    }
    // Make sure all pending tasks are executed.
    ui_test_utils::RunAllPendingInMessageLoop();
    running_ = false;
  }

  CHROMEGTK_CALLBACK_1(Waiter, gboolean, OnWindowStateEvent,
                       GdkEventWindowState*);

 private:
  Browser* browser_;
  gulong handler_id_;
  NotificationRegistrar registrar_;

  // Are we currently running the message loop?
  bool running_;

  DISALLOW_COPY_AND_ASSIGN(Waiter);
};

gboolean Waiter::OnWindowStateEvent(GtkWidget* widget,
                                    GdkEventWindowState* event) {
  MessageLoop::current()->Quit();
  return false;
}

}  // namespace

namespace chromeos {

class ScreenLockerTest : public CrosInProcessBrowserTest {
 public:
  ScreenLockerTest() : mock_screen_lock_library_(NULL),
                       mock_input_method_library_(NULL) {
  }

 protected:
  MockScreenLockLibrary *mock_screen_lock_library_;
  MockInputMethodLibrary *mock_input_method_library_;

  // Test the no password mode with different unlock scheme given by
  // |unlock| function.
  void TestNoPassword(void (unlock)(views::Widget*)) {
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    UserManager::Get()->OffTheRecordUserLoggedIn();
    ScreenLocker::Show();
    scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
    tester->EmulateWindowManagerReady();
    if (!chromeos::ScreenLocker::GetTester()->IsLocked())
      ui_test_utils::WaitForNotification(
          NotificationType::SCREEN_LOCK_STATE_CHANGED);
    EXPECT_TRUE(tester->IsLocked());
    tester->InjectMockAuthenticator("", "");

    unlock(tester->GetWidget());

    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_TRUE(tester->IsLocked());

    // Emulate LockScreen request from PowerManager (via SessionManager).
    ScreenLocker::Hide();
    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_FALSE(tester->IsLocked());
  }

 private:
  virtual void SetUpInProcessBrowserTestFixture() {
    cros_mock_->InitStatusAreaMocks();
    cros_mock_->InitMockScreenLockLibrary();
    mock_screen_lock_library_ = cros_mock_->mock_screen_lock_library();
    mock_input_method_library_ = cros_mock_->mock_input_method_library();
    EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_))
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    // Expectations for the status are on the screen lock window.
    cros_mock_->SetStatusAreaMocksExpectations();
    // Expectations for the status area on the browser window.
    cros_mock_->SetStatusAreaMocksExpectations();
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
    command_line->AppendSwitch(switches::kNoFirstRun);
  }

  DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest);
};

// PulseAudioMixer sometimes crashes at exit. See http://crosbug.om/9303
IN_PROC_BROWSER_TEST_F(ScreenLockerTest, FLAKY_TestBasic) {
  EXPECT_CALL(*mock_input_method_library_, GetNumActiveInputMethods())
      .Times(1)
      .WillRepeatedly((testing::Return(0)))
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  if (!chromeos::ScreenLocker::GetTester()->IsLocked())
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);

  // Test to make sure that the widget is actually appearing and is of
  // reasonable size, preventing a regression of
  // http://code.google.com/p/chromium-os/issues/detail?id=5987
  gfx::Rect lock_bounds;
  tester->GetChildWidget()->GetBounds(&lock_bounds, true);
  EXPECT_GT(lock_bounds.width(), 10);
  EXPECT_GT(lock_bounds.height(), 10);

  tester->InjectMockAuthenticator("user", "pass");
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("fail");
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  // Successful authentication simply send a unlock request to PowerManager.
  EXPECT_TRUE(tester->IsLocked());

  // Emulate LockScreen request from PowerManager (via SessionManager).
  // TODO(oshima): Find out better way to handle this in mock.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestFullscreenExit) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  {
    Waiter waiter(browser());
    browser()->ToggleFullscreenMode();
    waiter.Wait(false /* not locked */, true /* full screen */);
    EXPECT_TRUE(browser()->window()->IsFullscreen());
    EXPECT_FALSE(tester->IsLocked());
  }
  {
    Waiter waiter(browser());
    UserManager::Get()->UserLoggedIn("user");
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    waiter.Wait(true /* locked */, false /* full screen */);
    EXPECT_FALSE(browser()->window()->IsFullscreen());
    EXPECT_TRUE(tester->IsLocked());
  }
  tester->InjectMockAuthenticator("user", "pass");
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

void MouseMove(views::Widget* widget) {
  ui_controls::SendMouseMove(10, 10);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseMove) {
  TestNoPassword(MouseMove);
}

void MouseClick(views::Widget* widget) {
  ui_controls::SendMouseClick(ui_controls::RIGHT);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseClick) {
  TestNoPassword(MouseClick);
}

void KeyPress(views::Widget* widget) {
  ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()),
                            app::VKEY_SPACE, false, false, false, false);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithKeyPress) {
  TestNoPassword(KeyPress);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestShowTwice) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(2)
      .RetiresOnSaturation();

  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  if (!chromeos::ScreenLocker::GetTester()->IsLocked())
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);
  EXPECT_TRUE(tester->IsLocked());

  // Calling Show again simply send LockCompleted signal.
  ScreenLocker::Show();
  EXPECT_TRUE(tester->IsLocked());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prerender/prerender_interceptor.h"

#include <string>

#include "base/callback.h"
#include "base/file_path.h"
#include "base/message_loop_proxy.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/browser_thread.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_flags.h"
#include "net/test/test_server.h"
#include "net/url_request/url_request_unittest.h"

class PrerenderInterceptorTest : public testing::Test {
 public:
  PrerenderInterceptorTest();

  void MakeTestUrl(const std::string& base);
  virtual void SetUp();

  net::TestServer test_server_;
  GURL gurl_;
  GURL last_intercepted_gurl_;
  scoped_ptr<net::URLRequest> req_;
 private:
  void SetLastInterceptedGurl(const GURL& url);

  PrerenderInterceptor prerender_interceptor_;
  MessageLoopForIO io_loop_;
  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
  BrowserThread ui_thread_;
};

PrerenderInterceptorTest::PrerenderInterceptorTest()
    : test_server_(net::TestServer::TYPE_HTTP,
                   FilePath(FILE_PATH_LITERAL("chrome/test/data"))),
      last_intercepted_gurl_("http://not.initialized/"),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          prerender_interceptor_(
              NewCallback(this,
                          &PrerenderInterceptorTest::SetLastInterceptedGurl))),
      ui_thread_(BrowserThread::UI, &io_loop_) {
}

void PrerenderInterceptorTest::SetUp() {
  testing::Test::SetUp();
  last_intercepted_gurl_ = GURL("http://nothing.intercepted/");

  io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
  ASSERT_TRUE(test_server_.Start());
}

void PrerenderInterceptorTest::MakeTestUrl(const std::string& base) {
  gurl_ = test_server_.GetURL(base);
  req_.reset(new TestURLRequest(gurl_, new TestDelegate()));
}

void PrerenderInterceptorTest::SetLastInterceptedGurl(const GURL& url) {
  last_intercepted_gurl_ = url;
}

TEST_F(PrerenderInterceptorTest, Interception) {
  MakeTestUrl("files/prerender/doc1.html");
  req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
  req_->Start();

  MessageLoop::current()->Run();
  EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
  EXPECT_EQ(gurl_, last_intercepted_gurl_);
}

TEST_F(PrerenderInterceptorTest, NotAPrefetch) {
  MakeTestUrl("files/prerender/doc2.html");
  req_->set_load_flags(req_->load_flags() & ~net::LOAD_PREFETCH);
  req_->Start();

  MessageLoop::current()->Run();
  EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
  EXPECT_NE(gurl_, last_intercepted_gurl_);
}

TEST_F(PrerenderInterceptorTest, WrongMimeType) {
  MakeTestUrl("files/prerender/image.jpeg");
  req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
  req_->Start();

  MessageLoop::current()->Run();
  EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
  EXPECT_NE(gurl_, last_intercepted_gurl_);
}

<commit_msg>Disabling PrerenderInterceptorTests's due to memory leaks.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prerender/prerender_interceptor.h"

#include <string>

#include "base/callback.h"
#include "base/file_path.h"
#include "base/message_loop_proxy.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/browser_thread.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_flags.h"
#include "net/test/test_server.h"
#include "net/url_request/url_request_unittest.h"

class PrerenderInterceptorTest : public testing::Test {
 public:
  PrerenderInterceptorTest();

  void MakeTestUrl(const std::string& base);
  virtual void SetUp();

  net::TestServer test_server_;
  GURL gurl_;
  GURL last_intercepted_gurl_;
  scoped_ptr<net::URLRequest> req_;
 private:
  void SetLastInterceptedGurl(const GURL& url);

  PrerenderInterceptor prerender_interceptor_;
  MessageLoopForIO io_loop_;
  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
  BrowserThread ui_thread_;
};

PrerenderInterceptorTest::PrerenderInterceptorTest()
    : test_server_(net::TestServer::TYPE_HTTP,
                   FilePath(FILE_PATH_LITERAL("chrome/test/data"))),
      last_intercepted_gurl_("http://not.initialized/"),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          prerender_interceptor_(
              NewCallback(this,
                          &PrerenderInterceptorTest::SetLastInterceptedGurl))),
      ui_thread_(BrowserThread::UI, &io_loop_) {
}

void PrerenderInterceptorTest::SetUp() {
  testing::Test::SetUp();
  last_intercepted_gurl_ = GURL("http://nothing.intercepted/");

  io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
  ASSERT_TRUE(test_server_.Start());
}

void PrerenderInterceptorTest::MakeTestUrl(const std::string& base) {
  gurl_ = test_server_.GetURL(base);
  req_.reset(new TestURLRequest(gurl_, new TestDelegate()));
}

void PrerenderInterceptorTest::SetLastInterceptedGurl(const GURL& url) {
  last_intercepted_gurl_ = url;
}

// Temporarily disabling PrerenderInterceptorTest's due to a leak.
// I have a fix, but will land in the morning.
// http://crbug.com/65993
TEST_F(PrerenderInterceptorTest, DISABLED_Interception) {
  MakeTestUrl("files/prerender/doc1.html");
  req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
  req_->Start();

  MessageLoop::current()->Run();
  EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
  EXPECT_EQ(gurl_, last_intercepted_gurl_);
}

TEST_F(PrerenderInterceptorTest, DISABLED_NotAPrefetch) {
  MakeTestUrl("files/prerender/doc2.html");
  req_->set_load_flags(req_->load_flags() & ~net::LOAD_PREFETCH);
  req_->Start();

  MessageLoop::current()->Run();
  EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
  EXPECT_NE(gurl_, last_intercepted_gurl_);
}

TEST_F(PrerenderInterceptorTest, DISABLED_WrongMimeType) {
  MakeTestUrl("files/prerender/image.jpeg");
  req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
  req_->Start();

  MessageLoop::current()->Run();
  EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
  EXPECT_NE(gurl_, last_intercepted_gurl_);
}

<|endoftext|>


<commit_before>/*
 * ProbingPT.cpp
 *
 *  Created on: 3 Nov 2015
 *      Author: hieu
 */
#include <boost/foreach.hpp>
#include "ProbingPT.h"
#include "../System.h"
#include "../Scores.h"
#include "../Phrase.h"
#include "../legacy/InputFileStream.h"
#include "../legacy/ProbingPT/probing_hash_utils.hh"
#include "../FF/FeatureFunctions.h"
#include "../Search/Manager.h"
#include "../legacy/FactorCollection.h"
#include "../legacy/ProbingPT/quering.hh"
#include "../legacy/Util2.h"

using namespace std;

namespace Moses2
{

ProbingPT::ProbingPT(size_t startInd, const std::string &line)
:PhraseTable(startInd, line)
{
	  ReadParameters();
}

ProbingPT::~ProbingPT()
{
  delete m_engine;
}

void ProbingPT::Load(System &system)
{
  m_engine = new QueryEngine(m_path.c_str());

  m_unkId = 456456546456;

  FactorCollection &vocab = system.GetVocab();

  // source vocab
  const std::map<uint64_t, std::string> &sourceVocab = m_engine->getSourceVocab();
  std::map<uint64_t, std::string>::const_iterator iterSource;
  for (iterSource = sourceVocab.begin(); iterSource != sourceVocab.end(); ++iterSource) {
	const string &wordStr = iterSource->second;
	const Factor *factor = vocab.AddFactor(wordStr, system);

	uint64_t probingId = iterSource->first;
	size_t factorId = factor->GetId();

	if (factorId >= m_sourceVocab.size()) {
		m_sourceVocab.resize(factorId + 1, m_unkId);
	}
	m_sourceVocab[factorId] = probingId;
  }

  // target vocab
  InputFileStream targetVocabStrme(m_path + "/TargetVocab.dat");
  string line;
  while (getline(targetVocabStrme, line)) {
	  vector<string> toks = Tokenize(line, "\t");
	  assert(toks.size());
  	  const Factor *factor = vocab.AddFactor(toks[0], system);
  	  uint32_t probingId = Scan<uint32_t>(toks[1]);

  	  if (probingId >= m_targetVocab.size()) {
  		m_targetVocab.resize(probingId + 1, NULL);
  	  }
  	  m_targetVocab[probingId] = factor;
  }

  // memory mapped file to tps
  string filePath = m_path + "/TargetColl.dat";
  file.open(filePath.c_str());
  if (!file.is_open()) {
    throw "Couldn't open file ";
  }

  data = file.data();

  size_t size = file.size();

  // cache
  CreateCache(system);
}

void ProbingPT::Lookup(const Manager &mgr, InputPaths &inputPaths) const
{
  BOOST_FOREACH(InputPath *path, inputPaths) {
	TargetPhrases *tpsPtr;
	tpsPtr = Lookup(mgr, mgr.GetPool(), *path);
	path->AddTargetPhrases(*this, tpsPtr);
  }
}

TargetPhrases* ProbingPT::Lookup(const Manager &mgr,
		MemPool &pool,
		InputPath &inputPath) const
{
	/*
	if (inputPath.prefixPath && inputPath.prefixPath->GetTargetPhrases(*this) == NULL) {
		// assume all paths have prefixes, except rules with 1 word source
		return NULL;
	}
	else {
		const Phrase &sourcePhrase = inputPath.subPhrase;
		std::pair<TargetPhrases*, uint64_t> tpsAndKey = CreateTargetPhrase(pool, mgr.system, sourcePhrase);
		return tpsAndKey.first;
	}
	*/
	const Phrase &sourcePhrase = inputPath.subPhrase;

	// get hash for source phrase
	std::pair<bool, uint64_t> keyStruct = GetSourceProbingId(sourcePhrase);
	if (!keyStruct.first) {
	  return NULL;
	}

	// check in cache
	Cache::const_iterator iter = m_cache.find(keyStruct.second);
	if (iter != m_cache.end()) {
    	    cerr << "cache 1\n";
		TargetPhrases *tps = iter->second;
		return tps;
	}
        else {
          cerr << "cache 0\n";
        }

	// query pt
	TargetPhrases *tps = CreateTargetPhrase(pool, mgr.system, sourcePhrase, keyStruct.second);
	return tps;
}

std::pair<bool, uint64_t> ProbingPT::GetSourceProbingId(const Phrase &sourcePhrase) const
{
  std::pair<bool, uint64_t> ret;

  // create a target phrase from the 1st word of the source, prefix with 'ProbingPT:'
  size_t sourceSize = sourcePhrase.GetSize();
  assert(sourceSize);

  uint64_t probingSource[sourceSize];
  ConvertToProbingSourcePhrase(sourcePhrase, ret.first, probingSource);
  if (!ret.first) {
	// source phrase contains a word unknown in the pt.
	// We know immediately there's no translation for it
  }
  else {
	  ret.second = m_engine->getKey(probingSource, sourceSize);
  }

  return ret;

}

TargetPhrases *ProbingPT::CreateTargetPhrase(
		  MemPool &pool,
		  const System &system,
		  const Phrase &sourcePhrase,
		  uint64_t key) const
{
  TargetPhrases *tps = NULL;

  //Actual lookup
  std::pair<bool, uint64_t> query_result; // 1st=found, 2nd=target file offset
  query_result = m_engine->query(key);

  if (query_result.first) {
	  const char *offset = data + query_result.second;
	  uint64_t *numTP = (uint64_t*) offset;

	  tps = new (pool.Allocate<TargetPhrases>()) TargetPhrases(pool, *numTP);

	  offset += sizeof(uint64_t);
	  for (size_t i = 0; i < *numTP; ++i) {
		  TargetPhrase *tp = CreateTargetPhrase(pool, system, offset);
		  assert(tp);
		  const FeatureFunctions &ffs = system.featureFunctions;
		  ffs.EvaluateInIsolation(pool, system, sourcePhrase, *tp);

		  tps->AddTargetPhrase(*tp);

	  }

	  tps->SortAndPrune(m_tableLimit);
	  system.featureFunctions.EvaluateAfterTablePruning(pool, *tps, sourcePhrase);
	  //cerr << *tps << endl;
  }

  return tps;
}

TargetPhrase *ProbingPT::CreateTargetPhrase(
		  MemPool &pool,
		  const System &system,
		  const char *&offset) const
{
	TargetPhraseInfo *tpInfo = (TargetPhraseInfo*) offset;
    TargetPhrase *tp = new (pool.Allocate<TargetPhrase>()) TargetPhrase(pool, *this, system, tpInfo->numWords);

	offset += sizeof(TargetPhraseInfo);

	// scores
	SCORE *scores = (SCORE*) offset;

  size_t totalNumScores = m_engine->num_scores + m_engine->num_lex_scores;

  if (m_engine->logProb) {
	    // set pt score for rule
	    tp->GetScores().PlusEquals(system, *this, scores);

	    // save scores for other FF, eg. lex RO. Just give the offset
	    if (m_engine->num_lex_scores) {
		  tp->scoreProperties = scores + m_engine->num_scores;
	    }
  }
  else {
	  // log score 1st
	  SCORE logScores[totalNumScores];
	  for (size_t i = 0; i < totalNumScores; ++i) {
		  logScores[i] = FloorScore(TransformScore(scores[i]));
	  }

      // set pt score for rule
	  tp->GetScores().PlusEquals(system, *this, logScores);

      // save scores for other FF, eg. lex RO.
	  tp->scoreProperties = pool.Allocate<SCORE>(m_engine->num_lex_scores);
	  for (size_t i = 0; i < m_engine->num_lex_scores; ++i) {
		  tp->scoreProperties[i] = logScores[i + m_engine->num_scores];
	  }
  }

  offset += sizeof(SCORE) * totalNumScores;

  // words
  for (size_t i = 0; i < tpInfo->numWords; ++i) {
	  uint32_t *probingId = (uint32_t*) offset;

	  const Factor *factor = GetTargetFactor(*probingId);
	  assert(factor);

	  Word &word = (*tp)[i];
	  word[0] = factor;

	  offset += sizeof(uint32_t);
  }

  // properties TODO

  return tp;
}

void ProbingPT::ConvertToProbingSourcePhrase(const Phrase &sourcePhrase, bool &ok, uint64_t probingSource[]) const
{

  size_t size = sourcePhrase.GetSize();
  for (size_t i = 0; i < size; ++i) {
    const Factor *factor = sourcePhrase[i][0];
    uint64_t probingId = GetSourceProbingId(factor);
    if (probingId == m_unkId) {
      ok = false;
      return;
    } else {
      probingSource[i] = probingId;
    }
  }

  ok = true;
}

void ProbingPT::CreateCache(System &system)
{
	if (m_maxCacheSize == 0) {
		return;
	}

	string filePath = m_path + "/cache";
	InputFileStream strme(filePath);

	string line;
	getline(strme, line);
	//float totalCount = Scan<float>(line);

	MemPool &pool = system.GetSystemPool();
	FactorCollection &vocab = system.GetVocab();

	size_t lineCount = 0;
	while (getline(strme, line) && lineCount < m_maxCacheSize) {
		vector<string> toks = Tokenize(line, "\t");
		assert(toks.size() == 2);
		PhraseImpl *sourcePhrase = PhraseImpl::CreateFromString(pool, vocab, system, toks[1]);

		std::pair<bool, uint64_t> retStruct = GetSourceProbingId(*sourcePhrase);
		if (!retStruct.first) {
		  return;
		}

		TargetPhrases *tps = CreateTargetPhrase(pool, system, *sourcePhrase, retStruct.second);
		assert(tps);

		m_cache[retStruct.second] = tps;

		++lineCount;
	}

}

}

<commit_msg>Revert "debug cache"<commit_after>/*
 * ProbingPT.cpp
 *
 *  Created on: 3 Nov 2015
 *      Author: hieu
 */
#include <boost/foreach.hpp>
#include "ProbingPT.h"
#include "../System.h"
#include "../Scores.h"
#include "../Phrase.h"
#include "../legacy/InputFileStream.h"
#include "../legacy/ProbingPT/probing_hash_utils.hh"
#include "../FF/FeatureFunctions.h"
#include "../Search/Manager.h"
#include "../legacy/FactorCollection.h"
#include "../legacy/ProbingPT/quering.hh"
#include "../legacy/Util2.h"

using namespace std;

namespace Moses2
{

ProbingPT::ProbingPT(size_t startInd, const std::string &line)
:PhraseTable(startInd, line)
{
	  ReadParameters();
}

ProbingPT::~ProbingPT()
{
  delete m_engine;
}

void ProbingPT::Load(System &system)
{
  m_engine = new QueryEngine(m_path.c_str());

  m_unkId = 456456546456;

  FactorCollection &vocab = system.GetVocab();

  // source vocab
  const std::map<uint64_t, std::string> &sourceVocab = m_engine->getSourceVocab();
  std::map<uint64_t, std::string>::const_iterator iterSource;
  for (iterSource = sourceVocab.begin(); iterSource != sourceVocab.end(); ++iterSource) {
	const string &wordStr = iterSource->second;
	const Factor *factor = vocab.AddFactor(wordStr, system);

	uint64_t probingId = iterSource->first;
	size_t factorId = factor->GetId();

	if (factorId >= m_sourceVocab.size()) {
		m_sourceVocab.resize(factorId + 1, m_unkId);
	}
	m_sourceVocab[factorId] = probingId;
  }

  // target vocab
  InputFileStream targetVocabStrme(m_path + "/TargetVocab.dat");
  string line;
  while (getline(targetVocabStrme, line)) {
	  vector<string> toks = Tokenize(line, "\t");
	  assert(toks.size());
  	  const Factor *factor = vocab.AddFactor(toks[0], system);
  	  uint32_t probingId = Scan<uint32_t>(toks[1]);

  	  if (probingId >= m_targetVocab.size()) {
  		m_targetVocab.resize(probingId + 1, NULL);
  	  }
  	  m_targetVocab[probingId] = factor;
  }

  // memory mapped file to tps
  string filePath = m_path + "/TargetColl.dat";
  file.open(filePath.c_str());
  if (!file.is_open()) {
    throw "Couldn't open file ";
  }

  data = file.data();

  size_t size = file.size();

  // cache
  CreateCache(system);
}

void ProbingPT::Lookup(const Manager &mgr, InputPaths &inputPaths) const
{
  BOOST_FOREACH(InputPath *path, inputPaths) {
	TargetPhrases *tpsPtr;
	tpsPtr = Lookup(mgr, mgr.GetPool(), *path);
	path->AddTargetPhrases(*this, tpsPtr);
  }
}

TargetPhrases* ProbingPT::Lookup(const Manager &mgr,
		MemPool &pool,
		InputPath &inputPath) const
{
	/*
	if (inputPath.prefixPath && inputPath.prefixPath->GetTargetPhrases(*this) == NULL) {
		// assume all paths have prefixes, except rules with 1 word source
		return NULL;
	}
	else {
		const Phrase &sourcePhrase = inputPath.subPhrase;
		std::pair<TargetPhrases*, uint64_t> tpsAndKey = CreateTargetPhrase(pool, mgr.system, sourcePhrase);
		return tpsAndKey.first;
	}
	*/
	const Phrase &sourcePhrase = inputPath.subPhrase;

	// get hash for source phrase
	std::pair<bool, uint64_t> keyStruct = GetSourceProbingId(sourcePhrase);
	if (!keyStruct.first) {
	  return NULL;
	}

	// check in cache
	Cache::const_iterator iter = m_cache.find(keyStruct.second);
	if (iter != m_cache.end()) {
		TargetPhrases *tps = iter->second;
		return tps;
	}

	// query pt
	TargetPhrases *tps = CreateTargetPhrase(pool, mgr.system, sourcePhrase, keyStruct.second);
	return tps;
}

std::pair<bool, uint64_t> ProbingPT::GetSourceProbingId(const Phrase &sourcePhrase) const
{
  std::pair<bool, uint64_t> ret;

  // create a target phrase from the 1st word of the source, prefix with 'ProbingPT:'
  size_t sourceSize = sourcePhrase.GetSize();
  assert(sourceSize);

  uint64_t probingSource[sourceSize];
  ConvertToProbingSourcePhrase(sourcePhrase, ret.first, probingSource);
  if (!ret.first) {
	// source phrase contains a word unknown in the pt.
	// We know immediately there's no translation for it
  }
  else {
	  ret.second = m_engine->getKey(probingSource, sourceSize);
  }

  return ret;

}

TargetPhrases *ProbingPT::CreateTargetPhrase(
		  MemPool &pool,
		  const System &system,
		  const Phrase &sourcePhrase,
		  uint64_t key) const
{
  TargetPhrases *tps = NULL;

  //Actual lookup
  std::pair<bool, uint64_t> query_result; // 1st=found, 2nd=target file offset
  query_result = m_engine->query(key);

  if (query_result.first) {
	  const char *offset = data + query_result.second;
	  uint64_t *numTP = (uint64_t*) offset;

	  tps = new (pool.Allocate<TargetPhrases>()) TargetPhrases(pool, *numTP);

	  offset += sizeof(uint64_t);
	  for (size_t i = 0; i < *numTP; ++i) {
		  TargetPhrase *tp = CreateTargetPhrase(pool, system, offset);
		  assert(tp);
		  const FeatureFunctions &ffs = system.featureFunctions;
		  ffs.EvaluateInIsolation(pool, system, sourcePhrase, *tp);

		  tps->AddTargetPhrase(*tp);

	  }

	  tps->SortAndPrune(m_tableLimit);
	  system.featureFunctions.EvaluateAfterTablePruning(pool, *tps, sourcePhrase);
	  //cerr << *tps << endl;
  }

  return tps;
}

TargetPhrase *ProbingPT::CreateTargetPhrase(
		  MemPool &pool,
		  const System &system,
		  const char *&offset) const
{
	TargetPhraseInfo *tpInfo = (TargetPhraseInfo*) offset;
    TargetPhrase *tp = new (pool.Allocate<TargetPhrase>()) TargetPhrase(pool, *this, system, tpInfo->numWords);

	offset += sizeof(TargetPhraseInfo);

	// scores
	SCORE *scores = (SCORE*) offset;

  size_t totalNumScores = m_engine->num_scores + m_engine->num_lex_scores;

  if (m_engine->logProb) {
	    // set pt score for rule
	    tp->GetScores().PlusEquals(system, *this, scores);

	    // save scores for other FF, eg. lex RO. Just give the offset
	    if (m_engine->num_lex_scores) {
		  tp->scoreProperties = scores + m_engine->num_scores;
	    }
  }
  else {
	  // log score 1st
	  SCORE logScores[totalNumScores];
	  for (size_t i = 0; i < totalNumScores; ++i) {
		  logScores[i] = FloorScore(TransformScore(scores[i]));
	  }

      // set pt score for rule
	  tp->GetScores().PlusEquals(system, *this, logScores);

      // save scores for other FF, eg. lex RO.
	  tp->scoreProperties = pool.Allocate<SCORE>(m_engine->num_lex_scores);
	  for (size_t i = 0; i < m_engine->num_lex_scores; ++i) {
		  tp->scoreProperties[i] = logScores[i + m_engine->num_scores];
	  }
  }

  offset += sizeof(SCORE) * totalNumScores;

  // words
  for (size_t i = 0; i < tpInfo->numWords; ++i) {
	  uint32_t *probingId = (uint32_t*) offset;

	  const Factor *factor = GetTargetFactor(*probingId);
	  assert(factor);

	  Word &word = (*tp)[i];
	  word[0] = factor;

	  offset += sizeof(uint32_t);
  }

  // properties TODO

  return tp;
}

void ProbingPT::ConvertToProbingSourcePhrase(const Phrase &sourcePhrase, bool &ok, uint64_t probingSource[]) const
{

  size_t size = sourcePhrase.GetSize();
  for (size_t i = 0; i < size; ++i) {
    const Factor *factor = sourcePhrase[i][0];
    uint64_t probingId = GetSourceProbingId(factor);
    if (probingId == m_unkId) {
      ok = false;
      return;
    } else {
      probingSource[i] = probingId;
    }
  }

  ok = true;
}

void ProbingPT::CreateCache(System &system)
{
	if (m_maxCacheSize == 0) {
		return;
	}

	string filePath = m_path + "/cache";
	InputFileStream strme(filePath);

	string line;
	getline(strme, line);
	//float totalCount = Scan<float>(line);

	MemPool &pool = system.GetSystemPool();
	FactorCollection &vocab = system.GetVocab();

	size_t lineCount = 0;
	while (getline(strme, line) && lineCount < m_maxCacheSize) {
		vector<string> toks = Tokenize(line, "\t");
		assert(toks.size() == 2);
		PhraseImpl *sourcePhrase = PhraseImpl::CreateFromString(pool, vocab, system, toks[1]);

		std::pair<bool, uint64_t> retStruct = GetSourceProbingId(*sourcePhrase);
		if (!retStruct.first) {
		  return;
		}

		TargetPhrases *tps = CreateTargetPhrase(pool, system, *sourcePhrase, retStruct.second);
		assert(tps);

		m_cache[retStruct.second] = tps;

		++lineCount;
	}

}

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2002 - present, H. Hernan Saez
 * 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 the copyright holder 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 COPYRIGHT HOLDER 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 "Rendering/Compositions/TonemappingComposition.hpp"

#include "Rendering/CommandBuffer.hpp"
#include "Rendering/DescriptorSet.hpp"
#include "Rendering/Pipeline.hpp"
#include "Rendering/RenderPass.hpp"
#include "Rendering/Sampler.hpp"
#include "Rendering/ShaderProgram.hpp"
#include "Rendering/Texture.hpp"
#include "Rendering/UniformBuffer.hpp"
#include "Simulation/AssetManager.hpp"

using namespace crimild;
using namespace crimild::compositions;

Composition crimild::compositions::tonemapping( Composition cmp, crimild::Real32 exposure ) noexcept
{
    auto renderPass = cmp.create< RenderPass >();
    renderPass->attachments = {
        [ & ] {
            auto att = cmp.createAttachment( "tonemapping" );
            att->usage = Attachment::Usage::COLOR_ATTACHMENT;
            att->format = Format::R8G8B8A8_UNORM;
            att->imageView = crimild::alloc< ImageView >();
            att->imageView->image = crimild::alloc< Image >();
            return crimild::retain( att );
        }(),
    };

    renderPass->setDescriptors(
        [ & ] {
            auto descriptorSet = crimild::alloc< DescriptorSet >();
            descriptorSet->descriptors = {
                {
                    .descriptorType = DescriptorType::UNIFORM_BUFFER,
                    .obj = crimild::alloc< UniformBuffer >( exposure ),
                },
                {
                    .descriptorType = DescriptorType::TEXTURE,
                    .obj = [ & ] {
                        auto texture = crimild::alloc< Texture >();
                        texture->imageView = cmp.getOutput()->imageView;
                        texture->sampler = [] {
                            auto sampler = crimild::alloc< Sampler >();
                            sampler->setMinFilter( Sampler::Filter::NEAREST );
                            sampler->setMagFilter( Sampler::Filter::NEAREST );
                            return sampler;
                        }();
                        return texture;
                    }(),
                },
            };
            return descriptorSet;
        }() );

    renderPass->setGraphicsPipeline(
        [] {
            auto pipeline = crimild::alloc< GraphicsPipeline >();
            pipeline->setProgram(
                [] {
                    auto program = crimild::alloc< ShaderProgram >(
                        Array< SharedPointer< Shader > > {
                            crimild::alloc< Shader >(
                                Shader::Stage::VERTEX,
                                CRIMILD_TO_STRING(
                                    vec2 positions[ 6 ] = vec2[](
                                        vec2( -1.0, 1.0 ),
                                        vec2( -1.0, -1.0 ),
                                        vec2( 1.0, -1.0 ),

                                        vec2( -1.0, 1.0 ),
                                        vec2( 1.0, -1.0 ),
                                        vec2( 1.0, 1.0 ) );

                                    vec2 texCoords[ 6 ] = vec2[](
                                        vec2( 0.0, 0.0 ),
                                        vec2( 0.0, 1.0 ),
                                        vec2( 1.0, 1.0 ),

                                        vec2( 0.0, 0.0 ),
                                        vec2( 1.0, 1.0 ),
                                        vec2( 1.0, 0.0 ) );

                                    layout( location = 0 ) out vec2 outTexCoord;

                                    void main() {
                                        gl_Position = vec4( positions[ gl_VertexIndex ], 0.0, 1.0 );
                                        outTexCoord = texCoords[ gl_VertexIndex ];
                                    } ) ),
                                crimild::alloc< Shader >(
                                    Shader::Stage::FRAGMENT,
                                    CRIMILD_TO_STRING(
                                        layout( location = 0 ) in vec2 inTexCoord;

                                        layout( set = 0, binding = 0 ) uniform Uniforms {
                                            float exposure;
                                        };

                                        layout( set = 0, binding = 1 ) uniform sampler2D uHDRMap;

                                        layout( location = 0 ) out vec4 outColor;

                                        void main() {
                                            const float gamma = 2.2;

                                            // Reinhard tone mapping
                                            vec3 hdrColor = texture( uHDRMap, inTexCoord ).rgb;
                                            vec3 mapped = vec3( 1.0 ) - exp( -hdrColor * exposure );

                                            // Gamma correction
                                            mapped = pow( mapped, vec3( 1.0 / gamma ) );

                                            outColor = vec4( mapped, 1.0 );
                                        } ) ),
                        } );
                    program->descriptorSetLayouts = {
                        [] {
                            auto layout = crimild::alloc< DescriptorSetLayout >();
                            layout->bindings = {
                                {
                                    .descriptorType = DescriptorType::UNIFORM_BUFFER,
                                    .stage = Shader::Stage::FRAGMENT,
                                },
                                {
                                    .descriptorType = DescriptorType::TEXTURE,
                                    .stage = Shader::Stage::FRAGMENT,
                                },
                            };
                            return layout;
                        }(),
                    };
                    return program;
                }() );
            pipeline->viewport = { .scalingMode = ScalingMode::DYNAMIC };
            pipeline->scissor = { .scalingMode = ScalingMode::DYNAMIC };
            return pipeline;
        }() );

    renderPass->commands = [ & ] {
        auto commandBuffer = crimild::alloc< CommandBuffer >();
        commandBuffer->bindGraphicsPipeline( renderPass->getGraphicsPipeline() );
        commandBuffer->bindDescriptorSet( renderPass->getDescriptors() );
        commandBuffer->draw( 6 );
        return commandBuffer;
    }();

    cmp.setOutput( crimild::get_ptr( renderPass->attachments[ 0 ] ) );

    return cmp;
}
<commit_msg>Fix viewport dimensions in tonemapping composition<commit_after>/*
 * Copyright (c) 2002 - present, H. Hernan Saez
 * 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 the copyright holder 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 COPYRIGHT HOLDER 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 "Rendering/Compositions/TonemappingComposition.hpp"

#include "Rendering/CommandBuffer.hpp"
#include "Rendering/DescriptorSet.hpp"
#include "Rendering/Pipeline.hpp"
#include "Rendering/RenderPass.hpp"
#include "Rendering/Sampler.hpp"
#include "Rendering/ShaderProgram.hpp"
#include "Rendering/Texture.hpp"
#include "Rendering/UniformBuffer.hpp"
#include "Simulation/AssetManager.hpp"

using namespace crimild;
using namespace crimild::compositions;

Composition crimild::compositions::tonemapping( Composition cmp, crimild::Real32 exposure ) noexcept
{
    auto renderPass = cmp.create< RenderPass >();
    renderPass->attachments = {
        [ & ] {
            auto att = cmp.createAttachment( "tonemapping" );
            att->usage = Attachment::Usage::COLOR_ATTACHMENT;
            att->format = Format::R8G8B8A8_UNORM;
            att->imageView = crimild::alloc< ImageView >();
            att->imageView->image = crimild::alloc< Image >();
            return crimild::retain( att );
        }(),
    };

    renderPass->setDescriptors(
        [ & ] {
            auto descriptorSet = crimild::alloc< DescriptorSet >();
            descriptorSet->descriptors = {
                {
                    .descriptorType = DescriptorType::UNIFORM_BUFFER,
                    .obj = crimild::alloc< UniformBuffer >( exposure ),
                },
                {
                    .descriptorType = DescriptorType::TEXTURE,
                    .obj = [ & ] {
                        auto texture = crimild::alloc< Texture >();
                        texture->imageView = cmp.getOutput()->imageView;
                        texture->sampler = [] {
                            auto sampler = crimild::alloc< Sampler >();
                            sampler->setMinFilter( Sampler::Filter::NEAREST );
                            sampler->setMagFilter( Sampler::Filter::NEAREST );
                            return sampler;
                        }();
                        return texture;
                    }(),
                },
            };
            return descriptorSet;
        }() );

    renderPass->setGraphicsPipeline(
        [] {
            auto pipeline = crimild::alloc< GraphicsPipeline >();
            pipeline->setProgram(
                [] {
                    auto program = crimild::alloc< ShaderProgram >(
                        Array< SharedPointer< Shader > > {
                            crimild::alloc< Shader >(
                                Shader::Stage::VERTEX,
                                CRIMILD_TO_STRING(
                                    vec2 positions[ 6 ] = vec2[](
                                        vec2( -1.0, 1.0 ),
                                        vec2( -1.0, -1.0 ),
                                        vec2( 1.0, -1.0 ),

                                        vec2( -1.0, 1.0 ),
                                        vec2( 1.0, -1.0 ),
                                        vec2( 1.0, 1.0 ) );

                                    vec2 texCoords[ 6 ] = vec2[](
                                        vec2( 0.0, 0.0 ),
                                        vec2( 0.0, 1.0 ),
                                        vec2( 1.0, 1.0 ),

                                        vec2( 0.0, 0.0 ),
                                        vec2( 1.0, 1.0 ),
                                        vec2( 1.0, 0.0 ) );

                                    layout( location = 0 ) out vec2 outTexCoord;

                                    void main() {
                                        gl_Position = vec4( positions[ gl_VertexIndex ], 0.0, 1.0 );
                                        outTexCoord = texCoords[ gl_VertexIndex ];
                                    } ) ),
                                crimild::alloc< Shader >(
                                    Shader::Stage::FRAGMENT,
                                    CRIMILD_TO_STRING(
                                        layout( location = 0 ) in vec2 inTexCoord;

                                        layout( set = 0, binding = 0 ) uniform Uniforms {
                                            float exposure;
                                        };

                                        layout( set = 0, binding = 1 ) uniform sampler2D uHDRMap;

                                        layout( location = 0 ) out vec4 outColor;

                                        void main() {
                                            const float gamma = 2.2;

                                            // Reinhard tone mapping
                                            vec3 hdrColor = texture( uHDRMap, inTexCoord ).rgb;
                                            vec3 mapped = vec3( 1.0 ) - exp( -hdrColor * exposure );

                                            // Gamma correction
                                            mapped = pow( mapped, vec3( 1.0 / gamma ) );

                                            outColor = vec4( mapped, 1.0 );
                                        } ) ),
                        } );
                    program->descriptorSetLayouts = {
                        [] {
                            auto layout = crimild::alloc< DescriptorSetLayout >();
                            layout->bindings = {
                                {
                                    .descriptorType = DescriptorType::UNIFORM_BUFFER,
                                    .stage = Shader::Stage::FRAGMENT,
                                },
                                {
                                    .descriptorType = DescriptorType::TEXTURE,
                                    .stage = Shader::Stage::FRAGMENT,
                                },
                            };
                            return layout;
                        }(),
                    };
                    return program;
                }() );
            pipeline->viewport = { .scalingMode = ScalingMode::DYNAMIC };
            pipeline->scissor = { .scalingMode = ScalingMode::DYNAMIC };
            return pipeline;
        }() );

    auto viewport = ViewportDimensions {
        .scalingMode = ScalingMode::RELATIVE,
    };

    renderPass->commands = [ & ] {
        auto commandBuffer = crimild::alloc< CommandBuffer >();
        commandBuffer->setViewport( viewport );
        commandBuffer->setScissor( viewport );
        commandBuffer->bindGraphicsPipeline( renderPass->getGraphicsPipeline() );
        commandBuffer->bindDescriptorSet( renderPass->getDescriptors() );
        commandBuffer->draw( 6 );
        return commandBuffer;
    }();

    cmp.setOutput( crimild::get_ptr( renderPass->attachments[ 0 ] ) );

    return cmp;
}
<|endoftext|>


<commit_before>#include "EventDialog.h"
#include "ui_EventDialog.h"

#include <QDebug>
#include <QLineEdit>
#include <QPushButton>
#include <QSqlRelationalDelegate>
#include <QSqlRelationalTableModel>
#include <QTableView>

// TODO Get the columns from the Database class
enum EventColumn {
    IDColumn = 0,
    TypeColumn = 1,
    ConversationColumn = 2,
    CharacterColumn = 3,
    AudioFileColumn = 4,
    TextColumn = 5
};

EventDialog::EventDialog(QWidget *parent) :
    QDialog(parent), ui(new Ui::EventDialog), m_row(0), m_result(0), m_delegate(new QSqlRelationalDelegate(this))
{
    ui->setupUi(this);

    m_columnToComboBoxMap.insert(TypeColumn, ui->typeComboBox);
    m_columnToComboBoxMap.insert(ConversationColumn, ui->conversationComboBox);
    m_columnToComboBoxMap.insert(CharacterColumn, ui->characterComboBox);
    m_columnToComboBoxMap.insert(AudioFileColumn, ui->audioFileComboBox);

    connect(ui->typeComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(changedEventType(QString)));

    foreach(QComboBox *comboBox, m_columnToComboBoxMap) {
        connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkWriteReady()));
        connect(comboBox, SIGNAL(editTextChanged(QString)), this, SLOT(checkWriteReady()));
    }
    connect(ui->textEdit, SIGNAL(textChanged()), this, SLOT(checkWriteReady()));

    checkWriteReady();
}

void EventDialog::changedEventType(const QString &eventType)
{
    // TODO Maybe change the event entry box depending event type?
    ui->eventTypeGroupBox->setTitle(eventType);
}

void EventDialog::accept()
{
    // Manually set the result first so it's propogated to the delegate before closing
    setResult(QDialog::Accepted);
    done(QDialog::Accepted);
}

EventDialog::~EventDialog()
{
    delete ui;
}

void EventDialog::setModelRow(QSqlRelationalTableModel *model, int row) {
    m_row = row;
    m_model = model;

    foreach(QComboBox *comboBox, m_columnToComboBoxMap)
        setupComboBox(comboBox);

    setupTextEdit(ui->textEdit);
}

void EventDialog::writeToModel() {
    foreach(QComboBox *comboBox, m_columnToComboBoxMap)
        writeComboBox(comboBox);

    writeTextEdit(ui->textEdit);
}

void EventDialog::setupComboBox(QComboBox *comboBox) {
    Q_ASSERT(comboBox);
    if (!comboBox)
        return;

    const int comboBoxColumn = m_columnToComboBoxMap.key(comboBox);
    const QModelIndex index = m_model->index(m_row, comboBoxColumn);
    QWidget *delegateWidget = m_delegate->createEditor(this, QStyleOptionViewItem(), index);
    QComboBox *delegateComboBox = qobject_cast<QComboBox*>(delegateWidget);
    Q_ASSERT(delegateComboBox);
    if (!delegateComboBox)
        return;
    m_delegate->setEditorData(delegateComboBox, index);

    QAbstractItemModel *abstractModel = delegateComboBox->model();
    QSqlTableModel *model = qobject_cast<QSqlTableModel*>(abstractModel);
    Q_ASSERT(model);
    if (!model)
        return;

    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    comboBox->setModel(model);
    comboBox->setModelColumn(delegateComboBox->modelColumn());
    comboBox->setCurrentIndex(delegateComboBox->currentIndex());

    delete delegateComboBox;
}

void EventDialog::setupTextEdit(QTextEdit *textEdit) {
    const QModelIndex index = m_model->index(m_row, TextColumn);
    QWidget *delegateWidget = m_delegate->createEditor(this, QStyleOptionViewItem(), index);
    QLineEdit *delegateLineEdit = qobject_cast<QLineEdit*>(delegateWidget);
    Q_ASSERT(delegateLineEdit);
    if (!delegateLineEdit)
        return;
    m_delegate->setEditorData(delegateLineEdit, index);

    textEdit->setText(delegateLineEdit->text());

    delete delegateLineEdit;
}

void EventDialog::writeComboBox(QComboBox *comboBox) {
    Q_ASSERT(comboBox);
    if (!comboBox)
        return;

    QSqlTableModel *relationModel = qobject_cast<QSqlTableModel*>(comboBox->model());
    Q_ASSERT(relationModel);
    if (!relationModel)
        return;

    // Need to get text before writing new items as the combobox
    // index can be reset afterwards.
    const QString &comboBoxText = comboBox->currentText();
    relationModel->submitAll();
    const int comboBoxRow = comboBox->findText(comboBoxText);
    comboBox->setCurrentIndex(comboBoxRow);

    // A hacky but successful way to clear the model's relation cache.
    const QSqlTableModel::EditStrategy editStrategy = m_model->editStrategy();
    Q_ASSERT(editStrategy != QSqlTableModel::OnManualSubmit);
    m_model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    m_model->submitAll();
    m_model->setEditStrategy(editStrategy);

    const int comboBoxColumn = m_columnToComboBoxMap.key(comboBox);
    const QModelIndex index = m_model->index(m_row, comboBoxColumn);
    m_delegate->setModelData(comboBox, m_model, index);
}

void EventDialog::writeTextEdit(QTextEdit *textEdit) {
    QLineEdit *lineEdit = new QLineEdit(textEdit->toPlainText(), this);
    const QModelIndex index = m_model->index(m_row, TextColumn);
    m_delegate->setModelData(lineEdit, m_model, index);
    delete lineEdit;
}

void EventDialog::checkWriteReady() {
    bool isReadyToWrite = true;

    foreach(QComboBox *comboBox, m_columnToComboBoxMap)
        if (comboBox->currentIndex() == -1 || comboBox->currentText().isEmpty()) {
            isReadyToWrite = false;
            break;
        }

    if (isReadyToWrite && ui->textEdit->toPlainText().isEmpty())
        isReadyToWrite = false;

    QPushButton *ok = ui->buttonBox->button(QDialogButtonBox::Ok);
    Q_ASSERT(ok);
    if (ok)
        ok->setEnabled(isReadyToWrite);
}
<commit_msg>Fix adding new events.<commit_after>#include "EventDialog.h"
#include "ui_EventDialog.h"

#include <QDebug>
#include <QLineEdit>
#include <QPushButton>
#include <QSqlRelationalDelegate>
#include <QSqlRelationalTableModel>
#include <QTableView>

// TODO Get the columns from the Database class
enum EventColumn {
    IDColumn = 0,
    TypeColumn = 1,
    ConversationColumn = 2,
    CharacterColumn = 3,
    AudioFileColumn = 4,
    TextColumn = 5
};

EventDialog::EventDialog(QWidget *parent) :
    QDialog(parent), ui(new Ui::EventDialog), m_row(0), m_result(0), m_delegate(new QSqlRelationalDelegate(this))
{
    ui->setupUi(this);

    m_columnToComboBoxMap.insert(TypeColumn, ui->typeComboBox);
    m_columnToComboBoxMap.insert(ConversationColumn, ui->conversationComboBox);
    m_columnToComboBoxMap.insert(CharacterColumn, ui->characterComboBox);
    m_columnToComboBoxMap.insert(AudioFileColumn, ui->audioFileComboBox);

    connect(ui->typeComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(changedEventType(QString)));

    foreach(QComboBox *comboBox, m_columnToComboBoxMap) {
        connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkWriteReady()));
        connect(comboBox, SIGNAL(editTextChanged(QString)), this, SLOT(checkWriteReady()));
    }
    connect(ui->textEdit, SIGNAL(textChanged()), this, SLOT(checkWriteReady()));

    checkWriteReady();
}

void EventDialog::changedEventType(const QString &eventType)
{
    // TODO Maybe change the event entry box depending event type?
    ui->eventTypeGroupBox->setTitle(eventType);
}

void EventDialog::accept()
{
    // Manually set the result first so it's propogated to the delegate before closing
    setResult(QDialog::Accepted);
    done(QDialog::Accepted);
}

EventDialog::~EventDialog()
{
    delete ui;
}

void EventDialog::setModelRow(QSqlRelationalTableModel *model, int row) {
    m_row = row;
    m_model = model;

    foreach(QComboBox *comboBox, m_columnToComboBoxMap)
        setupComboBox(comboBox);

    setupTextEdit(ui->textEdit);
}

void EventDialog::writeToModel() {
    foreach(QComboBox *comboBox, m_columnToComboBoxMap)
        writeComboBox(comboBox);

    writeTextEdit(ui->textEdit);
}

void EventDialog::setupComboBox(QComboBox *comboBox) {
    Q_ASSERT(comboBox);
    if (!comboBox)
        return;

    const int comboBoxColumn = m_columnToComboBoxMap.key(comboBox);
    QModelIndex index = m_model->index(m_row, comboBoxColumn);
    if (!index.isValid()) {
        // If this index is invalid, we're probably creating new
        // data so try the previous row
        index = m_model->index(m_row-1, comboBoxColumn);
        Q_ASSERT(index.isValid());
        if (!index.isValid())
            return;
    }
    QWidget *delegateWidget = m_delegate->createEditor(this, QStyleOptionViewItem(), index);
    QComboBox *delegateComboBox = qobject_cast<QComboBox*>(delegateWidget);
    Q_ASSERT(delegateComboBox);
    if (!delegateComboBox)
        return;
    m_delegate->setEditorData(delegateComboBox, index);

    QAbstractItemModel *abstractModel = delegateComboBox->model();
    QSqlTableModel *model = qobject_cast<QSqlTableModel*>(abstractModel);
    Q_ASSERT(model);
    if (!model)
        return;

    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    comboBox->setModel(model);
    comboBox->setModelColumn(delegateComboBox->modelColumn());
    comboBox->setCurrentIndex(delegateComboBox->currentIndex());

    delete delegateComboBox;
}

void EventDialog::setupTextEdit(QTextEdit *textEdit) {
    QModelIndex index = m_model->index(m_row, TextColumn);
    if (!index.isValid())
        return;
    QWidget *delegateWidget = m_delegate->createEditor(this, QStyleOptionViewItem(), index);
    QLineEdit *delegateLineEdit = qobject_cast<QLineEdit*>(delegateWidget);
    Q_ASSERT(delegateLineEdit);
    if (!delegateLineEdit)
        return;
    m_delegate->setEditorData(delegateLineEdit, index);

    textEdit->setText(delegateLineEdit->text());

    delete delegateLineEdit;
}

void EventDialog::writeComboBox(QComboBox *comboBox) {
    Q_ASSERT(comboBox);
    if (!comboBox)
        return;

    QSqlTableModel *relationModel = qobject_cast<QSqlTableModel*>(comboBox->model());
    Q_ASSERT(relationModel);
    if (!relationModel)
        return;

    // Need to get text before writing new items as the combobox
    // index can be reset afterwards.
    const QString &comboBoxText = comboBox->currentText();
    relationModel->submitAll();
    const int comboBoxRow = comboBox->findText(comboBoxText);
    comboBox->setCurrentIndex(comboBoxRow);

    // A hacky but successful way to clear the model's relation cache.
    const QSqlTableModel::EditStrategy editStrategy = m_model->editStrategy();
    Q_ASSERT(editStrategy != QSqlTableModel::OnManualSubmit);
    m_model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    m_model->submitAll();
    m_model->setEditStrategy(editStrategy);

    const int comboBoxColumn = m_columnToComboBoxMap.key(comboBox);
    const QModelIndex index = m_model->index(m_row, comboBoxColumn);
    m_delegate->setModelData(comboBox, m_model, index);
}

void EventDialog::writeTextEdit(QTextEdit *textEdit) {
    QLineEdit *lineEdit = new QLineEdit(textEdit->toPlainText(), this);
    const QModelIndex index = m_model->index(m_row, TextColumn);
    m_delegate->setModelData(lineEdit, m_model, index);
    delete lineEdit;
}

void EventDialog::checkWriteReady() {
    bool isReadyToWrite = true;

    foreach(QComboBox *comboBox, m_columnToComboBoxMap)
        if (comboBox->currentIndex() == -1 || comboBox->currentText().isEmpty()) {
            isReadyToWrite = false;
            break;
        }

    if (isReadyToWrite && ui->textEdit->toPlainText().isEmpty())
        isReadyToWrite = false;

    QPushButton *ok = ui->buttonBox->button(QDialogButtonBox::Ok);
    Q_ASSERT(ok);
    if (ok)
        ok->setEnabled(isReadyToWrite);
}
<|endoftext|>