1 #include "../filezilla.h"
2 #include "../Options.h"
3 #include "settingsdialog.h"
4 #include "optionspage.h"
5 #include "optionspage_logging.h"
6 #include "../textctrlex.h"
7 
8 #include <wx/filedlg.h>
9 #include <wx/statbox.h>
10 
11 struct COptionsPageLogging::impl final
12 {
13 	wxCheckBox* timestamps_{};
14 	wxCheckBox* log_{};
15 	wxTextCtrlEx* file_{};
16 	wxButton* browse_{};
17 	wxCheckBox* do_limit_{};
18 	wxTextCtrlEx* limit_{};
19 };
20 
COptionsPageLogging()21 COptionsPageLogging::COptionsPageLogging()
22 	: impl_(std::make_unique<impl>())
23 {}
24 
~COptionsPageLogging()25 COptionsPageLogging::~COptionsPageLogging()
26 {
27 }
28 
CreateControls(wxWindow * parent)29 bool COptionsPageLogging::CreateControls(wxWindow* parent)
30 {
31 	auto const& lay = m_pOwner->layout();
32 
33 	Create(parent);
34 	auto main = lay.createFlex(1);
35 	main->AddGrowableCol(0);
36 	main->AddGrowableRow(0);
37 	SetSizer(main);
38 
39 	{
40 		auto [box, inner] = lay.createStatBox(main, _("Logging"), 1);
41 
42 		impl_->timestamps_ = new wxCheckBox(box, nullID, _("&Show timestamps in message log"));
43 		inner->Add(impl_->timestamps_);
44 
45 		impl_->log_ = new wxCheckBox(box, nullID, _("&Log to file"));
46 		inner->Add(impl_->log_);
47 		auto row = lay.createFlex(3);
48 		row->AddGrowableCol(1);
49 		inner->Add(row, 0, wxLEFT|wxGROW, lay.indent);
50 		row->Add(new wxStaticText(box, nullID, _("Filename:")), lay.valign);
51 		impl_->file_ = new wxTextCtrlEx(box, nullID, wxString());
52 		row->Add(impl_->file_, lay.valigng);
53 		impl_->browse_ = new wxButton(box, nullID, _("&Browse"));
54 		row->Add(impl_->browse_, lay.valign);
55 		impl_->browse_->Bind(wxEVT_BUTTON, &COptionsPageLogging::OnBrowse, this);
56 
57 		impl_->do_limit_ = new wxCheckBox(box, nullID, _("Limit size of logfile"));
58 		inner->Add(impl_->do_limit_, 0, wxLEFT, lay.indent);
59 		row = lay.createFlex(3);
60 		inner->Add(row, 0, wxLEFT, lay.indent * 2);
61 		row->Add(new wxStaticText(box, nullID, _("Limit:")), lay.valign);
62 		impl_->limit_ = new wxTextCtrlEx(box, nullID, wxString());
63 		row->Add(impl_->limit_, lay.valign)->SetMinSize(lay.dlgUnits(20), -1);
64 		impl_->limit_->SetMaxLength(4);
65 		row->Add(new wxStaticText(box, nullID, _("MiB")), lay.valign);
66 
67 		inner->Add(new wxStaticText(box, nullID, _("If the size of the logfile reaches the limit, it gets renamed by adding \".1\" to the end of the filename (possibly overwriting older logfiles) and a new file gets created.")), 0, wxLEFT, lay.indent * 2);
68 		inner->Add(new wxStaticText(box, nullID, _("Changing logfile settings requires restart of FileZilla.")), 0, wxLEFT, lay.indent);
69 
70 		impl_->do_limit_->Bind(wxEVT_CHECKBOX, &COptionsPageLogging::OnCheck, this);
71 		impl_->log_->Bind(wxEVT_CHECKBOX, &COptionsPageLogging::OnCheck, this);
72 	}
73 
74 	return true;
75 }
LoadPage()76 bool COptionsPageLogging::LoadPage()
77 {
78 	impl_->timestamps_->SetValue(m_pOptions->get_bool(OPTION_MESSAGELOG_TIMESTAMP));
79 
80 	std::wstring const filename = m_pOptions->get_string(OPTION_LOGGING_FILE);
81 	impl_->log_->SetValue(!filename.empty());
82 	impl_->file_->ChangeValue(filename);
83 
84 	int const limit = m_pOptions->get_int(OPTION_LOGGING_FILE_SIZELIMIT);
85 	impl_->do_limit_->SetValue(limit > 0);
86 	impl_->limit_->ChangeValue(fz::to_wstring(limit));
87 
88 	SetCtrlState();
89 
90 	return true;
91 }
92 
SavePage()93 bool COptionsPageLogging::SavePage()
94 {
95 	m_pOptions->set(OPTION_MESSAGELOG_TIMESTAMP, impl_->timestamps_->GetValue());
96 
97 	std::wstring file;
98 	if (impl_->log_->GetValue()) {
99 		file = impl_->file_->GetValue().ToStdWstring();
100 	}
101 	m_pOptions->set(OPTION_LOGGING_FILE, file);
102 
103 	if (impl_->do_limit_->GetValue()) {
104 		m_pOptions->set(OPTION_LOGGING_FILE_SIZELIMIT, fz::to_integral<int>(impl_->limit_->GetValue().ToStdWstring()));
105 	}
106 	else {
107 		m_pOptions->set(OPTION_LOGGING_FILE_SIZELIMIT, 0);
108 	}
109 
110 	return true;
111 }
112 
Validate()113 bool COptionsPageLogging::Validate()
114 {
115 	if (impl_->log_->GetValue()) {
116 		wxString file = impl_->file_->GetValue();
117 		if (file.empty()) {
118 			return DisplayError(impl_->file_, _("You need to enter a name for the log file."));
119 		}
120 
121 		wxFileName fn(file);
122 		if (!fn.IsOk() || !fn.DirExists()) {
123 			return DisplayError(impl_->file_, _("Directory containing the logfile does not exist or filename is invalid."));
124 		}
125 
126 		if (impl_->do_limit_->GetValue()) {
127 			auto v = fz::to_integral<int>(impl_->limit_->GetValue().ToStdWstring());
128 			if (v < 1 || v > 2000) {
129 				return DisplayError(impl_->limit_, _("The limit needs to be between 1 and 2000 MiB"));
130 			}
131 		}
132 	}
133 	return true;
134 }
135 
SetCtrlState()136 void COptionsPageLogging::SetCtrlState()
137 {
138 	bool const log_to_file = impl_->log_->GetValue();
139 	bool const limit = impl_->do_limit_->GetValue();
140 
141 	impl_->file_->Enable(log_to_file);
142 	impl_->browse_->Enable(log_to_file);
143 	impl_->do_limit_->Enable(log_to_file);
144 	impl_->limit_->Enable(log_to_file && limit);
145 }
146 
OnBrowse(wxCommandEvent &)147 void COptionsPageLogging::OnBrowse(wxCommandEvent&)
148 {
149 	wxFileDialog dlg(this, _("Log file"), wxString(), _T("filezilla.log"), _T("Log files (*.log)|*.log"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
150 
151 	if (dlg.ShowModal() != wxID_OK) {
152 		return;
153 	}
154 
155 	impl_->file_->ChangeValue(dlg.GetPath());
156 }
157 
OnCheck(wxCommandEvent &)158 void COptionsPageLogging::OnCheck(wxCommandEvent&)
159 {
160 	SetCtrlState();
161 }
162