|
| 1 | +#include "Locator.h" |
| 2 | +#include "Project.h" |
| 3 | +#include <LibGUI/GBoxLayout.h> |
| 4 | +#include <LibGUI/GTableView.h> |
| 5 | +#include <LibGUI/GTextBox.h> |
| 6 | +#include <LibGUI/GWindow.h> |
| 7 | + |
| 8 | +extern RefPtr<Project> g_project; |
| 9 | +extern void open_file(const String&); |
| 10 | +static RefPtr<GraphicsBitmap> s_file_icon; |
| 11 | + |
| 12 | +class LocatorSuggestionModel final : public GModel { |
| 13 | +public: |
| 14 | + explicit LocatorSuggestionModel(Vector<String>&& suggestions) |
| 15 | + : m_suggestions(move(suggestions)) |
| 16 | + { |
| 17 | + } |
| 18 | + |
| 19 | + enum Column { |
| 20 | + Icon, |
| 21 | + Name, |
| 22 | + __Column_Count, |
| 23 | + }; |
| 24 | + virtual int row_count(const GModelIndex& = GModelIndex()) const override { return m_suggestions.size(); } |
| 25 | + virtual int column_count(const GModelIndex& = GModelIndex()) const override { return Column::__Column_Count; } |
| 26 | + virtual GVariant data(const GModelIndex& index, Role role = Role::Display) const override |
| 27 | + { |
| 28 | + auto& suggestion = m_suggestions.at(index.row()); |
| 29 | + if (role == Role::Display) { |
| 30 | + if (index.column() == Column::Name) |
| 31 | + return suggestion; |
| 32 | + if (index.column() == Column::Icon) { |
| 33 | + if (!s_file_icon) { |
| 34 | + s_file_icon = GraphicsBitmap::load_from_file("/res/icons/16x16/filetype-unknown.png"); |
| 35 | + } |
| 36 | + return *s_file_icon; |
| 37 | + } |
| 38 | + } |
| 39 | + return {}; |
| 40 | + } |
| 41 | + virtual void update() override {}; |
| 42 | + |
| 43 | +private: |
| 44 | + Vector<String> m_suggestions; |
| 45 | +}; |
| 46 | + |
| 47 | +class LocatorTextBox final : public GTextBox { |
| 48 | + C_OBJECT(LocatorTextBox) |
| 49 | +public: |
| 50 | + virtual ~LocatorTextBox() override {} |
| 51 | + |
| 52 | + Function<void()> on_up; |
| 53 | + Function<void()> on_down; |
| 54 | + |
| 55 | + virtual void keydown_event(GKeyEvent& event) override |
| 56 | + { |
| 57 | + if (event.key() == Key_Up) |
| 58 | + on_up(); |
| 59 | + else if (event.key() == Key_Down) |
| 60 | + on_down(); |
| 61 | + |
| 62 | + GTextBox::keydown_event(event); |
| 63 | + } |
| 64 | + |
| 65 | +private: |
| 66 | + LocatorTextBox(GWidget* parent) |
| 67 | + : GTextBox(parent) |
| 68 | + { |
| 69 | + } |
| 70 | +}; |
| 71 | + |
| 72 | +Locator::Locator(GWidget* parent) |
| 73 | + : GWidget(parent) |
| 74 | +{ |
| 75 | + set_layout(make<GBoxLayout>(Orientation::Vertical)); |
| 76 | + set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); |
| 77 | + set_preferred_size(0, 20); |
| 78 | + m_textbox = LocatorTextBox::construct(this); |
| 79 | + m_textbox->on_change = [this] { |
| 80 | + update_suggestions(); |
| 81 | + }; |
| 82 | + m_textbox->on_escape_pressed = [this] { |
| 83 | + m_popup_window->hide(); |
| 84 | + }; |
| 85 | + m_textbox->on_up = [this] { |
| 86 | + GModelIndex new_index = m_suggestion_view->selection().first(); |
| 87 | + if (new_index.is_valid()) |
| 88 | + new_index = m_suggestion_view->model()->index(new_index.row() - 1); |
| 89 | + else |
| 90 | + new_index = m_suggestion_view->model()->index(0); |
| 91 | + |
| 92 | + if (new_index.is_valid()) |
| 93 | + m_suggestion_view->selection().set(new_index); |
| 94 | + }; |
| 95 | + m_textbox->on_down = [this] { |
| 96 | + GModelIndex new_index = m_suggestion_view->selection().first(); |
| 97 | + if (new_index.is_valid()) |
| 98 | + new_index = m_suggestion_view->model()->index(new_index.row() + 1); |
| 99 | + else |
| 100 | + new_index = m_suggestion_view->model()->index(0); |
| 101 | + |
| 102 | + if (new_index.is_valid()) |
| 103 | + m_suggestion_view->selection().set(new_index); |
| 104 | + }; |
| 105 | + m_textbox->on_return_pressed = [this] { |
| 106 | + auto selected_index = m_suggestion_view->selection().first(); |
| 107 | + if (!selected_index.is_valid()) |
| 108 | + return; |
| 109 | + auto filename_index = m_suggestion_view->model()->index(selected_index.row(), LocatorSuggestionModel::Column::Name); |
| 110 | + auto filename = m_suggestion_view->model()->data(filename_index, GModel::Role::Display).to_string(); |
| 111 | + open_file(filename); |
| 112 | + close(); |
| 113 | + }; |
| 114 | + |
| 115 | + m_popup_window = GWindow::construct(); |
| 116 | + // FIXME: This is obviously not a tooltip window, but it's the closest thing to what we want atm. |
| 117 | + m_popup_window->set_window_type(GWindowType::Tooltip); |
| 118 | + m_popup_window->set_rect(0, 0, 500, 200); |
| 119 | + |
| 120 | + m_suggestion_view = GTableView::construct(nullptr); |
| 121 | + m_suggestion_view->set_size_columns_to_fit_content(true); |
| 122 | + m_suggestion_view->set_headers_visible(false); |
| 123 | + m_popup_window->set_main_widget(m_suggestion_view); |
| 124 | +} |
| 125 | + |
| 126 | +Locator::~Locator() |
| 127 | +{ |
| 128 | +} |
| 129 | + |
| 130 | +void Locator::open() |
| 131 | +{ |
| 132 | + m_textbox->set_focus(true); |
| 133 | + if (!m_textbox->text().is_empty()) { |
| 134 | + m_textbox->select_all(); |
| 135 | + m_popup_window->show(); |
| 136 | + } |
| 137 | +} |
| 138 | + |
| 139 | +void Locator::close() |
| 140 | +{ |
| 141 | + m_popup_window->hide(); |
| 142 | +} |
| 143 | + |
| 144 | +void Locator::keydown_event(GKeyEvent& event) |
| 145 | +{ |
| 146 | + GWidget::keydown_event(event); |
| 147 | +} |
| 148 | + |
| 149 | +void Locator::update_suggestions() |
| 150 | +{ |
| 151 | + auto typed_text = m_textbox->text(); |
| 152 | + Vector<String> suggestions; |
| 153 | + g_project->for_each_text_file([&](auto& file) { |
| 154 | + if (file.name().contains(typed_text)) |
| 155 | + suggestions.append(file.name()); |
| 156 | + }); |
| 157 | + dbg() << "I have " << suggestions.size() << " suggestion(s):"; |
| 158 | + for (auto& s : suggestions) { |
| 159 | + dbg() << " " << s; |
| 160 | + } |
| 161 | + |
| 162 | + m_suggestion_view->set_model(adopt(*new LocatorSuggestionModel(move(suggestions)))); |
| 163 | + |
| 164 | + m_popup_window->move_to(screen_relative_rect().top_left().translated(0, -m_popup_window->height())); |
| 165 | + dbg() << "Popup rect: " << m_popup_window->rect(); |
| 166 | + m_popup_window->show(); |
| 167 | +} |
0 commit comments