OSDN Git Service

- Make Hex Editor configurable
[winmerge-jp/winmerge-jp.git] / Src / Common / PreferencesDlg.cpp
1 /** 
2  * @file PreferencesDlg.cpp
3  *
4  * @brief Implementation file for CPreferencesDlg
5  *
6  * @note This code originates from AbstractSpoon / TodoList
7  * (http://www.abstractspoon.com/) but is modified to use in
8  * WinMerge.
9  */
10 // ID line follows -- this is updated by SVN
11 // $Id$
12
13 #include "StdAfx.h"
14 #include "PreferencesDlg.h"
15 #include "resource.h"
16 #include "UnicodeString.h"
17 #include "OptionsDef.h"
18 #include "OptionsMgr.h"
19 #include "SyntaxColors.h"
20 #include "Merge.h"
21 #include "paths.h" //paths_SplitFilename()
22 #include "FileOrFolderSelect.h"
23
24 #ifdef _DEBUG
25 #define new DEBUG_NEW
26 #undef THIS_FILE
27 static char THIS_FILE[] = __FILE__;
28 #endif
29
30 /**
31  * @brief Location for file compare specific help to open.
32  */
33 static TCHAR OptionsHelpLocation[] = _T("::/htmlhelp/Configuration.html");
34
35 /////////////////////////////////////////////////////////////////////////////
36 // CPreferencesDlg dialog
37
38 const TCHAR PATHDELIM = '>';
39
40 CPreferencesDlg::CPreferencesDlg(COptionsMgr *regOptions, SyntaxColors *colors,
41                 UINT nMenuID, CWnd* pParent)   // standard constructor
42 : CDialog(IDD_PREFERENCES, pParent)
43 , m_pOptionsMgr(regOptions)
44 , m_pageGeneral(regOptions)
45 , m_pageCompare(regOptions)
46 , m_pageMergeColors(regOptions)
47 , m_pSyntaxColors(colors)
48 , m_pageTextColors(regOptions, colors)
49 , m_pageSyntaxColors(regOptions, colors)
50 , m_pageArchive(regOptions)
51 , m_pageCodepage(regOptions)
52 , m_pageEditor(regOptions)
53 , m_pageSystem(regOptions)
54 , m_pageBackups(regOptions)
55 , m_pageVss(regOptions)
56 , m_pageShell(regOptions)
57 , m_pageCompareFolder(regOptions)
58 , m_pageCompareBinary(regOptions)
59 , m_pageCompareImage(regOptions)
60 {
61         UNREFERENCED_PARAMETER(nMenuID);
62 }
63
64 CPreferencesDlg::~CPreferencesDlg()
65 {
66 }
67
68 void CPreferencesDlg::DoDataExchange(CDataExchange* pDX)
69 {
70         CDialog::DoDataExchange(pDX);
71         //{{AFX_DATA_MAP(CPreferencesDlg)
72         DDX_Control(pDX, IDC_TREEOPT_PAGES, m_tcPages);
73         //}}AFX_DATA_MAP
74 }
75
76 BEGIN_MESSAGE_MAP(CPreferencesDlg, CDialog)
77         //{{AFX_MSG_MAP(CPreferencesDlg)
78         ON_WM_DESTROY()
79         ON_COMMAND(ID_HELP, OnHelpButton)
80         ON_BN_CLICKED(IDC_TREEOPT_HELP, OnHelpButton)
81         ON_NOTIFY(TVN_SELCHANGED, IDC_TREEOPT_PAGES, OnSelchangedPages)
82         ON_BN_CLICKED(IDC_TREEOPT_IMPORT, OnImportButton)
83         ON_BN_CLICKED(IDC_TREEOPT_EXPORT, OnExportButton)
84         //}}AFX_MSG_MAP
85 END_MESSAGE_MAP()
86
87 /////////////////////////////////////////////////////////////////////////////
88 // CPreferencesDlg message handlers
89
90 BOOL CPreferencesDlg::OnInitDialog() 
91 {
92         theApp.TranslateDialog(m_hWnd);
93         CDialog::OnInitDialog();
94
95         m_tcPages.SetIndent(0);
96
97         // Second parameter is 'path', page's parent page(s) and caption.
98         // '>' is used as path separator.
99         // For example "General" creates top-level "General" page
100         // and "General>Colors" creates "Colors" sub-page for "General"
101         AddPage(&m_pageGeneral, IDS_OPTIONSPG_GENERAL);
102         AddPage(&m_pageCompare, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_GENCOMPARE);
103         AddPage(&m_pageCompareFolder, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_FOLDERCOMPARE);
104         AddPage(&m_pageCompareBinary, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_BINARYCOMPARE);
105         AddPage(&m_pageCompareImage, IDS_OPTIONSPG_COMPARE, IDS_OPTIONSPG_IMAGECOMPARE);
106         AddPage(&m_pageEditor, IDS_OPTIONSPG_EDITOR);
107         AddPage(&m_pageMergeColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_MERGECOLORS);
108         AddPage(&m_pageSyntaxColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_SYNTAXCOLORS);
109         AddPage(&m_pageTextColors, IDS_OPTIONSPG_COLORS, IDS_OPTIONSPG_TEXTCOLORS);
110         AddPage(&m_pageArchive, IDS_OPTIONSPG_ARCHIVE);
111         AddPage(&m_pageSystem, IDS_OPTIONSPG_SYSTEM);
112         AddPage(&m_pageBackups, IDS_OPTIONSPG_BACKUPS);
113         AddPage(&m_pageVss, IDS_OPTIONSPG_VERSIONCONTROL);
114         AddPage(&m_pageCodepage, IDS_OPTIONSPG_CODEPAGE);
115         AddPage(&m_pageShell, IDS_OPTIONSPG_SHELL);
116
117         ReadOptions();
118         
119         CRect rPPHost;
120         GetDlgItem(IDC_TREEOPT_HOSTFRAME)->GetWindowRect(rPPHost);
121         ScreenToClient(rPPHost);
122
123         if (m_pphost.Create(rPPHost, this))
124                 SetActivePage(AfxGetApp()->GetProfileInt(_T("Settings"), _T("OptStartPage"), 0));
125
126         return TRUE;  // return TRUE unless you set the focus to a control
127                       // EXCEPTION: OCX Property Pages should return FALSE
128 }
129
130 void CPreferencesDlg::OnOK()
131 {
132         CDialog::OnOK();
133         m_pphost.OnOK();
134
135         SaveOptions();
136 }
137
138 void CPreferencesDlg::OnDestroy() 
139 {
140         CDialog::OnDestroy();
141         
142         AfxGetApp()->WriteProfileInt(_T("Settings"), _T("OptStartPage"), m_pphost.GetActiveIndex());
143 }
144
145 void CPreferencesDlg::OnHelpButton() 
146 {
147         theApp.ShowHelp(OptionsHelpLocation);
148 }
149
150 void CPreferencesDlg::AddPage(CPropertyPage* pPage, UINT nResourceID)
151 {
152         String sPath = theApp.LoadString(nResourceID);
153         AddPage(pPage, sPath.c_str());
154 }
155
156 void CPreferencesDlg::AddPage(CPropertyPage* pPage, UINT nTopHeading, UINT nSubHeading)
157 {
158         String sPath = theApp.LoadString(nTopHeading);
159         sPath += _T(">");
160         sPath += theApp.LoadString(nSubHeading);
161         AddPage(pPage, sPath.c_str());
162 }
163
164 void CPreferencesDlg::AddPage(CPropertyPage* pPage, LPCTSTR szPath)
165 {
166         CString sPath(szPath);
167
168         if (m_pphost.AddPage(pPage))
169         {
170                 HTREEITEM htiParent = TVI_ROOT; // default
171                 int nFind = sPath.Find(PATHDELIM);
172
173                 while (nFind != -1)
174                 {
175                         CString sParent = sPath.Left(nFind);
176                         sPath = sPath.Mid(nFind + 1);
177
178                         // see if parent already exists
179                         HTREEITEM htiParentParent = htiParent;
180                         htiParent = m_tcPages.GetChildItem(htiParentParent);
181
182                         while (htiParent)
183                         {
184                                 if (sParent.CompareNoCase(m_tcPages.GetItemText(htiParent)) == 0)
185                                         break;
186
187                                 htiParent = m_tcPages.GetNextItem(htiParent, TVGN_NEXT);
188                         }
189
190                         if (!htiParent)
191                                 htiParent = m_tcPages.InsertItem(sParent, htiParentParent);
192
193                         nFind = sPath.Find(PATHDELIM);
194                 }
195
196                 HTREEITEM hti = m_tcPages.InsertItem(sPath, htiParent); // whatever's left
197                 m_tcPages.EnsureVisible(hti);
198
199                 // map both ways
200                 m_tcPages.SetItemData(hti, (DWORD)pPage);
201                 m_mapPP2HTI[(void*)pPage] = (void*)hti;
202         }
203 }
204
205 void CPreferencesDlg::OnSelchangedPages(NMHDR* pNMHDR, LRESULT* pResult) 
206 {
207         UNREFERENCED_PARAMETER(pNMHDR);
208         HTREEITEM htiSel = m_tcPages.GetSelectedItem();
209
210         while (m_tcPages.ItemHasChildren(htiSel))
211                 htiSel = m_tcPages.GetChildItem(htiSel);
212
213         CPropertyPage* pPage = (CPropertyPage*)m_tcPages.GetItemData(htiSel);
214         ASSERT (pPage);
215
216         if (pPage)
217         {
218                 m_pphost.SetActivePage(pPage, FALSE);
219
220                 // update caption
221                 String sCaption = LangFormatString1(IDS_OPTIONS_TITLE, GetItemPath(htiSel));
222                 SetWindowText(sCaption.c_str());
223         }
224
225         m_tcPages.SetFocus();
226         
227         *pResult = 0;
228 }
229
230 void CPreferencesDlg::SetActivePage(int nPage)
231 {
232         m_pphost.SetActivePage(nPage, FALSE);
233
234         // synchronize tree
235         CPropertyPage* pPage = m_pphost.GetActivePage();
236         HTREEITEM hti = NULL;
237
238         if (m_mapPP2HTI.Lookup(pPage, (void*&)hti) && hti)
239                 m_tcPages.SelectItem(hti);
240 }
241
242 CString CPreferencesDlg::GetItemPath(HTREEITEM hti)
243 {
244         CString sPath = m_tcPages.GetItemText(hti);
245
246         while (hti = m_tcPages.GetParentItem(hti))
247                 sPath = m_tcPages.GetItemText(hti) + _T(" > ") + sPath;
248
249         return sPath;
250 }
251
252 /**
253  * @brief Read options from storage to UI controls.
254  * @param [in] bUpdate If TRUE UpdateData() is called
255  */
256 void CPreferencesDlg::ReadOptions(BOOL bUpdate)
257 {
258         m_pageGeneral.ReadOptions();
259         m_pageMergeColors.ReadOptions();
260         m_pageTextColors.ReadOptions();
261         m_pageSyntaxColors.ReadOptions();
262         m_pageSystem.ReadOptions();
263         m_pageCompare.ReadOptions();
264         m_pageCompareFolder.ReadOptions();
265         m_pageCompareBinary.ReadOptions();
266         m_pageCompareImage.ReadOptions();
267         m_pageEditor.ReadOptions();
268         m_pageCodepage.ReadOptions();
269         m_pageVss.ReadOptions();
270         m_pageArchive.ReadOptions();
271         m_pageBackups.ReadOptions();
272         m_pageShell.ReadOptions();
273
274         if (bUpdate)
275         {
276                 SafeUpdatePage(&m_pageGeneral, FALSE);
277                 SafeUpdatePage(&m_pageMergeColors, FALSE);
278                 SafeUpdatePage(&m_pageTextColors, FALSE);
279                 SafeUpdatePage(&m_pageSyntaxColors, FALSE);
280                 SafeUpdatePage(&m_pageSystem, FALSE);
281                 SafeUpdatePage(&m_pageCompare, FALSE);
282                 SafeUpdatePage(&m_pageCompareFolder, FALSE);
283                 SafeUpdatePage(&m_pageCompareBinary, FALSE);
284                 SafeUpdatePage(&m_pageCompareImage, FALSE);
285                 SafeUpdatePage(&m_pageEditor, FALSE);
286                 SafeUpdatePage(&m_pageCodepage, FALSE);
287                 SafeUpdatePage(&m_pageVss, FALSE);
288                 SafeUpdatePage(&m_pageArchive, FALSE);
289                 SafeUpdatePage(&m_pageBackups, FALSE);
290                 SafeUpdatePage(&m_pageShell, FALSE);
291         }
292 }
293
294 /**
295  * @brief Write options from UI to storage.
296  */
297 void CPreferencesDlg::SaveOptions()
298 {
299         m_pageGeneral.WriteOptions();
300         m_pageSystem.WriteOptions();
301         m_pageCompare.WriteOptions();
302         m_pageCompareFolder.WriteOptions();
303         m_pageCompareBinary.WriteOptions();
304         m_pageCompareImage.WriteOptions();
305         m_pageEditor.WriteOptions();
306         m_pageMergeColors.WriteOptions();
307         m_pageTextColors.WriteOptions();
308         m_pageSyntaxColors.WriteOptions();
309         m_pageCodepage.WriteOptions();
310         m_pageVss.WriteOptions();       
311         m_pageArchive.WriteOptions();
312         m_pageBackups.WriteOptions();
313         m_pageShell.WriteOptions();
314 }
315
316 void CPreferencesDlg::SetSyntaxColors(SyntaxColors *pColors)
317 {
318         m_pSyntaxColors = pColors;
319 }
320
321 /**
322  * @brief Imports options from file.
323  */
324 void CPreferencesDlg::OnImportButton()
325 {
326         String s;
327         if (SelectFile(GetSafeHwnd(), s, NULL, IDS_OPT_IMPORT_CAPTION, IDS_INIFILES, TRUE))
328         {
329                 if (m_pOptionsMgr->ImportOptions(s) == COption::OPT_OK)
330                 {
331                         ReadOptions(TRUE);
332                         LangMessageBox(IDS_OPT_IMPORT_DONE, MB_ICONINFORMATION);
333                 }
334                 else
335                         LangMessageBox(IDS_OPT_IMPORT_ERR, MB_ICONWARNING);
336         }
337 }
338
339 /**
340  * @brief Exports options to file.
341  */
342 void CPreferencesDlg::OnExportButton()
343 {
344         String settingsFile;
345         if (SelectFile(GetSafeHwnd(), settingsFile, NULL, IDS_OPT_EXPORT_CAPTION, IDS_INIFILES,
346                 FALSE))
347         {
348                 // Add settings file extension if it is missing
349                 // So we allow 'filename.otherext' but add extension for 'filename'
350                 String extension;
351                 paths_SplitFilename(settingsFile, NULL, NULL, &extension);
352                 if (extension.empty())
353                         settingsFile += _T(".ini");
354
355                 // Save all new settings before exporting
356                 m_pphost.UpdatePagesData();
357                 SaveOptions();
358
359                 if (m_pOptionsMgr->ExportOptions(settingsFile) == COption::OPT_OK)
360                         LangMessageBox(IDS_OPT_EXPORT_DONE, MB_ICONINFORMATION);
361                 else
362                         LangMessageBox(IDS_OPT_EXPORT_ERR, MB_ICONWARNING);
363         }
364 }
365
366 /**
367  * @brief Do a safe UpdateData call for propertypage.
368  * This function does safe UpdateData call for given propertypage. As it is,
369  * all propertypages may not have been yet initialized properly, so we must
370  * have some care when calling updateData for them.
371  * @param [in] pPage Propertypage to update.
372  * @param bSaveAndValidate UpdateData direction parameter.
373  */
374 void CPreferencesDlg::SafeUpdatePage(CPropertyPage* pPage, BOOL bSaveAndValidate)
375 {
376         if (pPage->GetSafeHwnd() != NULL)
377                 pPage->UpdateData(bSaveAndValidate);
378 }