1 // Copyright 2018 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <QDialogButtonBox>
6 #include <QLabel>
7 #include <QLineEdit>
8 #include <QMessageBox>
9 #include <QString>
10 #include <QVBoxLayout>
11 #include "citra_qt/applets/swkbd.h"
12
QtKeyboardValidator(QtKeyboard * keyboard_)13 QtKeyboardValidator::QtKeyboardValidator(QtKeyboard* keyboard_) : keyboard(keyboard_) {}
14
validate(QString & input,int & pos) const15 QtKeyboardValidator::State QtKeyboardValidator::validate(QString& input, int& pos) const {
16 if (keyboard->ValidateFilters(input.toStdString()) == Frontend::ValidationError::None) {
17 if (input.size() > keyboard->config.max_text_length)
18 return State::Invalid;
19 return State::Acceptable;
20 } else {
21 return State::Invalid;
22 }
23 }
24
QtKeyboardDialog(QWidget * parent,QtKeyboard * keyboard_)25 QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_)
26 : QDialog(parent), keyboard(keyboard_) {
27 using namespace Frontend;
28 const auto config = keyboard->config;
29 layout = new QVBoxLayout;
30 label = new QLabel(QString::fromStdString(config.hint_text));
31 line_edit = new QLineEdit;
32 line_edit->setValidator(new QtKeyboardValidator(keyboard));
33 buttons = new QDialogButtonBox;
34 // Initialize buttons
35 switch (config.button_config) {
36 case ButtonConfig::Triple:
37 buttons->addButton(config.button_text[1].empty()
38 ? tr(SWKBD_BUTTON_FORGOT)
39 : QString::fromStdString(config.button_text[1]),
40 QDialogButtonBox::ButtonRole::HelpRole);
41 [[fallthrough]];
42 case ButtonConfig::Dual:
43 buttons->addButton(config.button_text[0].empty()
44 ? tr(SWKBD_BUTTON_CANCEL)
45 : QString::fromStdString(config.button_text[0]),
46 QDialogButtonBox::ButtonRole::RejectRole);
47 [[fallthrough]];
48 case ButtonConfig::Single:
49 buttons->addButton(config.button_text[2].empty()
50 ? tr(SWKBD_BUTTON_OKAY)
51 : QString::fromStdString(config.button_text[2]),
52 QDialogButtonBox::ButtonRole::AcceptRole);
53 break;
54 case ButtonConfig::None:
55 break;
56 }
57 connect(buttons, &QDialogButtonBox::accepted, this, [=] { Submit(); });
58 connect(buttons, &QDialogButtonBox::rejected, this, [=] {
59 button = QtKeyboard::cancel_id;
60 accept();
61 });
62 connect(buttons, &QDialogButtonBox::helpRequested, this, [=] {
63 button = QtKeyboard::forgot_id;
64 accept();
65 });
66 layout->addWidget(label);
67 layout->addWidget(line_edit);
68 layout->addWidget(buttons);
69 setLayout(layout);
70 }
71
Submit()72 void QtKeyboardDialog::Submit() {
73 auto error = keyboard->ValidateInput(line_edit->text().toStdString());
74 if (error != Frontend::ValidationError::None) {
75 HandleValidationError(error);
76 } else {
77 button = keyboard->ok_id;
78 text = line_edit->text();
79 accept();
80 }
81 }
82
HandleValidationError(Frontend::ValidationError error)83 void QtKeyboardDialog::HandleValidationError(Frontend::ValidationError error) {
84 using namespace Frontend;
85 const std::unordered_map<ValidationError, QString> VALIDATION_ERROR_MESSAGES = {
86 {ValidationError::FixedLengthRequired,
87 tr("Text length is not correct (should be %1 characters)")
88 .arg(keyboard->config.max_text_length)},
89 {ValidationError::MaxLengthExceeded,
90 tr("Text is too long (should be no more than %1 characters)")
91 .arg(keyboard->config.max_text_length)},
92 {ValidationError::BlankInputNotAllowed, tr("Blank input is not allowed")},
93 {ValidationError::EmptyInputNotAllowed, tr("Empty input is not allowed")},
94 };
95 QMessageBox::critical(this, tr("Validation error"), VALIDATION_ERROR_MESSAGES.at(error));
96 }
97
QtKeyboard(QWidget & parent_)98 QtKeyboard::QtKeyboard(QWidget& parent_) : parent(parent_) {}
99
Execute(const Frontend::KeyboardConfig & config)100 void QtKeyboard::Execute(const Frontend::KeyboardConfig& config) {
101 SoftwareKeyboard::Execute(config);
102 if (this->config.button_config != Frontend::ButtonConfig::None) {
103 ok_id = static_cast<u8>(this->config.button_config);
104 }
105 QMetaObject::invokeMethod(this, "OpenInputDialog", Qt::BlockingQueuedConnection);
106 Finalize(result_text, result_button);
107 }
108
ShowError(const std::string & error)109 void QtKeyboard::ShowError(const std::string& error) {
110 QString message = QString::fromStdString(error);
111 QMetaObject::invokeMethod(this, "ShowErrorDialog", Qt::BlockingQueuedConnection,
112 Q_ARG(QString, message));
113 }
114
OpenInputDialog()115 void QtKeyboard::OpenInputDialog() {
116 QtKeyboardDialog dialog(&parent, this);
117 dialog.setWindowFlags(dialog.windowFlags() &
118 ~(Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint));
119 dialog.setWindowModality(Qt::WindowModal);
120 dialog.exec();
121
122 result_text = dialog.text.toStdString();
123 result_button = dialog.button;
124 LOG_INFO(Frontend, "SWKBD input dialog finished, text={}, button={}", result_text,
125 result_button);
126 }
127
ShowErrorDialog(QString message)128 void QtKeyboard::ShowErrorDialog(QString message) {
129 QMessageBox::critical(&parent, tr("Software Keyboard"), message);
130 }
131