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