OSDN Git Service

Allow NUL and \\.\NUL in paths specified as command line arguments (#2056)
[winmerge-jp/winmerge-jp.git] / Src / SubeditList.cpp
1 // SubeditList.cpp : implementation file
2 //
3
4 #include "stdafx.h"
5 #include "SubeditList.h"
6 #include "Win_VersionHelper.h"
7 #include "WildcardDropList.h"
8
9 #ifdef _DEBUG
10 #define new DEBUG_NEW
11 #undef THIS_FILE
12 static char THIS_FILE[] = __FILE__;
13 #endif
14
15 constexpr UINT IDC_IPEDIT = 1000;
16
17 /// Some stuff is from https://www.codeguru.com/cpp/controls/listview/editingitemsandsubitem/article.php/c923/Editable-subitems.htm
18
19 /////////////////////////////////////////////////////////////////////////////
20 // CSubeditList
21
22 CSubeditList::CSubeditList()
23 {
24 }
25
26 CSubeditList::~CSubeditList()
27 {
28 }
29
30 void CSubeditList::SetColumnAttribute(int nCol, int limit, int attribute)
31 {
32         if (!IsValidCol(nCol))
33                 return;
34
35         if (m_columnsAttributes.size() <= static_cast<size_t>(nCol))
36                 m_columnsAttributes.resize(static_cast<size_t>(nCol) + 1);
37
38         std::pair<int, int>& r = m_columnsAttributes[nCol];
39         if (limit) r.first = limit;
40         r.second |= attribute;
41 }
42
43 void CSubeditList::SetItemBooleanValue(int nItem, int nSubItem, bool value)
44 {
45         if (IsWin7_OrGreater())
46                 SetItemText(nItem, nSubItem, value ? _T("\u2611") : _T("\u2610"));
47         else
48                 SetItemText(nItem, nSubItem, value ? _T("true") : _T("false"));
49 }
50
51 bool CSubeditList::GetItemBooleanValue(int nItem, int nSubItem) const
52 {
53         CString text = GetItemText(nItem, nSubItem);
54         return (text.Compare(_T("true")) == 0 || text.Compare(_T("\u2611")) == 0);
55 }
56
57 bool CSubeditList::IsValidCol(int nSubItem) const
58 {
59         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
60         unsigned nColumnCount = static_cast<unsigned>(pHeader->GetItemCount());
61         return static_cast<unsigned>(nSubItem) < nColumnCount;
62 }
63
64 bool CSubeditList::IsValidRowCol(int nItem, int nSubItem) const
65 {
66         unsigned nItemCount = static_cast<unsigned>(GetItemCount());
67         if (static_cast<unsigned>(nItem) >= nItemCount)
68                 return false;
69
70         return IsValidCol(nSubItem);
71 }
72
73 /**
74  * @brief Get the edit style for the specified column.
75  * @param [in] nCol Column to get edit style
76  * @return Edit style for the specified column
77  * @remarks Returns EditStyle::EDIT_BOX; as default if a column with no edit style is specified.
78  */
79 CSubeditList::EditStyle CSubeditList::GetEditStyle(int nCol) const
80 {
81         if (static_cast<size_t>(nCol) >= m_columnsAttributes.size() || !IsValidCol(nCol))
82                 return EditStyle::EDIT_BOX;
83
84         return static_cast<EditStyle>(m_columnsAttributes[nCol].second & EDIT_STYLES_ALL);
85 }
86
87 /**
88  * @brief Set the edit style for the specified column.
89  * @param [in] nCol Column to set the edit style
90  * @param [in] style Edit style to set
91  */
92 void CSubeditList::SetEditStyle(int nCol, EditStyle style)
93 {
94         if (!IsValidCol(nCol))
95                 return;
96
97         static_assert(static_cast<int>(EditStyle::EDIT_BOX) == 0, "assume 0-value by default");
98
99         if (m_columnsAttributes.size() <= static_cast<size_t>(nCol))
100                 m_columnsAttributes.resize(static_cast<size_t>(nCol) + 1);
101
102         auto& r = m_columnsAttributes[nCol];
103         r.second = (r.second & ~EDIT_STYLES_ALL) | static_cast<int>(style);
104 }
105
106 /**
107  * @brief Get the character limit for the specified column.
108  * @param [in] nCol Column to get character limit
109  * @return Character limit for the specified column
110  * @remarks Currently, this setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
111  */
112 int CSubeditList::GetLimitTextSize(int nCol) const
113 {
114         // Currently, this setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
115         if (!IsValidCol(nCol) || GetEditStyle(nCol) != EditStyle::WILDCARD_DROP_LIST)
116                 return 0;
117
118         return m_columnsAttributes[nCol].first;
119 }
120
121 /**
122  * @brief Set the character limit for the specified column.
123  * @param [in] nCol Column to set the character limit
124  * @param [in] nLimitTextSize Character limit to set
125  * @remarks Currently, this setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
126  */
127 void CSubeditList::SetLimitTextSize(int nCol, int nLimitTextSize)
128 {
129         if (!IsValidCol(nCol) || GetEditStyle(nCol) != EditStyle::WILDCARD_DROP_LIST)
130                 return;
131
132         if (m_columnsAttributes.size() <= static_cast<size_t>(nCol))
133                 m_columnsAttributes.resize(static_cast<size_t>(nCol) + 1);
134
135         m_columnsAttributes[nCol].first = nLimitTextSize;
136 }
137
138 /**
139  * @brief Get the wildcard drop list fixed pattern for the specified cell.
140  * @param [in] nItem Th row index to get wildcard drop list fixed pattern
141  * @param [in] nSubItem The column to get wildcard drop list fixed pattern
142  * @return Wildcard drop list fixed pattern for the specified cell
143  */
144 String CSubeditList::GetDropListFixedPattern(int nItem, int nSubItem) const
145 {
146         // This setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
147         if (!IsValidRowCol(nItem, nSubItem) || GetEditStyle(nSubItem) != EditStyle::WILDCARD_DROP_LIST)
148                 return _T("");
149
150         if (static_cast<size_t>(nItem) < m_dropListFixedPattern.size())
151                 if (static_cast<size_t>(nSubItem) < m_dropListFixedPattern[nItem].size())
152                         return m_dropListFixedPattern[nItem][nSubItem];
153
154         return _T("");
155 }
156
157 /**
158  * @brief Set the wildcard drop list fixed pattern for the specified cell.
159  * @param [in] nItem The row index to set wildcard drop list fixed pattern
160  * @param [in] nSubItem The column to set wildcard drop list fixed pattern
161  * @param [in] fixedPattern Wildcard drop list fixed pattern to set
162  */
163 void CSubeditList::SetDropListFixedPattern(int nItem, int nSubItem, const String& fixedPattern)
164 {
165         // This setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
166         if (!IsValidRowCol(nItem, nSubItem) || GetEditStyle(nSubItem) != EditStyle::WILDCARD_DROP_LIST)
167                 return;
168
169         if (m_dropListFixedPattern.size() <= static_cast<size_t>(nItem))
170                 m_dropListFixedPattern.resize(static_cast<size_t>(nItem) + 1);
171
172         auto& sub = m_dropListFixedPattern[nItem];
173         if (sub.size() <= static_cast<size_t>(nSubItem))
174                 sub.resize(static_cast<size_t>(nSubItem) + 1, _T(""));
175
176         sub[nSubItem] = fixedPattern;
177 }
178
179 /**
180  * @brief Get the dropdown list data for the specified cell.
181  * @param [in] nItem The row index to get dropdown list data
182  * @param [in] nSubItem The column to get dropdown list data
183  * @return dropdown list data for the specified cell
184  */
185 std::vector<String> CSubeditList::GetDropdownList(int nItem, int nSubItem) const
186 {
187         // This setting is valid only for columns whose edit style is EditStyle::DROPDOWN_LIST.
188         if (!IsValidRowCol(nItem, nSubItem) || GetEditStyle(nSubItem) != EditStyle::DROPDOWN_LIST)
189                 return {};
190
191         if (static_cast<size_t>(nItem) < m_dropList.size())
192                 if (static_cast<size_t>(nSubItem) < m_dropList[nItem].size())
193                         return m_dropList[nItem][nSubItem];
194
195         return {};
196 }
197
198 /**
199  * @brief Set the drop list data for the specified cell.
200  * @param [in] nItem The row index to set dropdown list data
201  * @param [in] nSubItem The column to set dropdown list data
202  * @param [in] list dropdown list data to set
203  */
204 void CSubeditList::SetDropdownList(int nItem, int nSubItem, const std::vector<String>& list)
205 {
206         // This setting is valid only for columns whose edit style is EditStyle::DROPDOWN_LIST.
207         if (!IsValidRowCol(nItem, nSubItem) || GetEditStyle(nSubItem) != EditStyle::DROPDOWN_LIST)
208                 return;
209
210         if (m_dropList.size() <= static_cast<size_t>(nItem))
211                 m_dropList.resize(static_cast<size_t>(nItem) + 1);
212
213         auto& sub = m_dropList[nItem];
214         if (sub.size() <= static_cast<size_t>(nSubItem))
215                 sub.resize(static_cast<size_t>(nSubItem) + 1);
216
217         sub[nSubItem] = list;
218 }
219
220 // HitTestEx    - Determine the row index and column index for a point
221 // Returns      - the row index or -1 if point is not over a row
222 // point        - point to be tested.
223 // col          - to hold the column index
224 int CSubeditList::HitTestEx(CPoint &point, int *col) const
225 {
226         int row = HitTest( point, NULL );
227         
228         if( col ) *col = 0;
229  
230         // Make sure that the ListView is in LVS_REPORT
231         if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
232                 return row;
233  
234         // Get the top and bottom row visible
235         row = GetTopIndex();
236         int bottom = row + GetCountPerPage();
237         int itemCount = GetItemCount();
238         if( bottom > itemCount )
239                 bottom = itemCount;
240         
241         // Get the number of columns
242         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
243         int nColumnCount = pHeader->GetItemCount();
244  
245         // Loop through the visible rows
246         for( ;row <=bottom;row++)
247         {
248                 // Get bounding rect of item and check whether point falls in it.
249                 CRect rect;
250                 GetItemRect( row, &rect, LVIR_BOUNDS );
251                 if( rect.PtInRect(point) )
252                 {
253                         // Now find the column
254                         for( int colnum = 0; colnum < nColumnCount; colnum++ )
255                         {
256                                 int colwidth = GetColumnWidth(colnum);
257                                 if( point.x >= rect.left 
258                                         && point.x <= (rect.left + colwidth ) )
259                                 {
260                                         if( col ) *col = colnum;
261                                         return row;
262                                 }
263                                 rect.left += colwidth;
264                         }
265                 }
266         }
267         return -1;
268 }
269
270 #ifndef WM_MOUSEHWHEEL
271 #  define WM_MOUSEHWHEEL 0x20e
272 #endif
273
274 BEGIN_MESSAGE_MAP(CSubeditList, CListCtrl)
275         //{{AFX_MSG_MAP(CSubeditList)
276                 // NOTE - the ClassWizard will add and remove mapping macros here.
277         ON_WM_LBUTTONDOWN()
278         ON_WM_VSCROLL()
279         ON_WM_HSCROLL()
280         ON_WM_MOUSEWHEEL()
281         ON_WM_MOUSEHWHEEL()
282         //}}AFX_MSG_MAP
283 END_MESSAGE_MAP()
284
285 /////////////////////////////////////////////////////////////////////////////
286 // CSubeditList message handlers
287
288
289 // EditSubLabel         - Start edit of a sub item label
290 // Returns              - Temporary pointer to the new edit control
291 // nItem                - The row index of the item to edit
292 // nCol                 - The column of the sub item.
293 //CEdit* CSubeditList::EditSubLabel(int nItem, int nCol)
294 CInPlaceEdit* CSubeditList::EditSubLabel( int nItem, int nCol )
295 {
296         // The returned pointer should not be saved
297          
298         // Make sure that the item is visible
299         if( !EnsureVisible( nItem, TRUE ) ) return NULL;
300          
301         // Make sure that nCol is valid
302         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
303         int nColumnCount = pHeader->GetItemCount();
304         if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
305                 return NULL;
306
307         if (GetEditStyle(nCol) != EditStyle::EDIT_BOX)
308                 return NULL;
309         // Get the column offset
310         int offset = 0;
311         for( int i = 0; i < nCol; i++ )
312                 offset += GetColumnWidth( i );
313          
314         CRect rect;
315         GetItemRect( nItem, &rect, LVIR_BOUNDS );
316          
317         // Now scroll if we need to expose the column
318         CRect rcClient;
319         GetClientRect( &rcClient );
320         int dx = offset + rect.left;
321         if( dx < 0 || dx > rcClient.right )
322         {
323                 Scroll(CSize(dx, 0));
324                 rect.left -= dx;
325         }
326
327         // Get Column alignment
328         LV_COLUMN lvcol;
329         lvcol.mask = LVCF_FMT;
330         GetColumn( nCol, &lvcol );
331         DWORD dwStyle ;
332         if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
333                 dwStyle = ES_LEFT;
334         else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
335                 dwStyle = ES_RIGHT;
336         else dwStyle = ES_CENTER;
337
338         rect.left += offset+4;
339         rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
340         if( rect.right > rcClient.right) rect.right = rcClient.right;
341
342         dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
343         CInPlaceEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText(nItem, nCol));
344         pEdit->Create( dwStyle, rect, this, IDC_IPEDIT );
345
346         return pEdit;
347 }
348
349 /**
350  * @brief Start edit of a sub item label with dropdown list.
351  * @param [in] nItem The row index of the item to edit
352  * @param [in] nCol The column of the sub item
353  */
354 void CSubeditList::EditSubLabelDropdownList( int nItem, int nCol )
355 {
356         // Make sure that the item is visible
357         if( !EnsureVisible( nItem, TRUE ) ) return;
358
359         // Make sure that nCol is valid
360         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
361         int nColumnCount = pHeader->GetItemCount();
362         if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
363                 return;
364
365         if (GetEditStyle(nCol) != EditStyle::DROPDOWN_LIST)
366                 return;
367
368         // Get the column offset
369         int offset = 0;
370         for( int i = 0; i < nCol; i++ )
371                 offset += GetColumnWidth( i );
372          
373         CRect rect;
374         GetItemRect( nItem, &rect, LVIR_BOUNDS );
375          
376         // Now scroll if we need to expose the column
377         CRect rcClient;
378         GetClientRect( &rcClient );
379         int dx = offset + rect.left;
380         if( dx < 0 || dx > rcClient.right )
381         {
382                 Scroll(CSize(dx, 0));
383                 rect.left -= dx;
384         }
385
386         // Get Column alignment
387         LV_COLUMN lvcol;
388         lvcol.mask = LVCF_FMT;
389         GetColumn( nCol, &lvcol );
390         DWORD dwStyle = 0;
391
392         rect.left += offset+4;
393         rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
394         if( rect.right > rcClient.right) rect.right = rcClient.right;
395
396         dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST|CBS_AUTOHSCROLL;
397         CInPlaceComboBox *pComboBox = new CInPlaceComboBox(nItem, nCol, GetItemText(nItem, nCol), GetDropdownList(nItem, nCol));
398         pComboBox->Create( dwStyle, rect, this, IDC_IPEDIT );
399
400         SetItemText(nItem, nCol, _T(""));
401 }
402
403 /**
404  * @brief Start edit of a sub item label with wilcard drop list.
405  * @param [in] nItem The row index of the item to edit
406  * @param [in] nCol The column of the sub item
407  */
408 void CSubeditList::EditSubLabelWildcardDropList( int nItem, int nCol )
409 {
410         // Make sure that the item is visible
411         if( !EnsureVisible( nItem, TRUE ) ) return;
412
413         // Make sure that nCol is valid
414         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
415         int nColumnCount = pHeader->GetItemCount();
416         if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
417                 return;
418
419         if (GetEditStyle(nCol) != EditStyle::WILDCARD_DROP_LIST)
420                 return;
421
422         CString pattern = GetDropListFixedPattern(nItem, nCol).c_str();
423         int nLimitTextSize = GetLimitTextSize(nCol);
424         WildcardDropList::OnItemActivate(m_hWnd, nItem, nCol, 4, pattern, true, nLimitTextSize);
425 }
426
427 void CSubeditList::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
428 {
429         if( GetFocus() != this ) SetFocus();
430         CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
431 }
432
433 void CSubeditList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
434 {
435         if( GetFocus() != this ) SetFocus();
436         CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
437 }
438
439 BOOL CSubeditList::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
440 {
441         if( GetFocus() != this ) SetFocus();
442         return CListCtrl::OnMouseWheel(nFlags, zDelta, pt);
443 }
444
445 void CSubeditList::OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt)
446 {
447         if( GetFocus() != this ) SetFocus();
448         CListCtrl::OnMouseHWheel(nFlags, zDelta, pt);
449 }
450
451 void CSubeditList::OnLButtonDown(UINT nFlags, CPoint point)
452 {
453         int colnum;
454         CListCtrl::OnLButtonDown(nFlags, point);
455         int index = HitTestEx(point, &colnum);
456         if( index != -1 )
457         {
458                 if ((size_t)colnum >= m_columnsAttributes.size())
459                         return;
460
461                 UINT flag = LVIS_FOCUSED;
462                 //if ((GetItemState(index, flag) & flag) == flag && colnum > 0)
463                 if ((GetItemState(index, flag) & flag) == flag)
464                 {
465                         auto pr = m_columnsAttributes[(size_t)colnum];
466                         if (!(pr.second & READ_ONLY))
467                         {
468                                 if (pr.second & BOOLEAN_VALUE)
469                                 {
470                                         CString text = GetItemText(index, colnum);
471                                         if (IsWin7_OrGreater())
472                                         {
473                                                 SetItemText(index, colnum, text.Compare(_T("\u2611")) == 0 ?
474                                                         _T("\u2610") : _T("\u2611"));
475                                         }
476                                         else
477                                         {
478                                                 SetItemText(index, colnum, text.Compare(_T("true")) == 0 ?
479                                                         _T("false") : _T("true"));
480                                         }
481                                 }
482                                 else
483                                 {
484                                         switch (GetEditStyle(colnum))
485                                         {
486                                         case EditStyle::EDIT_BOX:
487                                                 EditSubLabel(index, colnum);
488                                                 break;
489                                         case EditStyle::DROPDOWN_LIST:
490                                                 EditSubLabelDropdownList(index, colnum);
491                                                 break;
492                                         case EditStyle::WILDCARD_DROP_LIST:
493                                                 EditSubLabelWildcardDropList(index, colnum);
494                                                 break;
495                                         default:
496                                                 break;
497                                         }
498                                 }
499                         }
500                 }
501                 else
502                 {
503                         SetItemState(index, LVIS_SELECTED | LVIS_FOCUSED,
504                                         LVIS_SELECTED | LVIS_FOCUSED);
505                 }
506         }
507 }
508
509 /////////////////////////////////////////////////////////////////////////////
510 // CInPlaceEdit
511
512 CInPlaceEdit::CInPlaceEdit(int iItem, int iSubItem, CString sInitText)
513 : m_sInitText( sInitText )
514 , m_iItem(iItem)
515 , m_iSubItem(iSubItem)
516 , m_bESC(false)
517 {
518 }
519
520 CInPlaceEdit::~CInPlaceEdit()
521 {
522 }
523
524
525 BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
526         //{{AFX_MSG_MAP(CInPlaceEdit)
527         ON_WM_KILLFOCUS()
528         ON_WM_NCDESTROY()
529         ON_WM_CHAR()
530         ON_WM_CREATE()
531         //}}AFX_MSG_MAP
532         ON_WM_LBUTTONDOWN()
533 END_MESSAGE_MAP()
534
535 /////////////////////////////////////////////////////////////////////////////
536 // CInPlaceEdit message handlers
537          
538 BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)
539 {
540         if( pMsg->message == WM_KEYDOWN )
541         {
542                 if(pMsg->wParam == VK_RETURN
543                                 || pMsg->wParam == VK_DELETE
544                                 || pMsg->wParam == VK_ESCAPE
545                                 || GetKeyState( VK_CONTROL)
546                                 )
547                 {
548                         ::TranslateMessage(pMsg);
549                         ::DispatchMessage(pMsg);
550                         return TRUE;                            // DO NOT process further
551                 }
552         }
553
554         return CEdit::PreTranslateMessage(pMsg);
555 }
556
557
558 void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
559 {
560         CEdit::OnKillFocus(pNewWnd);
561
562         if (!m_bESC)
563         {
564                 CString str;
565                 GetWindowText(str);
566                 static_cast<CListCtrl*>(GetParent())->SetItemText(m_iItem, m_iSubItem, str);
567         }
568
569         DestroyWindow();
570 }
571          
572 void CInPlaceEdit::OnNcDestroy()
573 {
574         CEdit::OnNcDestroy();
575
576         delete this;
577 }
578
579
580 void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
581 {
582         if( nChar == VK_ESCAPE || nChar == VK_RETURN)
583         {
584                 if( nChar == VK_ESCAPE )
585                         m_bESC = true;
586                 GetParent()->SetFocus();
587                 return;
588         }
589
590         CEdit::OnChar(nChar, nRepCnt, nFlags);
591
592         // Resize edit control if needed
593
594         // Get text extent
595         CString str;
596
597         GetWindowText( str );
598         CWindowDC dc(this);
599         CFont *pFont = GetParent()->GetFont();
600         CFont *pFontDC = dc.SelectObject( pFont );
601         LONG width = dc.GetTextExtent( str ).cx + 5; // add some extra buffer
602         dc.SelectObject( pFontDC );
603
604         // Get client rect
605         CRect rect, parentrect;
606         GetClientRect( &rect );
607         GetParent()->GetClientRect( &parentrect );
608
609         // Transform rect to parent coordinates
610         ClientToScreen( &rect );
611         GetParent()->ScreenToClient( &rect );
612
613         // Check whether control needs to be resized
614         // and whether there is space to grow
615         if( width > rect.Width() )
616         {
617                 width += rect.left;
618                 rect.right = (std::min)(width, parentrect.right);
619                 MoveWindow( &rect );
620         }
621 }
622
623 int CInPlaceEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
624 {
625         if (CEdit::OnCreate(lpCreateStruct) == -1)
626                 return -1;
627
628         // Set the proper font
629         CFont* font = GetParent()->GetFont();
630         SetFont(font);
631          
632         SetWindowText( m_sInitText );
633         SetFocus();
634         SetSel( 0, -1 );
635         return 0;
636 }
637
638 /////////////////////////////////////////////////////////////////////////////
639 // CInPlaceComboBox
640
641 CInPlaceComboBox::CInPlaceComboBox(int iItem, int iSubItem, CString sInitText, const std::vector<String>& list)
642 : m_sInitText( sInitText )
643 , m_list(list)
644 , m_iItem(iItem)
645 , m_iSubItem(iSubItem)
646 , m_bESC(false)
647 {
648 }
649
650 CInPlaceComboBox::~CInPlaceComboBox()
651 {
652 }
653
654
655 BEGIN_MESSAGE_MAP(CInPlaceComboBox, CComboBox)
656         //{{AFX_MSG_MAP(CInPlaceComboBox)
657         ON_WM_KILLFOCUS()
658         ON_WM_NCDESTROY()
659         ON_WM_CHAR()
660         ON_WM_CREATE()
661         ON_WM_LBUTTONDOWN()
662         //}}AFX_MSG_MAP
663 END_MESSAGE_MAP()
664
665 /////////////////////////////////////////////////////////////////////////////
666 // CInPlaceComboBox message handlers
667          
668 BOOL CInPlaceComboBox::PreTranslateMessage(MSG* pMsg)
669 {
670         if( pMsg->message == WM_KEYDOWN )
671         {
672                 if(pMsg->wParam == VK_RETURN
673                                 || pMsg->wParam == VK_DELETE
674                                 || pMsg->wParam == VK_ESCAPE
675                                 || GetKeyState( VK_CONTROL)
676                                 )
677                 {
678                         ::TranslateMessage(pMsg);
679                         ::DispatchMessage(pMsg);
680                         return TRUE;                            // DO NOT process further
681                 }
682         }
683
684         return CComboBox::PreTranslateMessage(pMsg);
685 }
686
687 void CInPlaceComboBox::OnKillFocus(CWnd* pNewWnd)
688 {
689         CComboBox::OnKillFocus(pNewWnd);
690
691         if (!m_bESC)
692         {
693                 CString str;
694                 GetWindowText(str);
695                 static_cast<CListCtrl*>(GetParent())->SetItemText(m_iItem, m_iSubItem, str);
696         }
697
698         DestroyWindow();
699 }
700          
701 void CInPlaceComboBox::OnNcDestroy()
702 {
703         CComboBox::OnNcDestroy();
704
705         delete this;
706 }
707
708 void CInPlaceComboBox::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
709 {
710         if (nChar == VK_ESCAPE || nChar == VK_RETURN)
711         {
712                 if (nChar == VK_ESCAPE)
713                         m_bESC = true;
714                 GetParent()->SetFocus();
715                 return;
716         }
717
718         CComboBox::OnChar(nChar, nRepCnt, nFlags);
719 }
720
721 int CInPlaceComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct)
722 {
723         if (CComboBox::OnCreate(lpCreateStruct) == -1)
724                 return -1;
725
726         // Set the proper font
727         CFont* font = GetParent()->GetFont();
728         SetFont(font);
729          
730         int sel = -1;
731         for (int i = 0; i < static_cast<int>(m_list.size()); ++i)
732         {
733                 AddString(m_list[i].c_str());
734                 if (m_sInitText == m_list[i].c_str())
735                         sel = i;
736         }
737         if (sel >= 0)
738                 SetCurSel(sel);
739         SetFocus();
740         return 0;
741 }