1 // SubeditList.cpp : implementation file
5 #include "SubeditList.h"
6 #include "Win_VersionHelper.h"
7 #include "WildcardDropList.h"
12 static char THIS_FILE[] = __FILE__;
15 #define IDC_IPEDIT 1000
17 /// Some stuff is from https://www.codeguru.com/cpp/controls/listview/editingitemsandsubitem/article.php/c923/Editable-subitems.htm
19 /////////////////////////////////////////////////////////////////////////////
22 CSubeditList::CSubeditList()
26 CSubeditList::~CSubeditList()
30 void CSubeditList::SetItemBooleanValue(int nItem, int nSubItem, bool value)
32 if (IsWin7_OrGreater())
33 SetItemText(nItem, nSubItem, value ? _T("\u2611") : _T("\u2610"));
35 SetItemText(nItem, nSubItem, value ? _T("true") : _T("false"));
38 bool CSubeditList::GetItemBooleanValue(int nItem, int nSubItem) const
40 CString text = GetItemText(nItem, nSubItem);
41 return (text.Compare(_T("true")) == 0 || text.Compare(_T("\u2611")) == 0);
45 * @brief Get the edit style for the specified column.
46 * @param [in] nCol Column to get edit style
47 * @return
\81@Edit style for the specified column
48 * @remarks Returns EditStyle::EDIT_BOX; as default if a column with no edit style is specified.
50 CSubeditList::EditStyle CSubeditList::GetEditStyle(int nCol) const
52 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
53 int nColumnCount = pHeader->GetItemCount();
55 if (nCol < 0 || nCol >= nColumnCount)
56 return EditStyle::EDIT_BOX;
58 if (nCol >= m_editStyle.size())
59 return EditStyle::EDIT_BOX;
61 return m_editStyle.at(nCol);
65 * @brief Set the edit style for the specified column.
66 * @param [in] nCol Column to set the edit style
67 * @param [in] style Edit style to set
69 void CSubeditList::SetEditStyle(int nCol, EditStyle style)
71 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
72 int nColumnCount = pHeader->GetItemCount();
73 if (nCol < 0 || nCol >= nColumnCount)
76 for (size_t i = m_editStyle.size(); i <= nCol; i++)
77 m_editStyle.push_back(EditStyle::EDIT_BOX);
79 m_editStyle[nCol] = style;
83 * @brief Get the character limit for the specified column.
84 * @param [in] nCol Column to get character limit
85 * @return
\81@Character limit for the specified column
86 * @remarks Currently, this setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
88 int CSubeditList::GetLimitTextSize(int nCol) const
90 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
91 int nColumnCount = pHeader->GetItemCount();
93 if (nCol < 0 || nCol >= nColumnCount)
96 // Currently, this setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
97 if (GetEditStyle(nCol) != EditStyle::WILDCARD_DROP_LIST)
100 if (nCol >= m_limitTextSize.size())
103 return m_limitTextSize.at(nCol);
107 * @brief Set the character limit for the specified column.
108 * @param [in] nCol Column to set the character limit
109 * @param [in] nLimitTextSize Character limit to set
110 * @remarks Currently, this setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
112 void CSubeditList::SetLimitTextSize(int nCol, int nLimitTextSize)
114 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
115 int nColumnCount = pHeader->GetItemCount();
116 if (nCol < 0 || nCol >= nColumnCount)
119 // Currently, this setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
120 if (GetEditStyle(nCol) != EditStyle::WILDCARD_DROP_LIST)
123 for (size_t i = m_limitTextSize.size(); i <= nCol; i++)
124 m_limitTextSize.push_back(0);
126 m_limitTextSize[nCol] = nLimitTextSize;
130 * @brief Get the wildcard drop list fixed pattern for the specified cell.
131 * @param [in] nItem Th row index to get wildcard drop list fixed pattern
132 * @param [in] nSubItem The column to get wildcard drop list fixed pattern
133 * @return Wildcard drop list fixed pattern for the specified cell
135 String CSubeditList::GetDropListFixedPattern(int nItem, int nSubItem) const
137 int nItemCount = GetItemCount();
138 if (nItem < 0 || nItem >= nItemCount)
141 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
142 int nColumnCount = pHeader->GetItemCount();
143 if (nSubItem < 0 || nSubItem >= nColumnCount)
146 // This setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
147 if (GetEditStyle(nSubItem) != EditStyle::WILDCARD_DROP_LIST)
150 if (nItem < m_dropListFixedPattern.size())
151 if (nSubItem < m_dropListFixedPattern[nItem].size())
152 return m_dropListFixedPattern[nItem][nSubItem];
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
163 void CSubeditList::SetDropListFixedPattern(int nItem, int nSubItem, const String& fixedPattern)
165 int nItemCount = GetItemCount();
166 if (nItem < 0 || nItem >= nItemCount)
169 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
170 int nColumnCount = pHeader->GetItemCount();
171 if (nSubItem < 0 || nSubItem >= nColumnCount)
174 // This setting is valid only for columns whose edit style is EditStyle::WILDCARD_DROPLIST.
175 if (GetEditStyle(nSubItem) != EditStyle::WILDCARD_DROP_LIST)
178 for (size_t i = m_dropListFixedPattern.size(); i <= nItem; i++)
179 m_dropListFixedPattern.push_back(std::vector<String>());
181 for (size_t i = m_dropListFixedPattern[nItem].size(); i <= nSubItem; i++)
182 m_dropListFixedPattern[nItem].push_back(_T(""));
184 m_dropListFixedPattern[nItem][nSubItem] = fixedPattern;
187 // HitTestEx - Determine the row index and column index for a point
188 // Returns - the row index or -1 if point is not over a row
189 // point - point to be tested.
190 // col - to hold the column index
191 int CSubeditList::HitTestEx(CPoint &point, int *col) const
194 int row = HitTest( point, NULL );
198 // Make sure that the ListView is in LVS_REPORT
199 if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
202 // Get the top and bottom row visible
204 int bottom = row + GetCountPerPage();
205 if( bottom > GetItemCount() )
206 bottom = GetItemCount();
208 // Get the number of columns
209 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
210 int nColumnCount = pHeader->GetItemCount();
212 // Loop through the visible rows
213 for( ;row <=bottom;row++)
215 // Get bounding rect of item and check whether point falls in it.
217 GetItemRect( row, &rect, LVIR_BOUNDS );
218 if( rect.PtInRect(point) )
220 // Now find the column
221 for( colnum = 0; colnum < nColumnCount; colnum++ )
223 int colwidth = GetColumnWidth(colnum);
224 if( point.x >= rect.left
225 && point.x <= (rect.left + colwidth ) )
227 if( col ) *col = colnum;
230 rect.left += colwidth;
238 BEGIN_MESSAGE_MAP(CSubeditList, CListCtrl)
239 //{{AFX_MSG_MAP(CSubeditList)
240 // NOTE - the ClassWizard will add and remove mapping macros here.
241 ON_NOTIFY(LVN_ENDLABELEDIT, IDC_SUBSTITUTION_FILTERS, OnEndLabelEdit)
246 /////////////////////////////////////////////////////////////////////////////
247 // CSubeditList message handlers
250 // EditSubLabel - Start edit of a sub item label
251 // Returns - Temporary pointer to the new edit control
252 // nItem - The row index of the item to edit
253 // nCol - The column of the sub item.
254 //CEdit* CSubeditList::EditSubLabel(int nItem, int nCol)
255 CInPlaceEdit* CSubeditList::EditSubLabel( int nItem, int nCol )
257 // The returned pointer should not be saved
259 // Make sure that the item is visible
260 if( !EnsureVisible( nItem, TRUE ) ) return NULL;
262 // Make sure that nCol is valid
263 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
264 int nColumnCount = pHeader->GetItemCount();
265 if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
268 if (GetEditStyle(nCol) != EditStyle::EDIT_BOX)
270 // Get the column offset
272 for( int i = 0; i < nCol; i++ )
273 offset += GetColumnWidth( i );
276 GetItemRect( nItem, &rect, LVIR_BOUNDS );
278 // Now scroll if we need to expose the column
280 GetClientRect( &rcClient );
281 if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
284 size.cx = offset + rect.left;
287 rect.left -= size.cx;
290 // Get Column alignment
292 lvcol.mask = LVCF_FMT;
293 GetColumn( nCol, &lvcol );
295 if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
297 else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
299 else dwStyle = ES_CENTER;
301 rect.left += offset+4;
302 rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
303 if( rect.right > rcClient.right) rect.right = rcClient.right;
305 dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
306 CInPlaceEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText( nItem, nCol ));
307 pEdit->Create( dwStyle, rect, this, IDC_IPEDIT );
313 * @brief Start edit of a sub item label with wilcard drop list.
314 * @param [in] nItem The row index of the item to edit
315 * @param [in] nCol The column of the sub item
317 void CSubeditList::EditSubLabelWildcardDropList( int nItem, int nCol )
319 // Make sure that the item is visible
320 if( !EnsureVisible( nItem, TRUE ) ) return;
322 // Make sure that nCol is valid
323 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
324 int nColumnCount = pHeader->GetItemCount();
325 if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
328 if (GetEditStyle(nCol) != EditStyle::WILDCARD_DROP_LIST)
331 CString pattern = GetDropListFixedPattern(nItem, nCol).c_str();
332 int nLimitTextSize = GetLimitTextSize(nCol);
333 WildcardDropList::OnItemActivate(m_hWnd, nItem, nCol, 4, pattern, true, nLimitTextSize);
336 void CSubeditList::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
338 if( GetFocus() != this ) SetFocus();
339 CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
342 void CSubeditList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
344 if( GetFocus() != this ) SetFocus();
345 CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
348 void CSubeditList::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
350 LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
351 LV_ITEM *plvItem = &plvDispInfo->item;
353 if (plvItem->pszText != NULL)
355 SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
360 void CSubeditList::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
362 LV_DISPINFO* plvDispInfo = (LV_DISPINFO*)pNMHDR;
363 LV_ITEM* plvItem = &plvDispInfo->item;
364 plvItem->iSubItem = 1;
366 // if (plvItem->pszText != NULL)
368 // SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
373 void CSubeditList::OnLButtonDown(UINT nFlags, CPoint point)
377 CListCtrl::OnLButtonDown(nFlags, point);
378 if( ( index = HitTestEx( point, &colnum )) != -1 )
380 UINT flag = LVIS_FOCUSED;
381 //if ((GetItemState(index, flag) & flag) == flag && colnum > 0)
382 if ((GetItemState(index, flag) & flag) == flag)
384 // Add check for LVS_EDITLABELS
385 if (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS)
387 if (m_readOnlyColumns.find(colnum) == m_readOnlyColumns.end())
388 if (m_binaryValueColumns.find(colnum) != m_binaryValueColumns.end())
390 CString text = GetItemText(index, colnum);
391 if (IsWin7_OrGreater())
393 SetItemText(index, colnum, text.Compare(_T("\u2611")) == 0 ?
394 _T("\u2610") : _T("\u2611"));
398 SetItemText(index, colnum, text.Compare(_T("true")) == 0 ?
399 _T("false") : _T("true"));
404 switch (GetEditStyle(colnum))
406 case EditStyle::EDIT_BOX:
407 EditSubLabel(index, colnum);
409 case EditStyle::WILDCARD_DROP_LIST:
410 EditSubLabelWildcardDropList(index, colnum);
420 SetItemState(index, LVIS_SELECTED | LVIS_FOCUSED,
421 LVIS_SELECTED | LVIS_FOCUSED);
426 /////////////////////////////////////////////////////////////////////////////
429 CInPlaceEdit::CInPlaceEdit(int iItem, int iSubItem, CString sInitText)
430 :m_sInitText( sInitText )
433 m_iSubItem = iSubItem;
437 CInPlaceEdit::~CInPlaceEdit()
442 BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
443 //{{AFX_MSG_MAP(CInPlaceEdit)
452 /////////////////////////////////////////////////////////////////////////////
453 // CInPlaceEdit message handlers
455 BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)
457 if( pMsg->message == WM_KEYDOWN )
459 if(pMsg->wParam == VK_RETURN
460 || pMsg->wParam == VK_DELETE
461 || pMsg->wParam == VK_ESCAPE
462 || GetKeyState( VK_CONTROL)
465 ::TranslateMessage(pMsg);
466 ::DispatchMessage(pMsg);
467 return TRUE; // DO NOT process further
471 return CEdit::PreTranslateMessage(pMsg);
475 void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
477 CEdit::OnKillFocus(pNewWnd);
482 // Send Notification to parent of ListView ctrl
483 LV_DISPINFO dispinfo;
484 dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
485 dispinfo.hdr.idFrom = GetDlgCtrlID();
486 dispinfo.hdr.code = LVN_ENDLABELEDIT;
488 dispinfo.item.mask = LVIF_TEXT;
489 dispinfo.item.iItem = m_iItem;
490 dispinfo.item.iSubItem = m_iSubItem;
491 dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
492 dispinfo.item.cchTextMax = str.GetLength();
494 GetParent()->GetParent()->SendMessage( WM_NOTIFY, GetParent()->GetDlgCtrlID(),
500 void CInPlaceEdit::OnNcDestroy()
502 CEdit::OnNcDestroy();
508 void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
510 if( nChar == VK_ESCAPE || nChar == VK_RETURN)
512 if( nChar == VK_ESCAPE )
514 GetParent()->SetFocus();
519 CEdit::OnChar(nChar, nRepCnt, nFlags);
521 // Resize edit control if needed
526 GetWindowText( str );
528 CFont *pFont = GetParent()->GetFont();
529 CFont *pFontDC = dc.SelectObject( pFont );
530 CSize size = dc.GetTextExtent( str );
531 dc.SelectObject( pFontDC );
532 size.cx += 5; // add some extra buffer
535 CRect rect, parentrect;
536 GetClientRect( &rect );
537 GetParent()->GetClientRect( &parentrect );
539 // Transform rect to parent coordinates
540 ClientToScreen( &rect );
541 GetParent()->ScreenToClient( &rect );
543 // Check whether control needs to be resized
544 // and whether there is space to grow
545 if( size.cx > rect.Width() )
547 if( size.cx + rect.left < parentrect.right )
548 rect.right = rect.left + size.cx;
550 rect.right = parentrect.right;
555 int CInPlaceEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
557 if (CEdit::OnCreate(lpCreateStruct) == -1)
560 // Set the proper font
561 CFont* font = GetParent()->GetFont();
564 SetWindowText( m_sInitText );