OSDN Git Service

Shell Extension for Windows 11 or later (5)
[winmerge-jp/winmerge-jp.git] / Src / DirColsDlg.cpp
1 /** 
2  * @file  DirColsDlg.cpp
3  *
4  * @brief Implementation file for CDirColsDlg
5  *
6  * @date  Created: 2003-08-19
7  */
8
9
10 #include "stdafx.h"
11 #include "DirColsDlg.h"
12 #include <algorithm>
13
14 #ifdef _DEBUG
15 #define new DEBUG_NEW
16 #endif
17
18 /////////////////////////////////////////////////////////////////////////////
19 // CDirColsDlg dialog
20
21 /**
22  * @brief Default dialog constructor.
23  * @param [in] pParent Dialog's parent component (window).
24  */
25 CDirColsDlg::CDirColsDlg(CWnd* pParent /*= nullptr*/)
26         : CTrDialog(CDirColsDlg::IDD, pParent)
27         , m_bReset(false)
28 {
29 }
30
31 /**
32  * @brief Handle dialog data exchange between controls and variables.
33  */
34 void CDirColsDlg::DoDataExchange(CDataExchange* pDX)
35 {
36         CTrDialog::DoDataExchange(pDX);
37         //{{AFX_DATA_MAP(CDirColsDlg)
38         DDX_Control(pDX, IDC_COLDLG_LIST, m_listColumns);
39         //}}AFX_DATA_MAP
40 }
41
42 BEGIN_MESSAGE_MAP(CDirColsDlg, CTrDialog)
43         //{{AFX_MSG_MAP(CDirColsDlg)
44         ON_BN_CLICKED(IDC_UP, OnUp)
45         ON_BN_CLICKED(IDC_DOWN, OnDown)
46         ON_BN_CLICKED(IDC_COLDLG_DEFAULTS, OnDefaults)
47         //}}AFX_MSG_MAP
48         ON_NOTIFY(LVN_ITEMCHANGED, IDC_COLDLG_LIST, OnLvnItemchangedColdlgList)
49 END_MESSAGE_MAP()
50
51 /////////////////////////////////////////////////////////////////////////////
52 // CDirColsDlg message handlers
53
54 /**
55  * @brief Initialize listcontrol in dialog.
56  */
57 void CDirColsDlg::InitList()
58 {
59         const int lpx = CClientDC(this).GetDeviceCaps(LOGPIXELSX);
60         auto pointToPixel = [lpx](int point) { return MulDiv(point, lpx, 72); };
61
62         // Show selection across entire row.
63         // Also enable infotips.
64         m_listColumns.SetExtendedStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
65         m_listColumns.InsertColumn(0, _T(""), LVCFMT_LEFT, pointToPixel(148));
66 }
67
68 /**
69  * @brief Dialog initialisation. Load column lists.
70  */
71 BOOL CDirColsDlg::OnInitDialog() 
72 {
73         CTrDialog::OnInitDialog();
74         InitList();
75         LoadLists();
76         
77         return TRUE;  // return TRUE unless you set the focus to a control
78                       // EXCEPTION: OCX Property Pages should return FALSE
79 }
80
81 /**
82  * @brief Load listboxes on screen from column array.
83  */
84 void CDirColsDlg::LoadLists()
85 {
86         for (ColumnArray::iterator iter = m_cols.begin(); iter != m_cols.end(); ++iter)
87         {
88                 const column & c = *iter;
89                 int x = m_listColumns.InsertItem(m_listColumns.GetItemCount(),
90                         c.name.c_str());
91                 m_listColumns.SetItemData(x, c.log_col);
92                 if (c.phy_col >= 0)
93                         m_listColumns.SetCheck(x, TRUE);
94         }
95         SortArrayToLogicalOrder();
96         
97         // Set first item to selected state
98         SelectItem(0);
99 }
100
101 /**
102  * @brief Select item in list.
103  * @param [in] index Index of item to select.
104  */
105 void CDirColsDlg::SelectItem(int index)
106 {
107         m_listColumns.SetItemState(index, LVIS_SELECTED, LVIS_SELECTED);
108 }
109
110 /**
111  * @brief Load listboxes on screen from defaults column array
112  */
113 void CDirColsDlg::LoadDefLists()
114 {
115         for (ColumnArray::iterator iter = m_defCols.begin(); iter != m_defCols.end(); ++iter)
116         {
117                 const column & c = *iter;
118                 int x = m_listColumns.InsertItem(m_listColumns.GetItemCount(),
119                         c.name.c_str());
120                 m_listColumns.SetItemData(x, c.log_col);
121                 if (c.phy_col >= 0)
122                         m_listColumns.SetCheck(x, TRUE);
123         }
124         SortArrayToLogicalOrder();
125 }
126 /**
127  * @brief Sort m_cols so that it is in logical column order.
128  */
129 void CDirColsDlg::SortArrayToLogicalOrder()
130 {
131         std::sort(m_cols.begin(), m_cols.end(), &CompareColumnsByLogicalOrder);
132 }
133
134 /**
135  * @brief Compare column order of two columns.
136  * @param [in] el1 First column to compare.
137  * @param [in] el2 Second column to compare.
138  * @return Column order.
139  */
140 bool CDirColsDlg::CompareColumnsByLogicalOrder( const column & el1, const column & el2 )
141 {
142    return el1.log_col < el2.log_col;
143 }
144
145 /**
146  * @brief Move column name in the list.
147  * @param [in] index Index of column to move.
148  * @param [in] newIndex New index for the column to move.
149  */
150 void CDirColsDlg::MoveItem(int index, int newIndex)
151 {
152         // Get current column data
153         String text =  m_listColumns.GetItemText(index, 0);
154         bool checked = !!m_listColumns.GetCheck(index);
155         UINT state = m_listColumns.GetItemState(index, LVIS_SELECTED);
156         DWORD_PTR data = m_listColumns.GetItemData(index);
157
158         // Delete column
159         m_listColumns.DeleteItem(index);
160         
161         // Insert column in new index
162         m_listColumns.InsertItem(newIndex, text.c_str());
163         m_listColumns.SetItemState(newIndex, state, LVIS_SELECTED);
164         m_listColumns.SetItemData(newIndex, data);
165         if (checked)
166                 m_listColumns.SetCheck(newIndex);
167 }
168
169 /**
170  * @brief Move selected items one position up or down.
171  * @param [in] bUp If `true` items are moved up,
172  *  if `false` items are moved down.
173  */
174 void CDirColsDlg::MoveSelectedItems(bool bUp)
175 {
176         int firstInd = -1;
177         POSITION pos = m_listColumns.GetFirstSelectedItemPosition();
178
179         while (pos != nullptr)
180         {
181                 int ind = m_listColumns.GetNextSelectedItem(pos);
182                 int newInd = bUp ? ind - 1: ind + 1;
183                 
184                 // Remember first item
185                 if (firstInd == -1)
186                         firstInd = newInd;
187                 MoveItem(ind, newInd);
188         }
189         m_listColumns.EnsureVisible(firstInd, FALSE);
190 }
191
192 /**
193  * @brief Move selected items up in list.
194  */
195 void CDirColsDlg::OnUp()
196 {
197         MoveSelectedItems(true);
198 }
199
200 /**
201  * @brief Move selected items down (in show list)
202  */
203 void CDirColsDlg::OnDown() 
204 {
205         MoveSelectedItems(false);
206 }
207
208 /**
209  * @brief Move hidden columns as last items in the list.
210  */
211 void CDirColsDlg::SanitizeOrder()
212 {
213         // Find last visible column.
214         int i = m_listColumns.GetItemCount() - 1;
215         for ( ; i >= 0; i--)
216         {
217                 if (m_listColumns.GetCheck(i))
218                         break;
219         }
220
221         // Move all hidden columns below last visible column.
222         for (int j = i; j >= 0; j--)
223         {
224                 if (!m_listColumns.GetCheck(j))
225                 {
226                         MoveItem(j, i);
227                         i--;
228                 }
229         }
230 }
231
232 /**
233  * @brief User clicked ok, so we update m_cols and close.
234  */
235 void CDirColsDlg::OnOK() 
236 {
237         SanitizeOrder();
238
239         for (int i = 0; i < m_listColumns.GetItemCount(); i++)
240         {
241                 bool checked = !!m_listColumns.GetCheck(i);
242                 DWORD_PTR data = m_listColumns.GetItemData(i);
243                 column & col1 = m_cols[data];
244                 if (checked)
245                         col1.phy_col = i;
246                 else
247                         col1.phy_col = -1;
248         }
249
250         CTrDialog::OnOK();
251 }
252
253 /**
254  * @brief Empty lists and load default columns and order.
255  */
256 void CDirColsDlg::OnDefaults()
257 {
258         m_listColumns.DeleteAllItems();
259         m_bReset = true;
260         LoadDefLists();
261 }
262
263 /**
264  * @brief Update description when selected item changes.
265  */
266 void CDirColsDlg::OnLvnItemchangedColdlgList(NMHDR *pNMHDR, LRESULT *pResult)
267 {
268         POSITION pos = m_listColumns.GetFirstSelectedItemPosition();
269
270         if (pos != nullptr)
271         {
272                 int ind = m_listColumns.GetNextSelectedItem(pos);
273                 DWORD_PTR data = m_listColumns.GetItemData(ind);
274
275                 ColumnArray::size_type j;
276                 for (j = 0; j < m_cols.size(); j++)
277                 {
278                         if (static_cast<DWORD_PTR>(m_cols[j].log_col) == data)
279                                 break;
280                 }
281                 SetDlgItemText(IDC_COLDLG_DESC, m_cols[j].desc);
282
283                 // Disable Up/Down -buttons when first/last items are selected.
284                 EnableDlgItem(IDC_UP, ind != 0);
285                 EnableDlgItem(IDC_DOWN,
286                         ind != m_listColumns.GetItemCount() - static_cast<int>(m_listColumns.GetSelectedCount()));
287         }
288         *pResult = 0;
289 }