1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
20 #include <wx/button.h>
21 #include <wx/textctrl.h>
22 #include <wx/listbox.h>
23 #include <wx/checklst.h>
24 #include <wx/strconv.h>
26 #include "Core.h" // for Core::GetState()
27 #include "LogWindow.h"
28 #include "ConsoleListener.h"
33 // Milliseconds between msgQueue flushes to wxTextCtrl
34 #define UPDATETIME 200
36 BEGIN_EVENT_TABLE(CLogWindow
, wxPanel
)
37 EVT_CLOSE(CLogWindow::OnClose
)
38 EVT_TEXT_ENTER(IDM_SUBMITCMD
, CLogWindow::OnSubmit
)
39 EVT_BUTTON(IDM_CLEARLOG
, CLogWindow::OnClear
)
40 EVT_BUTTON(IDM_TOGGLEALL
, CLogWindow::OnToggleAll
)
41 EVT_RADIOBOX(IDM_VERBOSITY
, CLogWindow::OnOptionsCheck
)
42 EVT_CHOICE(IDM_FONT
, CLogWindow::OnOptionsCheck
)
43 EVT_CHECKBOX(IDM_WRAPLINE
, CLogWindow::OnOptionsCheck
)
44 EVT_CHECKBOX(IDM_WRITEFILE
, CLogWindow::OnOptionsCheck
)
45 EVT_CHECKBOX(IDM_WRITECONSOLE
, CLogWindow::OnOptionsCheck
)
46 EVT_CHECKBOX(IDM_WRITEWINDOW
, CLogWindow::OnOptionsCheck
)
47 EVT_CHECKLISTBOX(IDM_LOGCHECKS
, CLogWindow::OnLogCheck
)
48 EVT_TIMER(IDTM_UPDATELOG
, CLogWindow::OnLogTimer
)
51 CLogWindow::CLogWindow(CFrame
*parent
, wxWindowID id
, const wxPoint
& pos
,
52 const wxSize
& size
, long style
, const wxString
& name
)
53 : wxPanel(parent
, id
, pos
, size
, style
, name
)
54 , Parent(parent
) , m_LogAccess(true)
55 , m_Log(NULL
), m_cmdline(NULL
), m_FontChoice(NULL
)
58 , m_SJISConv(wxFONTENCODING_EUC_JP
)
60 , m_SJISConv(wxFONTENCODING_SHIFT_JIS
)
63 m_LogManager
= LogManager::GetInstance();
64 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
65 m_LogManager
->addListener((LogTypes::LOG_TYPE
)i
, this);
66 m_fileLog
= m_LogManager
->getFileListener();
67 m_console
= m_LogManager
->getConsoleListener();
74 void CLogWindow::CreateGUIControls()
77 wxArrayString wxLevels
, wxLevelsUse
;
78 wxLevels
.Add(wxT("Notice"));
79 wxLevels
.Add(wxT("Error"));
80 wxLevels
.Add(wxT("Warning"));
81 wxLevels
.Add(wxT("Info"));
82 wxLevels
.Add(wxT("Debug"));
83 for (int i
= 0; i
< MAX_LOGLEVEL
; ++i
) wxLevelsUse
.Add(wxString::Format(wxT("%s"), wxLevels
.Item(i
).c_str()));
84 m_verbosity
= new wxRadioBox(this, IDM_VERBOSITY
, wxT("Verbosity"), wxDefaultPosition
, wxDefaultSize
, wxLevelsUse
, 0, wxRA_SPECIFY_ROWS
, wxDefaultValidator
);
85 // Don't take up so much space
86 m_verbosity
->SetFont(wxFont(7, wxFONTFAMILY_DEFAULT
, wxFONTSTYLE_NORMAL
, wxFONTWEIGHT_NORMAL
));
89 m_FontChoice
= new wxChoice(this, IDM_FONT
, wxDefaultPosition
, wxDefaultSize
, 0, NULL
, 0, wxDefaultValidator
);
91 m_FontChoice
->Append(wxT("Default font"));
92 m_FontChoice
->Append(wxT("Monospaced font"));
93 m_FontChoice
->Append(wxT("Selected font"));
94 m_FontChoice
->SetSelection(0);
95 // wxTextCtrl *Tmp = CreateTextCtrl(this);
96 // DefaultFont = Tmp->GetFont();
98 MonoSpaceFont
.SetNativeFontInfoUserDesc(wxString::FromAscii("lucida console windows-1252"));
99 Font
.push_back(DefaultFont
);
100 Font
.push_back(MonoSpaceFont
);
101 Font
.push_back(DebuggerFont
);
104 wxCheckBox
* m_WrapLine
= new wxCheckBox(this, IDM_WRAPLINE
, wxT("Word Wrap"));
105 m_writeFileCB
= new wxCheckBox(this, IDM_WRITEFILE
, wxT("Write to File"), wxDefaultPosition
, wxDefaultSize
, 0);
106 m_writeConsoleCB
= new wxCheckBox(this, IDM_WRITECONSOLE
, wxT("Write to Console"), wxDefaultPosition
, wxDefaultSize
, 0);
107 m_writeWindowCB
= new wxCheckBox(this, IDM_WRITEWINDOW
, wxT("Write to Window ->"), wxDefaultPosition
, wxDefaultSize
, 0);
109 m_checks
= new wxCheckListBox(this, IDM_LOGCHECKS
, wxDefaultPosition
, wxDefaultSize
);
111 // Log viewer and submit row
112 m_Log
= CreateTextCtrl(this, IDM_LOG
, wxTE_RICH
| wxTE_MULTILINE
| wxTE_READONLY
| wxTE_DONTWRAP
);
113 m_cmdline
= new wxTextCtrl(this, IDM_SUBMITCMD
, wxEmptyString
, wxDefaultPosition
, wxDefaultSize
,
114 wxTE_PROCESS_ENTER
| wxTE_PROCESS_TAB
);
115 //m_cmdline->SetFont(DebuggerFont);
118 sUber
= new wxBoxSizer(wxHORIZONTAL
); // whole plane
119 sLeft
= new wxBoxSizer(wxVERTICAL
); // left sizer
120 sRight
= new wxBoxSizer(wxVERTICAL
); // right sizer
121 sRightBottom
= new wxBoxSizer(wxHORIZONTAL
); // submit row
122 // Left side: buttons (-submit), options, and log type selection
123 wxStaticBoxSizer
* sbLeftOptions
= new wxStaticBoxSizer(wxVERTICAL
, this, wxT("Options"));
125 wxBoxSizer
* sLogCtrl
= new wxBoxSizer(wxHORIZONTAL
);
126 sLogCtrl
->Add(new wxButton(this, IDM_TOGGLEALL
, wxT("Toggle all"), wxDefaultPosition
, wxDefaultSize
, wxBU_EXACTFIT
), 1);
127 sLogCtrl
->Add(new wxButton(this, IDM_CLEARLOG
, wxT("Clear"), wxDefaultPosition
, wxDefaultSize
, wxBU_EXACTFIT
), 1);
129 sbLeftOptions
->Add(m_FontChoice
, 0, (wxDOWN
), 1);
130 sbLeftOptions
->Add(m_WrapLine
, 0, (wxDOWN
), 1);
131 sbLeftOptions
->Add(m_writeFileCB
, 0, (wxDOWN
), 1);
132 sbLeftOptions
->Add(m_writeConsoleCB
, 0, (wxDOWN
), 1);
133 sbLeftOptions
->Add(m_writeWindowCB
, 0);
135 sLeft
->Add(m_verbosity
, 0, wxEXPAND
| (wxLEFT
| wxRIGHT
), 5);
136 sLeft
->Add(sbLeftOptions
, 0, wxEXPAND
| (wxLEFT
| wxRIGHT
), 5);
137 sLeft
->Add(sLogCtrl
, 0, wxEXPAND
);
138 sLeft
->Add(m_checks
, 1, wxEXPAND
);
142 sUber
->Add(sLeft
, 0, wxEXPAND
);
143 sUber
->Add(sRight
, 1, wxEXPAND
);
144 this->SetSizer(sUber
);
147 // SetAffirmativeId(IDM_SUBMITCMD);
149 m_cmdline
->SetFocus();
151 m_LogTimer
= new wxTimer(this, IDTM_UPDATELOG
);
152 m_LogTimer
->Start(UPDATETIME
);
155 CLogWindow::~CLogWindow()
157 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
159 m_LogManager
->removeListener((LogTypes::LOG_TYPE
)i
, this);
165 void CLogWindow::OnClose(wxCloseEvent
& event
)
168 wxGetApp().GetCFrame()->ToggleLogWindow(false);
172 void CLogWindow::SaveSettings()
175 ini
.Set("LogWindow", "x", Parent
->m_Mgr
->GetPane(wxT("Pane 1")).rect
.GetWidth());
176 ini
.Set("LogWindow", "y", Parent
->m_Mgr
->GetPane(wxT("Pane 1")).rect
.GetHeight());
177 ini
.Set("LogWindow", "pos", Parent
->m_Mgr
->GetPane(wxT("Pane 1")).dock_direction
);
178 ini
.Set("Options", "Verbosity", m_verbosity
->GetSelection() + 1);
179 ini
.Set("Options", "Font", m_FontChoice
->GetSelection());
180 ini
.Set("Options", "WriteToFile", m_writeFile
);
181 ini
.Set("Options", "WriteToConsole", m_writeConsole
);
182 ini
.Set("Options", "WriteToWindow", m_writeWindow
);
183 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
184 ini
.Set("Logs", m_LogManager
->getShortName((LogTypes::LOG_TYPE
)i
), m_checks
->IsChecked(i
));
185 ini
.Save(File::GetUserPath(F_LOGGERCONFIG_IDX
));
188 void CLogWindow::LoadSettings()
191 ini
.Load(File::GetUserPath(F_LOGGERCONFIG_IDX
));
193 ini
.Get("Options", "Verbosity", &verbosity
, 0);
194 if (verbosity
< 1) verbosity
= 1;
195 if (verbosity
> MAX_LOGLEVEL
) verbosity
= MAX_LOGLEVEL
;
196 m_verbosity
->SetSelection(verbosity
- 1);
197 ini
.Get("Options", "Font", &font
, 0);
198 m_FontChoice
->SetSelection(font
);
199 if (m_FontChoice
->GetSelection() < (int)Font
.size())
200 m_Log
->SetDefaultStyle(wxTextAttr(wxNullColour
, wxNullColour
, Font
.at(m_FontChoice
->GetSelection())));
201 ini
.Get("Options", "WriteToFile", &m_writeFile
, true);
202 m_writeFileCB
->SetValue(m_writeFile
);
203 ini
.Get("Options", "WriteToConsole", &m_writeConsole
, true);
204 m_writeConsoleCB
->SetValue(m_writeConsole
);
205 ini
.Get("Options", "WriteToWindow", &m_writeWindow
, true);
206 m_writeWindowCB
->SetValue(m_writeWindow
);
207 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
210 ini
.Get("Logs", m_LogManager
->getShortName((LogTypes::LOG_TYPE
)i
), &enable
, true);
212 if (m_writeWindow
&& enable
)
213 m_LogManager
->addListener((LogTypes::LOG_TYPE
)i
, this);
215 m_LogManager
->removeListener((LogTypes::LOG_TYPE
)i
, this);
217 if (m_writeFile
&& enable
)
218 m_LogManager
->addListener((LogTypes::LOG_TYPE
)i
, m_fileLog
);
220 m_LogManager
->removeListener((LogTypes::LOG_TYPE
)i
, m_fileLog
);
222 if (m_writeConsole
&& enable
)
223 m_LogManager
->addListener((LogTypes::LOG_TYPE
)i
, m_console
);
225 m_LogManager
->removeListener((LogTypes::LOG_TYPE
)i
, m_console
);
226 m_LogManager
->setLogLevel((LogTypes::LOG_TYPE
)i
, (LogTypes::LOG_LEVELS
)(verbosity
));
231 void CLogWindow::OnSubmit(wxCommandEvent
& WXUNUSED (event
))
233 if (!m_cmdline
) return;
234 Console_Submit(m_cmdline
->GetValue().To8BitData());
235 m_cmdline
->SetValue(wxEmptyString
);
239 void CLogWindow::OnClear(wxCommandEvent
& WXUNUSED (event
))
243 m_LogSection
.Enter();
244 int msgQueueSize
= (int)msgQueue
.size();
245 for (int i
= 0; i
< msgQueueSize
; i
++)
247 m_LogSection
.Leave();
249 m_console
->ClearScreen();
250 NOTICE_LOG(CONSOLE
, "Console cleared");
254 // Enable or disable all boxes for the current verbosity level and save the changes.
255 void CLogWindow::OnToggleAll(wxCommandEvent
& WXUNUSED (event
))
257 static bool enableAll
= false;
258 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
260 ToggleLog(i
, enableAll
);
264 enableAll
= !enableAll
;
267 // Append checkboxes and update checked groups.
268 void CLogWindow::UpdateChecks()
270 // This is only run once to append checkboxes to the wxCheckListBox.
271 if (m_checks
->GetCount() == 0)
273 // [F|RES] hide the window while we fill it... wxwidgets gets trouble
274 // if you don't do it (at least the win version)
277 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; i
++)
279 m_checks
->Append(wxString::FromAscii(m_LogManager
->getFullName( (LogTypes::LOG_TYPE
)i
)));
285 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; i
++)
288 m_LogManager
->isListener((LogTypes::LOG_TYPE
)i
, this) ||
289 m_LogManager
->isListener((LogTypes::LOG_TYPE
)i
, m_console
) ||
290 m_LogManager
->isListener((LogTypes::LOG_TYPE
)i
, m_fileLog
));
295 void CLogWindow::UnPopulateRight()
297 sRight
->Detach(m_Log
);
298 sRight
->Detach(sRightBottom
);
299 sRightBottom
= new wxBoxSizer(wxHORIZONTAL
);
301 void CLogWindow::PopulateRight()
303 sRightBottom
->Add(m_cmdline
, 1, wxEXPAND
);
304 sRight
->Add(m_Log
, 1, wxEXPAND
| wxSHRINK
);
305 sRight
->Add(sRightBottom
, 0, wxEXPAND
);
309 wxTextCtrl
* CLogWindow::CreateTextCtrl(wxPanel
* parent
, wxWindowID id
, long Style
)
311 wxTextCtrl
* TC
= new wxTextCtrl(parent
, id
, wxEmptyString
, wxDefaultPosition
, wxDefaultSize
, Style
);
312 TC
->SetBackgroundColour(*wxBLACK
);
315 if (m_FontChoice
->GetSelection() < (int)Font
.size())
316 TC
->SetDefaultStyle(wxTextAttr(wxNullColour
, wxNullColour
, Font
.at(m_FontChoice
->GetSelection())));
321 // When an option is changed, save the change
322 void CLogWindow::OnOptionsCheck(wxCommandEvent
& event
)
326 switch (event
.GetId())
331 int v
= m_verbosity
->GetSelection() + 1;
332 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; i
++)
334 m_LogManager
->setLogLevel((LogTypes::LOG_TYPE
)i
, (LogTypes::LOG_LEVELS
)v
);
340 // SetWindowStyleFlag doesn't fully work, we need to redraw the window
341 //m_Log->SetWindowStyleFlag(m_Log->GetWindowStyleFlag() ^ wxTE_DONTWRAP);
342 /* Notice: To retain the colors when changing word wrapping we need to
343 loop through every letter with GetStyle and then reapply them letter by letter */
344 // Prevent m_Log access while it's being destroyed
347 Text
= m_Log
->GetValue();
349 switch (event
.IsChecked())
351 case 0: m_Log
= CreateTextCtrl(this, IDM_LOG
, wxTE_RICH
| wxTE_MULTILINE
| wxTE_READONLY
| wxTE_DONTWRAP
); break;
352 case 1: m_Log
= CreateTextCtrl(this, IDM_LOG
, wxTE_RICH
| wxTE_MULTILINE
| wxTE_READONLY
| wxTE_WORDWRAP
); break;
354 m_Log
->SetDefaultStyle(wxTextAttr(*wxWHITE
));
355 m_Log
->AppendText(Text
);
361 // Update selected font
362 Font
.at(Font
.size()-1) = DebuggerFont
;
363 m_Log
->SetStyle(0, m_Log
->GetLastPosition(), wxTextAttr(wxNullColour
, wxNullColour
, Font
.at(event
.GetSelection())));
364 m_Log
->SetDefaultStyle(wxTextAttr(wxNullColour
, wxNullColour
, Font
.at(event
.GetSelection())));
368 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
370 m_writeFile
= event
.IsChecked();
371 if (m_checks
->IsChecked(i
))
374 m_LogManager
->addListener((LogTypes::LOG_TYPE
)i
, m_fileLog
);
376 m_LogManager
->removeListener((LogTypes::LOG_TYPE
)i
, m_fileLog
);
381 case IDM_WRITEWINDOW
:
382 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
384 m_writeWindow
= event
.IsChecked();
385 if (m_checks
->IsChecked(i
))
388 m_LogManager
->addListener((LogTypes::LOG_TYPE
)i
, this);
390 m_LogManager
->removeListener((LogTypes::LOG_TYPE
)i
, this);
395 case IDM_WRITECONSOLE
:
396 for (int i
= 0; i
< LogTypes::NUMBER_OF_LOGS
; ++i
)
398 m_writeConsole
= event
.IsChecked();
399 if (m_checks
->IsChecked(i
))
402 m_LogManager
->addListener((LogTypes::LOG_TYPE
)i
, m_console
);
404 m_LogManager
->removeListener((LogTypes::LOG_TYPE
)i
, m_console
);
408 if (m_writeConsole && !m_console->IsOpen())
409 wxGetApp().GetCFrame()->ToggleConsole(true);
410 else if (!m_writeConsole && m_console->IsOpen())
411 wxGetApp().GetCFrame()->ToggleConsole(false);
418 // When a checkbox is changed
419 void CLogWindow::OnLogCheck(wxCommandEvent
& event
)
421 int i
= event
.GetInt();
422 ToggleLog(i
, m_checks
->IsChecked(i
));
427 void CLogWindow::ToggleLog(int _logType
, bool enable
)
429 LogTypes::LOG_TYPE logType
= (LogTypes::LOG_TYPE
)_logType
;
431 m_checks
->Check(_logType
, enable
);
433 m_LogManager
->setEnable(logType
, enable
);
438 m_LogManager
->addListener(logType
, this);
440 m_LogManager
->addListener(logType
, m_fileLog
);
442 m_LogManager
->addListener(logType
, m_console
);
446 m_LogManager
->removeListener(logType
, this);
447 m_LogManager
->removeListener(logType
, m_fileLog
);
448 m_LogManager
->removeListener(logType
, m_console
);
452 void CLogWindow::OnLogTimer(wxTimerEvent
& WXUNUSED(event
))
454 if (!m_LogAccess
) return;
458 // Better auto scroll than wxTE_AUTO_SCROLL
459 if (msgQueue
.size() > 0)
461 m_Log
->ScrollLines(1);
462 m_Log
->ShowPosition( m_Log
->GetLastPosition() );
467 void CLogWindow::NotifyUpdate()
473 void CLogWindow::UpdateLog()
475 if (!m_LogAccess
) return;
479 wxString collected_text
;
481 m_LogSection
.Enter();
483 collected_text
.reserve(100 * msgQueue
.size());
484 int msgQueueSize
= (int)msgQueue
.size();
485 for (int i
= 0; i
< msgQueueSize
; i
++)
487 switch (msgQueue
.front().first
)
491 m_Log
->SetDefaultStyle(wxTextAttr(*wxRED
));
495 m_Log
->SetDefaultStyle(wxTextAttr(wxColour(255, 255, 0)));
499 m_Log
->SetDefaultStyle(wxTextAttr(*wxGREEN
));
503 m_Log
->SetDefaultStyle(wxTextAttr(*wxCYAN
));
507 m_Log
->SetDefaultStyle(wxTextAttr(wxColour(211, 211, 211)));
511 m_Log
->SetDefaultStyle(wxTextAttr(*wxWHITE
));
514 if (msgQueue
.front().second
.size())
516 int j
= m_Log
->GetLastPosition();
517 m_Log
->AppendText(msgQueue
.front().second
);
519 m_Log
->SetStyle(j
, j
+ 9, wxTextAttr(*wxWHITE
));
521 collected_text
.Append(msgQueue
.front().second
);
524 m_LogSection
.Leave();
525 // Write all text at once, needs multiple SetStyle, may not be better
526 //if (collected_text.size()) m_Log->AppendText(collected_text);
527 // Return in 0.2 seconds
528 m_LogTimer
->Start(UPDATETIME
);
531 void CLogWindow::Log(LogTypes::LOG_LEVELS level
, const char *text
)
533 m_LogSection
.Enter();
534 if (msgQueue
.size() >= 100)
536 msgQueue
.push(std::pair
<u8
, wxString
>((u8
)level
, wxString(text
, m_SJISConv
)));
537 m_LogSection
.Leave();