FindDialog.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Copyright (c) 2021-2022, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "FindDialog.h"
  7. #include <AK/Array.h>
  8. #include <AK/Hex.h>
  9. #include <AK/String.h>
  10. #include <AK/StringView.h>
  11. #include <Applications/HexEditor/FindDialogGML.h>
  12. #include <LibGUI/BoxLayout.h>
  13. #include <LibGUI/Button.h>
  14. #include <LibGUI/MessageBox.h>
  15. #include <LibGUI/RadioButton.h>
  16. #include <LibGUI/TextBox.h>
  17. #include <LibGUI/Widget.h>
  18. struct Option {
  19. StringView title;
  20. OptionId opt;
  21. bool enabled;
  22. bool default_action;
  23. };
  24. static constexpr Array<Option, 2> options = {
  25. {
  26. { "ASCII String", OPTION_ASCII_STRING, true, true },
  27. { "Hex value", OPTION_HEX_VALUE, true, false },
  28. }
  29. };
  30. GUI::Dialog::ExecResult FindDialog::show(GUI::Window* parent_window, String& out_text, ByteBuffer& out_buffer, bool& find_all)
  31. {
  32. auto dialog = FindDialog::construct();
  33. if (parent_window)
  34. dialog->set_icon(parent_window->icon());
  35. if (!out_text.is_empty() && !out_text.is_null())
  36. dialog->m_text_editor->set_text(out_text);
  37. dialog->m_find_button->set_enabled(!dialog->m_text_editor->text().is_empty());
  38. dialog->m_find_all_button->set_enabled(!dialog->m_text_editor->text().is_empty());
  39. auto result = dialog->exec();
  40. if (result != ExecResult::OK)
  41. return result;
  42. auto selected_option = dialog->selected_option();
  43. auto processed = dialog->process_input(dialog->text_value(), selected_option);
  44. out_text = dialog->text_value();
  45. if (processed.is_error()) {
  46. GUI::MessageBox::show_error(parent_window, processed.error());
  47. result = ExecResult::Aborted;
  48. } else {
  49. out_buffer = move(processed.value());
  50. }
  51. find_all = dialog->find_all();
  52. dbgln("Find: value={} option={} find_all={}", out_text.characters(), (int)selected_option, find_all);
  53. return result;
  54. }
  55. Result<ByteBuffer, String> FindDialog::process_input(String text_value, OptionId opt)
  56. {
  57. dbgln("process_input opt={}", (int)opt);
  58. switch (opt) {
  59. case OPTION_ASCII_STRING: {
  60. if (text_value.is_empty())
  61. return String("Input is empty");
  62. return text_value.to_byte_buffer();
  63. }
  64. case OPTION_HEX_VALUE: {
  65. auto decoded = decode_hex(text_value.replace(" ", "", true));
  66. if (decoded.is_error())
  67. return String::formatted("Input is invalid: {}", decoded.error().string_literal());
  68. return decoded.value();
  69. }
  70. default:
  71. VERIFY_NOT_REACHED();
  72. }
  73. }
  74. FindDialog::FindDialog()
  75. : Dialog(nullptr)
  76. {
  77. resize(280, 146);
  78. center_on_screen();
  79. set_resizable(false);
  80. set_title("Find");
  81. auto& main_widget = set_main_widget<GUI::Widget>();
  82. if (!main_widget.load_from_gml(find_dialog_gml))
  83. VERIFY_NOT_REACHED();
  84. m_text_editor = *main_widget.find_descendant_of_type_named<GUI::TextBox>("text_editor");
  85. m_find_button = *main_widget.find_descendant_of_type_named<GUI::Button>("find_button");
  86. m_find_all_button = *main_widget.find_descendant_of_type_named<GUI::Button>("find_all_button");
  87. m_cancel_button = *main_widget.find_descendant_of_type_named<GUI::Button>("cancel_button");
  88. auto& radio_container = *main_widget.find_descendant_of_type_named<GUI::Widget>("radio_container");
  89. for (size_t i = 0; i < options.size(); i++) {
  90. auto action = options[i];
  91. auto& radio = radio_container.add<GUI::RadioButton>();
  92. radio.set_enabled(action.enabled);
  93. radio.set_text(action.title);
  94. radio.on_checked = [this, i](auto) {
  95. m_selected_option = options[i].opt;
  96. };
  97. if (action.default_action) {
  98. radio.set_checked(true);
  99. m_selected_option = options[i].opt;
  100. }
  101. }
  102. m_text_editor->on_change = [this]() {
  103. m_find_button->set_enabled(!m_text_editor->text().is_empty());
  104. m_find_all_button->set_enabled(!m_text_editor->text().is_empty());
  105. };
  106. m_text_editor->on_return_pressed = [this] {
  107. m_find_button->click();
  108. };
  109. m_find_button->on_click = [this](auto) {
  110. auto text = m_text_editor->text();
  111. if (!text.is_empty()) {
  112. m_text_value = text;
  113. done(ExecResult::OK);
  114. }
  115. };
  116. m_find_all_button->on_click = [this](auto) {
  117. m_find_all = true;
  118. m_find_button->click();
  119. };
  120. m_cancel_button->on_click = [this](auto) {
  121. done(ExecResult::Cancel);
  122. };
  123. }