update for HEAD-2003091401
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / Uictrl.cpp
1 //*******************************************************************************
2 // COPYRIGHT NOTES
3 // ---------------
4 // You may use this source code, compile or redistribute it as part of your application 
5 // for free. You cannot redistribute it as a part of a software development 
6 // library without the agreement of the author. If the sources are 
7 // distributed along with the application, you should leave the original 
8 // copyright notes in the source code without any changes.
9 // This code can be used WITHOUT ANY WARRANTIES at your own risk.
10 // 
11 // For the latest updates to this code, check this site:
12 // http://www.masmex.com 
13 // after Sept 2000
14 // 
15 // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
16 //*******************************************************************************
17
18 #include "stdafx.h"
19 #include "UICtrl.h"
20 #include "InPlaceEdit.h"
21 #include "TextProgressCtrl.h"
22 #include "UIres.h"
23 #include "ctype.h"
24 #include "cbformats.h"
25 #include <yvals.h>
26
27 //////////////////////////////////////////////////////
28 // Temporarily changes the view type
29 //////////////////////////////////////////////////////
30 CChangeViewType::CChangeViewType(CUIODListCtrl *pLC,DWORD dwType)
31 {
32         m_pLC = pLC;
33         m_dwType = m_pLC->GetViewType();        
34         m_pLC->SetViewType(dwType);
35 }
36
37 CChangeViewType::~CChangeViewType()
38 {
39         m_pLC->SetViewType(m_dwType);
40 }
41 //////////////////////////////////////////////////////////
42
43 LPCTSTR CUIODListCtrl::szEntryHeadings          = _T("Headings");
44 LPCTSTR CUIODListCtrl::szEntryStyle                     = _T("Style");
45 LPCTSTR CUIODListCtrl::szEntryRowSel            = _T("RowSelection");
46 LPCTSTR CUIODListCtrl::szEntryViewType          = _T("ViewType");
47 LPCTSTR CUIODListCtrl::szEntryColumnSizing      = _T("ColumnSizing");
48 LPCTSTR CUIODListCtrl::szEntrySortColumn        = _T("SortColumn");
49 LPCTSTR CUIODListCtrl::szEntrySubItems          = _T("Columns");
50 LPCTSTR CUIODListCtrl::szEntryColOrder          = _T("ColumnOrder");
51 LPCTSTR CUIODListCtrl::szEntryColWidths         = _T("ColumnWidths");
52
53 IMPLEMENT_SERIAL(CUIODListCtrl, CListCtrl, 0)
54
55 #define COLUMN_DELIMITER '|'
56 #define COLUMN_DELIMITER_STR "|"
57
58 const int nMaxDigLen = _MAX_INT_DIG*4;
59
60 //////////////////////////////
61 //
62 // CUIODListCtrl
63 //
64 //////////////////////////////
65 BEGIN_MESSAGE_MAP(CUIODListCtrl, CListCtrl)
66         //{{AFX_MSG_MAP(CUIODListCtrl)
67         ON_MESSAGE(WM_APP_ON_PROPERTIES_KEY,OnAppPropertiesKey)
68         ON_MESSAGE(WM_APP_ON_DELETE_KEY,OnAppDeleteKey)
69         ON_MESSAGE(WM_APP_ON_CONTEXT_MENU_KEY,OnAppContextMenuKey)
70         ON_MESSAGE(WM_APP_ON_BACKSPACE_KEY,OnAppBackspaceKey)
71         ON_MESSAGE(WM_APP_ON_EDIT_KEY,OnAppEditKey)
72         ON_MESSAGE(WM_APP_ON_REFRESH_KEY,OnAppRefreshKey)
73
74         ON_NOTIFY_REFLECT_EX(LVN_BEGINDRAG, OnBegindrag)
75         ON_NOTIFY_REFLECT_EX(LVN_BEGINRDRAG, OnBeginRDrag)
76         ON_WM_CREATE()
77         ON_WM_DESTROY()
78         ON_MESSAGE(LVM_SETCOLUMNWIDTH,OnSetColumnWidth)
79         ON_MESSAGE(LVM_DELETEALLITEMS,OnDeleteAllItems)
80         ON_MESSAGE(LVM_DELETEITEM,OnDeleteItem)
81         ON_MESSAGE(LVM_DELETECOLUMN,OnDeleteColumn)
82         ON_MESSAGE(WM_UPDATEHEADERWIDTH,OnUpdateHeaderWidth)
83         ON_WM_SIZE()
84         ON_WM_PAINT()
85         ON_WM_SETFOCUS()
86         ON_WM_KILLFOCUS()
87         ON_WM_CONTEXTMENU()
88         ON_WM_INITMENUPOPUP()
89         ON_WM_LBUTTONDOWN()
90         ON_WM_HSCROLL()
91         ON_WM_VSCROLL()
92         ON_COMMAND(ID_UI_VIEW_LARGE_ICONS,OnViewLargeIcons)
93         ON_COMMAND(ID_UI_VIEW_SMALL_ICONS,OnViewSmallIcons)
94         ON_COMMAND(ID_UI_VIEW_DETAILS,OnViewDetails)
95         ON_COMMAND(ID_UI_VIEW_LIST,OnViewList)
96         ON_COMMAND(ID_UI_VIEW_FULL_ROW_SELECTION,OnViewFullRowSelection)
97         ON_COMMAND(ID_UI_VIEW_COLUMN_ORDERING,OnViewColumnOrdering)
98         ON_COMMAND(ID_UI_VIEW_COLUMN_SIZING,OnViewColumnSizing)
99         ON_COMMAND(ID_UI_VIEW_GRIDLINES,OnViewGridlines)
100         ON_COMMAND(ID_UI_VIEW_CHECKBOXES,OnViewCheckboxes)
101         ON_COMMAND(ID_UI_VIEW_TRACK_SELECT,OnViewTrackSelect)
102         ON_COMMAND(ID_UI_VIEW_EDIT_COLUMN,OnViewEditColumn)
103         ON_COMMAND(ID_HEADER_REMOVE_COL,OnHeaderRemoveColumn)
104         ON_COMMAND(ID_HEADER_EDIT_TEXT,OnHeaderEditText)
105         ON_COMMAND(ID_HEADER_RESET,OnHeaderReset)
106         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
107         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
108         ON_WM_DROPFILES()
109         ON_MESSAGE(LVM_SETIMAGELIST, OnSetImageList)
110         ON_MESSAGE(LVM_SETTEXTCOLOR, OnSetTextColor)
111         ON_MESSAGE(LVM_SETTEXTBKCOLOR, OnSetTextBkColor)
112         ON_MESSAGE(LVM_SETBKCOLOR, OnSetBkColor)
113         ON_MESSAGE(LVM_GETITEMTEXT, OnGetItemText)
114         //}}AFX_MSG_MAP
115         ON_MESSAGE(WM_APP_OLE_DD_DROP, OnDragDrop)
116         ON_MESSAGE(WM_APP_OLE_DD_DODRAGDROP, OnDDDoDragDrop)
117         ON_MESSAGE(WM_APP_OLE_DD_OVER, OnDragOver)
118         ON_MESSAGE(WM_APP_OLE_DD_ENTER, OnDragEnter)
119         ON_MESSAGE(WM_APP_OLE_DD_LEAVE, OnDragLeave)
120 END_MESSAGE_MAP()
121
122
123 CUIODListCtrl::CUIODListCtrl(bool bDragDrop) 
124 {
125         m_PopupID = 0;
126         m_MultiPopupID = 0;
127         m_bDragDrop = bDragDrop;
128         m_bDropFiles = true;
129         m_pColWidths = NULL;
130         m_pColOrder = NULL;
131         m_pColTypes = NULL;
132         m_hOrigFont = NULL;
133         m_pPopupWnd = NULL;
134         m_nImageList = LVSIL_SMALL;
135         m_nColClicked = -1;
136         m_nSortColumn = 0;
137         m_nSubItems = 0;
138         m_nItems = 0;
139         m_nImage = 0;
140         m_dwExStyle = LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_INFOTIP;
141         m_dwViewType = LVS_REPORT;
142         m_bDelayPaint = false;
143         m_bColumnSizing=TRUE;
144         m_bRClickChangeIconSize = TRUE;
145         // this is toggled on in InitListCtrl
146         m_bFullRowSel=FALSE;
147         m_bClientWidthSel=TRUE;
148         m_bSortAscending=TRUE;
149         m_bToolTips=FALSE;
150         m_bEditSubItems = true;
151         m_cxClient=0;
152         m_cxStateImageOffset=0;
153
154         m_clrText=::GetSysColor(COLOR_WINDOWTEXT);
155         m_clrTextBk=::GetSysColor(COLOR_WINDOW);
156         m_clrBkgnd=::GetSysColor(COLOR_WINDOW);
157         m_strNoItemsMess.LoadString(IDS_NO_ITEMS_MESS);
158 }
159
160 CUIODListCtrl::~CUIODListCtrl()
161 {
162         Empty();
163 }
164
165 void CUIODListCtrl::AllItemsDeleted()
166 {
167
168 }
169
170 void CUIODListCtrl::Empty()
171 {
172         m_objList.DeleteAll();
173         delete []m_pColWidths;
174         delete []m_pColOrder;
175         delete []m_pColTypes;
176         m_pColWidths = NULL;
177         m_pColOrder = NULL;
178         m_pColTypes = NULL;
179 }
180
181 // should be overridden to do any initialization
182 void CUIODListCtrl::Init()
183 {
184 }
185
186 void CUIODListCtrl::UpdateEvent(LPARAM lHint,CObject *pHint)
187 {
188         GetParent()->SendMessage(WM_APP_UPDATE_ALL_VIEWS,(WPARAM)lHint,(LPARAM)pHint);
189 }
190
191 BOOL CUIODListCtrl::SetViewType(DWORD dwViewType,UINT nFlags)
192 {
193         BOOL bRet = ModifyStyle(LVS_TYPEMASK,dwViewType & LVS_TYPEMASK,nFlags);
194         if (bRet)
195                 SaveProfile();
196         return bRet;
197 }
198
199 DWORD CUIODListCtrl::GetViewType() const
200 {
201         return(GetStyle() & LVS_TYPEMASK);
202 }
203
204 void CUIODListCtrl::ChangeStyle(UINT &dwStyle)
205 {
206         LoadProfile();
207         dwStyle |= LVS_SHOWSELALWAYS | m_dwViewType;
208 }
209
210 // offsets for first and other columns
211 #define OFFSET_FIRST    2
212 #define OFFSET_OTHER    6
213
214 void CUIODListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
215 {
216         CDC* pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
217         CRect rcItem(lpDrawItemStruct->rcItem);
218         UINT uiFlags=ILD_TRANSPARENT;
219         CImageList* pImageList;
220         int nItem=lpDrawItemStruct->itemID;
221         BOOL bFocus=(GetFocus()==this);
222         COLORREF clrTextSave, clrBkSave;
223         COLORREF clrImage=m_clrBkgnd;
224         static _TCHAR szBuff[MAX_PATH];
225         LPCTSTR pszText;
226
227         if (m_cxClient == 0)
228         {
229                 CRect rcClient;
230                 GetClientRect(rcClient);
231                 m_cxClient = rcClient.Width();
232         }
233 // get item data
234
235         LV_ITEM lvi;
236         lvi.mask=LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
237         lvi.iItem=nItem;
238         lvi.iSubItem=0;
239         lvi.pszText=szBuff;
240         lvi.cchTextMax=sizeof(szBuff);
241         lvi.stateMask=0xFFFF;           // get all state flags
242         GetItem(&lvi);
243
244         BOOL bSelected=(bFocus || (GetStyle() & LVS_SHOWSELALWAYS)) && lvi.state & LVIS_SELECTED;
245         bSelected=bSelected || (lvi.state & LVIS_DROPHILITED);
246
247 // set colors if item is selected
248
249         CRect rcAllLabels;
250         GetItemRect(nItem,rcAllLabels,LVIR_BOUNDS);
251         CRect rcLabel;
252         GetItemRect(nItem,rcLabel,LVIR_LABEL);
253         rcAllLabels.left=rcLabel.left;
254 //      if(m_bClientWidthSel && rcAllLabels.right<m_cxClient)
255 //              rcAllLabels.right=m_cxClient;
256         int     BkMode = pDC->SetBkMode(TRANSPARENT);
257         CUIListCtrlData *pData = (CUIListCtrlData*)lvi.lParam;
258         ASSERT(pData->IsKindOf(RUNTIME_CLASS(CUIListCtrlData)));
259         CFont *pOldFont = NULL;
260         if (pData && pData->IsFontSet())
261         {
262                 pOldFont = pDC->SelectObject((CFont*)pData->GetFont());
263         }
264         if(bSelected)
265         {
266                 if (bFocus) 
267                 {
268                         clrTextSave=pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
269                         clrBkSave=pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
270                         pDC->FillRect(rcAllLabels,&CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
271                 }
272                 else 
273                 {
274                         clrTextSave=pDC->GetTextColor();
275                         clrBkSave=pDC->GetBkColor();
276                         DWORD clrTextBk;
277                         if (pData)
278                         {
279                                 pDC->SetTextColor(pData->GetTextColor());
280                                 clrTextBk = pData->GetBkColor();
281                         }
282                         else 
283                         {
284                                 clrTextBk = m_clrTextBk;
285                                 pDC->SetTextColor(m_clrText);
286                         }
287                         CRect rc(rcAllLabels);
288                         pDC->FillRect(rcAllLabels,&CBrush(clrTextBk));
289                         pDC->FrameRect(rc,&CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
290                 }
291         }
292         else 
293         {
294                 CUIListCtrlData *pData = (CUIListCtrlData *)lvi.lParam;
295                 if (pData) 
296                 {
297                         ASSERT(pData->IsKindOf(RUNTIME_CLASS(CUIListCtrlData)));
298                         pDC->SetTextColor(pData->GetTextColor());
299                         pDC->SetBkColor(pData->GetBkColor());
300                         pDC->FillRect(rcAllLabels,&CBrush(pData->GetBkColor()));
301                 }
302                 else
303                         pDC->FillRect(rcAllLabels,&CBrush(m_clrTextBk));
304         }
305 // set color and mask for the icon
306
307         if(lvi.state & LVIS_CUT)
308         {
309                 clrImage=m_clrBkgnd;
310                 uiFlags|=ILD_BLEND50;
311         }
312         else if(bSelected)
313         {
314                 clrImage=::GetSysColor(COLOR_HIGHLIGHT);
315                 uiFlags|=ILD_BLEND50;
316         }
317
318 // draw state icon
319
320         UINT nStateImageMask=lvi.state & LVIS_STATEIMAGEMASK;
321         if(nStateImageMask)
322         {
323                 int nImage=(nStateImageMask>>12)-1;
324                 pImageList=GetImageList(LVSIL_STATE);
325                 if(pImageList)
326                         pImageList->Draw(pDC,nImage,CPoint(rcItem.left,rcItem.top),ILD_TRANSPARENT);
327         }
328
329 // draw normal and overlay icon
330
331         CRect rcIcon;
332         GetItemRect(nItem,rcIcon,LVIR_ICON);
333
334         pImageList=GetImageList(LVSIL_SMALL);
335         if(pImageList)
336         {
337                 UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
338                 if(rcItem.left<rcItem.right-1)
339                         ImageList_DrawEx(pImageList->m_hImageList,lvi.iImage,pDC->m_hDC,rcIcon.left,rcIcon.top,16,16,m_clrBkgnd,clrImage,uiFlags | nOvlImageMask);
340         }
341
342 // draw item label
343
344         GetItemRect(nItem,rcItem,LVIR_LABEL);
345         rcItem.right-=m_cxStateImageOffset;
346
347         pszText=MakeShortString(pDC,szBuff,rcItem.right-rcItem.left,2*OFFSET_FIRST);
348
349         rcLabel=rcItem;
350         rcLabel.left+=OFFSET_FIRST;
351         rcLabel.right-=OFFSET_FIRST;
352
353         pDC->DrawText(pszText,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
354 // draw labels for extra columns
355
356         LV_COLUMN lvc;
357         lvc.mask=LVCF_FMT | LVCF_WIDTH;
358
359         for(int nColumn=1; GetColumn(nColumn,&lvc); nColumn++)
360         {
361                 rcItem.left=rcItem.right;
362                 rcItem.right+=lvc.cx;
363
364                 int nRetLen=GetItemText(nItem,nColumn,szBuff,sizeof(szBuff));
365                 if(nRetLen==0) continue;
366
367                 pszText=MakeShortString(pDC,szBuff,rcItem.right-rcItem.left,2*OFFSET_OTHER);
368
369                 UINT nJustify=DT_LEFT;
370
371                 if(pszText==szBuff)
372                 {
373                         switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
374                         {
375                         case LVCFMT_RIGHT:
376                                 nJustify=DT_RIGHT;
377                                 break;
378                         case LVCFMT_CENTER:
379                                 nJustify=DT_CENTER;
380                                 break;
381                         default:
382                                 break;
383                         }
384                 }
385
386                 rcLabel=rcItem;
387                 rcLabel.left+=OFFSET_OTHER;
388                 rcLabel.right-=OFFSET_OTHER;
389
390                 pDC->DrawText(pszText,-1,rcLabel,nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
391         }
392         if (pData->IsKindOf(RUNTIME_CLASS(CUIStrListCtrlData)))
393         {
394                 CUIStrListCtrlData *pStrData = (CUIStrListCtrlData*)pData;
395                 if (!pStrData->GetExtraString().IsEmpty())
396                 {
397                         rcLabel=rcAllLabels;
398                         rcLabel.top += (m_cySmallIcon+1);
399                         pDC->DrawText(pStrData->GetExtraString(),-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
400                 }
401         }
402 // draw focus rectangle if item has focus
403
404         if(lvi.state & LVIS_FOCUSED && bFocus)
405                 pDC->DrawFocusRect(rcAllLabels);
406
407 // set original colors if item was selected
408
409         if(bSelected)
410         {
411             pDC->SetTextColor(clrTextSave);
412                 pDC->SetBkColor(clrBkSave);
413         }
414         if (pOldFont)
415                 pDC->SelectObject(pOldFont);
416         pDC->SetBkMode(BkMode);
417 }
418
419 LPCTSTR CUIODListCtrl::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
420 {
421         static const _TCHAR szThreeDots[]=_T("...");
422
423         int nStringLen=lstrlen(lpszLong);
424
425         if(nStringLen==0 || pDC->GetTextExtent(lpszLong,nStringLen).cx+nOffset<=nColumnLen)
426                 return(lpszLong);
427
428         static _TCHAR szShort[MAX_PATH];
429
430         lstrcpy(szShort,lpszLong);
431         int nAddLen=pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
432
433         for(int i=nStringLen-1; i>0; i--)
434         {
435                 szShort[i]=0;
436                 if(pDC->GetTextExtent(szShort,i).cx+nOffset+nAddLen<=nColumnLen)
437                         break;
438         }
439
440         lstrcat(szShort,szThreeDots);
441
442         return(szShort);
443 }
444
445 void CUIODListCtrl::RepaintSelectedItems()
446 {
447         CRect rcItem, rcLabel;
448
449 // invalidate focused item so it can repaint properly
450
451         int nItem=GetNextItem(-1,LVNI_FOCUSED);
452
453         if(nItem!=-1)
454         {
455                 GetItemRect(nItem,rcItem,LVIR_BOUNDS);
456                 GetItemRect(nItem,rcLabel,LVIR_LABEL);
457                 rcItem.left=rcLabel.left;
458
459                 InvalidateRect(rcItem,FALSE);
460         }
461
462 // if selected items should not be preserved, invalidate them
463
464 //      if(!(GetStyle() & LVS_SHOWSELALWAYS))
465 //      {
466                 for(nItem=GetNextItem(-1,LVNI_SELECTED);
467                         nItem!=-1; nItem=GetNextItem(nItem,LVNI_SELECTED))
468                 {
469                         GetItemRect(nItem,rcItem,LVIR_BOUNDS);
470                         GetItemRect(nItem,rcLabel,LVIR_LABEL);
471                         rcItem.left=rcLabel.left;
472
473                         InvalidateRect(rcItem,FALSE);
474                 }
475 //      }
476
477 // update changes 
478
479         UpdateWindow();
480 }
481
482 void CUIODListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItem)
483 {
484         lpMeasureItem->itemHeight = (m_cySmallIcon+1)*3;
485 }
486
487
488 BOOL CUIODListCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
489 {
490         LPNMHDR pnmh;
491
492         switch (message)
493         {
494                         case WM_DRAWITEM:
495                                 ASSERT(pResult == NULL);       
496                                 DrawItem((LPDRAWITEMSTRUCT)lParam);
497                                 break;
498                         case WM_MEASUREITEM:
499                                 ASSERT(pResult == NULL);       
500                                 MeasureItem((LPMEASUREITEMSTRUCT)lParam);
501                                 break;
502                         case WM_NOTIFY:
503                                 pnmh = (LPNMHDR)lParam;
504                                 if (pnmh->code == LVN_ITEMCHANGED)
505                                 {
506                                         NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pnmh;
507                                         if ((pNMListView->uNewState & LVIS_SELECTED) == LVIS_SELECTED && 
508                                                 (pNMListView->uNewState & LVIS_FOCUSED) == LVIS_FOCUSED) 
509                                         {
510                                                 return OnSelChanged(pNMListView->iItem,pResult);
511                                         }       
512                                 }
513                                 else if (pnmh->code == LVN_GETDISPINFO) 
514                                 {
515                                         return GetDispInfo((LV_DISPINFO*)pnmh);
516                                 }
517                                 else if (pnmh->code == LVN_COLUMNCLICK) 
518                                 {
519                                         return ColumnClick((NM_LISTVIEW*)pnmh);
520                                 }
521                                 else if (pnmh->code == LVN_ENDLABELEDIT) 
522                                 {
523                                         return OnEndLabelEdit(pnmh,pResult);
524                                 }
525                                 else if (pnmh->code == NM_DBLCLK) 
526                                 {
527                                         return DoubleClick((NM_LISTVIEW*)pnmh);
528                                 }
529                                 else if (pnmh->code == NM_RETURN) 
530                                 {
531                                         return OnEnter((NM_LISTVIEW*)pnmh);
532                                 }
533                                 else if (pnmh->code == NM_CUSTOMDRAW)
534                                 {
535                                      LPNMLVCUSTOMDRAW  lplvcd = (LPNMLVCUSTOMDRAW)lParam;
536                                          if(lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
537                                          {
538                                                 //tell the control we want pre-paint notifications for each item
539                                                 *pResult = CDRF_NOTIFYITEMDRAW;
540                                                 return TRUE;
541                                          }
542                                          if (lplvcd->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM))
543                                          {
544                                                  return SubItemPrePaint(lplvcd,pResult);
545                                          }
546                                          if (lplvcd->nmcd.dwDrawStage == (CDDS_ITEMPOSTPAINT | CDDS_SUBITEM))
547                                          {
548                                                  return SubItemPostPaint(lplvcd,pResult);
549                                          }
550                                          if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
551                                          {
552                                                  return ItemPrePaint(lplvcd,pResult);
553                                          }
554                                          if (lplvcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT)
555                                          {
556                                                  return ItemPostPaint(lplvcd,pResult);
557                                          }
558                         }
559         }
560         return CWnd::OnChildNotify(message, wParam, lParam, pResult);
561 }
562
563 LRESULT CUIODListCtrl::OnUpdateHeaderWidth(WPARAM wParam,LPARAM lParam)
564 {
565         // lParam = column that has changed its width
566         int nItem = lParam;
567         m_pColWidths[nItem] = GetColumnWidth(nItem);
568     GetParent()->SendMessage(WM_HEADERWIDTHCHANGED,(WPARAM)GetSafeHwnd(),nItem);
569         return TRUE;
570 }
571
572 BOOL CUIODListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
573 {
574         LPNMHDR pnmh = (LPNMHDR)lParam;
575         if ((pnmh->code == HDN_BEGINTRACKW || pnmh->code == HDN_BEGINTRACKA)) 
576         {
577                 if (m_bColumnSizing == FALSE) 
578                 {
579                         *pResult = TRUE;
580                         return TRUE;
581                 }
582                 LPNMHEADER phdr = (LPNMHEADER)lParam;
583                 if (phdr->pitem->mask & HDI_WIDTH)
584                 {
585                 }
586         }
587         if ((pnmh->code == HDN_ITEMCHANGINGW || pnmh->code == HDN_ITEMCHANGINGA)) 
588         {
589                 LPNMHEADER phdr = (LPNMHEADER)lParam;
590         }
591         if ((pnmh->code == HDN_ENDTRACKW || pnmh->code == HDN_ENDTRACKA)) 
592         {
593             HD_NOTIFY *phdn = (HD_NOTIFY*)pnmh;
594                 LPNMHEADER phdr = (LPNMHEADER)lParam;
595                 if (m_bColumnSizing == TRUE && (phdr->pitem->mask & HDI_WIDTH))
596                         PostMessage(WM_UPDATEHEADERWIDTH,(WPARAM)phdn->hdr.hwndFrom,(LPARAM)phdn->iItem);
597         } 
598         // wParam is zero for Header ctrl
599         if( wParam == 0 && pnmh->code == NM_RCLICK )
600         {
601                 // Right button was clicked on header
602                 CPoint ptScreen(GetMessagePos());
603                 CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
604                 ASSERT(pHeader);
605                 CPoint ptClient(ptScreen);
606                 pHeader->ScreenToClient(&ptClient);
607                 
608                 // Determine the column index
609                 int index=-1;
610                 CRect rcCol;
611                 for( int i=0; Header_GetItemRect(pHeader->m_hWnd, i, &rcCol); i++ )
612                 {
613                         if( rcCol.PtInRect( ptClient ) )
614                         {
615                                 index = i;
616                                 break;
617                         }
618                 }
619                 OnRClickHeader(ptScreen,index);
620         }
621         return CWnd::OnNotify(wParam,lParam,pResult);
622 }
623
624 DWORD CUIODListCtrl::GetItemData(int nIndex) const
625 {
626         if (nIndex != LB_ERR)
627         {
628                 const CUIListCtrlData* pListObj = GetListCtrlData(nIndex);
629                 if (pListObj)
630                         return pListObj->GetExtData();
631         }
632         return 0;
633 }
634
635 BOOL CUIODListCtrl::SetItemDataAutoDelete(int nIndex,CObject *pObj)
636 {
637         ASSERT_KINDOF(CObject,pObj);
638         return SetItemData(nIndex,(DWORD)pObj,true);
639 }
640
641 BOOL CUIODListCtrl::SetItemData(int nIndex,DWORD dwData,bool bAutoDelete)
642 {
643         if (nIndex != LB_ERR) 
644         {
645                 CUIListCtrlData* pListObj = GetListCtrlData(nIndex);
646                 if (pListObj) 
647                 {
648                         pListObj->SetExtData(dwData);
649                         pListObj->SetAutoDelete(bAutoDelete);
650                         return TRUE;
651                 }
652         }
653         return FALSE;
654 }
655
656 int CUIODListCtrl::SetIcon(int nRow,int nImage)
657 {
658         LV_ITEM lvItem;
659         ZeroMemory(&lvItem,sizeof(LV_ITEM));
660         lvItem.mask = LVIF_IMAGE;
661         lvItem.iItem = nRow;
662         lvItem.iImage = nImage;
663         SetItem(&lvItem);
664         return lvItem.iImage;
665 }
666
667 int CUIODListCtrl::SetIcon(int nRow,UINT nIconID)
668 {
669         int nImage = GetImageIndex(nIconID);
670         return SetIcon(nRow,nImage);
671 }
672
673 BOOL CUIODListCtrl::SetColumnFormat(int nCol,int fmt)
674 {
675         LVCOLUMN lvCol;
676         ZeroMemory(&lvCol,sizeof(lvCol));
677         lvCol.mask = LVCF_FMT;
678         lvCol.fmt = fmt;
679         return SetColumn(nCol,&lvCol);
680 }
681
682 void CUIODListCtrl::SetTextColor(int nRow, int nCol, COLORREF TextColor)
683 {
684         CUIListCtrlData *pData = GetListCtrlData(nRow);
685         if (pData)
686                 pData->SetTextColor(TextColor,nCol);
687 }
688
689 void CUIODListCtrl::SetDefaultTextColor(int nRow,int nCol)
690 {
691         CUIListCtrlData *pData = GetListCtrlData(nRow);
692         if (pData)
693                 pData->SetDefaultTextColor(nCol);
694 }
695
696 void CUIODListCtrl::SetBkColor(int nRow,int nCol,COLORREF BkColor)
697 {
698         CUIListCtrlData *pData = GetListCtrlData(nRow);
699         if (pData)
700                 pData->SetBkColor(BkColor,nCol);
701 }
702
703 void CUIODListCtrl::SetDefaultBkColor(int nRow,int nCol)
704 {
705         CUIListCtrlData *pData = GetListCtrlData(nRow);
706         if (pData)
707                 pData->SetDefaultBkColor(nCol);
708 }
709
710 CUIListCtrlData *CUIODListCtrl::GetListCtrlData(int nItem) const
711 {
712         CUIListCtrlData *pData = (CUIListCtrlData *)CListCtrl::GetItemData(nItem);
713         if (pData == NULL)
714                 return NULL;
715         ASSERT(pData->IsKindOf(RUNTIME_CLASS(CUIListCtrlData)));
716         return pData;
717 }
718
719 int CUIODListCtrl::AddColumn(LPCTSTR szText)
720 {
721         // don't add again
722         int nCol = FindColumn(szText);
723         if (nCol >= 0)
724                 return nCol;
725         nCol = InsertColumn(m_nSubItems,szText);
726         if (nCol != -1)
727         {
728                 m_strHeadings += COLUMN_DELIMITER_STR;
729                 m_strHeadings += szText;
730                 m_nSubItems++;
731                 SaveProfile();
732                 LoadProfile();
733         }
734         return nCol;
735 }
736
737 int CUIODListCtrl::FindColumn(LPCTSTR pszText)
738 {
739         LPCTSTR pszHeadings = m_strHeadings;
740         int nCol=0;
741         while (*pszHeadings != '\0')
742         {
743                 if (*pszHeadings == COLUMN_DELIMITER)
744                         nCol++;
745                 if (_tcsnicmp(pszHeadings,pszText,_tcslen(pszText)) == 0)
746                 {
747                         break;                  
748                 }
749                 pszHeadings = _tcsinc(pszHeadings);
750         }
751         return *pszHeadings == '\0' ? -1 : nCol;
752 }
753
754 BOOL CUIODListCtrl::InitListCtrl(UINT IconID,LPCTSTR szHeadings,LPCTSTR pszProfile)
755 {
756         static UINT Icons[2];
757
758         Icons[0] = IconID;
759         Icons[1] = 0;
760         return InitListCtrl(&Icons[0],szHeadings,pszProfile);
761 }
762
763 BOOL CUIODListCtrl::InitListCtrl(LPCTSTR szHeadings,LPCTSTR pszProfile)
764 {
765         static UINT Icons[1];
766
767         Icons[0] = 0;
768         return InitListCtrl(&Icons[0],szHeadings,pszProfile);
769 }
770
771 int CUIODListCtrl::InitListCtrl(const UINT *pIconIDs,LPCTSTR szHeadings,LPCTSTR pszProfile)
772 {
773         BOOL bFailed = FALSE;
774         // TODO: Add extra initialization here
775         if (pszProfile)
776         {
777                 SetSection(pszProfile);
778         }
779         //clean up
780         if (m_nSubItems) 
781         {
782                 if (m_strHeadings == szHeadings)
783                         return m_nSubItems;
784                 DeleteAllItems();
785                 int nSubItems=m_nSubItems;
786                 for(int i=0;i < nSubItems;i++)
787                         DeleteColumn(0);
788                 m_nSubItems = 0;
789                 Empty();
790         }
791         if (pszProfile == NULL)
792         {
793                 if (!m_strSection.IsEmpty())
794                         pszProfile = m_strSection;
795         }
796         if (pszProfile)
797         {
798                 LoadProfile();
799                 // Use profile headings if found
800                 if (!m_strHeadings.IsEmpty())
801                 {
802                         if (m_strHeadings != szHeadings)
803                         {
804                                 m_strHeadings = szHeadings;
805                                 SaveProfile();
806                         }
807                 }
808         }
809         if (m_dwExStyle)
810                 SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, m_dwExStyle);
811
812         // at least one image
813         if (pIconIDs && *pIconIDs) 
814         {
815                 // load the icons and add them to the image lists
816                 int i;
817                 for(i=0;*pIconIDs;i++,pIconIDs++) 
818                 {
819                         if (AddIcon(*pIconIDs) == -1)
820                                 bFailed = TRUE;
821                 } 
822         }
823
824         // Now initialize the columns we will need
825         // Initialize the LV_COLUMN structure
826         // the mask specifies that the .fmt, .ex, width, and .subitem members 
827         // of the structure are valid,
828         LV_COLUMN lvC;
829         lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
830         lvC.fmt = LVCFMT_LEFT;  // left align the column
831
832         if (szHeadings)
833         {
834                 // parse the string, format it and get column count
835                 const int MAX_HEADING_LEN = 512;
836                 TCHAR szHeadingsCopy[MAX_HEADING_LEN]; 
837                 if (_tcslen(szHeadings) >= MAX_HEADING_LEN-1)
838                 {
839                         _tcsncpy(szHeadingsCopy,szHeadings,MAX_HEADING_LEN-1);
840                         szHeadingsCopy[MAX_HEADING_LEN-1] = '\0';
841                 }
842                 else
843                         _tcscpy(szHeadingsCopy,szHeadings);
844                 LPTSTR p = szHeadingsCopy;
845                 int nCols = 0;
846                 while (*p != '\0')
847                 {
848                                 if (*p == COLUMN_DELIMITER) 
849                                 {
850                                          nCols++;
851                                          *p = '\0';
852                                 }
853                                 p = _tcsinc(p);
854                 }
855                 if (*szHeadingsCopy)            
856                         nCols++;
857                 LPTSTR pszText = szHeadingsCopy;
858                 m_nSubItems = nCols; 
859                 for (int index = 0;index < nCols; index++)
860                 {
861                         lvC.iSubItem = index;
862                         lvC.pszText = pszText;
863 //                      lvC.cx = LVSCW_AUTOSIZE_USEHEADER;  
864                         lvC.cx = 100;  
865                         if (InsertColumn(index, &lvC) == -1) 
866                         {
867                                 TRACE(_T("InsertColumn failed\n"));
868                                 m_nSubItems--;
869                                 bFailed = TRUE;
870                         }
871                         while (*pszText)
872                                    pszText = _tcsinc(pszText);
873                         pszText = _tcsinc(pszText);     // Runs past the end of the buffer
874                 }
875                 // Add the columns.
876                 m_strHeadings = szHeadings;
877                 if (pszProfile)
878                 {
879                         SaveProfile();
880                         LoadProfile();
881                 }
882                 if (m_pColOrder)
883                 {
884                         SendMessage(LVM_SETCOLUMNORDERARRAY,(WPARAM)nCols,(LPARAM)m_pColOrder);
885                 }
886                 if (m_pColWidths)
887                 {
888                         for(int i=0;i < nCols;i++)
889                         {
890                                 if (m_pColWidths[i] != 0)
891                                         SetColumnWidth(i,m_pColWidths[i]);
892                         }
893                 }
894                 else
895                 {
896                         m_pColWidths = new int[nCols];
897                         for(int i=0;i < nCols;i++)
898                         {
899                                 m_pColWidths[i] = GetColumnWidth(i);
900                         }
901                 }
902                 if (m_pColTypes == NULL)
903                 {
904                         // set default column types
905                         m_pColTypes = new int[nCols];
906                         for(int i=0;i < nCols;i++)
907                         {
908                                 m_pColTypes[i] = e_Text;
909                         }                       
910                 }
911         }
912         SetSortHeader();
913         return m_nSubItems;
914 }
915
916 void CUIODListCtrl::GetImageLists(CImageList **pILSmall,CImageList **pILLarge)
917 {
918         *pILSmall = GetImageList(LVSIL_SMALL);
919         if (*pILSmall == NULL)
920         {
921                 CreateImageLists();
922                 *pILSmall = GetImageList(LVSIL_SMALL);
923         }
924         *pILLarge = GetImageList(LVSIL_NORMAL);
925         ASSERT(*pILSmall);
926         ASSERT(*pILLarge);
927 }
928
929 void CUIODListCtrl::CreateImageLists()
930 {
931         m_cxSmallIcon = ::GetSystemMetrics(SM_CXSMICON);
932         m_cySmallIcon = ::GetSystemMetrics(SM_CYSMICON);
933         m_cxLargeIcon = ::GetSystemMetrics(SM_CXICON);
934         m_cyLargeIcon = ::GetSystemMetrics(SM_CYICON);
935         if (m_ImageSmall.GetSafeHandle() != NULL)
936                 m_ImageSmall.DeleteImageList(); 
937         if (m_ImageLarge.GetSafeHandle() != NULL)
938                 m_ImageLarge.DeleteImageList(); 
939         // create the small icon image list     
940         m_ImageSmall.Create(m_cxSmallIcon,
941                                                 m_cySmallIcon,
942                                                 ILC_MASK | ILC_COLOR16, 
943                                                 1,
944                                                 1);     
945         // create the large icon image list     
946         m_ImageLarge.Create(m_cxLargeIcon,
947                                                 m_cyLargeIcon,
948                                                 ILC_MASK | ILC_COLOR16, 
949                                                 1,
950                                                 1);     
951         // Associate the image lists with the list view
952         SetImageList(&m_ImageSmall, LVSIL_SMALL);
953         SetImageList(&m_ImageLarge, LVSIL_NORMAL);
954 }
955
956 void CUIODListCtrl::AddExtraString(int nRow,LPCTSTR pszExtraText)
957 {
958         CUIStrListCtrlData *pData = (CUIStrListCtrlData *)GetListCtrlData(nRow);
959         ASSERT_KINDOF(CUIStrListCtrlData,pData);
960         pData->AddExtraString(pszExtraText);    
961 }
962
963 void CUIODListCtrl::ConvertToTime(CString &str)
964 {
965         int nPoint = str.Find(GetDecimalSep());
966         int nSecs=0;
967         if (nPoint == -1)
968                 nSecs = _ttoi(str);
969         else
970         {
971                 LPTSTR pszStop;
972                 double dSecs = _tcstod(str,&pszStop);
973                 nSecs = dSecs;
974         }
975         if (nSecs == 0)
976                 return;
977         int nMins = nSecs / 60;
978         nSecs = nSecs % 60;
979         str.Format(_T("%u:%u"),nMins,nSecs);
980 }
981
982 void CUIODListCtrl::AddThousandSeps(CString &str)
983 {
984         CString strTemp;
985         CString strExp;
986         CString strNeg;
987         int nDouble = str.Find(GetDecimalSep());
988         if (nDouble >= 0)
989         {
990                 strTemp = str.Left(nDouble);
991                 strExp = str.Right(str.GetLength()-nDouble);
992         }
993         else
994         {
995                 if (str.Find(GetNegativeSign()) == 0)
996                 {
997                         strNeg = str.Left(1);
998                         strTemp = str.Right(str.GetLength()-1);
999                 }
1000                 else
1001                         strTemp = str;
1002         }
1003         int len = strTemp.GetLength();
1004         if (len <= 3 || len > nMaxDigLen)
1005                 return;
1006         LPCTSTR pBuf = strTemp;
1007         pBuf += (len-1);
1008         TCHAR tempbuf[nMaxDigLen+1];
1009         LPTSTR pTempBuf = tempbuf;
1010         LPCTSTR pSep = GetThousandSep();
1011         for(int i=0;i < len;i++)
1012         {
1013                 if (i && ((i % 3) == 0)) 
1014                 {
1015                         if (*pTempBuf != *pSep)
1016                         {
1017                                 *pTempBuf =  *pSep;
1018                                 pTempBuf = _tcsinc(pTempBuf);
1019                         }
1020                 }
1021                 *pTempBuf = *pBuf;
1022                 pTempBuf = _tcsinc(pTempBuf);
1023                 pBuf = _tcsdec(strTemp,pBuf);
1024         }
1025         *pTempBuf = '\0';
1026         _tcsrev(tempbuf);
1027         str = strNeg;
1028         str += tempbuf;
1029         str += strExp;
1030 }
1031
1032 BOOL CUIODListCtrl::AddString(int nRow,int nCol,int nValue,CUIODListCtrl::eColTypes type)
1033 {
1034         CString sValue;
1035         sValue.Format(_T("%d"),nValue);
1036         return AddString(nRow,nCol,sValue,type);
1037 }
1038
1039 BOOL CUIODListCtrl::AddString(int nRow,int nCol,double dValue,CUIODListCtrl::eColTypes type)
1040 {
1041         char szBuf[nMaxDigLen];
1042         _gcvt(dValue,_MAX_INT_DIG,szBuf);
1043 #ifdef _UNICODE
1044 USES_CONVERSION;        
1045         return AddString(nRow,nCol,A2W(szBuf),type);
1046 #else   
1047         return AddString(nRow,nCol,szBuf,type);
1048 #endif  
1049 }
1050
1051 BOOL CUIODListCtrl::AddString(int nRow,int nCol,COleDateTime &dtValue,CUIODListCtrl::eColTypes type)
1052 {
1053         return AddString(nRow,nCol,dtValue.Format(),type);
1054 }
1055
1056 BOOL CUIODListCtrl::AddString(int nRow,int nCol,LPCTSTR szItem,CUIODListCtrl::eColTypes type)
1057 {
1058         if (m_nItems == 0) 
1059         {
1060                 TRACE(_T("No rows defined in ODListCtrl\n")); 
1061                 return FALSE;
1062         }
1063         if (nCol >= m_nSubItems) 
1064         {
1065                 TRACE(_T("Tried to add invalid column number(%d) in ODListCtrl\n"),nCol); 
1066                 return FALSE;
1067         }
1068         SetColType(nCol,type);
1069 //      return SetItemText(nRow,nCol/*+m_nImage*/,szItem);
1070         CUIStrListCtrlData *pData = (CUIStrListCtrlData *)GetListCtrlData(nRow);
1071         ASSERT_KINDOF(CUIStrListCtrlData,pData);
1072         BOOL ret=FALSE;
1073         if (type == e_NumericFormatComma || type == e_DoubleFormatComma)
1074         {
1075                 CString sBuf(szItem);
1076                 AddThousandSeps(sBuf);
1077                 ret = pData->AddString(nCol,sBuf);
1078         }
1079         else if (type == e_NumericFormatTime || type == e_DoubleFormatTime)
1080         {
1081                 CString sBuf(szItem);
1082                 ConvertToTime(sBuf);
1083                 ret = pData->AddString(nCol,sBuf);
1084         }
1085         else
1086                 ret = pData->AddString(nCol,szItem);
1087         return ret;
1088 }                                                 
1089
1090 void CUIODListCtrl::UpdateString(int nRow)
1091
1092         CRect rect;
1093         if (GetItemRect(nRow,&rect,LVIR_BOUNDS))
1094         {
1095                 RedrawItems(nRow,nRow);
1096                 UpdateWindow();
1097         }
1098 }
1099
1100 int CUIODListCtrl::AddCallBackItem(DWORD dwData,int nImage)
1101 {
1102         if (m_nSubItems == 0) 
1103         {
1104                 TRACE(_T("No columns defined in ODListCtrl\n")); 
1105                 return FALSE;
1106         }
1107         CUIListCtrlData *pListCtrlData = GetNewListCtrlData(dwData,m_nItems);
1108         BOOL ret = InsertItem(LPSTR_TEXTCALLBACK,(LPARAM)pListCtrlData,nImage);
1109         if (ret)
1110                 m_objList.Append(pListCtrlData);
1111         else
1112                 delete pListCtrlData;
1113         return ret ? m_nItems-1 : -1;
1114 }
1115
1116 int CUIODListCtrl::AddTextItem(int nImage)
1117 {
1118         CUIStrListCtrlData *pListCtrlData = new CUIStrListCtrlData(m_nSubItems);
1119         if (InsertItem(LPSTR_TEXTCALLBACK,(LPARAM)pListCtrlData,nImage))
1120         {
1121                 m_objList.Append(pListCtrlData);
1122                 return m_nItems-1;
1123         }
1124         delete pListCtrlData;
1125         return -1;
1126 }
1127
1128 int CUIODListCtrl::GetImageIndex(UINT nIconID)
1129 {
1130         int nImage = 0;
1131         if (nIconID)
1132         {
1133                 if (!m_mapImageIndex.Lookup(nIconID,nImage))
1134                 {
1135                         nImage = AddIcon(nIconID);
1136                 }
1137         }
1138         return nImage;
1139 }
1140
1141 // from handle
1142 int CUIODListCtrl::AddIcon(HICON hIcon,UINT nIconID)
1143 {
1144         CImageList *pILSmall = NULL;
1145         CImageList *pILLarge = NULL;
1146         GetImageLists(&pILSmall,&pILLarge);
1147         int nSmallIndex = pILSmall->Add(hIcon);
1148         // save the image ID
1149         if (nIconID)
1150                 m_mapImageIndex[nIconID] = nSmallIndex;
1151         int nLargeIndex = pILLarge->Add(hIcon); 
1152         if (nSmallIndex == -1 || nLargeIndex == -1)
1153         {
1154                 TRACE(_T("Failed to add icon to image list in CUIODListCtrl\n"));
1155                 return -1;
1156         }
1157         return nSmallIndex;
1158 }
1159
1160 // from resource id
1161 int CUIODListCtrl::AddIcon(UINT nIconID)
1162 {
1163         HICON hIcon = AfxGetApp()->LoadIcon(nIconID);
1164         if (hIcon == NULL)
1165         {
1166                 TRACE(_T("LoadIcon failed in CUIODListCtrl\n"));
1167                 return -1;
1168         }
1169         return AddIcon(hIcon,nIconID);
1170 }
1171
1172 // from file
1173 int CUIODListCtrl::AddIcon(LPCTSTR pszIcon)
1174 {
1175         CString sImageFile;
1176         int nIndex;
1177         if (m_mapImageFile.Lookup(sImageFile,nIndex))
1178         {
1179                 return nIndex;
1180         }
1181     HICON hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), 
1182             pszIcon,
1183             IMAGE_ICON,
1184             ::GetSystemMetrics(SM_CXICON),
1185             ::GetSystemMetrics(SM_CYICON),
1186             LR_LOADFROMFILE);
1187         if (hIcon == NULL)
1188         {
1189                 TRACE(_T("LoadImage(Large) failed in CUIODListCtrl\n"));
1190         }
1191     HICON hIconSm = (HICON)LoadImage(AfxGetInstanceHandle(), 
1192             pszIcon,
1193             IMAGE_ICON,
1194             ::GetSystemMetrics(SM_CXSMICON),
1195             ::GetSystemMetrics(SM_CYSMICON),
1196             LR_LOADFROMFILE);
1197         if (hIconSm == NULL)
1198         {
1199                 TRACE(_T("LoadImage(Small) failed in CUIODListCtrl\n"));
1200         }
1201         if (hIcon == NULL && hIconSm == NULL)
1202                 return -1;
1203         CImageList *pILSmall = NULL;
1204         CImageList *pILLarge = NULL;
1205         GetImageLists(&pILSmall,&pILLarge);
1206         int nSmallIndex = pILSmall->Add(hIconSm);
1207         int nLargeIndex = pILLarge->Add(hIcon); 
1208         if (nSmallIndex == -1 || nLargeIndex == -1)
1209         {
1210                 TRACE(_T("Failed to add icon to image list in CUIODListCtrl\n"));
1211                 return -1;
1212         }
1213         sImageFile = pszIcon;
1214         m_mapImageFile[sImageFile] = nSmallIndex;
1215         return nSmallIndex;
1216 }
1217
1218 BOOL CUIODListCtrl::InsertItem(LPTSTR szItem,LPARAM lParam,int nImage)
1219 {
1220         LV_ITEM lvi;
1221         lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
1222         lvi.state = 0;      
1223         lvi.stateMask = 0;  
1224
1225         lvi.iItem = m_nItems;
1226         lvi.iSubItem = 0;
1227         lvi.pszText = szItem; 
1228         lvi.cchTextMax = MAX_TEXT;
1229         lvi.iImage = nImage;
1230         lvi.lParam = lParam;
1231         if (CListCtrl::InsertItem(&lvi) == -1) 
1232         {
1233                 TRACE1("Unable to insert item %u into list control\n",m_nItems);
1234                 return FALSE;
1235         }
1236         if (nImage) 
1237                 m_nImage = 1;
1238         m_nItems++;
1239         return TRUE;
1240 }
1241
1242 int CUIODListCtrl::SetCurSel(int nSelect)
1243 {
1244         if (GetItemCount() && SetItemState(nSelect,LVIS_SELECTED | LVIS_FOCUSED,LVIS_SELECTED | LVIS_FOCUSED))
1245                 return TRUE;
1246         return -1;
1247 }
1248
1249 // messages
1250 LRESULT CUIODListCtrl::OnSetColumnWidth(WPARAM wParam,LPARAM lParam)
1251 {
1252         Default();
1253         return TRUE;
1254 }
1255
1256 LRESULT CUIODListCtrl::OnDeleteAllItems(WPARAM wParam,LPARAM lParam)
1257 {
1258         m_nItems=0;
1259         m_nImage=0;
1260         m_hOrigFont=NULL;
1261         AllItemsDeleted();
1262         m_objList.DeleteAll();
1263         TRACE0("All items deleted in CUIODListCtrl\n");
1264         Default();
1265         return TRUE;
1266 }
1267
1268 CUIListCtrlData *CUIODListCtrl::GetNewListCtrlData(DWORD dwData,int nItem)
1269 {
1270         CUIListCtrlData *pListCtrlData = new CUIListCtrlData(m_nSubItems);
1271         pListCtrlData->SetExtData(dwData); 
1272         return pListCtrlData;
1273 }
1274
1275 int CUIODListCtrl::FindItem(DWORD dwExtData)
1276 {
1277         int count = GetItemCount();
1278         CUIListCtrlData *pData;
1279         for(int i=0;i < count;i++) 
1280         {
1281                 pData = GetListCtrlData(i);
1282                 if (pData->GetExtData() == dwExtData)
1283                         break;
1284         }
1285         return i == count ? -1 : i;
1286 }
1287
1288 BOOL CUIODListCtrl::GetFullRowSel() const
1289 {
1290         return(m_bFullRowSel);
1291 }
1292
1293 DWORD CUIODListCtrl::GetExStyle() 
1294 {
1295         return SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE);
1296 }
1297
1298 BOOL CUIODListCtrl::SetExStyle(UINT nStyle,BOOL bModify)
1299 {
1300         DWORD dwStyle = GetExStyle();
1301         if (bModify)
1302                 dwStyle |= nStyle;
1303         else
1304                 dwStyle &= ~nStyle;
1305         BOOL bRet = SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
1306         if (bRet)
1307                 SaveProfile();
1308         return bRet;
1309 }
1310
1311 void CUIODListCtrl::SetFullRowSel(bool bSet)
1312 {
1313         // no painting during change
1314         if ((bSet && m_bFullRowSel==TRUE) || (!bSet && m_bFullRowSel==FALSE))
1315                 return;
1316         m_bFullRowSel=bSet;
1317         if(!(GetStyle() & LVS_OWNERDRAWFIXED)) 
1318         {
1319                 SetExStyle(LVS_EX_FULLROWSELECT,m_bFullRowSel);
1320         }
1321         RedrawItems(GetCurSel(),GetCurSel());
1322         SaveProfile();
1323 }
1324
1325 void CUIODListCtrl::SetIconSize(int nImageList)
1326 {
1327         m_nImageList = nImageList;
1328
1329         CRect rc;
1330         GetWindowRect(rc);
1331         GetParent()->ScreenToClient(rc);
1332         rc.bottom++; // Force a WM_MEASUREITEM message
1333         MoveWindow(rc,FALSE);
1334         rc.bottom--; // We really don't want to resize it
1335         MoveWindow(rc,TRUE);
1336 }
1337
1338 void CUIODListCtrl::ChangeIconSize()
1339 {
1340         SetCurSel(0);
1341         EnsureVisible(0,0);
1342         if (m_nImageList == LVSIL_NORMAL)
1343                 SetIconSize(LVSIL_SMALL);
1344         else
1345                 SetIconSize(LVSIL_NORMAL);
1346 }
1347
1348 BOOL CUIODListCtrl::GetDispInfo(LV_DISPINFO *pDispInfo)
1349 {
1350         CUIStrListCtrlData *pData = (CUIStrListCtrlData*)pDispInfo->item.lParam;
1351         ASSERT_KINDOF(CUIStrListCtrlData,pData);
1352         if (!pData->IsKindOf(RUNTIME_CLASS(CUIStrListCtrlData)))
1353                 return FALSE;
1354         pDispInfo->item.pszText = pData->GetString(pDispInfo->item.iSubItem);
1355         return TRUE;
1356 }
1357
1358 BOOL CUIODListCtrl::PopupMenuItem(int nItem,int nCol,CMenu *pPopup,CPoint point)
1359 {
1360         int nCurSel = GetCurSel();
1361         int nSel = GetNextSel(nCurSel);
1362         UINT nPopupID = (nSel == -1 ? m_PopupID : m_MultiPopupID);
1363         if (nPopupID && (nCol == 0 && nItem != -1))
1364         {
1365                 CMenu menu;
1366                 VERIFY(menu.LoadMenu(nPopupID));
1367                 CMenu* pMyPopup = menu.GetSubMenu(0);
1368                 ASSERT(pMyPopup != NULL);
1369                 if (m_pPopupWnd == NULL)
1370                         m_pPopupWnd = this;
1371                 pMyPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, m_pPopupWnd);
1372                 return TRUE;
1373         }
1374         return nSel == -1 ? FALSE : TRUE;
1375 }
1376
1377 int CUIODListCtrl::HitTestEx(CPoint &point, int *col) const
1378 {
1379         int colnum = 0;
1380         int row = HitTest( point, NULL );
1381         
1382         if( col ) *col = 0;
1383
1384         // Make sure that the ListView is in LVS_REPORT
1385         if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)
1386                 return row;
1387
1388         // Get the top and bottom row visible
1389         row = GetTopIndex();
1390         int bottom = row + GetCountPerPage();
1391         if( bottom > GetItemCount() )
1392                 bottom = GetItemCount();
1393         
1394         // Get the number of columns
1395         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
1396         int nColumnCount = pHeader->GetItemCount();
1397         CRect rcHeader;
1398         pHeader->GetClientRect(&rcHeader);
1399         if (point.y >= 0 && point.y <= rcHeader.Height())
1400                 return -2;
1401
1402         // Loop through the visible rows
1403         for( ;row <=bottom;row++)
1404         {
1405                 // Get bounding rect of item and check whether point falls in it.
1406                 CRect rect;
1407                 GetItemRect( row, &rect, LVIR_BOUNDS );
1408                 if( rect.PtInRect(point) )
1409                 {
1410                         // Now find the column
1411                         for( colnum = 0; colnum < nColumnCount; colnum++ )
1412                         {
1413                                 int colwidth = GetColumnWidth(colnum);
1414                                 if( point.x >= rect.left 
1415                                         && point.x <= (rect.left + colwidth ) )
1416                                 {
1417                                         if( col ) *col = colnum;
1418                                         return row;
1419                                 }
1420                                 rect.left += colwidth;
1421                         }
1422                 }
1423         }
1424         return -1;
1425 }
1426
1427 CEdit* CUIODListCtrl::EditSubLabel( int nItem, int nCol )
1428 {
1429         // The returned pointer should not be saved
1430         if (m_bEditSubItems == false || (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS) != LVS_EDITLABELS)
1431         {
1432                 return NULL;
1433         }
1434
1435         // Make sure that the item is visible
1436         if( !EnsureVisible( nItem, TRUE ) ) 
1437                 return NULL;
1438
1439         // Make sure that nCol is valid
1440         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
1441         if (pHeader == NULL)
1442                 return NULL;
1443         int nColumnCount = pHeader->GetItemCount();
1444         if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
1445                 return NULL;
1446
1447         // Get the column offset
1448         int offset = 0;
1449         for( int i = 0; i < nCol; i++ )
1450                 offset += GetColumnWidth( i );
1451
1452         CRect rect;
1453         GetItemRect( nItem, &rect, LVIR_BOUNDS );
1454
1455         // Now scroll if we need to expose the column
1456         CRect rcClient;
1457         GetClientRect( &rcClient );
1458         if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
1459         {
1460                 CSize size;
1461                 size.cx = offset + rect.left;
1462                 size.cy = 0;
1463                 Scroll( size );
1464                 rect.left -= size.cx;
1465         }
1466
1467         // Get Column alignment
1468         LV_COLUMN lvcol;
1469         lvcol.mask = LVCF_FMT;
1470         GetColumn( nCol, &lvcol );
1471         DWORD dwStyle ;
1472         if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
1473                 dwStyle = ES_LEFT;
1474         else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
1475                 dwStyle = ES_RIGHT;
1476         else dwStyle = ES_CENTER;
1477
1478         rect.left += offset+4;
1479         rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
1480         if( rect.right > rcClient.right) rect.right = rcClient.right;
1481
1482         dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
1483         CEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText( nItem, nCol ));
1484         pEdit->Create( dwStyle, rect, this, -1/*IDC_IPEDIT*/ );
1485
1486         return pEdit;
1487 }
1488
1489 void CUIODListCtrl::DeleteProgressBar(int nRow,int nCol)
1490 {
1491         CUIListCtrlData *pData = GetListCtrlData(nRow);
1492         if (pData)
1493         {
1494                 pData->DestroyCtrl(nCol);
1495                 RedrawItems(nRow,nRow);
1496         }
1497 }
1498
1499 void CUIODListCtrl::UpdateProgressBar(int nRow,int nCol,int nPos)
1500 {
1501         CUIListCtrlData *pData = GetListCtrlData(nRow);
1502         ASSERT(pData);
1503         if (pData == NULL)
1504                 return;
1505         CTextProgressCtrl *pCtrl = (CTextProgressCtrl*)pData->GetCtrl(nCol);
1506         if (pCtrl)
1507         {
1508                 pCtrl->SetPos(nPos);
1509                 RedrawItems(nRow,nRow);
1510         }
1511 }
1512
1513 CTextProgressCtrl *CUIODListCtrl::AddProgressBar(int nItem,int nCol,int nMin,int nMax)
1514 {
1515         // The returned pointer should not be saved
1516         if (GetViewType() != LVS_REPORT)
1517                 return NULL;
1518         CUIListCtrlData *pData = GetListCtrlData(nItem);
1519         if (pData == NULL)
1520                 return NULL;
1521         CTextProgressCtrl *pCtrl = new CTextProgressCtrl;
1522         pData->SetCtrl(pCtrl,nCol);
1523         pCtrl->SetRange(nMin,nMax);
1524         return pCtrl;
1525 }
1526
1527 //
1528 // Message handlers
1529 //
1530 void CUIODListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
1531 {
1532         if (GetFocus() != this) 
1533                 SetFocus();
1534         CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
1535 }
1536
1537 void CUIODListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
1538 {
1539         if (GetFocus() != this) 
1540                 SetFocus();
1541         CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
1542 }
1543
1544 void CUIODListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
1545 {
1546         CListCtrl::OnLButtonDown(nFlags, point);
1547 }
1548
1549 BOOL CUIODListCtrl::OnSelChanged(int nItem, LRESULT* pResult)
1550 {
1551         *pResult = 0;
1552         return FALSE;
1553 }
1554
1555 BOOL CUIODListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
1556 {
1557         LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
1558         LV_ITEM *plvItem = &plvDispInfo->item;
1559
1560         if (plvItem->pszText != NULL)
1561         {
1562                 if (plvItem->iItem == -1)
1563                 {
1564                         CHeaderCtrl *pHeader = (CHeaderCtrl*)GetDlgItem(0);
1565                         if (pHeader)
1566                         {
1567                                 CString strText;
1568                                 GetHeaderText(pHeader,plvItem->iSubItem,strText);
1569                                 HD_ITEM hdItem;
1570                                 ZeroMemory(&hdItem,sizeof(hdItem));
1571                                 hdItem.mask = HDI_TEXT;
1572                                 hdItem.pszText = plvItem->pszText;
1573                                 hdItem.cchTextMax = lstrlen(plvItem->pszText);
1574                                 ReplaceString(m_strHeadings,strText,plvItem->pszText);
1575                                 if (EndLabelEdit(plvItem->iItem,plvItem->iSubItem,plvItem->pszText))
1576                                         pHeader->SetItem(plvItem->iSubItem,&hdItem);
1577                         }
1578                 }
1579                 else
1580                 {
1581                         if (EndLabelEdit(plvItem->iItem,plvItem->iSubItem,plvItem->pszText))
1582                                 AddString(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
1583                 }
1584         }
1585         *pResult = FALSE;
1586         return TRUE;
1587 }
1588
1589 LRESULT CUIODListCtrl::OnDeleteItem(WPARAM wParam,LPARAM lParam)
1590 {
1591         if (m_nItems)
1592                 m_nItems--;
1593         TRACE(_T("Item deleted %d\n"),wParam);
1594         return Default();
1595 }
1596
1597 LRESULT CUIODListCtrl::OnDeleteColumn(WPARAM wParam,LPARAM lParam)
1598 {
1599         if (m_nSubItems)
1600                 m_nSubItems--;
1601         TRACE(_T("Column deleted %d\n"),wParam);
1602         return Default();
1603 }
1604
1605 LRESULT CUIODListCtrl::OnSetImageList(WPARAM wParam, LPARAM lParam)
1606 {
1607         if((int)wParam==LVSIL_STATE)
1608         {
1609                 int cx, cy;
1610
1611                 if(::ImageList_GetIconSize((HIMAGELIST)lParam,&cx,&cy))
1612                         m_cxStateImageOffset=cx;
1613                 else
1614                         m_cxStateImageOffset=0;
1615         }
1616
1617         return Default();
1618 }
1619
1620 LRESULT CUIODListCtrl::OnSetTextColor(WPARAM wParam, LPARAM lParam)
1621 {
1622         m_clrText=(COLORREF)lParam;
1623         return(Default());
1624 }
1625
1626 LRESULT CUIODListCtrl::OnSetTextBkColor(WPARAM wParam, LPARAM lParam)
1627 {
1628         m_clrTextBk=(COLORREF)lParam;
1629         return(Default());
1630 }
1631
1632 LRESULT CUIODListCtrl::OnSetBkColor(WPARAM wParam, LPARAM lParam)
1633 {
1634         m_clrBkgnd=(COLORREF)lParam;
1635         return(Default());
1636 }
1637
1638 void CUIODListCtrl::OnSize(UINT nType, int cx, int cy) 
1639 {
1640         m_cxClient=cx;
1641         CListCtrl::OnSize(nType, cx, cy);
1642 }
1643
1644 void CUIODListCtrl::OnPaint() 
1645 {
1646         if (m_bDelayPaint)
1647                 return;
1648         Default();
1649     if (GetItemCount() <= 0)
1650     {
1651         COLORREF clrText = ::GetSysColor(COLOR_WINDOWTEXT);
1652         COLORREF clrTextBk = ::GetSysColor(COLOR_WINDOW);
1653
1654         CDC* pDC = GetDC();
1655         // Save dc state
1656         int nSavedDC = pDC->SaveDC();
1657
1658         CRect rc;
1659         GetWindowRect(&rc);
1660         ScreenToClient(&rc);
1661
1662         CHeaderCtrl* pHC;
1663         pHC = GetHeaderCtrl();
1664         if (pHC != NULL)
1665         {
1666             CRect rcH;
1667             pHC->GetItemRect(0, &rcH);
1668             rc.top += rcH.bottom;
1669         }
1670         rc.top += 10;
1671
1672         pDC->SetTextColor(clrText);
1673         pDC->SetBkColor(clrTextBk);
1674         pDC->FillRect(rc, &CBrush(clrTextBk));
1675         pDC->SelectStockObject(ANSI_VAR_FONT);
1676         pDC->DrawText(m_strNoItemsMess, -1, rc, 
1677                       DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);
1678
1679         // Restore dc
1680         pDC->RestoreDC(nSavedDC);
1681         ReleaseDC(pDC);
1682     }
1683     // Do not call CListCtrl::OnPaint() for painting messages
1684         // in full row select mode, we need to extend the clipping region
1685         // so we can paint a selection all the way to the right
1686         if(m_bClientWidthSel && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT && GetFullRowSel() && (GetStyle() & LVS_OWNERDRAWFIXED))
1687         {
1688                 CRect rcAllLabels;
1689                 GetItemRect(0,rcAllLabels,LVIR_BOUNDS);
1690
1691                 if(rcAllLabels.right<m_cxClient)
1692                 {
1693                         // need to call BeginPaint (in CPaintDC c-tor)
1694                         // to get correct clipping rect
1695                         CPaintDC dc(this);
1696
1697                         CRect rcClip;
1698                         dc.GetClipBox(rcClip);
1699
1700                         rcClip.left=min(rcAllLabels.right-1,rcClip.left);
1701 //                      rcClip.right=m_cxClient;
1702
1703                         InvalidateRect(rcClip,FALSE);
1704                         // EndPaint will be called in CPaintDC d-tor
1705                 }
1706         }
1707
1708 //      CListCtrl::OnPaint();
1709 }
1710
1711 void CUIODListCtrl::OnSetFocus(CWnd* pOldWnd) 
1712 {
1713         CListCtrl::OnSetFocus(pOldWnd);
1714
1715         if(pOldWnd!=NULL && ::IsWindow(pOldWnd->m_hWnd))
1716         {
1717                 // check if we are getting focus from label edit box
1718                 if(pOldWnd!=NULL && pOldWnd->GetParent()==this)
1719                         return;
1720         }
1721 }
1722
1723 void CUIODListCtrl::OnKillFocus(CWnd* pNewWnd) 
1724 {
1725         CListCtrl::OnKillFocus(pNewWnd);
1726
1727         // check if we are losing focus to label edit box
1728         if (pNewWnd!=NULL && pNewWnd->GetParent()==this)
1729                 return;
1730 }
1731
1732 void CUIODListCtrl::OnRClickHeader(CPoint point,int nColIndex)
1733 {
1734         m_nColClicked = nColIndex;
1735         CMenu menu;
1736         VERIFY(menu.LoadMenu(IDR_POPUPMENU_HEADERCTRL));
1737         CMenu* pPopup = menu.GetSubMenu(0);
1738         ASSERT(pPopup != NULL);         
1739         pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);
1740 }
1741
1742 void CUIODListCtrl::OnHeaderRemoveColumn()
1743 {
1744         if (m_nColClicked != -1)
1745         {
1746                 int nWidth = GetColumnWidth(m_nColClicked);
1747                 if (nWidth)
1748                 {
1749                         m_pColWidths[m_nColClicked] = nWidth;
1750                         SetColumnWidth(m_nColClicked,0);
1751                 }
1752                 m_nColClicked = -1;
1753         }
1754 }
1755
1756 void CUIODListCtrl::OnHeaderEditText()
1757 {
1758         CHeaderCtrl *pHeader = (CHeaderCtrl*)GetDlgItem(0);
1759         if (pHeader == NULL)
1760                 return;
1761
1762         CString strText;
1763         int cxy = GetHeaderText(pHeader,m_nColClicked,strText);
1764         int xPos = 0;
1765         for(int i=0;i < m_nSubItems;i++)
1766         {
1767                 if (i == m_nColClicked)
1768                         break;
1769                 xPos += m_pColWidths[i];
1770         }
1771         CRect rect;
1772         rect.left = xPos;
1773         rect.right = rect.left+cxy;
1774         rect.top = 0;
1775         rect.bottom = GetSystemMetrics(SM_CXHSCROLL);
1776         TRACE2("Creating header edit control at left=%d,right=%d\n",rect.left,rect.right);
1777         DWORD dwStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
1778         CEdit *pEdit = new CInPlaceEdit(-1, m_nColClicked, strText);
1779         pEdit->Create( dwStyle, rect, this, -1/*IDC_IPEDIT*/ );
1780         m_nColClicked = -1;
1781 }
1782
1783 int CUIODListCtrl::GetHeaderText(CHeaderCtrl *pHeader,int nPos,CString &strText)
1784 {
1785         HD_ITEM hdItem;
1786         ZeroMemory(&hdItem,sizeof(hdItem));
1787         int nLen = 128;
1788         int nRes;
1789         do
1790         {
1791                 nLen *= 2;
1792                 hdItem.mask = HDI_TEXT | HDI_WIDTH;
1793                 hdItem.cchTextMax = nLen;
1794                 hdItem.pszText = strText.GetBufferSetLength(nLen);
1795                 pHeader->GetItem(nPos,&hdItem);
1796                 nRes = lstrlen(hdItem.pszText);
1797         } while (nRes == nLen-1);
1798         strText.ReleaseBuffer(-1);
1799         return hdItem.cxy;
1800 }
1801
1802 void CUIODListCtrl::OnHeaderReset()
1803 {
1804         for(int i=0;i < m_nSubItems;i++)
1805         {
1806                 SetColumnWidth(i,m_pColWidths[i]);
1807         }
1808         m_nColClicked = -1;
1809 }
1810
1811 void CUIODListCtrl::OnContextMenu(CWnd *pWnd,CPoint point)      
1812 {
1813         CPoint ptClient(point);
1814         ScreenToClient(&ptClient);      
1815         int nCol;
1816         int nRow = HitTestEx(ptClient,&nCol);
1817         if (nRow == -2)
1818                 return;
1819         ShowPopupMenu(nRow,nCol,point);
1820 }
1821
1822 void CUIODListCtrl::ShowPopupMenu(int nRow,int nCol,CPoint point)
1823 {
1824         CMenu menu;
1825         VERIFY(menu.LoadMenu(IDR_POPUPMENU_LISTCTRL));
1826         CMenu* pPopup = menu.GetSubMenu(0);
1827         ASSERT(pPopup != NULL);
1828         m_PopupPoint.x = 0;
1829         m_PopupPoint.y = 0;
1830         if (PopupMenuItem(nRow,nCol,pPopup,point))
1831                 return;
1832         m_PopupPoint = point;
1833         pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);
1834 }
1835
1836 void CUIODListCtrl::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
1837 {
1838         // is it for us?
1839         if (m_PopupPoint.x == 0 && m_PopupPoint.y == 0)
1840                 return;
1841         if (pPopupMenu->GetMenuItemID(0) == ID_HEADER_REMOVE_COL)
1842         {
1843                 if (m_nColClicked == -1)
1844                 {
1845                         pPopupMenu->EnableMenuItem(ID_HEADER_EDIT_TEXT,MF_BYCOMMAND | MF_GRAYED);
1846                         pPopupMenu->EnableMenuItem(ID_HEADER_RESET,MF_BYCOMMAND | MF_GRAYED);
1847                 }
1848                 return;
1849         }
1850         // These commands are only available in report mode(detail mode)
1851         UINT nEnabled = (GetViewType() == LVS_REPORT) ? MF_ENABLED : MF_GRAYED; 
1852         pPopupMenu->EnableMenuItem(ID_UI_VIEW_FULL_ROW_SELECTION,MF_BYCOMMAND | nEnabled);
1853         pPopupMenu->EnableMenuItem(ID_UI_VIEW_GRIDLINES,MF_BYCOMMAND | nEnabled);
1854         pPopupMenu->EnableMenuItem(ID_UI_VIEW_COLUMN_SIZING,MF_BYCOMMAND | nEnabled);
1855         pPopupMenu->EnableMenuItem(ID_UI_VIEW_COLUMN_ORDERING,MF_BYCOMMAND | nEnabled);
1856         if (nEnabled == MF_ENABLED)
1857                 pPopupMenu->EnableMenuItem(ID_UI_VIEW_EDIT_COLUMN,MF_BYCOMMAND | (m_bEditSubItems && (GetStyle() & LVS_EDITLABELS)) ? MF_ENABLED : MF_GRAYED);
1858         else
1859                 pPopupMenu->EnableMenuItem(ID_UI_VIEW_EDIT_COLUMN,MF_BYCOMMAND | MF_GRAYED);
1860         // won't work with owner draw list control
1861         if (GetStyle() & LVS_OWNERDRAWFIXED)
1862         {
1863                 pPopupMenu->EnableMenuItem(ID_UI_VIEW_CHECKBOXES,MF_BYCOMMAND | MF_GRAYED);
1864         }
1865         UINT nIDItem=ID_VIEW_DETAILS;
1866         switch(GetViewType())
1867         {
1868         case LVS_ICON:
1869                         nIDItem = ID_UI_VIEW_LARGE_ICONS;
1870                         break;
1871         case LVS_SMALLICON:
1872                         nIDItem = ID_UI_VIEW_SMALL_ICONS;
1873                         break;
1874         case LVS_LIST:
1875                         nIDItem = ID_UI_VIEW_LIST;
1876                         break;
1877         case LVS_REPORT:
1878                         nIDItem = ID_UI_VIEW_DETAILS;
1879                         break;
1880         }
1881         pPopupMenu->CheckMenuRadioItem(ID_UI_VIEW_LARGE_ICONS,ID_VIEW_LIST,nIDItem,MF_BYCOMMAND);
1882         DWORD dwExStyle = GetExStyle();
1883         if (m_bFullRowSel)
1884                 pPopupMenu->CheckMenuItem(ID_UI_VIEW_FULL_ROW_SELECTION,MF_BYCOMMAND | MF_CHECKED);
1885         if (m_bColumnSizing)
1886                 pPopupMenu->CheckMenuItem(ID_UI_VIEW_COLUMN_SIZING,MF_BYCOMMAND | MF_CHECKED);
1887         if ((dwExStyle & LVS_EX_HEADERDRAGDROP))
1888                 pPopupMenu->CheckMenuItem(ID_UI_VIEW_COLUMN_ORDERING,MF_BYCOMMAND | MF_CHECKED);
1889         if ((dwExStyle & LVS_EX_GRIDLINES))
1890                 pPopupMenu->CheckMenuItem(ID_UI_VIEW_GRIDLINES,MF_BYCOMMAND | MF_CHECKED);
1891         if ((dwExStyle & LVS_EX_CHECKBOXES))
1892                 pPopupMenu->CheckMenuItem(ID_UI_VIEW_CHECKBOXES,MF_BYCOMMAND | MF_CHECKED);
1893         if ((dwExStyle & LVS_EX_TRACKSELECT))
1894                 pPopupMenu->CheckMenuItem(ID_UI_VIEW_TRACK_SELECT,MF_BYCOMMAND | MF_CHECKED);
1895 }
1896
1897 void CUIODListCtrl::OnViewLargeIcons()
1898 {
1899         SetViewType(LVS_ICON);
1900 }
1901
1902 void CUIODListCtrl::OnViewSmallIcons()
1903 {
1904         SetViewType(LVS_SMALLICON);
1905 }
1906
1907 void CUIODListCtrl::OnViewDetails()
1908 {
1909         SetViewType(LVS_REPORT);
1910 }
1911
1912 void CUIODListCtrl::OnViewList()
1913 {
1914         SetViewType(LVS_LIST);
1915 }
1916
1917 void CUIODListCtrl::OnViewFullRowSelection()
1918 {
1919         ToggleFullRowSel();
1920 }
1921
1922 void CUIODListCtrl::OnViewTrackSelect()
1923 {
1924         ToggleTrackSelect();
1925 }
1926
1927 void CUIODListCtrl::OnViewGridlines()
1928 {
1929         ToggleGridLines();
1930 }
1931
1932 void CUIODListCtrl::OnViewCheckboxes()
1933 {
1934         ToggleCheckBoxes();
1935 }
1936
1937 void CUIODListCtrl::OnViewColumnOrdering()
1938 {
1939         ToggleHeaderDragDrop();
1940 }
1941
1942 void CUIODListCtrl::OnViewColumnSizing()
1943 {
1944         ToggleColumnSizing();
1945 }
1946
1947 void CUIODListCtrl::OnViewEditColumn()
1948 {
1949         int index;
1950         int colnum;
1951         CPoint point(m_PopupPoint);
1952         ScreenToClient(&point);
1953         if (( index = HitTestEx( point, &colnum )) != -1)
1954         {
1955                 UINT flag = LVIS_FOCUSED;
1956                 if( (GetItemState( index, flag ) & flag) == flag && colnum > 0)
1957                 {
1958                         // Add check for LVS_EDITLABELS
1959                         EditSubLabel( index, colnum );
1960                 }
1961         }
1962 }
1963
1964 LRESULT CUIODListCtrl::OnGetItemText(WPARAM wParam, LPARAM lParam)
1965 {
1966         int iItem = (int)wParam; 
1967         LV_ITEM *pitem = (LV_ITEM*)lParam;
1968         int nSubItem = pitem->iSubItem;
1969         int nLen = pitem->cchTextMax;
1970         const CUIStrListCtrlData *pData = (CUIStrListCtrlData *)GetListCtrlData(iItem);
1971 //      ASSERT_KINDOF(CUIStrListCtrlData,pData);
1972         if (!pData->IsKindOf(RUNTIME_CLASS(CUIStrListCtrlData)))
1973         {
1974                 NMLVDISPINFO di;
1975                 di.hdr.hwndFrom = GetSafeHwnd();
1976                 di.hdr.code = LVN_GETDISPINFO;
1977                 memcpy(&di.item,pitem,sizeof(LVITEM));
1978                 di.item.mask = LVIF_TEXT;
1979 #if 1 // bugfix by Rex Lee
1980                 di.item.iItem = iItem;
1981 #endif
1982                 SendMessage(WM_NOTIFY,0,(LPARAM)&di);
1983                 _tcsncpy(pitem->pszText,di.item.pszText,nLen);
1984         }
1985         else
1986         {
1987                 LPTSTR pStr = ((CUIStrListCtrlData *)pData)->GetString(nSubItem);
1988                 if (pStr)
1989                 {
1990                         _tcsncpy(pitem->pszText,pStr,nLen);
1991                         nLen = min(lstrlen(pStr)+1,nLen);
1992                         pitem->pszText[nLen-1] = '\0';
1993                         return nLen;
1994                 }
1995         }
1996         return 0L;
1997 }
1998
1999 int CUIODListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
2000 {
2001         if (CListCtrl::OnCreate(lpCreateStruct) == -1)
2002                 return -1;
2003         
2004         // TODO: Add your specialized creation code here
2005         RegisterDropTarget();
2006         
2007         return 0;
2008 }
2009
2010 int CALLBACK CompareFunc(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort);
2011
2012 PFNLVCOMPARE CUIODListCtrl::GetCompareFunc()
2013 {
2014         return CompareFunc;
2015 }
2016
2017 BOOL CUIODListCtrl::ColumnClick(NM_LISTVIEW* pNMListView)
2018 {
2019         if (pNMListView->iSubItem != m_nSortColumn)
2020                 m_bSortAscending = TRUE;
2021         else
2022                 m_bSortAscending = !m_bSortAscending;
2023         m_nSortColumn = pNMListView->iSubItem;
2024
2025         m_HeaderCtrl.SetSortImage(m_nSortColumn,m_bSortAscending);
2026         ASSERT(m_pColTypes);
2027         CUIODListCtrlSortInfo sortinfo(pNMListView->iSubItem,m_pColTypes[pNMListView->iSubItem],m_bSortAscending);
2028         SortItems(GetCompareFunc(),(DWORD)&sortinfo);
2029         int item = GetCurSel();
2030         EnsureVisible(item,0);
2031         return TRUE;
2032 }
2033
2034 ///////////////////////////////////////////////
2035 // static callback for sorting when the header is clicked in report mode
2036 int CALLBACK CompareFunc(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort)
2037 {
2038         CUIStrListCtrlData *pData1 = (CUIStrListCtrlData*)lParam1;
2039         CUIStrListCtrlData *pData2 = (CUIStrListCtrlData*)lParam2;
2040         ASSERT(pData1);
2041         ASSERT(pData2);
2042         ASSERT_KINDOF(CUIStrListCtrlData,pData1);
2043         ASSERT_KINDOF(CUIStrListCtrlData,pData2);
2044         CUIODListCtrlSortInfo *pSortInfo = (CUIODListCtrlSortInfo *)lParamSort;
2045         int ret=0;
2046         switch(pSortInfo->GetColType())
2047         {
2048                 case CUIODListCtrl::e_DateTime:
2049                         {
2050                                 COleDateTime time1;
2051                                 CString str1(pData1->GetString(pSortInfo->GetColumn()));
2052                                 if (!str1.IsEmpty())
2053                                         time1.ParseDateTime(str1);
2054                                 COleDateTime time2;
2055                                 CString str2(pData2->GetString(pSortInfo->GetColumn()));
2056                                 if (!str2.IsEmpty())
2057                                         time2.ParseDateTime(str2);
2058                                 if (time1 > time2)
2059                                         ret = 1;
2060                                 else if (time1 < time2)
2061                                         ret = -1;
2062                                 break;
2063                         }
2064                 case CUIODListCtrl::e_NumericFormat:
2065                         {
2066                                 int num1 = _ttoi(CUIODListCtrl::StripNonNumeric((LPCTSTR)pData1->GetString(pSortInfo->GetColumn()),CUIODListCtrl::e_Numeric));
2067                                 int num2 = _ttoi(CUIODListCtrl::StripNonNumeric((LPCTSTR)pData2->GetString(pSortInfo->GetColumn()),CUIODListCtrl::e_Numeric));
2068                                 ret = num1-num2;
2069                                 break;
2070                         }
2071                 case CUIODListCtrl::e_Numeric:
2072                         {
2073                                 int num1 = _ttoi((LPCTSTR)pData1->GetString(pSortInfo->GetColumn()));
2074                                 int num2 = _ttoi((LPCTSTR)pData2->GetString(pSortInfo->GetColumn()));
2075                                 ret = num1-num2;
2076                                 break;
2077                         }
2078                 case CUIODListCtrl::e_DoubleFormat:
2079                         {
2080                                 double num1 = _tcstod(CUIODListCtrl::StripNonNumeric((LPCTSTR)pData1->GetString(pSortInfo->GetColumn()),CUIODListCtrl::e_Double),NULL);
2081                                 double num2 = _tcstod(CUIODListCtrl::StripNonNumeric((LPCTSTR)pData2->GetString(pSortInfo->GetColumn()),CUIODListCtrl::e_Double),NULL);
2082                                 if (num1 > num2)
2083                                         ret = 1;
2084                                 else if (num1 < num2)
2085                                         ret = -1;
2086                                 break;
2087                         }
2088                 case CUIODListCtrl::e_Double:
2089                         {
2090                                 double num1 = _tcstod((LPCTSTR)pData1->GetString(pSortInfo->GetColumn()),NULL);
2091                                 double num2 = _tcstod((LPCTSTR)pData2->GetString(pSortInfo->GetColumn()),NULL);
2092                                 if (num1 > num2)
2093                                         ret = 1;
2094                                 else if (num1 < num2)
2095                                         ret = -1;
2096                                 break;
2097                         }
2098                 case CUIODListCtrl::e_Text:
2099                 default:
2100                         ret = CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE | NORM_IGNOREKANATYPE,
2101                                                         (LPCTSTR)pData1->GetString(pSortInfo->GetColumn()),
2102                                                         pData1->GetStringLen(pSortInfo->GetColumn()),
2103                                                         (LPCTSTR)pData2->GetString(pSortInfo->GetColumn()),
2104                                                         pData2->GetStringLen(pSortInfo->GetColumn())) - 2;
2105                         break;
2106         }
2107         if (!pSortInfo->Ascending())
2108                 ret = -ret;
2109         return ret;
2110 }
2111
2112 void CUIODListCtrl::ReplaceString(CString &rStr,LPCTSTR pszOldText,LPCTSTR pszNewText)
2113 {
2114         int nPos = rStr.Find(pszOldText);
2115         CString strLeft;
2116         if (nPos != -1)
2117         {
2118                 strLeft = rStr.Left(nPos);
2119                 CString strRight(rStr.Right(rStr.GetLength()-(nPos+lstrlen(pszOldText))));
2120                 strLeft += pszNewText;
2121                 strLeft += strRight;
2122         }
2123         rStr = strLeft;
2124 }
2125
2126 void CUIODListCtrl::Sort()
2127 {
2128         ASSERT(m_pColTypes);
2129         CUIODListCtrlSortInfo sortinfo(m_nSortColumn,m_pColTypes[m_nSortColumn],m_bSortAscending);
2130         SortItems(GetCompareFunc(),(DWORD)&sortinfo);
2131         m_HeaderCtrl.SetSortImage(m_nSortColumn,m_bSortAscending);
2132         TRACE1("Sorting column %d\n",m_nSortColumn);
2133 }
2134
2135 void CUIODListCtrl::SetColFont(int nRow,int nCol,CFont *pFont)
2136 {
2137         CUIListCtrlData* pListObj = GetListCtrlData(nRow);
2138         if (pListObj)
2139         {
2140                 ASSERT(pFont);
2141                 if (pFont)
2142                         pListObj->SetFont(pFont,nCol);
2143         }
2144 }
2145
2146 void CUIODListCtrl::SetRowFont(int nRow,CFont *pFont)
2147 {
2148         CUIListCtrlData* pListObj = GetListCtrlData(nRow);
2149         if (pListObj)
2150         {
2151                 ASSERT(pFont);
2152                 if (pFont)
2153                         pListObj->SetFont(pFont);
2154         }
2155 }
2156
2157 void CUIODListCtrl::SetColBold(int nRow,int nCol,BOOL bBold)
2158 {
2159         CUIListCtrlData* pListObj = GetListCtrlData(nRow);
2160         if (pListObj)
2161         {
2162                 if (!pListObj->IsFontSet(nCol))
2163                 {
2164                         pListObj->SetFont(GetFont(),nCol);
2165                 }
2166                 const CFont *pFont = pListObj->GetFont(nCol);
2167                 LOGFONT lf;
2168                 ((CFont*)pFont)->GetLogFont(&lf);
2169                 lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL; 
2170                 CFont font;
2171                 font.CreateFontIndirect(&lf);
2172                 pListObj->SetFont(&font,nCol);
2173                 CRect rect;
2174                 RedrawItems(nRow,nRow);
2175                 UpdateWindow();
2176         }       
2177 }
2178
2179 void CUIODListCtrl::SetRowBold(int nRow,BOOL bBold)
2180 {
2181         CUIListCtrlData* pListObj = GetListCtrlData(nRow);
2182         if (pListObj)
2183         {
2184                 if (!pListObj->IsFontSet(-1))
2185                 {
2186                         pListObj->SetFont(GetFont());
2187                 }
2188                 const CFont *pFont = pListObj->GetFont();
2189                 LOGFONT lf;
2190                 ((CFont*)pFont)->GetLogFont(&lf);
2191                 lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL; 
2192                 CFont font;
2193                 font.CreateFontIndirect(&lf);
2194                 pListObj->SetFont(&font);
2195                 CRect rect;
2196                 RedrawItems(nRow,nRow);
2197                 UpdateWindow();
2198         }       
2199 }
2200
2201 BOOL CUIODListCtrl::SubItemPostPaint(LPNMLVCUSTOMDRAW lplvcd,LRESULT *pResult)
2202 {
2203         if (m_hOrigFont)
2204         {
2205                 CDC *pDC = CDC::FromHandle(lplvcd->nmcd.hdc);
2206                 pDC->SelectObject(CFont::FromHandle(m_hOrigFont));
2207                 m_hOrigFont = NULL;
2208         }
2209         return TRUE;
2210 }
2211
2212 BOOL CUIODListCtrl::SubItemPrePaint(LPNMLVCUSTOMDRAW lplvcd,LRESULT *pResult)
2213 {
2214         *pResult = CDRF_DODEFAULT;
2215         int nRow = lplvcd->nmcd.dwItemSpec;
2216         int nCol = lplvcd->iSubItem;
2217         CUIListCtrlData* pListObj = GetListCtrlData(nRow);
2218         if (pListObj == NULL)
2219                 return FALSE;
2220         *pResult = CDRF_NOTIFYPOSTPAINT;
2221         lplvcd->clrText = pListObj->GetTextColor(nCol);
2222         lplvcd->clrTextBk = pListObj->GetBkColor(nCol);
2223         if (pListObj->IsFontSet(nCol))
2224         {
2225                 CDC *pDC = CDC::FromHandle(lplvcd->nmcd.hdc);
2226                 CFont *pOldFont = pDC->SelectObject((CFont*)pListObj->GetFont(nCol));
2227                 m_hOrigFont = (HFONT)pOldFont;
2228                 *pResult |= CDRF_NEWFONT;
2229         }
2230         CTextProgressCtrl *pWnd = (CTextProgressCtrl*)pListObj->GetCtrl(nCol);
2231         if (pWnd == NULL)
2232                 return TRUE;
2233         CRect rcItem;
2234         GetItemRect(nRow,rcItem,LVIR_LABEL);
2235         rcItem.left = lplvcd->nmcd.rc.left;
2236         rcItem.right = lplvcd->nmcd.rc.right;
2237         CDC *pDC = CDC::FromHandle(lplvcd->nmcd.hdc);
2238         pWnd->DoPaint(pDC,rcItem,GetItemState(nRow,LVIS_SELECTED) == LVIS_SELECTED);
2239         *pResult = CDRF_SKIPDEFAULT;
2240         return TRUE;
2241 }
2242
2243 BOOL CUIODListCtrl::ItemPrePaint(LPNMLVCUSTOMDRAW lplvcd,LRESULT *pResult)
2244 {
2245     *pResult = CDRF_NOTIFYSUBITEMDRAW;
2246         return TRUE;
2247 }
2248
2249 BOOL CUIODListCtrl::ItemPostPaint(LPNMLVCUSTOMDRAW lplvcd,LRESULT *pResult)
2250 {
2251         *pResult = CDRF_DODEFAULT;
2252         return TRUE;
2253 }
2254
2255 ///////////////////////////////////////////////
2256 // Persistence
2257 ///////////////////////////////////////////////
2258 void CUIODListCtrl::SetSection(LPCTSTR pszSection) 
2259 {
2260         if (pszSection == NULL)
2261                 m_strSection.Empty();
2262         else
2263         {
2264                 SaveProfile();
2265                 m_strSection = _T("UIODListControl\\");
2266                 m_strSection += pszSection;
2267         }
2268 }
2269
2270 LPCTSTR CUIODListCtrl::GetSection() const
2271 {
2272         return m_strSection;
2273 }
2274
2275 void CUIODListCtrl::LoadProfile() 
2276 {
2277         if (m_strSection.IsEmpty())
2278                 return;
2279         CWinApp *pApp = AfxGetApp();
2280         if (pApp == NULL)
2281                 return; 
2282         LPCTSTR pszSection = GetSection();
2283
2284         m_strHeadings = pApp->GetProfileString(pszSection,szEntryHeadings);
2285         m_dwExStyle = pApp->GetProfileInt(pszSection,szEntryStyle,m_dwExStyle);
2286         m_bFullRowSel = pApp->GetProfileInt(pszSection,szEntryRowSel,m_bFullRowSel);
2287         m_dwViewType = pApp->GetProfileInt(pszSection,szEntryViewType,m_dwViewType);
2288         m_bColumnSizing = pApp->GetProfileInt(pszSection,szEntryColumnSizing,m_bColumnSizing);
2289         m_nSortColumn = pApp->GetProfileInt(pszSection,szEntrySortColumn,m_nSortColumn);
2290         int nSubItems = pApp->GetProfileInt(pszSection,szEntrySubItems,0);
2291         if (nSubItems)
2292         {
2293                 delete []m_pColOrder;
2294                 delete []m_pColWidths;
2295                 m_pColOrder = new int[nSubItems];
2296                 m_pColWidths = new int[nSubItems];
2297                 CString strEntry;
2298                 for(int i=0;i < nSubItems;i++)
2299                 {
2300                         strEntry.Format(_T("%s%d"),szEntryColOrder,i+1);
2301                         m_pColOrder[i] = pApp->GetProfileInt(pszSection,strEntry,0);
2302                         strEntry.Format(_T("%s%d"),szEntryColWidths,i+1);
2303                         m_pColWidths[i] = pApp->GetProfileInt(pszSection,strEntry,0);
2304                 }
2305         }
2306 }
2307
2308 void CUIODListCtrl::SaveProfile()
2309 {
2310         if (m_strSection.IsEmpty())
2311                 return;
2312         CWinApp *pApp = AfxGetApp();
2313         if (pApp == NULL)
2314                 return;         
2315         LPCTSTR pszSection = GetSection();
2316
2317         pApp->WriteProfileString(pszSection,szEntryHeadings,m_strHeadings);
2318         pApp->WriteProfileInt(pszSection,szEntryStyle,SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE));
2319         pApp->WriteProfileInt(pszSection,szEntryRowSel,m_bFullRowSel);
2320         pApp->WriteProfileInt(pszSection,szEntryViewType,GetViewType());
2321         pApp->WriteProfileInt(pszSection,szEntryColumnSizing,m_bColumnSizing);
2322         pApp->WriteProfileInt(pszSection,szEntrySubItems,m_nSubItems);
2323         pApp->WriteProfileInt(pszSection,szEntrySortColumn,m_nSortColumn);
2324         if (m_nSubItems)
2325         {
2326                 delete []m_pColOrder;
2327                 m_pColOrder = new int[m_nSubItems],0;
2328                 SendMessage(LVM_GETCOLUMNORDERARRAY,(WPARAM)m_nSubItems,(LPARAM)m_pColOrder);
2329                 CString strEntry;
2330                 for(int i=0;i < m_nSubItems;i++)
2331                 {
2332                         strEntry.Format(_T("%s%d"),szEntryColOrder,i+1);
2333                         pApp->WriteProfileInt(pszSection,strEntry,m_pColOrder[i]);
2334                         if (m_pColWidths)
2335                         {
2336                                 strEntry.Format(_T("%s%d"),szEntryColWidths,i+1);
2337                                 pApp->WriteProfileInt(pszSection,strEntry,m_pColWidths[i]);
2338                         }
2339                 }
2340         }
2341 }
2342
2343 void CUIODListCtrl::Serialize(CArchive& ar)
2344 {
2345         if (ar.IsStoring())
2346         {
2347                 ar << m_strHeadings;
2348                 ar << m_nSubItems;
2349                 m_pColOrder = new int[m_nSubItems];
2350                 SendMessage(LVM_GETCOLUMNORDERARRAY,(WPARAM)m_nSubItems,(LPARAM)m_pColOrder);
2351                 for(int i=0;i < m_nSubItems;i++)
2352                 {
2353                         ar << (int)m_pColOrder[i];
2354                         ar << (int)GetColumnWidth(i);
2355                 }
2356                 delete []m_pColOrder;
2357                 m_pColOrder = NULL;
2358                 ar << SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE);
2359                 ar << m_dwViewType;
2360                 ar << m_bFullRowSel;
2361                 ar << m_bColumnSizing;
2362         }
2363         else
2364         {
2365                 ar >> m_strHeadings;
2366                 ar >> m_nSubItems;
2367                 delete []m_pColOrder;
2368                 delete []m_pColWidths;
2369                 m_pColOrder = new int[m_nSubItems];
2370                 m_pColWidths = new int[m_nSubItems];
2371                 for(int i=0;i < m_nSubItems;i++)
2372                 {
2373                         ar >> (int)m_pColOrder[i];
2374                         ar >> (int)m_pColWidths[i];
2375                 }
2376                 ar >> m_dwExStyle;
2377                 ar >> m_bFullRowSel;
2378                 ar >> m_dwViewType;
2379                 ar >> m_bColumnSizing;
2380         }
2381 }
2382 /////////////////////////////////////////////////////////////////
2383 // OLE drag and drop
2384 /////////////////////////////////////////////////////////////////
2385
2386 /////////////////////////////////////////////////////////////////////////////
2387
2388 // CUIODListCtrl message handlers
2389 #include "UIDragImage.h"
2390
2391 BOOL CUIODListCtrl::OnBeginRDrag(NMHDR* pNMHDR, LRESULT* pResult) 
2392 {
2393         NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
2394         // TODO: Add your control notification handler code here
2395         *pResult = 0;   
2396         DoOleDrag(pNMListView,true);
2397         return TRUE;
2398 }
2399
2400 BOOL CUIODListCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
2401 {
2402         NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
2403         // TODO: Add your control notification handler code here
2404         *pResult = 0;   
2405         DoOleDrag(pNMListView,false);
2406         return TRUE;
2407 }
2408
2409 void CUIODListCtrl::DoOleDrag(NM_LISTVIEW* pNMListView,bool bRightMenu)
2410 {
2411         int nSelected = GetSelectedCount();
2412         if (nSelected == 0 || pNMListView->iItem == -1)
2413                 return;
2414         BOOL bRet=TRUE;
2415         if (bRet == FALSE)
2416                 return;
2417         // View type LVS_ICON etc
2418         int nType = GetViewType();
2419         // 2 ints(nSelected,nType) + ImageData + CRect 
2420     HANDLE hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,sizeof(int)*2+sizeof(DD_ImageData)*nSelected+sizeof(CRect));
2421     int *pData = (int*)::GlobalLock(hData);
2422         *pData++ = nType;
2423         *pData++ = nSelected;
2424         // add the selections
2425     DD_ImageData *pImageData = (DD_ImageData*)pData;
2426         CRect rcItem;
2427         CRect rcIcon;
2428         CRect rcTotalItem;
2429         int iItem = pNMListView->iItem;
2430         GetItemRect(iItem,rcItem,LVIR_LABEL); 
2431         GetItemRect(iItem,rcIcon,LVIR_ICON);
2432         rcTotalItem.left = rcIcon.left;
2433         rcTotalItem.top = rcIcon.top;
2434         rcTotalItem.right = rcIcon.right+rcItem.right;
2435         rcTotalItem.bottom = 0;
2436         CPoint point(pNMListView->ptAction);
2437         CPoint ptHitTest;
2438         UINT flag=0;
2439         iItem = GetNextSel(-1);
2440         int *pRows = new int[nSelected+1];
2441         pRows[0] = iItem;
2442         for(int i=1;iItem != -1;i++)
2443         {
2444                 GetItemRect(iItem,rcItem,LVIR_LABEL); 
2445                 GetItemRect(iItem,rcIcon,LVIR_ICON); 
2446                 ptHitTest.x = rcItem.left;
2447                 ptHitTest.y = rcItem.top;
2448                 HitTest(ptHitTest,&flag);
2449                 if ((flag & LVHT_BELOW) != LVHT_BELOW && (flag & LVHT_ABOVE) != LVHT_ABOVE)
2450                 {
2451                         pImageData->m_rcItem = rcItem;
2452                         pImageData->m_rcIcon = rcIcon;
2453                         pImageData->m_ptDrag = point;
2454                         rcTotalItem.bottom += rcIcon.bottom;
2455                         pImageData++;
2456                 }
2457                 CCF_String ccfText(GetItemText(iItem,0));
2458                 CWDClipboardData::Instance()->SetData(&m_OleDataSource,&ccfText,CWDClipboardData::e_cfString);
2459                 iItem = GetNextSel(iItem);
2460                 pRows[i] = iItem;
2461         }
2462         pData = (int*)pImageData;
2463         *pData++ = rcTotalItem.left;
2464         *pData++ = rcTotalItem.right;
2465         *pData++ = rcTotalItem.top;
2466         *pData = rcTotalItem.bottom;
2467     ::GlobalUnlock (hData);
2468     m_OleDataSource.CacheGlobalData(m_OleDropTarget.GetClipboardFormat(), hData);
2469         CCF_RightMenu rm;
2470         rm.SetRightDrag(bRightMenu);
2471         CWDClipboardData::Instance()->SetData(&m_OleDataSource,&rm,CWDClipboardData::e_cfRightMenu);
2472         DWORD dwDragEffect = SendMessage(WM_APP_OLE_DD_DODRAGDROP,(WPARAM)pRows,(LPARAM)&m_OleDataSource);
2473         if (dwDragEffect == 0)
2474                 dwDragEffect = GetParent()->SendMessage(WM_APP_OLE_DD_DODRAGDROP,(WPARAM)pRows,(LPARAM)&m_OleDataSource);
2475         if (dwDragEffect)
2476         {
2477                 // Start the DragDrop
2478                 DROPEFFECT effect = m_OleDataSource.DoDragDrop(dwDragEffect,NULL);
2479                 // Clear the cache
2480                 m_OleDataSource.Empty();        
2481         }
2482         delete []pRows;
2483 }
2484
2485 void CUIODListCtrl::RegisterDropTarget()
2486 {
2487         if (!IsDragDrop())
2488                 return;
2489         VERIFY(m_OleDropTarget.Register(this));
2490         if (IsDropFiles())
2491                 DragAcceptFiles();
2492 }
2493
2494 DROPEFFECT CUIODListCtrl::SelectCurrentTarget(CDD_OleDropTargetInfo *pInfo)
2495 {
2496         // No method to select a list ctrl item during drag and drop
2497         UINT flags;
2498         int iItem = HitTest(pInfo->GetPoint(), &flags);
2499         pInfo->SetItem(iItem);
2500         // save it
2501         m_iItemDrop = iItem;
2502         LRESULT lResult = SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)pInfo);
2503         if (lResult == 0)
2504         {
2505                 lResult = GetParent()->SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)pInfo);
2506         }
2507         // returns 0 if allowed (so the default is allowed)
2508         if (lResult)
2509         {
2510                 // return what was ever set
2511                 return pInfo->GetDropEffect();
2512         }
2513         return DROPEFFECT_NONE;
2514 }
2515
2516 ///////////////////////////////////////////////
2517
2518 void CUIODListCtrl::PostNcDestroy() 
2519 {
2520         // TODO: Add your specialized code here and/or call the base class
2521
2522         CListCtrl::PostNcDestroy();
2523 }
2524
2525 void CUIODListCtrl::OnDestroy() 
2526 {
2527         SaveProfile();  
2528
2529         CListCtrl::OnDestroy();
2530         
2531         // TODO: Add your message handler code here
2532 }
2533
2534 void CUIODListCtrl::PreSubclassWindow() 
2535 {
2536         CListCtrl::PreSubclassWindow();
2537
2538         // Add initialization code
2539         EnableToolTips(m_bToolTips);
2540         SetSortHeader();
2541 }
2542
2543 int CUIODListCtrl::OnToolHitTest(CPoint point, TOOLINFO * pTI) const
2544 {
2545         int row, col;
2546         CRect cellrect;
2547         row = CellRectFromPoint(point, &cellrect, &col );
2548
2549         if ( row == -1 ) 
2550                 return -1;
2551         if (GetStringWidth(GetItemText(row,col))-10 < cellrect.Width())
2552                 return -1;
2553
2554         CToolTipCtrl* pToolTip = AfxGetThreadState()->m_pToolTip;
2555         pToolTip->SendMessage(TTM_SETDELAYTIME,TTDT_AUTOPOP,10000);
2556         pToolTip->SendMessage(TTM_SETMAXTIPWIDTH,0,30);
2557
2558         pTI->hwnd = m_hWnd;
2559         pTI->uId = (UINT)((row<<10)+(col&0x3ff)+1);
2560         pTI->lpszText = LPSTR_TEXTCALLBACK;
2561
2562         pTI->rect = cellrect;
2563         return pTI->uId;
2564 }
2565
2566 // CellRectFromPoint    - Determine the row, col and bounding rect of a cell
2567 // Returns              - row index on success, -1 otherwise// point            - point to be tested.
2568 // cellrect             - to hold the bounding rect// col                       - to hold the column index
2569 int CUIODListCtrl::CellRectFromPoint(CPoint & point, RECT * cellrect, int * col) const
2570 {
2571         int colnum;     
2572         // Make sure that the ListView is in LVS_REPORT
2573         if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)
2574                 return -1;      
2575         // Get the top and bottom row visible   
2576         int row = GetTopIndex();
2577         int bottom = row + GetCountPerPage();   
2578         if( bottom > GetItemCount() )
2579                 bottom = GetItemCount();                
2580         // Get the number of columns
2581         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
2582         int nColumnCount = pHeader->GetItemCount();     
2583         // Loop through the visible rows
2584         for( ;row <=bottom;row++)       
2585         {
2586                 // Get bounding rect of item and check whether point falls in it.               
2587                 CRect rect;
2588                 GetItemRect( row, &rect, LVIR_BOUNDS );         
2589                 if( rect.PtInRect(point) )
2590                 {
2591                         // Now find the column
2592                         for( colnum = 0; colnum < nColumnCount; colnum++ )
2593                         {
2594                                 int colwidth = GetColumnWidth(colnum);                          
2595                                 if( point.x >= rect.left && point.x <= (rect.left + colwidth ) )
2596                                 {
2597                                                 RECT rectClient;
2598                                                 GetClientRect( &rectClient );                                   
2599                                                 if( col ) 
2600                                                 {
2601                                                         CUIODListCtrl *pThis = const_cast<CUIODListCtrl*>(this);
2602                                                         if (m_pColOrder && pThis->SendMessage(LVM_GETCOLUMNORDERARRAY,(WPARAM)m_nSubItems,(LPARAM)m_pColOrder))
2603                                                                 *col = m_pColOrder[colnum];
2604                                                         else
2605                                                                 *col = colnum;
2606                                                 }
2607                                                 rect.right = rect.left + colwidth;
2608                                                 // Make sure that the right extent does not exceed
2609                                                 // the client area
2610                                                 if( rect.right > rectClient.right ) 
2611                                                         rect.right = rectClient.right;
2612                                                 *cellrect = rect;                                       
2613                                                 return row;             
2614                                 }
2615                                 rect.left += colwidth;
2616                         }       
2617                 }
2618         }
2619         return -1;
2620 }
2621
2622 BOOL CUIODListCtrl::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
2623 {
2624         // need to handle both ANSI and UNICODE versions of the message
2625         static WCHAR szToolTipW[256];
2626         static char szToolTipA[256];
2627         TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
2628         TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;    
2629         UINT nID = pNMHDR->idFrom;
2630         if( nID == 0 )
2631         {
2632                 // Notification in NT from automatically
2633                 return FALSE;           
2634         }
2635         // created tooltip      
2636         int row = ((nID-1) >> 10) & 0x3fffff;
2637         int col = (nID-1) & 0x3ff;      
2638         m_sToolTipText = GetItemText( row, col );
2639 #ifndef _UNICODE        
2640 //      if (pNMHDR->code == TTN_NEEDTEXTA)
2641 //              lstrcpyn(pTTTA->szText, strTipText, 80);
2642 //      else
2643 //              _mbstowcsz(pTTTW->szText, strTipText, 80);
2644         if (pNMHDR->code == TTN_NEEDTEXTA)
2645         {
2646                 pTTTA->lpszText = (LPSTR)(LPCSTR)m_sToolTipText;
2647         }
2648         else
2649         {
2650                 _mbstowcsz(szToolTipW, m_sToolTipText, sizeof(szToolTipW)-1);
2651                 pTTTW->lpszText = szToolTipW;   
2652         }
2653 #else
2654         if (pNMHDR->code == TTN_NEEDTEXTW)
2655         {
2656                 pTTTW->lpszText = (LPWSTR)(LPCWSTR)m_sToolTipText;
2657         }
2658         else
2659         {
2660                 _wcstombsz(szToolTipA, m_sToolTipText, sizeof(szToolTipA)-1);
2661                 pTTTA->lpszText = szToolTipA;
2662         }
2663 //              pTTTA->lpszText = (LPTSTR)(LPCTSTR)m_sToolTipText;
2664 //      if (pNMHDR->code == TTN_NEEDTEXTA)
2665 //              _wcstombsz(pTTTA->szText, strTipText, 80);
2666 //      else
2667 //              lstrcpyn(pTTTW->szText, strTipText, 80);
2668 #endif  
2669         *pResult = 0;
2670         return TRUE;    
2671         // message was handled
2672 }
2673
2674 CODHeaderCtrl::CODHeaderCtrl()
2675 {
2676         m_nSortCol = -1;
2677 }
2678
2679 CODHeaderCtrl::~CODHeaderCtrl()
2680 {
2681 }
2682
2683 int CODHeaderCtrl::SetSortImage(int nCol, BOOL bAsc)
2684 {
2685         if (m_hWnd == NULL)
2686                 return -1;
2687         int nPrevCol = m_nSortCol;
2688         
2689         m_nSortCol = nCol;      
2690         m_bSortAsc = bAsc;
2691         // Change the item to ownder drawn      
2692         HD_ITEM hditem; 
2693         hditem.mask = HDI_FORMAT;
2694         GetItem( nCol, &hditem );       
2695         hditem.fmt |= HDF_OWNERDRAW;
2696         SetItem( nCol, &hditem );       // Invalidate header control so that it gets redrawn
2697         Invalidate();   
2698         return nPrevCol;
2699 }
2700
2701 void CODHeaderCtrl::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
2702 {
2703         CDC dc;
2704
2705         dc.Attach( lpDrawItemStruct->hDC );
2706
2707         // Get the column rect
2708         CRect rcLabel( lpDrawItemStruct->rcItem );
2709
2710         // Save DC
2711         int nSavedDC = dc.SaveDC();
2712
2713         // Set clipping region to limit drawing within column
2714         CRgn rgn;
2715         rgn.CreateRectRgnIndirect( &rcLabel );
2716         dc.SelectObject( &rgn );
2717         rgn.DeleteObject();
2718
2719         // Draw the background
2720         dc.FillRect(rcLabel, &CBrush(::GetSysColor(COLOR_3DFACE)));
2721         
2722         // Labels are offset by a certain amount  
2723         // This offset is related to the width of a space character
2724         int offset = dc.GetTextExtent(_T(" "), 1 ).cx*2;
2725
2726
2727         // Get the column text and format
2728         TCHAR buf[256];
2729         HD_ITEM hditem;
2730         
2731         hditem.mask = HDI_TEXT | HDI_FORMAT;
2732         hditem.pszText = buf;
2733         hditem.cchTextMax = 255;
2734
2735         GetItem( lpDrawItemStruct->itemID, &hditem );
2736
2737         // Determine format for drawing column label
2738         UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP 
2739                                                 | DT_VCENTER | DT_END_ELLIPSIS ;
2740
2741         if( hditem.fmt & HDF_CENTER)
2742                 uFormat |= DT_CENTER;
2743         else if( hditem.fmt & HDF_RIGHT)
2744                 uFormat |= DT_RIGHT;
2745         else
2746                 uFormat |= DT_LEFT;
2747
2748         // Adjust the rect if the mouse button is pressed on it
2749         if( lpDrawItemStruct->itemState == ODS_SELECTED )
2750         {
2751                 rcLabel.left++;
2752                 rcLabel.top += 2;
2753                 rcLabel.right++;
2754         }
2755
2756         // Adjust the rect further if Sort arrow is to be displayed
2757         if( lpDrawItemStruct->itemID == (UINT)m_nSortCol )
2758         {
2759                 rcLabel.right -= 3 * offset;
2760         }
2761
2762         rcLabel.left += offset;
2763         rcLabel.right -= offset;
2764
2765         // Draw column label
2766         if( rcLabel.left < rcLabel.right )
2767                 dc.DrawText(buf,-1,rcLabel, uFormat);
2768
2769         // Draw the Sort arrow
2770         if( lpDrawItemStruct->itemID == (UINT)m_nSortCol )
2771         {
2772                 CRect rcIcon( lpDrawItemStruct->rcItem );
2773
2774                 // Set up pens to use for drawing the triangle
2775                 CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
2776                 CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
2777                 CPen *pOldPen = dc.SelectObject( &penLight );
2778
2779                 if( m_bSortAsc )
2780                 {
2781                         // Draw triangle pointing upwards
2782                         dc.MoveTo( rcIcon.right - 2*offset, offset-1);
2783                         dc.LineTo( rcIcon.right - 3*offset/2, rcIcon.bottom - offset );
2784                         dc.LineTo( rcIcon.right - 5*offset/2-2, rcIcon.bottom - offset );
2785                         dc.MoveTo( rcIcon.right - 5*offset/2-1, rcIcon.bottom - offset-1 );
2786
2787                         dc.SelectObject( &penShadow );
2788                         dc.LineTo( rcIcon.right - 2*offset, offset-2);
2789                 }
2790                 else
2791                 {
2792                         // Draw triangle pointing downwords
2793                         dc.MoveTo( rcIcon.right - 3*offset/2, offset-1);
2794                         dc.LineTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset + 1 );
2795                         dc.MoveTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset );
2796
2797                         dc.SelectObject( &penShadow );
2798                         dc.LineTo( rcIcon.right - 5*offset/2-1, offset -1 );
2799                         dc.LineTo( rcIcon.right - 3*offset/2, offset -1);
2800                 }
2801
2802                 // Restore the pen
2803                 dc.SelectObject( pOldPen );
2804         }
2805
2806         // Restore dc
2807         dc.RestoreDC( nSavedDC );
2808
2809         // Detach the dc before returning
2810         dc.Detach();
2811 }
2812
2813 void CUIODListCtrl::SetSortColumn(int nCol,BOOL bAsc)
2814 {
2815         m_nSortColumn = nCol;
2816         m_bSortAscending = bAsc;
2817         m_HeaderCtrl.SetSortImage(nCol,bAsc);
2818 }
2819
2820 void CUIODListCtrl::SetSortHeader()
2821 {
2822         if (m_HeaderCtrl.GetSafeHwnd() == NULL && m_hWnd != NULL)
2823         {
2824                 m_HeaderCtrl.SubclassWindow( ::GetDlgItem(m_hWnd,0) );
2825         }
2826 }
2827
2828 CString CUIODListCtrl::StripNonNumeric(LPCTSTR pszOldNum,CUIODListCtrl::eColTypes type)
2829 {
2830         TCHAR szNewNum[255];
2831         LPTSTR pszNewNum = szNewNum;
2832         while (*pszOldNum != '\0')
2833         {
2834                 if ((type == CUIODListCtrl::e_Double && *pszOldNum == '.') || *pszOldNum == '-' || *pszOldNum == '+' || _istdigit(*pszOldNum))
2835                 {
2836                         *pszNewNum = *pszOldNum;
2837                         pszNewNum = _tcsinc(pszNewNum);
2838                 }
2839                 pszOldNum = _tcsinc(pszOldNum);
2840         }
2841         *pszNewNum = '\0';
2842         return szNewNum;
2843 }
2844
2845 BOOL CUIODListCtrl::PreTranslateMessage(MSG* pMsg)
2846 {
2847         if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN)
2848         {
2849                 if (pMsg->wParam == VK_F10 && (GetKeyState(VK_SHIFT) < 0))
2850                 {
2851                         PostMessage(WM_APP_ON_CONTEXT_MENU_KEY);
2852                         return TRUE;
2853                 }
2854                 else if (pMsg->wParam == VK_BACK)
2855                 {
2856                         PostMessage(WM_APP_ON_BACKSPACE_KEY);
2857                         return TRUE;
2858                 }
2859                 else if (pMsg->wParam == VK_F2)
2860                 {
2861                         PostMessage(WM_APP_ON_EDIT_KEY);
2862                         return TRUE;
2863                 }
2864                 else if (pMsg->wParam == VK_F5)
2865                 {
2866                         PostMessage(WM_APP_ON_REFRESH_KEY);
2867                         return TRUE;
2868                 }
2869                 else if (pMsg->wParam == VK_DELETE)
2870                 {
2871                         PostMessage(WM_APP_ON_DELETE_KEY);
2872                         return TRUE;
2873                 }
2874                 else if (pMsg->message == WM_SYSKEYDOWN && pMsg->wParam == VK_RETURN)
2875                 {
2876                         PostMessage(WM_APP_ON_PROPERTIES_KEY);
2877                         return TRUE;
2878                 }
2879         }
2880         return CListCtrl::PreTranslateMessage(pMsg);
2881 }
2882
2883 // User has finished editing a column
2884 bool CUIODListCtrl::EndLabelEdit(int nRow,int nCol,LPCTSTR pszText)
2885 {
2886         return false;
2887 }
2888
2889 // Left mouse button double clicked
2890 BOOL CUIODListCtrl::DoubleClick(NM_LISTVIEW* pNMListView)
2891 {
2892         return FALSE;
2893 }
2894
2895 // Enter Pressed
2896 BOOL CUIODListCtrl::OnEnter(NM_LISTVIEW* pNMListView)
2897 {
2898         return FALSE;
2899 }
2900
2901 // Delete key pressed
2902 bool CUIODListCtrl::DeleteKey(int nRow)
2903 {
2904         return false;
2905 }
2906
2907 // ALt-Enter pressed
2908 void CUIODListCtrl::ShowProperties(int nRow)
2909 {
2910 }
2911
2912 // F5 key pressed
2913 void CUIODListCtrl::Refresh()
2914 {
2915 }
2916
2917 // Backspace key pressed
2918 void CUIODListCtrl::GoBack(int nSelRow)
2919 {
2920 }
2921
2922 LRESULT CUIODListCtrl::OnDragDrop(WPARAM wParam,LPARAM lParam)
2923 {
2924         if (IsDragDrop() == false)
2925                 return 1L;
2926         // get the info we need
2927         CDD_OleDropTargetInfo *pInfo = (CDD_OleDropTargetInfo*)wParam;
2928         ASSERT(pInfo);
2929         return DragDrop(pInfo) ? 1 : 0;
2930 }
2931
2932 // user is currently over the list view window
2933 // return 1 if we are interested in the Clipboard format
2934 LRESULT CUIODListCtrl::OnDragOver(WPARAM wParam,LPARAM lParam)
2935 {
2936         if (IsDragDrop() == false)
2937                 return 1L;
2938         CDD_OleDropTargetInfo *pInfo = (CDD_OleDropTargetInfo*)wParam;
2939         ASSERT(pInfo);
2940         return DragOver(pInfo) ? 1 : 0;
2941 }
2942
2943 LRESULT CUIODListCtrl::OnDragEnter(WPARAM wParam,LPARAM lParam)
2944 {
2945         if (IsDragDrop() == false)
2946                 return 1L;
2947         CDD_OleDropTargetInfo *pInfo = (CDD_OleDropTargetInfo*)wParam;
2948         ASSERT(pInfo);
2949         return DragEnter(pInfo) ? 1 : 0;
2950 }
2951
2952 LRESULT CUIODListCtrl::OnDragLeave(WPARAM wParam,LPARAM lParam)
2953 {
2954         if (IsDragDrop() == false)
2955                 return 1L;
2956         CDD_OleDropTargetInfo *pInfo = (CDD_OleDropTargetInfo*)wParam;
2957         ASSERT(pInfo);
2958         return DragLeave(pInfo) ? 1 : 0;
2959 }
2960
2961 // Drag and drop initiated
2962 // Return 1 if processed
2963 LRESULT CUIODListCtrl::OnDDDoDragDrop(WPARAM wParam,LPARAM lParam)
2964 {
2965         if (IsDragDrop() == false)
2966                 return 1L;      
2967         COleDataSource *pOleDataSource = (COleDataSource*)lParam;
2968         int *pRows = (int*)wParam;
2969         ASSERT(pOleDataSource);
2970         return DoDragDrop(pRows,pOleDataSource);
2971 }
2972
2973 bool CUIODListCtrl::DragDrop(CDD_OleDropTargetInfo *pInfo)
2974 {
2975         return false;
2976 }
2977
2978 bool CUIODListCtrl::DragOver(CDD_OleDropTargetInfo *pInfo)
2979 {
2980         return false;
2981 }
2982
2983 bool CUIODListCtrl::DragEnter(CDD_OleDropTargetInfo *pInfo)
2984 {
2985         return false;
2986 }
2987
2988 bool CUIODListCtrl::DragLeave(CDD_OleDropTargetInfo *pInfo)
2989 {
2990         return false;
2991 }
2992
2993 DROPEFFECT CUIODListCtrl::DoDragDrop(int *pnRows,COleDataSource *pOleDataSource)
2994 {
2995         return true;
2996 }
2997
2998 void CUIODListCtrl::OnDropFiles(HDROP hDropInfo)
2999 {
3000         UINT wNumFilesDropped = DragQueryFile(hDropInfo, 0XFFFFFFFF, NULL, 0);
3001         TCHAR szFile[MAX_PATH];
3002         UINT nLen;
3003         UINT nFlags;
3004         POINT pt;
3005         ::DragQueryPoint(hDropInfo,&pt);
3006         int nRow = HitTest(CPoint(pt), &nFlags);
3007         for(UINT i=0; i < wNumFilesDropped;i++)
3008         {
3009                 nLen = DragQueryFile(hDropInfo,i,szFile,sizeof(szFile)/sizeof(TCHAR));
3010                 if (nLen)
3011                         OnDropFile(nRow,szFile,nFlags);
3012         }
3013 }
3014
3015 void CUIODListCtrl::OnDropFile(int nRow,LPCTSTR pszFile,UINT nFlags)
3016 {
3017 }
3018
3019 LRESULT CUIODListCtrl::OnAppPropertiesKey(WPARAM wParam, LPARAM lParam)
3020 {
3021         int item=-1;
3022         while ((item = GetNextSel(item)) != -1)
3023         {
3024                 ShowProperties(item);
3025         }
3026         return 1L;
3027 }
3028
3029 LRESULT CUIODListCtrl::OnAppDeleteKey(WPARAM wParam, LPARAM lParam)
3030 {
3031         int nNewItem = -1;
3032         int item=-1;
3033         CUIListCtrlData *pData = NULL;
3034         while ((item = GetNextSel(item)) != -1)
3035         {
3036                 pData = GetListCtrlData(item);
3037                 if (DeleteKey(item))
3038                 {
3039                         pData->SetDeleted(true);
3040                 }
3041                 nNewItem = item;
3042         }
3043         while ((item = GetCurSel()) != -1)
3044         {
3045                 pData = GetListCtrlData(item);                          
3046                 if (pData->IsDeleted())
3047                 {
3048                         if (!DeleteItem(item))
3049                                 SetItemState(item,0,LVIS_SELECTED);
3050                 }
3051                 else
3052                 {
3053                         SetItemState(item,0,LVIS_SELECTED);
3054                 }
3055                 if (GetItemCount() == 0)
3056                         break;
3057         }
3058         if (nNewItem != -1)     
3059         {
3060                 EnsureVisible(nNewItem,0);
3061                 SetCurSel(nNewItem);
3062         }
3063         return 1L;
3064 }
3065
3066 LRESULT CUIODListCtrl::OnAppRefreshKey(WPARAM wParam, LPARAM lParam)
3067 {
3068         Refresh();
3069         return 1L;
3070 }
3071
3072 LRESULT CUIODListCtrl::OnAppEditKey(WPARAM wParam, LPARAM lParam)
3073 {
3074         EditLabel(GetCurSel());
3075         return 1L;
3076 }
3077
3078 LRESULT CUIODListCtrl::OnAppContextMenuKey(WPARAM wParam, LPARAM lParam)
3079 {
3080         CPoint pt;
3081         if (GetCurSel() != -1)
3082                 GetItemPosition(GetCurSel(),&pt);
3083         ClientToScreen(&pt);
3084         ShowPopupMenu(GetCurSel(),0,pt);
3085         return 1L;
3086 }
3087
3088 LRESULT CUIODListCtrl::OnAppBackspaceKey(WPARAM wParam, LPARAM lParam)
3089 {
3090         GoBack(GetCurSel());
3091         return 1L;
3092 }