1 #include "../filezilla.h"
2 #include "settingsdialog.h"
3 #include "../Options.h"
4 #include "optionspage.h"
5 #include "optionspage_connection.h"
6 #include "optionspage_connection_ftp.h"
7 #include "optionspage_connection_active.h"
8 #include "optionspage_connection_passive.h"
9 #include "optionspage_ftpproxy.h"
10 #include "optionspage_connection_sftp.h"
11 #include "optionspage_filetype.h"
12 #include "optionspage_fileexists.h"
13 #include "optionspage_themes.h"
14 #include "optionspage_language.h"
15 #include "optionspage_transfer.h"
16 #include "optionspage_updatecheck.h"
17 #include "optionspage_logging.h"
18 #include "optionspage_debug.h"
19 #include "optionspage_interface.h"
20 #include "optionspage_dateformatting.h"
21 #include "optionspage_sizeformatting.h"
22 #include "optionspage_edit.h"
23 #include "optionspage_edit_associations.h"
24 #include "optionspage_passwords.h"
25 #include "optionspage_proxy.h"
26 #include "optionspage_filelists.h"
27 #include "../filezillaapp.h"
28 #include "../Mainfrm.h"
29 #include "../treectrlex.h"
30 
CSettingsDialog(CFileZillaEngineContext & engine_context)31 CSettingsDialog::CSettingsDialog(CFileZillaEngineContext & engine_context)
32 	: m_engine_context(engine_context)
33 {
34 	m_pOptions = COptions::Get();
35 }
36 
~CSettingsDialog()37 CSettingsDialog::~CSettingsDialog()
38 {
39 	m_activePanel = nullptr;
40 	m_pages.clear();
41 
42 	if (tree_) {
43 		// Trees can generate these events during destruction, not good.
44 		tree_->Unbind(wxEVT_TREE_SEL_CHANGING, &CSettingsDialog::OnPageChanging, this);
45 		tree_->Unbind(wxEVT_TREE_SEL_CHANGED, &CSettingsDialog::OnPageChanged, this);
46 	}
47 }
48 
Create(CMainFrame * pMainFrame)49 bool CSettingsDialog::Create(CMainFrame* pMainFrame)
50 {
51 	m_pMainFrame = pMainFrame;
52 
53 	SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
54 	if (!wxDialogEx::Create(pMainFrame, nullID, _("Settings"))) {
55 		return false;
56 	}
57 
58 	auto & lay = layout();
59 	auto * main = lay.createMain(this, 2);
60 	main->AddGrowableRow(0);
61 
62 	auto* left = lay.createFlex(1);
63 	left->AddGrowableRow(1);
64 	main->Add(left, 1, wxGROW);
65 
66 	left->Add(new wxStaticText(this, nullID, _("Select &page:")));
67 
68 	tree_ = new wxTreeCtrlEx(this, nullID, wxDefaultPosition, wxDefaultSize, DEFAULT_TREE_STYLE | wxTR_HIDE_ROOT);
69 	tree_->SetFocus();
70 	left->Add(tree_, 1, wxGROW);
71 
72 	auto ok = new wxButton(this, wxID_OK, _("OK"));
73 	ok->Bind(wxEVT_BUTTON, &CSettingsDialog::OnOK, this);
74 	ok->SetDefault();
75 	left->Add(ok, lay.grow);
76 	auto cancel = new wxButton(this, wxID_CANCEL, _("Cancel"));
77 	cancel->Bind(wxEVT_BUTTON, &CSettingsDialog::OnCancel, this);
78 	left->Add(cancel, lay.grow);
79 
80 	pagePanel_ = new wxPanel(this);
81 	main->Add(pagePanel_, lay.grow);
82 
83 	tree_->Bind(wxEVT_TREE_SEL_CHANGING, &CSettingsDialog::OnPageChanging, this);
84 	tree_->Bind(wxEVT_TREE_SEL_CHANGED, &CSettingsDialog::OnPageChanged, this);
85 
86 	if (!LoadPages()) {
87 		return false;
88 	}
89 
90 	return true;
91 }
92 
AddPage(wxString const & name,COptionsPage * page,int nest)93 void CSettingsDialog::AddPage(wxString const& name, COptionsPage* page, int nest)
94 {
95 	wxTreeItemId parent = tree_->GetRootItem();
96 	while (nest--) {
97 		parent = tree_->GetLastChild(parent);
98 		wxCHECK_RET(parent != wxTreeItemId(), "Nesting level too deep");
99 	}
100 
101 	t_page p;
102 	p.page = page;
103 	p.id = tree_->AppendItem(parent, name);
104 	if (parent != tree_->GetRootItem()) {
105 		tree_->Expand(parent);
106 	}
107 
108 	m_pages.push_back(p);
109 }
110 
LoadPages()111 bool CSettingsDialog::LoadPages()
112 {
113 	// Get the tree control.
114 
115 	if (!tree_) {
116 		return false;
117 	}
118 
119 	tree_->AddRoot(wxString());
120 
121 	// Create the instances of the page classes and fill the tree.
122 	AddPage(_("Connection"), new COptionsPageConnection, 0);
123 	AddPage(_("FTP"), new COptionsPageConnectionFTP, 1);
124 	AddPage(_("Active mode"), new COptionsPageConnectionActive, 2);
125 	AddPage(_("Passive mode"), new COptionsPageConnectionPassive, 2);
126 	AddPage(_("FTP Proxy"), new COptionsPageFtpProxy, 2);
127 	AddPage(_("SFTP"), new COptionsPageConnectionSFTP, 1);
128 	AddPage(_("Generic proxy"), new COptionsPageProxy, 1);
129 	AddPage(_("Transfers"), new COptionsPageTransfer, 0);
130 	AddPage(_("FTP: File Types"), new COptionsPageFiletype, 1);
131 	AddPage(_("File exists action"), new COptionsPageFileExists, 1);
132 	AddPage(_("Interface"), new COptionsPageInterface, 0);
133 	AddPage(_("Passwords"), new COptionsPagePasswords, 1);
134 	AddPage(_("Themes"), new COptionsPageThemes, 1);
135 	AddPage(_("Date/time format"), new COptionsPageDateFormatting, 1);
136 	AddPage(_("Filesize format"), new COptionsPageSizeFormatting, 1);
137 	AddPage(_("File lists"), new COptionsPageFilelists, 1);
138 	AddPage(_("Language"), new COptionsPageLanguage, 0);
139 	AddPage(_("File editing"), new COptionsPageEdit, 0);
140 	AddPage(_("Filetype associations"), new COptionsPageEditAssociations, 1);
141 #if FZ_MANUALUPDATECHECK && FZ_AUTOUPDATECHECK
142 	if (!m_pOptions->get_int(OPTION_DEFAULT_DISABLEUPDATECHECK)) {
143 		AddPage(_("Updates"), new COptionsPageUpdateCheck, 0);
144 	}
145 #endif //FZ_MANUALUPDATECHECK && FZ_AUTOUPDATECHECK
146 	AddPage(_("Logging"), new COptionsPageLogging, 0);
147 	AddPage(_("Debug"), new COptionsPageDebug, 0);
148 
149 	tree_->SetQuickBestSize(false);
150 	tree_->InvalidateBestSize();
151 	tree_->SetInitialSize();
152 
153 	// Compensate for scrollbar
154 	wxSize size = tree_->GetBestSize();
155 	int scrollWidth = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X, tree_);
156 	size.x += scrollWidth + 2;
157 	size.y = 400;
158 	tree_->SetInitialSize(size);
159 	Layout();
160 
161 	// Before we can initialize the pages, get the target panel in the settings
162 	// dialog.
163 	if (!pagePanel_) {
164 		return false;
165 	}
166 
167 	// Keep track of maximum page size
168 	size = wxSize();
169 
170 	for (auto const& page : m_pages) {
171 		if (!page.page->CreatePage(m_pOptions, this, pagePanel_, size)) {
172 			return false;
173 		}
174 	}
175 
176 	if (!LoadSettings()) {
177 		wxMessageBoxEx(_("Failed to load panels, invalid resource files?"));
178 		return false;
179 	}
180 
181 	wxSize canvas;
182 	canvas.x = GetSize().x - pagePanel_->GetSize().x;
183 	canvas.y = GetSize().y - pagePanel_->GetSize().y;
184 
185 	// Wrap pages nicely
186 	std::vector<wxWindow*> pages;
187 	for (auto const& page : m_pages) {
188 		pages.push_back(page.page);
189 	}
190 	wxGetApp().GetWrapEngine()->WrapRecursive(pages, 1.33, "Settings", canvas);
191 
192 #ifdef __WXGTK__
193 	// Pre-show dialog under GTK, else panels won't get initialized properly
194 	Show();
195 #endif
196 
197 	GetSizer()->Fit(this);
198 
199 	// Keep track of maximum page size
200 	size = pagePanel_->GetClientSize();
201 	for (auto const& page : m_pages) {
202 		auto sizer = page.page->GetSizer();
203 		if (sizer) {
204 			size.IncTo(sizer->GetMinSize());
205 		}
206 	}
207 
208 	wxSize panelSize = size;
209 #ifdef __WXGTK__
210 	panelSize.x += 1;
211 #endif
212 	pagePanel_->SetInitialSize(panelSize);
213 
214 	// Adjust pages sizes according to maximum size
215 	for (auto const& page : m_pages) {
216 		auto sizer = page.page->GetSizer();
217 		if (sizer) {
218 			sizer->SetMinSize(size);
219 			sizer->Fit(page.page);
220 			sizer->SetSizeHints(page.page);
221 		}
222 		if (GetLayoutDirection() == wxLayout_RightToLeft) {
223 			page.page->Move(wxPoint(1, 0));
224 		}
225 	}
226 
227 	GetSizer()->Fit(this);
228 
229 	for (auto const& page : m_pages) {
230 		page.page->Hide();
231 	}
232 
233 	// Select first page
234 	tree_->SelectItem(m_pages[0].id);
235 	if (!m_activePanel)	{
236 		m_activePanel = m_pages[0].page;
237 		m_activePanel->Display();
238 	}
239 
240 	return true;
241 }
242 
LoadSettings()243 bool CSettingsDialog::LoadSettings()
244 {
245 	for (auto const& page : m_pages) {
246 		if (!page.page->LoadPage()) {
247 			return false;
248 		}
249 	}
250 
251 	return true;
252 }
253 
OnPageChanged(wxTreeEvent & event)254 void CSettingsDialog::OnPageChanged(wxTreeEvent& event)
255 {
256 	if (m_activePanel) {
257 		m_activePanel->Hide();
258 	}
259 
260 	wxTreeItemId item = event.GetItem();
261 
262 	for (auto const& page : m_pages) {
263 		if (page.id == item) {
264 			m_activePanel = page.page;
265 			m_activePanel->Display();
266 			break;
267 		}
268 	}
269 }
270 
OnOK(wxCommandEvent &)271 void CSettingsDialog::OnOK(wxCommandEvent&)
272 {
273 	for (auto const& page : m_pages) {
274 		if (!page.page->Validate()) {
275 			if (m_activePanel != page.page) {
276 				tree_->SelectItem(page.id);
277 			}
278 			return;
279 		}
280 	}
281 
282 	for (auto const& page : m_pages) {
283 		page.page->SavePage();
284 	}
285 
286 	m_activePanel = nullptr;
287 	m_pages.clear();
288 
289 	EndModal(wxID_OK);
290 }
291 
OnCancel(wxCommandEvent &)292 void CSettingsDialog::OnCancel(wxCommandEvent&)
293 {
294 	m_activePanel = nullptr;
295 	m_pages.clear();
296 
297 	EndModal(wxID_CANCEL);
298 
299 	for (auto const& saved : m_oldValues) {
300 		m_pOptions->set(saved.first, saved.second);
301 	}
302 }
303 
OnPageChanging(wxTreeEvent & event)304 void CSettingsDialog::OnPageChanging(wxTreeEvent& event)
305 {
306 	if (!m_activePanel) {
307 		return;
308 	}
309 
310 	if (!m_activePanel->Validate()) {
311 		event.Veto();
312 	}
313 }
314 
RememberOldValue(interfaceOptions option)315 void CSettingsDialog::RememberOldValue(interfaceOptions option)
316 {
317 	m_oldValues[option] = m_pOptions->get_string(option);
318 }
319