Ember
Loading...
Searching...
No Matches
LogTab.cpp
Go to the documentation of this file.
1#include "Tabs/LogTab.h"
3#include <fstream>
4#include <iomanip>
5#include <sstream>
6#include <wx/clipbrd.h>
7#include <wx/filedlg.h>
8#include <wx/statline.h>
9#include <wx/textfile.h>
10#include <wx/wupdlock.h>
11
12namespace EmberForge {
13
14// ============================================================================
15// VirtualLogListCtrl Implementation
16// ============================================================================
17
18VirtualLogListCtrl::VirtualLogListCtrl(wxWindow *parent, wxWindowID id, LogTab *logTab)
19 : wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
20 wxLC_REPORT | wxLC_VIRTUAL | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES),
21 m_logTab(logTab), m_entries(nullptr) {
22 // Set dark theme colors
23 SetBackgroundColour(wxColour(30, 30, 30));
24 SetForegroundColour(wxColour(220, 220, 220));
25
26 // Add columns
27 InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 85);
28 InsertColumn(1, "Level", wxLIST_FORMAT_CENTER, 70);
29 InsertColumn(2, "Category", wxLIST_FORMAT_LEFT, 100);
30 InsertColumn(3, "Message", wxLIST_FORMAT_LEFT, 500);
31}
32
33void VirtualLogListCtrl::SetEntries(std::vector<std::shared_ptr<EmberCore::LogEntry>> *entries) {
34 m_entries = entries;
35 // Tell the list how many items we have - this is the key to virtual lists!
36 SetItemCount(entries ? entries->size() : 0);
37}
38
39wxString VirtualLogListCtrl::OnGetItemText(long item, long column) const {
40 // This is called by wxWidgets when it needs to display text for a cell
41 // Only called for VISIBLE rows - this is why virtual lists are fast!
42
43 if (!m_entries || item < 0 || item >= static_cast<long>(m_entries->size())) {
44 return "";
45 }
46
47 const auto &entry = (*m_entries)[item];
48
49 switch (column) {
50 case 0:
51 return m_logTab->FormatTimestamp(entry->timestamp);
52 case 1:
53 return m_logTab->GetLevelString(entry->level);
54 case 2:
55 return wxString(entry->category);
56 case 3:
57 return wxString(entry->message);
58 default:
59 return "";
60 }
61}
62
63wxListItemAttr *VirtualLogListCtrl::OnGetItemAttr(long item) const {
64 // This is called by wxWidgets when it needs attributes (colors) for a row
65 // Only called for VISIBLE rows!
66
67 if (!m_entries || item < 0 || item >= static_cast<long>(m_entries->size())) {
68 return nullptr;
69 }
70
71 const auto &entry = (*m_entries)[item];
72
73 // Set text color based on log level
74 m_itemAttr.SetTextColour(m_logTab->GetLevelColor(entry->level));
75 m_itemAttr.SetBackgroundColour(wxColour(30, 30, 30));
76
77 return const_cast<wxListItemAttr *>(&m_itemAttr);
78}
79
80// ============================================================================
81// LogTab Implementation
82// ============================================================================
83
85 ID_CATEGORY_FILTER, LogTab::OnCategoryFilterChanged) EVT_TEXT(ID_CATEGORY_FILTER, LogTab::OnCategoryFilterChanged)
86 EVT_SEARCHCTRL_SEARCH_BTN(ID_SEARCH_CTRL, LogTab::OnSearchTextChanged)
87 EVT_TEXT(ID_SEARCH_CTRL, LogTab::OnSearchTextChanged) EVT_CHECKBOX(ID_AUTO_SCROLL, LogTab::OnAutoScrollToggled)
88 EVT_BUTTON(ID_PAUSE_BTN, LogTab::OnPauseToggled) EVT_CHECKBOX(ID_CONSOLE_CHECK, LogTab::OnConsoleToggled)
89 EVT_CHECKBOX(ID_FILE_CHECK, LogTab::OnFileToggled) EVT_BUTTON(ID_CLEAR_BTN, LogTab::OnClearClicked)
90 EVT_BUTTON(ID_COPY_BTN, LogTab::OnCopyClicked) EVT_BUTTON(ID_EXPORT_BTN, LogTab::OnExportClicked)
91 EVT_LIST_ITEM_SELECTED(ID_LOG_LIST, LogTab::OnListItemSelected)
92 EVT_LIST_ITEM_RIGHT_CLICK(ID_LOG_LIST, LogTab::OnListItemRightClick) wxEND_EVENT_TABLE()
93
94 LogTab::LogTab(wxWindow *parent)
95 : wxPanel(parent, wxID_ANY), m_levelFilter(nullptr), m_categoryFilter(nullptr), m_searchCtrl(nullptr),
96 m_autoScrollCheck(nullptr), m_pauseBtn(nullptr), m_consoleCheck(nullptr), m_fileCheck(nullptr),
97 m_clearBtn(nullptr), m_copyBtn(nullptr), m_exportBtn(nullptr), m_logCountLabel(nullptr), m_logList(nullptr),
98 m_currentLevelFilter(EmberCore::LogLevel::All), m_currentCategoryFilter(""), m_currentSearchFilter(""),
99 m_autoScroll(true), m_paused(false), m_updatingCategories(false), m_observerId(0) {
100 SetBackgroundColour(wxColour(45, 45, 48));
101 CreateLayout();
102 SetupEventHandlers();
103}
104
106 // Remove observer to prevent dangling callback
107 if (m_observerId != 0) {
109 }
110}
111
113 // Guard against double initialization - only register observer once
114 if (m_observerId != 0) {
115 return; // Already initialized
116 }
117
118 // Load and apply settings from preferences
119 LoadSettings();
120
121 // Register as observer for log updates and store the ID for cleanup
123 // Use CallAfter to ensure we're on the main thread
124 CallAfter([this]() { OnLogUpdated(); });
125 });
126
127 // Initial load
129}
130
133 const auto &logSettings = prefs.GetBottomPanelSettings().logTab;
134
135 // Apply default level filter
136 // UI order: All(0), Trace(1), Info(2), Warning(3), Error(4), Critical(5)
137 // LogLevel enum: All=0, Trace=1, Info=2, Warning=3, Error=4, Critical=5
138 int levelIndex = logSettings.defaultLevelFilter;
139 if (levelIndex >= 0 && levelIndex < static_cast<int>(m_levelFilter->GetCount())) {
140 m_levelFilter->SetSelection(levelIndex);
141 m_currentLevelFilter = static_cast<EmberCore::LogLevel>(levelIndex);
142 }
143
144 // Apply auto-scroll setting
145 m_autoScroll = logSettings.autoScrollEnabled;
146 if (m_autoScrollCheck) {
148 }
149
150 // Apply console colors setting
151 EmberCore::Logger::GetInstance().SetConsoleColorsEnabled(logSettings.enableConsoleColors);
152
153 // Apply font size to log list
154 if (m_logList) {
155 wxFont font = m_logList->GetFont();
156 int fontSize = static_cast<int>(logSettings.fontSize);
157 font.SetPointSize(fontSize);
158 m_logList->SetFont(font);
159 }
160}
161
163 wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
164
165 // Create toolbar
167
168 // Add toolbar to main sizer
169 wxPanel *toolbarPanel = new wxPanel(this, wxID_ANY);
170 toolbarPanel->SetBackgroundColour(wxColour(60, 60, 63));
171
172 wxBoxSizer *toolbarSizer = new wxBoxSizer(wxVERTICAL);
173
174 // Row 1: Filter controls
175 wxBoxSizer *filterRow = new wxBoxSizer(wxHORIZONTAL);
176
177 // Level filter
178 wxStaticText *levelLabel = new wxStaticText(toolbarPanel, wxID_ANY, "Level:");
179 levelLabel->SetForegroundColour(wxColour(200, 200, 200));
180 filterRow->Add(levelLabel, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5);
181
182 wxArrayString levelChoices;
183 levelChoices.Add("All");
184 levelChoices.Add("Trace");
185 levelChoices.Add("Info");
186 levelChoices.Add("Warning");
187 levelChoices.Add("Error");
188 levelChoices.Add("Critical");
189 m_levelFilter = new wxChoice(toolbarPanel, ID_LEVEL_FILTER, wxDefaultPosition, wxSize(90, -1), levelChoices);
190 m_levelFilter->SetSelection(0);
191 filterRow->Add(m_levelFilter, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
192
193 // Category filter
194 wxStaticText *categoryLabel = new wxStaticText(toolbarPanel, wxID_ANY, "Category:");
195 categoryLabel->SetForegroundColour(wxColour(200, 200, 200));
196 filterRow->Add(categoryLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
197
198 m_categoryFilter = new wxComboBox(toolbarPanel, ID_CATEGORY_FILTER, "", wxDefaultPosition, wxSize(120, -1));
199 m_categoryFilter->Append(""); // Empty means all categories
200 filterRow->Add(m_categoryFilter, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
201
202 // Search
203 m_searchCtrl = new wxSearchCtrl(toolbarPanel, ID_SEARCH_CTRL, "", wxDefaultPosition, wxSize(150, -1));
204 m_searchCtrl->SetDescriptiveText("Search logs...");
205 filterRow->Add(m_searchCtrl, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
206
207 // Auto-scroll checkbox
208 m_autoScrollCheck = new wxCheckBox(toolbarPanel, ID_AUTO_SCROLL, "Auto-scroll");
209 m_autoScrollCheck->SetForegroundColour(wxColour(200, 200, 200));
210 m_autoScrollCheck->SetValue(true);
211 filterRow->Add(m_autoScrollCheck, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
212
213 // Pause/Play button
214 m_pauseBtn = new wxButton(toolbarPanel, ID_PAUSE_BTN, "Pause", wxDefaultPosition, wxSize(60, -1));
216 filterRow->Add(m_pauseBtn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
217
218 toolbarSizer->Add(filterRow, 0, wxEXPAND | wxALL, 3);
219
220 // Row 2: Log control and actions
221 wxBoxSizer *controlRow = new wxBoxSizer(wxHORIZONTAL);
222
223 // Console toggle
224 m_consoleCheck = new wxCheckBox(toolbarPanel, ID_CONSOLE_CHECK, "Console");
225 m_consoleCheck->SetForegroundColour(wxColour(200, 200, 200));
226 m_consoleCheck->SetValue(EmberCore::Logger::GetInstance().IsConsoleLoggingEnabled());
227 controlRow->Add(m_consoleCheck, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5);
228
229 // File toggle
230 m_fileCheck = new wxCheckBox(toolbarPanel, ID_FILE_CHECK, "File");
231 m_fileCheck->SetForegroundColour(wxColour(200, 200, 200));
232 m_fileCheck->SetValue(EmberCore::Logger::GetInstance().IsFileLoggingEnabled());
233 controlRow->Add(m_fileCheck, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
234
235 // Separator
236 controlRow->Add(new wxStaticLine(toolbarPanel, wxID_ANY, wxDefaultPosition, wxSize(1, 20), wxLI_VERTICAL), 0,
237 wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
238
239 // Action buttons
240 m_clearBtn = new wxButton(toolbarPanel, ID_CLEAR_BTN, "Clear", wxDefaultPosition, wxSize(60, -1));
241 controlRow->Add(m_clearBtn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
242
243 m_copyBtn = new wxButton(toolbarPanel, ID_COPY_BTN, "Copy", wxDefaultPosition, wxSize(60, -1));
244 controlRow->Add(m_copyBtn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
245
246 m_exportBtn = new wxButton(toolbarPanel, ID_EXPORT_BTN, "Export", wxDefaultPosition, wxSize(60, -1));
247 controlRow->Add(m_exportBtn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
248
249 controlRow->AddStretchSpacer();
250
251 // Log count display (right-aligned)
252 m_logCountLabel = new wxStaticText(toolbarPanel, wxID_ANY, "Showing 0 of 0 logs");
253 m_logCountLabel->SetForegroundColour(wxColour(150, 150, 150));
254 controlRow->Add(m_logCountLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
255
256 toolbarSizer->Add(controlRow, 0, wxEXPAND | wxALL, 3);
257
258 toolbarPanel->SetSizer(toolbarSizer);
259 mainSizer->Add(toolbarPanel, 0, wxEXPAND);
260
261 // Create log list
263 mainSizer->Add(m_logList, 1, wxEXPAND | wxALL, 2);
264
265 SetSizer(mainSizer);
266}
267
269 // Toolbar is created inline in CreateLayout
270}
271
273 // Use virtual list for efficient handling of large log counts
274 // The VirtualLogListCtrl only renders visible rows, making it fast even with 10000+ logs
275 m_logList = new VirtualLogListCtrl(this, ID_LOG_LIST, this);
276}
277
279 // Event handlers are set up via event table
280}
281
283 // Get filtered entries from Logger
284 auto &logger = EmberCore::Logger::GetInstance();
285 m_filteredEntries = logger.GetFilteredEntries(m_currentLevelFilter, m_currentCategoryFilter.ToStdString(),
286 m_currentSearchFilter.ToStdString());
287
288 // Update category choices
290
291 // Populate list
293
294 // Update log count display
296
297 // Auto-scroll if enabled
298 if (m_autoScroll && m_logList->GetItemCount() > 0) {
300 }
301}
302
303void LogTab::PopulateList(const std::vector<std::shared_ptr<EmberCore::LogEntry>> &entries) {
304 // Virtual list magic: instead of inserting 1000 items one by one,
305 // we just tell the list "there are 1000 items" and it asks for data
306 // only when it needs to display a row (typically ~15-20 visible rows)
307 m_logList->SetEntries(&m_filteredEntries);
308 m_logList->Refresh();
309}
310
312 // Set guard flag to prevent recursive event handling
314
315 auto &logger = EmberCore::Logger::GetInstance();
316 const auto &entries = logger.GetEntries();
317
318 // Collect unique categories
319 for (const auto &entry : entries) {
320 m_knownCategories.insert(entry->category);
321 }
322
323 // Save current selection
324 wxString currentSelection = m_categoryFilter->GetValue();
325
326 // Update choices
327 m_categoryFilter->Clear();
328 m_categoryFilter->Append(""); // All categories
329 for (const auto &category : m_knownCategories) {
330 m_categoryFilter->Append(wxString(category));
331 }
332
333 // Restore selection
334 int idx = m_categoryFilter->FindString(currentSelection);
335 if (idx != wxNOT_FOUND) {
336 m_categoryFilter->SetSelection(idx);
337 } else {
338 m_categoryFilter->SetValue(currentSelection);
339 }
340
341 // Clear guard flag
342 m_updatingCategories = false;
343}
344
345wxString LogTab::FormatTimestamp(const std::chrono::system_clock::time_point &timestamp) const {
346 auto time = std::chrono::system_clock::to_time_t(timestamp);
347 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp.time_since_epoch()) % 1000;
348
349 std::tm tm_buf;
350#ifdef _WIN32
351 localtime_s(&tm_buf, &time);
352#else
353 localtime_r(&time, &tm_buf);
354#endif
355
356 std::ostringstream oss;
357 oss << std::put_time(&tm_buf, "%H:%M:%S") << "." << std::setfill('0') << std::setw(3) << ms.count();
358 return wxString(oss.str());
359}
360
363 const auto &logSettings = prefs.GetBottomPanelSettings().logTab;
364
365 // If GUI colors are disabled, return default text color
366 if (!logSettings.enableGuiColors) {
367 return wxColour(220, 220, 220); // Default light gray text
368 }
369
370 // Return configured colors based on log level
371 switch (level) {
373 return wxColour(logSettings.traceColor.r, logSettings.traceColor.g, logSettings.traceColor.b);
375 return wxColour(logSettings.infoColor.r, logSettings.infoColor.g, logSettings.infoColor.b);
377 return wxColour(logSettings.warningColor.r, logSettings.warningColor.g, logSettings.warningColor.b);
379 return wxColour(logSettings.errorColor.r, logSettings.errorColor.g, logSettings.errorColor.b);
381 return wxColour(logSettings.criticalColor.r, logSettings.criticalColor.g, logSettings.criticalColor.b);
382 default:
383 return wxColour(200, 200, 200); // Light gray
384 }
385}
386
388 switch (level) {
390 return "TRACE";
392 return "INFO";
394 return "WARNING";
396 return "ERROR";
398 return "CRITICAL";
399 default:
400 return "ALL";
401 }
402}
403
405 if (m_logList && m_logList->GetItemCount() > 0) {
406 m_logList->EnsureVisible(m_logList->GetItemCount() - 1);
407 }
408}
409
411 // Reload settings in case they changed
412 LoadSettings();
413
414 // Refresh the log list
416}
417
419
421 // Nothing specific needed
422}
423
425 // Remove observer IMMEDIATELY when tab is closed to prevent dangling callback
426 // This is called before the tab is destroyed, ensuring no callbacks fire on destroyed object
427 if (m_observerId != 0) {
429 m_observerId = 0; // Mark as removed
430 }
431}
432
433// Filter methods
438
439void LogTab::SetCategoryFilter(const wxString &category) {
440 m_currentCategoryFilter = category;
442}
443
444void LogTab::SetSearchFilter(const wxString &searchText) {
445 m_currentSearchFilter = searchText;
447}
448
453
454 m_levelFilter->SetSelection(0);
455 m_categoryFilter->SetValue("");
456 m_searchCtrl->SetValue("");
457
459}
460
461// Log control methods
465
467
468// Actions
474
476 long selectedIdx = m_logList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
477 if (selectedIdx == -1) {
478 // No selection, copy all visible logs
479 wxString allLogs;
480 for (size_t i = 0; i < m_filteredEntries.size(); ++i) {
481 const auto &entry = m_filteredEntries[i];
482 allLogs +=
483 wxString::Format("[%s] [%s] [%s] %s\n", FormatTimestamp(entry->timestamp), GetLevelString(entry->level),
484 wxString(entry->category), wxString(entry->message));
485 }
486
487 if (wxTheClipboard->Open()) {
488 wxTheClipboard->SetData(new wxTextDataObject(allLogs));
489 wxTheClipboard->Close();
490 }
491 } else {
492 // Copy selected entry
493 if (selectedIdx < static_cast<long>(m_filteredEntries.size())) {
494 const auto &entry = m_filteredEntries[selectedIdx];
495 wxString logText =
496 wxString::Format("[%s] [%s] [%s] %s", FormatTimestamp(entry->timestamp), GetLevelString(entry->level),
497 wxString(entry->category), wxString(entry->message));
498
499 if (wxTheClipboard->Open()) {
500 wxTheClipboard->SetData(new wxTextDataObject(logText));
501 wxTheClipboard->Close();
502 }
503 }
504 }
505}
506
508 wxFileDialog saveDialog(this, "Export Logs", "", "logs.txt",
509 "Text files (*.txt)|*.txt|Log files (*.log)|*.log|All files (*.*)|*.*",
510 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
511
512 if (saveDialog.ShowModal() == wxID_CANCEL) {
513 return;
514 }
515
516 wxString filepath = saveDialog.GetPath();
517 std::ofstream file(filepath.ToStdString());
518
519 if (!file.is_open()) {
520 wxMessageBox("Failed to open file for writing.", "Export Error", wxOK | wxICON_ERROR);
521 return;
522 }
523
524 // Export all entries (not just filtered)
525 auto &logger = EmberCore::Logger::GetInstance();
526 const auto &entries = logger.GetEntries();
527
528 for (const auto &entry : entries) {
529 file << "[" << FormatTimestamp(entry->timestamp).ToStdString() << "] "
530 << "[" << GetLevelString(entry->level).ToStdString() << "] "
531 << "[" << entry->category << "] " << entry->message << "\n";
532 }
533
534 file.close();
535
536 LOG_INFO("LogTab", "Exported " + std::to_string(entries.size()) + " log entries to " + filepath.ToStdString());
537}
538
539// Event handlers
540void LogTab::OnLevelFilterChanged(wxCommandEvent &event) {
541 int selection = m_levelFilter->GetSelection();
542 m_currentLevelFilter = static_cast<EmberCore::LogLevel>(selection);
544}
545
546void LogTab::OnCategoryFilterChanged(wxCommandEvent &event) {
547 // Prevent recursive calls when UpdateCategoryChoices modifies the combobox
549 return;
550 }
551
554}
555
556void LogTab::OnSearchTextChanged(wxCommandEvent &event) {
559}
560
561void LogTab::OnAutoScrollToggled(wxCommandEvent &event) {
562 m_autoScroll = m_autoScrollCheck->GetValue();
563 if (m_autoScroll) {
565 }
566}
567
568void LogTab::OnConsoleToggled(wxCommandEvent &event) { SetConsoleLoggingEnabled(m_consoleCheck->GetValue()); }
569
570void LogTab::OnFileToggled(wxCommandEvent &event) { SetFileLoggingEnabled(m_fileCheck->GetValue()); }
571
572void LogTab::OnClearClicked(wxCommandEvent &event) { ClearLogs(); }
573
574void LogTab::OnCopyClicked(wxCommandEvent &event) { CopySelectedToClipboard(); }
575
576void LogTab::OnExportClicked(wxCommandEvent &event) { ExportLogs(); }
577
578void LogTab::OnListItemSelected(wxListEvent &event) {
579 // Could show detailed log info in a status bar or detail panel
580}
581
582void LogTab::OnListItemRightClick(wxListEvent &event) {
583 wxMenu menu;
584 menu.Append(wxID_COPY, "Copy");
585 menu.Append(wxID_CLEAR, "Clear All");
586
587 int id = GetPopupMenuSelectionFromUser(menu);
588 if (id == wxID_COPY) {
590 } else if (id == wxID_CLEAR) {
591 ClearLogs();
592 }
593}
594
596 // Don't update if paused
597 if (m_paused) {
598 return;
599 }
601}
602
603void LogTab::OnPauseToggled(wxCommandEvent &event) {
606
607 // If resuming, refresh to show any logs that came in while paused
608 if (!m_paused) {
610 }
611}
612
614 if (m_paused) {
615 // Paused state - green background, "Play" text
616 m_pauseBtn->SetLabel("Play");
617 m_pauseBtn->SetBackgroundColour(wxColour(60, 140, 60)); // Green
618 m_pauseBtn->SetForegroundColour(wxColour(255, 255, 255));
619 } else {
620 // Playing state - red background, "Pause" text
621 m_pauseBtn->SetLabel("Pause");
622 m_pauseBtn->SetBackgroundColour(wxColour(180, 60, 60)); // Red
623 m_pauseBtn->SetForegroundColour(wxColour(255, 255, 255));
624 }
625 m_pauseBtn->Refresh();
626}
627
629 size_t filteredCount = m_filteredEntries.size();
630 size_t totalCount = EmberCore::Logger::GetInstance().GetEntries().size();
631
632 // Always show "X of Y" format
633 wxString label = wxString::Format("Showing %zu of %zu logs", filteredCount, totalCount);
634
635 m_logCountLabel->SetLabel(label);
636}
637
638} // namespace EmberForge
BehaviorTreeProjectDialog::OnProjectNameChanged BehaviorTreeProjectDialog::OnRemoveFiles wxEND_EVENT_TABLE() BehaviorTreeProjectDialog
#define LOG_INFO(category, message)
Definition Logger.h:114
static Logger & GetInstance()
Definition Logger.cpp:251
const std::vector< std::shared_ptr< LogEntry > > & GetEntries() const
Definition Logger.h:77
ObserverId AddObserver(std::function< void()> observer)
Definition Logger.cpp:216
void RemoveObserver(ObserverId id)
Definition Logger.cpp:222
void SetConsoleColorsEnabled(bool enabled)
Definition Logger.cpp:240
void ClearEntries()
Definition Logger.cpp:214
void SetFileLoggingEnabled(bool enabled)
Definition Logger.h:70
void SetConsoleLoggingEnabled(bool enabled)
Definition Logger.h:67
static AppPreferencesManager & GetInstance()
BottomPanelSettings & GetBottomPanelSettings()
Log panel tab that displays application logs with filtering and control capabilities.
Definition LogTab.h:51
void OnFileToggled(wxCommandEvent &event)
Definition LogTab.cpp:570
void OnCategoryFilterChanged(wxCommandEvent &event)
Definition LogTab.cpp:546
void UpdateLogCountDisplay()
Definition LogTab.cpp:628
wxCheckBox * m_autoScrollCheck
Definition LogTab.h:123
wxButton * m_pauseBtn
Definition LogTab.h:124
void UpdatePauseButtonAppearance()
Definition LogTab.cpp:613
std::vector< std::shared_ptr< EmberCore::LogEntry > > m_filteredEntries
Definition LogTab.h:147
wxSearchCtrl * m_searchCtrl
Definition LogTab.h:122
wxButton * m_copyBtn
Definition LogTab.h:130
void OnListItemSelected(wxListEvent &event)
Definition LogTab.cpp:578
void OnCopyClicked(wxCommandEvent &event)
Definition LogTab.cpp:574
bool m_updatingCategories
Definition LogTab.h:146
wxString GetLevelString(EmberCore::LogLevel level) const
Definition LogTab.cpp:387
void OnSearchTextChanged(wxCommandEvent &event)
Definition LogTab.cpp:556
void Initialize() override
Called once when the tab is first created.
Definition LogTab.cpp:112
void OnClosed() override
Called when the tab is closed.
Definition LogTab.cpp:424
friend class VirtualLogListCtrl
Definition LogTab.h:138
void OnConsoleToggled(wxCommandEvent &event)
Definition LogTab.cpp:568
wxButton * m_clearBtn
Definition LogTab.h:129
void SetConsoleLoggingEnabled(bool enabled)
Definition LogTab.cpp:462
wxChoice * m_levelFilter
Definition LogTab.h:120
void OnLevelFilterChanged(wxCommandEvent &event)
Definition LogTab.cpp:540
virtual ~LogTab()
Definition LogTab.cpp:105
VirtualLogListCtrl * m_logList
Definition LogTab.h:135
void OnClearClicked(wxCommandEvent &event)
Definition LogTab.cpp:572
void SetFileLoggingEnabled(bool enabled)
Definition LogTab.cpp:466
void RefreshLogList()
Definition LogTab.cpp:282
wxColour GetLevelColor(EmberCore::LogLevel level) const
Definition LogTab.cpp:361
void Refresh() override
Refreshes the tab content.
Definition LogTab.cpp:410
void SetCategoryFilter(const wxString &category)
Definition LogTab.cpp:439
wxString m_currentSearchFilter
Definition LogTab.h:143
void OnDeactivated() override
Called when the tab becomes inactive.
Definition LogTab.cpp:420
void ScrollToBottom()
Definition LogTab.cpp:404
void SetupEventHandlers()
Definition LogTab.cpp:278
void PopulateList(const std::vector< std::shared_ptr< EmberCore::LogEntry > > &entries)
Definition LogTab.cpp:303
wxString m_currentCategoryFilter
Definition LogTab.h:142
void OnExportClicked(wxCommandEvent &event)
Definition LogTab.cpp:576
void SetSearchFilter(const wxString &searchText)
Definition LogTab.cpp:444
EmberCore::LogLevel m_currentLevelFilter
Definition LogTab.h:141
wxCheckBox * m_fileCheck
Definition LogTab.h:128
wxString FormatTimestamp(const std::chrono::system_clock::time_point &timestamp) const
Definition LogTab.cpp:345
void OnActivated() override
Called when the tab becomes active.
Definition LogTab.cpp:418
std::set< std::string > m_knownCategories
Definition LogTab.h:148
void OnListItemRightClick(wxListEvent &event)
Definition LogTab.cpp:582
wxCheckBox * m_consoleCheck
Definition LogTab.h:127
void SetLevelFilter(EmberCore::LogLevel level)
Definition LogTab.cpp:434
wxButton * m_exportBtn
Definition LogTab.h:131
void OnPauseToggled(wxCommandEvent &event)
Definition LogTab.cpp:603
wxComboBox * m_categoryFilter
Definition LogTab.h:121
void OnAutoScrollToggled(wxCommandEvent &event)
Definition LogTab.cpp:561
wxStaticText * m_logCountLabel
Definition LogTab.h:132
void UpdateCategoryChoices()
Definition LogTab.cpp:311
EmberCore::Logger::ObserverId m_observerId
Definition LogTab.h:151
void CopySelectedToClipboard()
Definition LogTab.cpp:475
std::vector< std::shared_ptr< EmberCore::LogEntry > > * m_entries
Definition LogTab.h:37
void SetEntries(std::vector< std::shared_ptr< EmberCore::LogEntry > > *entries)
Definition LogTab.cpp:33
wxListItemAttr * OnGetItemAttr(long item) const override
Definition LogTab.cpp:63
wxListItemAttr m_itemAttr
Definition LogTab.h:38
VirtualLogListCtrl(wxWindow *parent, wxWindowID id, LogTab *logTab)
Definition LogTab.cpp:18
wxString OnGetItemText(long item, long column) const override
Definition LogTab.cpp:39
Main types header for EmberCore.
LogLevel
Log levels for categorizing messages.
Definition Logger.h:16
LogTab::OnLevelFilterChanged LogTab::OnCategoryFilterChanged LogTab::OnAutoScrollToggled LogTab::OnConsoleToggled LogTab::OnClearClicked LogTab::OnExportClicked EVT_LIST_ITEM_RIGHT_CLICK(ID_LOG_LIST, LogTab::OnListItemRightClick) wxEND_EVENT_TABLE() LogTab
Definition LogTab.cpp:92
LogTab::OnLevelFilterChanged LogTab::OnCategoryFilterChanged LogTab::OnAutoScrollToggled LogTab::OnConsoleToggled EVT_CHECKBOX(ID_FILE_CHECK, LogTab::OnFileToggled) EVT_BUTTON(ID_CLEAR_BTN
LogTab::OnLevelFilterChanged LogTab::OnCategoryFilterChanged EVT_TEXT(ID_SEARCH_CTRL, LogTab::OnSearchTextChanged) EVT_CHECKBOX(ID_AUTO_SCROLL
LogTab::OnLevelFilterChanged EVT_COMBOBOX(ID_CATEGORY_FILTER, LogTab::OnCategoryFilterChanged) EVT_TEXT(ID_CATEGORY_FILTER
wxBEGIN_EVENT_TABLE(LogTab, wxPanel) EVT_CHOICE(ID_LEVEL_FILTER
LogTab::OnLevelFilterChanged LogTab::OnCategoryFilterChanged LogTab::OnAutoScrollToggled EVT_BUTTON(ID_PAUSE_BTN, LogTab::OnPauseToggled) EVT_CHECKBOX(ID_CONSOLE_CHECK