1 // Copyright (c) 2010, Amar Takhar
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of the Aegisub Group nor the names of its contributors
13 //     may be used to endorse or promote products derived from this software
14 //     without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 //
28 // Aegisub Project http://www.aegisub.org/
29 
30 #include "compat.h"
31 #include "dialog_manager.h"
32 #include "format.h"
33 #include "include/aegisub/context.h"
34 
35 #include <libaegisub/dispatch.h>
36 #include <libaegisub/log.h>
37 
38 #include <ctime>
39 #include <wx/button.h>
40 #include <wx/dialog.h>
41 #include <wx/sizer.h>
42 #include <wx/stattext.h>
43 #include <wx/textctrl.h>
44 
45 namespace {
46 class EmitLog final : public agi::log::Emitter {
47 	wxTextCtrl *text_ctrl;
48 public:
EmitLog(wxTextCtrl * t)49 	EmitLog(wxTextCtrl *t)
50 	: text_ctrl(t)
51 	{
52 		for (auto const& sm : agi::log::log->GetMessages())
53 			log(sm);
54 	}
55 
log(agi::log::SinkMessage const & sm)56 	void log(agi::log::SinkMessage const& sm) override {
57 		time_t time = sm.time / 1000000000;
58 #ifndef _WIN32
59 		tm tmtime;
60 		localtime_r(&time, &tmtime);
61 		auto log = fmt_wx("%c %02d:%02d:%02d %-6d <%-25s> [%s:%s:%d]  %s\n",
62 			agi::log::Severity_ID[sm.severity],
63 			tmtime.tm_hour,
64 			tmtime.tm_min,
65 			tmtime.tm_sec,
66 			(sm.time % 1000000000),
67 			sm.section,
68 			sm.file,
69 			sm.func,
70 			sm.line,
71 			sm.message);
72 #else
73 		auto log = fmt_wx("%c %-6ld <%-25s> [%s:%s:%d]  %s\n",
74 			agi::log::Severity_ID[sm.severity],
75 			(sm.time % 1000000000),
76 			sm.section,
77 			sm.file,
78 			sm.func,
79 			sm.line,
80 			sm.message);
81 #endif
82 
83 		if (wxIsMainThread())
84 			text_ctrl->AppendText(log);
85 		else
86 			agi::dispatch::Main().Async([=]{ text_ctrl->AppendText(log); });
87 	}
88 };
89 
90 class LogWindow : public wxDialog {
91 	agi::log::Emitter *emit_log;
92 
93 public:
94 	LogWindow(agi::Context *c);
95 	~LogWindow();
96 };
97 
LogWindow(agi::Context * c)98 LogWindow::LogWindow(agi::Context *c)
99 : wxDialog(c->parent, -1, _("Log window"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER)
100 {
101 	wxTextCtrl *text_ctrl = new wxTextCtrl(this, -1, "", wxDefaultPosition, wxSize(700,300), wxTE_MULTILINE|wxTE_READONLY);
102 	text_ctrl->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)));
103 
104 	wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
105 	sizer->Add(text_ctrl, wxSizerFlags(1).Expand().Border());
106 	sizer->Add(new wxButton(this, wxID_OK), wxSizerFlags(0).Border().Right());
107 	SetSizerAndFit(sizer);
108 
109 	agi::log::log->Subscribe(std::unique_ptr<agi::log::Emitter>(emit_log = new EmitLog(text_ctrl)));
110 }
111 
~LogWindow()112 LogWindow::~LogWindow() {
113 	agi::log::log->Unsubscribe(emit_log);
114 }
115 }
116 
ShowLogWindow(agi::Context * c)117 void ShowLogWindow(agi::Context *c) {
118 	c->dialog->Show<LogWindow>(c);
119 }
120