#include #include #include "../group_panel.h" #include "../filters.h" #include "../config.h" #include "filters.h" static inline void render_integer_filter(IntegerFilter* filter); static inline void render_string_filter(StringFilter* filter); static inline void render_buffer_filter(BufferFilter* filter); static inline void render_priority_filter(PriorityFilter* filter); static inline void render_group_filter(GroupFilter* filter); static std::unique_ptr render_add_filter_popup(); static void update_logcat_entries(const Config& active_config, const std::vector& logcat_entries, std::vector& filtered_logcat_entry_offsets); static void try_write_config(const Config& config); static void render_filter(Filter* filter, std::string* title, bool* request_removal) { ImGui::PushID(filter); ImGui::BeginGroupPanel(); if (title) { ImGui::AlignTextToFramePadding(); ImGui::Text("Title:%s%s", title->empty() ? "" : " ", title->c_str()); ImGui::SameLine(); bool popup_just_opened = false; if (ImGui::Button("Edit")) { ImGui::OpenPopup("change_filter_title"); popup_just_opened = true; } if (ImGui::BeginPopup("change_filter_title")) { ImGui::SetKeyboardFocusHere(); bool enter_pressed = ImGui::InputText("##title", title, ImGuiInputTextFlags_EnterReturnsTrue); if (enter_pressed || (!popup_just_opened && !ImGui::IsItemActive())) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } ImGui::SameLine(); } if (ImGui::Button("Remove")) { *request_removal = true; } { ImGui::SameLine(); bool disabled = filter->disabled(); if (ImGui::Checkbox("Disabled", &disabled)) { filter->disabled(disabled); } } { StringFilter* sfilter = dynamic_cast(filter); IntegerFilter* ifilter = !sfilter ? dynamic_cast(filter) : nullptr; if (sfilter || ifilter) { ImGui::SameLine(); ImGui::Checkbox("Inverted", sfilter ? &sfilter->inverted : &ifilter->inverted); } if (sfilter) { ImGui::SameLine(); ImGui::Checkbox("Exact match", &sfilter->exact_match); } } if (filter->error()) { ImGui::SameLine(); ImGui::Text("(%s)", filter->error()->c_str()); } if (IntegerFilter* ifilter = dynamic_cast(filter)) { render_integer_filter(ifilter); } else if (StringFilter* sfilter = dynamic_cast(filter)) { render_string_filter(sfilter); } else if (BufferFilter* bfilter = dynamic_cast(filter)) { render_buffer_filter(bfilter); } else if (PriorityFilter* pfilter = dynamic_cast(filter)) { render_priority_filter(pfilter); } else if (GroupFilter* gfilter = dynamic_cast(filter)) { render_group_filter(gfilter); } else { ImGui::TextUnformatted("An unknown filter, this probably shouldn't be mutated"); } ImGui::EndGroupPanel(); ImGui::PopID(); } static inline void render_integer_filter(IntegerFilter* filter) { const char* head; switch (filter->key) { case FilterKey::PID: head = "PID"; break; case FilterKey::TID: head = "TID"; break; default: head = "Something"; }; ImGui::AlignTextToFramePadding(); ImGui::Text("%s is%s", head, filter->inverted ? " not" : ""); ImGui::SameLine(); if (ImGui::InputScalar("##int", ImGuiDataType_U64, &filter->other)) { filter->updated(); } } static inline void render_string_filter(StringFilter* filter) { const char* head; switch (filter->key) { case FilterKey::User: head = "User"; break; case FilterKey::Tag: head = "Tag"; break; case FilterKey::Message: head = "Message"; break; default: head = "Something"; }; ImGui::AlignTextToFramePadding(); ImGui::Text("%s %s", head, filter->exact_match ? (filter->inverted ? "is not" : "is") : (filter->inverted ? "doesn't have" : "has")); ImGui::SameLine(); if (ImGui::InputText("##str", &filter->other)) { filter->updated(); } } static inline void render_buffer_filter(BufferFilter* filter) { auto update_if_needed = [&](bool updated) { if (updated) { filter->updated(); } }; ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted("Buffer is:"); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Unknown", &filter->wanted, static_cast(Buffer::Unknown))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Main", &filter->wanted, static_cast(Buffer::Main))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("System", &filter->wanted, static_cast(Buffer::System))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Radio", &filter->wanted, static_cast(Buffer::Radio))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Events", &filter->wanted, static_cast(Buffer::Events))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Crash", &filter->wanted, static_cast(Buffer::Crash))); } static inline void render_priority_filter(PriorityFilter* filter) { auto update_if_needed = [&](bool updated) { if (updated) { filter->updated(); } }; ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted("Priority is:"); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Unknown", &filter->wanted, static_cast(Priority::Unknown))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Verbose", &filter->wanted, static_cast(Priority::Verbose))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Debug", &filter->wanted, static_cast(Priority::Debug))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Info", &filter->wanted, static_cast(Priority::Info))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Warning", &filter->wanted, static_cast(Priority::Warn))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Error", &filter->wanted, static_cast(Priority::Error))); ImGui::SameLine(); update_if_needed(ImGui::CheckboxFlags("Fatal", &filter->wanted, static_cast(Priority::Fatal))); } static inline void render_group_filter(GroupFilter* filter) { int selected_type = static_cast(filter->type); if (ImGui::Combo("of these are true", &selected_type, "All\0Any\0One\0None\0")) { filter->type = static_cast(selected_type); } for (std::vector>::iterator it = filter->filters.begin(); it != filter->filters.end();) { bool removal_requested = false; render_filter(it->get(), nullptr, &removal_requested); if (removal_requested) { filter->filters.erase(it); filter->updated(); } else { it++; } } if (ImGui::Button("+ add filter")) { ImGui::OpenPopup("add_filter"); } if (ImGui::BeginPopup("add_filter")) { std::unique_ptr added_filter = render_add_filter_popup(); if (added_filter) { filter->filters.push_back(std::move(added_filter)); filter->updated(); } ImGui::EndPopup(); } } static std::unique_ptr render_add_filter_popup() { if (ImGui::Selectable("Buffer")) { return std::make_unique(0, false); } else if (ImGui::Selectable("User")) { return std::make_unique(FilterKey::User, "", false, true, false); } else if (ImGui::Selectable("PID")) { return std::make_unique(FilterKey::PID, 0, false, false); } else if (ImGui::Selectable("TID")) { return std::make_unique(FilterKey::TID, 0, false, false); } else if (ImGui::Selectable("Priority")) { return std::make_unique(0, false); } else if (ImGui::Selectable("Tag")) { return std::make_unique(FilterKey::Tag, "", false, true, false); } else if (ImGui::Selectable("Message")) { return std::make_unique(FilterKey::Message, "", false, true, false); } else if (ImGui::Selectable("Group of filters")) { return std::make_unique(std::vector>(), GroupFilter::Type::All, false); } return std::unique_ptr(); } static void update_logcat_entries(const Config& active_config, const std::vector& logcat_entries, std::vector& filtered_logcat_entry_offsets) { filtered_logcat_entry_offsets.clear(); for (size_t i=0; i < logcat_entries.size(); i++) { if (matches(logcat_entries[i], active_config.filters, active_config.exclusions)) { filtered_logcat_entry_offsets.push_back(i); } } } static void try_write_config(const Config& config) { try { write_config(config); } catch (const std::exception& e) { log(std::string("Failed to write config: ") + e.what()); } } void filters_fragment(Config& active_config, Filters& __restrict active_filters, Filters& __restrict inactive_filters, const std::vector& logcat_entries, std::vector& filtered_logcat_entry_offsets, bool* p_open) { ImGui::TextWrapped("You can use regex for strings by prepending \"regex:\". " "While editing titles, press Enter to use the new title or press Escape to keep the old one"); for (Filters::iterator it = inactive_filters.begin(); it != inactive_filters.end();) { bool removal_requested = false; render_filter(it->second.get(), &it->first, &removal_requested); if (removal_requested) { inactive_filters.erase(it); } else { it++; } } if (ImGui::Button("+ add filter")) { ImGui::OpenPopup("add_filter"); } if (ImGui::BeginPopup("add_filter")) { std::unique_ptr added_filter = render_add_filter_popup(); if (added_filter) { inactive_filters.push_back(std::make_pair("", std::move(added_filter))); } ImGui::EndPopup(); } ImGui::Separator(); ImVec2 button_size(4 * ImGui::GetFontSize(), 0); if (ImGui::Button("OK", button_size)) { active_filters = std::move(inactive_filters); try_write_config(active_config); update_logcat_entries(active_config, logcat_entries, filtered_logcat_entry_offsets); *p_open = false; } ImGui::SameLine(); if (ImGui::Button("Cancel", button_size)) { *p_open = false; } ImGui::SameLine(); if (ImGui::Button("Apply", button_size)) { copy_filters(active_filters, inactive_filters); try_write_config(active_config); update_logcat_entries(active_config, logcat_entries, filtered_logcat_entry_offsets); } }