Implemented log viewer dialog for the wx gui

- added new class LogViewDialog based on the already removed DebugLogDialog
- log output is only sent to the viewer if visible to avoid performance trouble
- text buffer is limited to 48k, older lines are removed if necessary
- red text color is used for error and panic messages and black for others
- minor related code cleanups
This commit is contained in:
Volker Ruppert 2014-01-12 19:27:01 +00:00
parent a1e397b5a2
commit 71feea84ed
4 changed files with 156 additions and 22 deletions

View File

@ -547,6 +547,109 @@ void PluginControlDialog::ShowHelp()
wxMessageBox(MSG_NO_HELP, MSG_NO_HELP_CAPTION, wxOK | wxICON_ERROR, this);
}
//////////////////////////////////////////////////////////////////////
// LogViewDialog implementation
//////////////////////////////////////////////////////////////////////
// all events go to OnEvent method
BEGIN_EVENT_TABLE(LogViewDialog, wxDialog)
EVT_BUTTON(-1, LogViewDialog::OnEvent)
END_EVENT_TABLE()
LogViewDialog::LogViewDialog(
wxWindow* parent,
wxWindowID id)
: wxDialog(parent, id, wxT(""), wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE)
{
lengthMax = LOG_VIEW_DEFAULT_LENGTH_MAX;
lengthTolerance = LOG_VIEW_DEFAULT_TOLERANCE;
SetTitle(wxT("Bochs Log Viewer"));
mainSizer = new wxBoxSizer(wxVERTICAL);
logSizer = new wxBoxSizer(wxHORIZONTAL);
buttonSizer = new wxBoxSizer(wxHORIZONTAL);
mainSizer->Add(logSizer, 0, wxALIGN_CENTER);
mainSizer->Add(buttonSizer, 0, wxALIGN_CENTER);
log = new wxTextCtrl(this, -1, "",
wxDefaultPosition, wxSize(575, 300),
wxTE_MULTILINE | wxTE_RICH | wxTE_READONLY);
wxFont font(8, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
wxTextAttr attr;
attr.SetFont(font);
log->SetDefaultStyle(attr);
logSizer->Add(log, 1, wxALL|wxGROW, 10);
// buttonSizer contents
wxButton *btn = new wxButton(this, wxID_OK, BTNLABEL_CLOSE);
buttonSizer->Add(btn, 0, wxALL, 5);
}
void LogViewDialog::Init()
{
SetSizer(mainSizer);
mainSizer->Fit(this);
wxSize size = mainSizer->GetMinSize();
int margin = 5;
SetSizeHints(size.GetWidth() + margin, size.GetHeight() + margin);
Center();
}
bool LogViewDialog::Show(bool val)
{
SIM->set_log_viewer(val);
if (val) wxDialog::Raise();
return wxDialog::Show(val);
}
void LogViewDialog::CheckLogLength()
{
// truncate the text control periodically to avoid a
// serious memory leak.
wxString str = log->GetValue();
Bit32u len = str.Length();
if (len > lengthMax + lengthTolerance) {
// Truncate the string. Start from length - lengthMax, search
// forward until we find the first \n.
for (Bit32u i = len - lengthMax; i<len-1; i++) {
if (str.GetChar(i) == '\n') {
// remove the \n and everything before it.
log->Remove(0, i+1);
return;
}
}
// no newline found?!
log->Remove(0, len - lengthMax);
}
}
void LogViewDialog::AppendText(int level, wxString prefix, wxString msg)
{
if ((level == LOGLEV_ERROR) || (level == LOGLEV_PANIC)) {
log->SetDefaultStyle(wxTextAttr(*wxRED));
} else {
log->SetDefaultStyle(wxTextAttr(*wxBLACK));
}
log->AppendText(prefix);
log->AppendText(wxT(" "));
log->AppendText(msg);
log->AppendText(wxT("\n"));
int n = log->GetLastPosition();
if (n>0) n--;
log->ShowPosition(n);
CheckLogLength();
}
void LogViewDialog::OnEvent(wxCommandEvent& event)
{
int id = event.GetId();
switch (id) {
case wxID_OK:
Show(false);
break;
default:
event.Skip();
}
}
/////////////////////////////////////////////////////////////////
// ParamDialog
/////////////////////////////////////////////////////////////////

View File

@ -33,6 +33,7 @@
#define BTNLABEL_HELP wxT("Help")
#define BTNLABEL_CANCEL wxT("Cancel")
#define BTNLABEL_OK wxT("Ok")
#define BTNLABEL_CLOSE wxT("Close")
#define BTNLABEL_CREATE_IMG wxT("Create Image")
#define BTNLABEL_BROWSE wxT("<--Browse")
@ -198,6 +199,29 @@ public:
DECLARE_EVENT_TABLE()
};
////////////////////////////////////////////////////////////////////////////
// LogViewDialog
////////////////////////////////////////////////////////////////////////////
class LogViewDialog: public wxDialog
{
private:
wxBoxSizer *mainSizer, *logSizer, *buttonSizer;
wxTextCtrl *log;
Bit32u lengthMax;
Bit32u lengthTolerance;
#define LOG_VIEW_DEFAULT_LENGTH_MAX (400*80)
#define LOG_VIEW_DEFAULT_TOLERANCE (200*80)
void CheckLogLength();
public:
LogViewDialog(wxWindow* parent, wxWindowID id);
~LogViewDialog() {}
void Init();
bool Show(bool val);
void AppendText(int level, wxString prefix, wxString msg);
void OnEvent(wxCommandEvent& event);
DECLARE_EVENT_TABLE()
};
////////////////////////////////////////////////////////////////////////////
// ParamDialog is a general purpose dialog box that displays and edits
// any combination of parameters. It's always made up of a

View File

@ -288,8 +288,8 @@ BxEvent *MyApp::DefaultCallback(void *thisptr, BxEvent *event)
fprintf(stderr, "%s\n", (const char *)text.mb_str(wxConvUTF8));
} else {
wxMessageBox(text, wxT("Error"), wxOK | wxICON_ERROR);
// maybe I can make OnLogMsg display something that looks appropriate.
// theFrame->OnLogMsg(event);
// maybe I can make OnLogAsk display something that looks appropriate.
// theFrame->OnLogAsk(event);
}
event->retcode = BX_LOG_ASK_CHOICE_DIE;
// There is only one thread at this point. if I choose DIE here, it will
@ -350,6 +350,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_Edit_Other, MyFrame::OnEditOther)
EVT_MENU(ID_Log_Prefs, MyFrame::OnLogPrefs)
EVT_MENU(ID_Log_PrefsDevice, MyFrame::OnLogPrefsDevice)
EVT_MENU(ID_Log_View, MyFrame::OnLogView)
// toolbar events
EVT_TOOL(ID_Edit_FD_0, MyFrame::OnToolbarClick)
EVT_TOOL(ID_Edit_FD_1, MyFrame::OnToolbarClick)
@ -360,7 +361,6 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_TOOL(ID_Toolbar_Copy, MyFrame::OnToolbarClick)
EVT_TOOL(ID_Toolbar_Paste, MyFrame::OnToolbarClick)
EVT_TOOL(ID_Toolbar_Snapshot, MyFrame::OnToolbarClick)
/*EVT_TOOL(ID_Toolbar_Config, MyFrame::OnToolbarClick)*/
EVT_TOOL(ID_Toolbar_Mouse_en, MyFrame::OnToolbarClick)
EVT_TOOL(ID_Toolbar_User, MyFrame::OnToolbarClick)
END_EVENT_TABLE()
@ -481,8 +481,6 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
menuBar->Append(menuHelp, wxT("&Help"));
SetMenuBar(menuBar);
// disable things that don't work yet
menuLog->Enable(ID_Log_View, FALSE); // not implemented
// enable ATA channels in menu
menuEdit->Enable(ID_Edit_ATA1, BX_MAX_ATA_CHANNEL > 1);
menuEdit->Enable(ID_Edit_ATA2, BX_MAX_ATA_CHANNEL > 2);
@ -514,9 +512,6 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
BX_ADD_TOOL(ID_Toolbar_Copy, copy_xpm, wxT("Copy to clipboard"));
BX_ADD_TOOL(ID_Toolbar_Paste, paste_xpm, wxT("Paste from clipboard"));
BX_ADD_TOOL(ID_Toolbar_Snapshot, snapshot_xpm, wxT("Save screen snapshot"));
// Omit config button because the whole wxWidgets interface is like
// one really big config button.
//BX_ADD_TOOL(ID_Toolbar_Config, configbutton_xpm, "Runtime Configuration");
BX_ADD_TOOL(ID_Toolbar_Mouse_en, mouse_xpm, wxT("Enable mouse capture\nThere is also a shortcut for this: a CTRL key + the middle mouse button."));
BX_ADD_TOOL(ID_Toolbar_User, userbutton_xpm, wxT("Keyboard shortcut"));
@ -531,11 +526,16 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
sz->Add(panel, 0, wxGROW);
SetAutoLayout(TRUE);
SetSizer(sz);
// create modeless logfile viewer
showLogView = new LogViewDialog(this, -1);
showLogView->Init();
}
MyFrame::~MyFrame()
{
delete panel;
delete showLogView;
wxLogDebug(wxT("MyFrame destructor"));
theFrame = NULL;
}
@ -784,6 +784,12 @@ void MyFrame::OnLogPrefsDevice(wxCommandEvent& WXUNUSED(event))
dlg.ShowModal();
}
void MyFrame::OnLogView(wxCommandEvent& WXUNUSED(event))
{
wxASSERT(showLogView != NULL);
showLogView->Show(true);
}
void MyFrame::OnQuit(wxCommandEvent& event)
{
wxBochsClosing = true;
@ -1112,9 +1118,14 @@ void MyFrame::OnSim2CIEvent(wxCommandEvent& event)
sim_thread->SendSyncResponse(be);
wxLogDebug(wxT("after SendSyncResponse"));
break;
case BX_SYNC_EVT_LOG_ASK:
case BX_ASYNC_EVT_LOG_MSG:
OnLogMsg(be);
showLogView->AppendText(be->u.logmsg.level, wxString(be->u.logmsg.prefix, wxConvUTF8),
wxString(be->u.logmsg.msg, wxConvUTF8));
free((void*)be->u.logmsg.prefix);
free((void*)be->u.logmsg.msg);
break;
case BX_SYNC_EVT_LOG_ASK:
OnLogAsk(be);
break;
case BX_ASYNC_EVT_QUIT_SIM:
wxMessageBox(wxT("Bochs simulation has stopped."), wxT("Bochs Stopped"),
@ -1133,16 +1144,13 @@ void MyFrame::OnSim2CIEvent(wxCommandEvent& event)
delete be;
}
void MyFrame::OnLogMsg(BxEvent *be)
void MyFrame::OnLogAsk(BxEvent *be)
{
wxLogDebug(wxT("log msg: level=%d, prefix='%s', msg='%s'"),
be->u.logmsg.level,
be->u.logmsg.prefix,
be->u.logmsg.msg);
if (be->type == BX_ASYNC_EVT_LOG_MSG)
return; // we don't have any place to display log messages
else
wxASSERT(be->type == BX_SYNC_EVT_LOG_ASK);
wxASSERT(be->type == BX_SYNC_EVT_LOG_ASK);
wxString levelName(SIM->get_log_level_name(be->u.logmsg.level), wxConvUTF8);
LogMsgAskDialog dlg(this, -1, levelName); // panic, error, etc.
#if !BX_DEBUGGER && !BX_GDBSTUB
@ -1161,9 +1169,9 @@ void MyFrame::OnLogMsg(BxEvent *be)
wxLogDebug(wxT("you chose %d"), n);
// This can be called from two different contexts:
// 1) before sim_thread starts, the default application callback can
// call OnLogMsg to display messages.
// call OnLogAsk to display messages.
// 2) after the sim_thread starts, the sim_thread callback can call
// OnLogMsg to display messages
// OnLogAsk to display messages
if (sim_thread)
sim_thread->SendSyncResponse(be); // only for case #2
}

View File

@ -29,9 +29,7 @@ class MyFrame;
class MyPanel;
class SimThread;
class ParamDialog;
#if BX_DEBUGGER
class DebugLogDialog;
#endif
class LogViewDialog;
//hack alert; yuck; FIXME
extern MyFrame *theFrame;
@ -85,7 +83,6 @@ enum
ID_Toolbar_Copy,
ID_Toolbar_Paste,
ID_Toolbar_Snapshot,
/*ID_Toolbar_Config,*/
ID_Toolbar_Mouse_en,
ID_Toolbar_User,
ID_Toolbar_SaveRestore,
@ -187,7 +184,7 @@ public:
bx_bool SimThreadControl(bx_bool resume);
void OnKillSim(wxCommandEvent& event);
void OnSim2CIEvent(wxCommandEvent& event);
void OnLogMsg(BxEvent *logMsgEvent);
void OnLogAsk(BxEvent *be);
void OnEditPluginCtrl(wxCommandEvent& event);
void OnEditCPU(wxCommandEvent& event);
void OnEditCPUID(wxCommandEvent& event);
@ -203,6 +200,7 @@ public:
void OnEditOther(wxCommandEvent& event);
void OnLogPrefs(wxCommandEvent& event);
void OnLogPrefsDevice(wxCommandEvent& event);
void OnLogView(wxCommandEvent& event);
void OnEditATA(wxCommandEvent& event);
void editFloppyConfig(int drive);
void editFirstCdrom();
@ -227,6 +225,7 @@ private:
wxMenu *menuLog;
wxMenu *menuHelp;
wxToolBar *bxToolBar;
LogViewDialog *showLogView;
public:
DECLARE_EVENT_TABLE()