2 * @file PreferencesDlg.cpp
4 * @brief Implementation file for CPreferencesDlg
6 * @note This code originates from AbstractSpoon / TodoList
7 * (http://www.abstractspoon.com/) but is modified to use in
12 #include "PreferencesDlg.h"
14 #include "UnicodeString.h"
15 #include "OptionsDef.h"
16 #include "OptionsMgr.h"
17 #include "SyntaxColors.h"
20 #include "FileOrFolderSelect.h"
21 #include "OptionsSyntaxColors.h"
28 * @brief Location for file compare specific help to open.
30 static TCHAR OptionsHelpLocation[] = _T("::/htmlhelp/Configuration.html");
32 /////////////////////////////////////////////////////////////////////////////
33 // CPreferencesDlg dialog
35 const TCHAR PATHDELIM = '>';
37 CPreferencesDlg::CPreferencesDlg(COptionsMgr *regOptions, SyntaxColors *colors,
38 UINT nMenuID /*= 0*/, CWnd* pParent /*= nullptr*/) // standard constructor
39 : CTrDialog(IDD_PREFERENCES, pParent)
40 , m_pOptionsMgr(regOptions)
41 , m_pSyntaxColors(colors)
42 , m_pageGeneral(regOptions)
43 , m_pageCompare(regOptions)
44 , m_pageMessageBoxes(regOptions)
45 , m_pageColorSchemes(regOptions)
46 , m_pageMergeColors(regOptions)
47 , m_pageTextColors(regOptions, colors)
48 , m_pageSyntaxColors(regOptions, colors)
49 , m_pageMarkerColors(regOptions, colors)
50 , m_pageDirColors(regOptions)
51 , m_pageArchive(regOptions)
52 , m_pageCodepage(regOptions)
53 , m_pageEditor(regOptions)
54 , m_pageEditorSyntax(regOptions)
55 , m_pageProject(regOptions)
56 , m_pageSystem(regOptions)
57 , m_pageBackups(regOptions)
58 , m_pageShell(regOptions)
59 , m_pageCompareFolder(regOptions)
60 , m_pageCompareTable(regOptions)
61 , m_pageCompareBinary(regOptions)
62 , m_pageCompareImage(regOptions)
64 UNREFERENCED_PARAMETER(nMenuID);
67 CPreferencesDlg::~CPreferencesDlg()
71 void CPreferencesDlg::DoDataExchange(CDataExchange* pDX)
73 CDialog::DoDataExchange(pDX);
74 //{{AFX_DATA_MAP(CPreferencesDlg)
75 DDX_Control(pDX, IDC_TREEOPT_PAGES, m_tcPages);
79 BEGIN_MESSAGE_MAP(CPreferencesDlg, CTrDialog)
80 //{{AFX_MSG_MAP(CPreferencesDlg)
82 ON_COMMAND(ID_HELP, OnHelpButton)
83 ON_BN_CLICKED(IDC_TREEOPT_HELP, OnHelpButton)
84 ON_NOTIFY(TVN_SELCHANGED, IDC_TREEOPT_PAGES, OnSelchangedPages)
85 ON_BN_CLICKED(IDC_TREEOPT_IMPORT, OnImportButton)
86 ON_BN_CLICKED(IDC_TREEOPT_EXPORT, OnExportButton)
87 ON_MESSAGE(WM_APP + IDC_COLOR_SCHEMES, OnColorSchemeChanged)
91 /////////////////////////////////////////////////////////////////////////////
92 // CPreferencesDlg message handlers
94 BOOL CPreferencesDlg::OnInitDialog()
96 CTrDialog::OnInitDialog();
98 m_tcPages.SetIndent(0);
100 // Second parameter is 'path', page's parent page(s) and caption.
101 // '>' is used as path separator.
102 // For example "General" creates top-level "General" page
103 // and "General>Colors" creates "Colors" sub-page for "General"
104 AddPage(&m_pageGeneral, IDS_OPTIONSPG_GENERAL);
105 AddPage(&m_pageCompare, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_GENCOMPARE);
106 AddPage(&m_pageCompareFolder, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_FOLDERCOMPARE);
107 AddPage(&m_pageCompareTable, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_TABLECOMPARE);
108 AddPage(&m_pageCompareBinary, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_BINARYCOMPARE);
109 AddPage(&m_pageCompareImage, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_IMAGECOMPARE);
110 AddPage(&m_pageMessageBoxes, IDS_OPTIONSPG_MESSAGEBOXES);
111 AddPage(&m_pageEditor, IDS_OPTIONSPG_EDITOR, IDS_OPTIONSPG_GENEDITOR);
112 AddPage(&m_pageEditorSyntax, IDS_OPTIONSPG_EDITOR, IDS_OPTIONSPG_EDITOR_SYNTAX);
113 AddPage(&m_pageColorSchemes, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_COLOR_SCHEMES);
114 AddPage(&m_pageMergeColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_MERGECOLORS);
115 AddPage(&m_pageSyntaxColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_SYNTAXCOLORS);
116 AddPage(&m_pageTextColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_TEXTCOLORS);
117 AddPage(&m_pageMarkerColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_MARKERCOLORS);
118 AddPage(&m_pageDirColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_DIRCOLORS);
119 AddPage(&m_pageArchive, IDS_OPTIONSPG_ARCHIVE);
120 AddPage(&m_pageProject, IDS_OPTIONSPG_PROJECT);
121 AddPage(&m_pageSystem, IDS_OPTIONSPG_SYSTEM);
122 AddPage(&m_pageBackups, IDS_OPTIONSPG_BACKUPS);
123 AddPage(&m_pageCodepage, IDS_OPTIONSPG_CODEPAGE);
124 AddPage(&m_pageShell, IDS_OPTIONSPG_SHELL);
129 GetDlgItem(IDC_TREEOPT_HOSTFRAME)->GetWindowRect(rPPHost);
130 ScreenToClient(rPPHost);
132 if (m_pphost.Create(rPPHost, this))
133 SetActivePage(AfxGetApp()->GetProfileInt(_T("Settings"), _T("OptStartPage"), 0));
135 // setup handler for resizing this dialog
136 m_constraint.InitializeCurrentSize(this);
137 m_constraint.DisallowHeightGrowth();
138 m_constraint.SubclassWnd(); // install subclassing
139 m_constraint.LoadPosition(_T("ResizeableDialogs"), _T("OptionsDlg"), false); // persist size via registry
140 return TRUE; // return TRUE unless you set the focus to a control
141 // EXCEPTION: OCX Property Pages should return FALSE
144 void CPreferencesDlg::OnOK()
151 AfxGetApp()->WriteProfileInt(_T("Settings"), _T("OptStartPage"), m_pphost.GetActiveIndex());
154 void CPreferencesDlg::OnSize(UINT nType, int cx, int cy)
156 CWnd::OnSize(nType, cx, cy);
158 if (CWnd *pPPHostWnd = GetDlgItem(IDC_TREEOPT_HOSTFRAME))
161 pPPHostWnd->GetWindowRect(rPPHost);
162 ScreenToClient(rPPHost);
163 m_pphost.MoveWindow(&rPPHost);
167 void CPreferencesDlg::OnHelpButton()
169 theApp.ShowHelp(OptionsHelpLocation);
172 void CPreferencesDlg::AddPage(CPropertyPage* pPage, UINT nResourceID)
174 String sPath = theApp.LoadString(nResourceID);
175 AddPage(pPage, sPath.c_str());
178 void CPreferencesDlg::AddPage(CPropertyPage* pPage, UINT nTopHeading, UINT nSubHeading)
180 String sPath = theApp.LoadString(nTopHeading);
182 sPath += theApp.LoadString(nSubHeading);
183 AddPage(pPage, sPath.c_str());
186 void CPreferencesDlg::AddPage(CPropertyPage* pPage, LPCTSTR szPath)
188 CString sPath(szPath);
190 if (m_pphost.AddPage(pPage))
192 HTREEITEM htiParent = TVI_ROOT; // default
193 int nFind = sPath.Find(PATHDELIM);
197 CString sParent = sPath.Left(nFind);
198 sPath = sPath.Mid(nFind + 1);
200 // see if parent already exists
201 HTREEITEM htiParentParent = htiParent;
202 htiParent = m_tcPages.GetChildItem(htiParentParent);
204 while (htiParent != nullptr)
206 if (sParent.CompareNoCase(m_tcPages.GetItemText(htiParent)) == 0)
209 htiParent = m_tcPages.GetNextItem(htiParent, TVGN_NEXT);
212 if (htiParent == nullptr)
213 htiParent = m_tcPages.InsertItem(sParent, htiParentParent);
215 nFind = sPath.Find(PATHDELIM);
218 HTREEITEM hti = m_tcPages.InsertItem(sPath, htiParent); // whatever's left
219 m_tcPages.EnsureVisible(hti);
222 m_tcPages.SetItemData(hti, static_cast<DWORD_PTR>(reinterpret_cast<uintptr_t>(pPage)));
223 m_mapPP2HTI[(void*)pPage] = (void*)hti;
227 void CPreferencesDlg::OnSelchangedPages(NMHDR* pNMHDR, LRESULT* pResult)
229 UNREFERENCED_PARAMETER(pNMHDR);
230 HTREEITEM htiSel = m_tcPages.GetSelectedItem();
232 while (m_tcPages.ItemHasChildren(htiSel))
233 htiSel = m_tcPages.GetChildItem(htiSel);
235 CPropertyPage* pPage = (CPropertyPage*)m_tcPages.GetItemData(htiSel);
236 ASSERT (pPage != nullptr);
238 if (pPage != nullptr)
240 m_pphost.SetActivePage(pPage, false);
243 String sCaption = strutils::format_string1(_("Options (%1)"), (LPCTSTR)GetItemPath(htiSel));
244 SetWindowText(sCaption.c_str());
247 m_tcPages.SetFocus();
252 void CPreferencesDlg::SetActivePage(int nPage)
254 m_pphost.SetActivePage(nPage, false);
257 CPropertyPage* pPage = m_pphost.GetActivePage();
258 HTREEITEM hti = nullptr;
260 if (m_mapPP2HTI.Lookup(pPage, (void*&)hti) && hti != nullptr)
261 m_tcPages.SelectItem(hti);
264 CString CPreferencesDlg::GetItemPath(HTREEITEM hti)
266 CString sPath = m_tcPages.GetItemText(hti);
268 hti = m_tcPages.GetParentItem(hti);
269 while (hti != nullptr)
271 sPath = m_tcPages.GetItemText(hti) + _T(" > ") + sPath;
272 hti = m_tcPages.GetParentItem(hti);
279 * @brief Read options from storage to UI controls.
280 * @param [in] bUpdate If `true` UpdateData() is called
282 void CPreferencesDlg::ReadOptions(bool bUpdate)
284 m_pageGeneral.ReadOptions();
285 m_pageColorSchemes.ReadOptions();
286 m_pageMergeColors.ReadOptions();
287 m_pageTextColors.ReadOptions();
288 m_pageSyntaxColors.ReadOptions();
289 m_pageMarkerColors.ReadOptions();
290 m_pageDirColors.ReadOptions();
291 m_pageSystem.ReadOptions();
292 m_pageCompare.ReadOptions();
293 m_pageCompareFolder.ReadOptions();
294 m_pageCompareTable.ReadOptions();
295 m_pageCompareBinary.ReadOptions();
296 m_pageCompareImage.ReadOptions();
297 m_pageMessageBoxes.ReadOptions();
298 m_pageEditor.ReadOptions();
299 m_pageEditorSyntax.ReadOptions();
300 m_pageCodepage.ReadOptions();
301 m_pageArchive.ReadOptions();
302 m_pageProject.ReadOptions();
303 m_pageBackups.ReadOptions();
304 m_pageShell.ReadOptions();
308 SafeUpdatePage(&m_pageGeneral, false);
309 SafeUpdatePage(&m_pageColorSchemes, false);
310 SafeUpdatePage(&m_pageMergeColors, false);
311 SafeUpdatePage(&m_pageTextColors, false);
312 SafeUpdatePage(&m_pageSyntaxColors, false);
313 SafeUpdatePage(&m_pageMarkerColors, false);
314 SafeUpdatePage(&m_pageDirColors, false);
315 SafeUpdatePage(&m_pageSystem, false);
316 SafeUpdatePage(&m_pageCompare, false);
317 SafeUpdatePage(&m_pageCompareFolder, false);
318 SafeUpdatePage(&m_pageCompareTable, false);
319 SafeUpdatePage(&m_pageCompareBinary, false);
320 SafeUpdatePage(&m_pageCompareImage, false);
321 SafeUpdatePage(&m_pageMessageBoxes, false);
322 SafeUpdatePage(&m_pageEditor, false);
323 SafeUpdatePage(&m_pageEditorSyntax, false);
324 SafeUpdatePage(&m_pageCodepage, false);
325 SafeUpdatePage(&m_pageArchive, false);
326 SafeUpdatePage(&m_pageProject, false);
327 SafeUpdatePage(&m_pageBackups, false);
328 SafeUpdatePage(&m_pageShell, false);
333 * @brief Write options from UI to storage.
335 void CPreferencesDlg::SaveOptions()
337 m_pageGeneral.WriteOptions();
338 m_pageSystem.WriteOptions();
339 m_pageCompare.WriteOptions();
340 m_pageCompareFolder.WriteOptions();
341 m_pageCompareTable.WriteOptions();
342 m_pageCompareBinary.WriteOptions();
343 m_pageCompareImage.WriteOptions();
344 m_pageMessageBoxes.WriteOptions();
345 m_pageEditor.WriteOptions();
346 m_pageEditorSyntax.WriteOptions();
347 m_pageColorSchemes.WriteOptions();
348 m_pageMergeColors.WriteOptions();
349 m_pageTextColors.WriteOptions();
350 m_pageSyntaxColors.WriteOptions();
351 m_pageMarkerColors.WriteOptions();
352 m_pageDirColors.WriteOptions();
353 m_pageCodepage.WriteOptions();
354 m_pageArchive.WriteOptions();
355 m_pageProject.WriteOptions();
356 m_pageBackups.WriteOptions();
357 m_pageShell.WriteOptions();
361 * @brief Imports options from file.
363 void CPreferencesDlg::OnImportButton()
366 if (SelectFile(GetSafeHwnd(), s, true, nullptr, _("Select file for import"), _("Options files (*.ini)|*.ini|All Files (*.*)|*.*||")))
368 if (m_pOptionsMgr->ImportOptions(s) == COption::OPT_OK)
370 Options::SyntaxColors::Load(m_pOptionsMgr, m_pSyntaxColors);
372 LangMessageBox(IDS_OPT_IMPORT_DONE, MB_ICONINFORMATION);
375 LangMessageBox(IDS_OPT_IMPORT_ERR, MB_ICONWARNING);
380 * @brief Exports options to file.
382 void CPreferencesDlg::OnExportButton()
385 if (SelectFile(GetSafeHwnd(), settingsFile, false, nullptr, _("Select file for export"),
386 _("Options files (*.ini)|*.ini|All Files (*.*)|*.*||")))
388 // Add settings file extension if it is missing
389 // So we allow 'filename.otherext' but add extension for 'filename'
390 if (paths::FindExtension(settingsFile).empty())
391 settingsFile += _T(".ini");
393 // Save all new settings before exporting
394 m_pphost.UpdatePagesData();
397 if (m_pOptionsMgr->ExportOptions(settingsFile, true) == COption::OPT_OK)
398 LangMessageBox(IDS_OPT_EXPORT_DONE, MB_ICONINFORMATION);
400 LangMessageBox(IDS_OPT_EXPORT_ERR, MB_ICONWARNING);
404 LRESULT CPreferencesDlg::OnColorSchemeChanged(WPARAM wParams, LPARAM lParam)
406 Options::SyntaxColors::Load(m_pOptionsMgr, m_pSyntaxColors);
412 * @brief Do a safe UpdateData call for propertypage.
413 * This function does safe UpdateData call for given propertypage. As it is,
414 * all propertypages may not have been yet initialized properly, so we must
415 * have some care when calling updateData for them.
416 * @param [in] pPage Propertypage to update.
417 * @param bSaveAndValidate UpdateData direction parameter.
419 void CPreferencesDlg::SafeUpdatePage(CPropertyPage* pPage, bool bSaveAndValidate)
421 if (pPage->GetSafeHwnd() != nullptr)
422 pPage->UpdateData(bSaveAndValidate);