xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/PanelListNotify.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // PanelListNotify.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "resource.h"
6 
7 #include "../../../Common/IntToString.h"
8 #include "../../../Common/StringConvert.h"
9 
10 #include "../../../Windows/PropVariant.h"
11 #include "../../../Windows/PropVariantConv.h"
12 
13 #include "../Common/PropIDUtils.h"
14 #include "../../PropID.h"
15 
16 #include "App.h"
17 #include "Panel.h"
18 #include "FormatUtils.h"
19 
20 using namespace NWindows;
21 
22 /* Unicode characters for space:
23 0x009C STRING TERMINATOR
24 0x00B7 Middle dot
25 0x237D Shouldered open box
26 0x2420 Symbol for space
27 0x2422 Blank symbol
28 0x2423 Open box
29 */
30 
31 #define SPACE_REPLACE_CHAR (wchar_t)(0x2423)
32 #define SPACE_TERMINATOR_CHAR (wchar_t)(0x9C)
33 
34 #define INT_TO_STR_SPEC(v) \
35   while (v >= 10) { temp[i++] = (Byte)('0' + (unsigned)(v % 10)); v /= 10; } \
36   *s++ = (Byte)('0' + (unsigned)v);
37 
ConvertSizeToString(UInt64 val,wchar_t * s)38 static void ConvertSizeToString(UInt64 val, wchar_t *s) throw()
39 {
40   Byte temp[32];
41   unsigned i = 0;
42 
43   if (val <= (UInt32)0xFFFFFFFF)
44   {
45     UInt32 val32 = (UInt32)val;
46     INT_TO_STR_SPEC(val32)
47   }
48   else
49   {
50     INT_TO_STR_SPEC(val)
51   }
52 
53   if (i < 3)
54   {
55     if (i != 0)
56     {
57       *s++ = temp[(size_t)i - 1];
58       if (i == 2)
59         *s++ = temp[0];
60     }
61     *s = 0;
62     return;
63   }
64 
65   unsigned r = i % 3;
66   if (r != 0)
67   {
68     s[0] = temp[--i];
69     if (r == 2)
70       s[1] = temp[--i];
71     s += r;
72   }
73 
74   do
75   {
76     s[0] = ' ';
77     s[1] = temp[(size_t)i - 1];
78     s[2] = temp[(size_t)i - 2];
79     s[3] = temp[(size_t)i - 3];
80     s += 4;
81   }
82   while (i -= 3);
83 
84   *s = 0;
85 }
86 
87 UString ConvertSizeToString(UInt64 value);
ConvertSizeToString(UInt64 value)88 UString ConvertSizeToString(UInt64 value)
89 {
90   wchar_t s[32];
91   ConvertSizeToString(value, s);
92   return s;
93 }
94 
95 bool IsSizeProp(UINT propID) throw();
IsSizeProp(UINT propID)96 bool IsSizeProp(UINT propID) throw()
97 {
98   switch (propID)
99   {
100     case kpidSize:
101     case kpidPackSize:
102     case kpidNumSubDirs:
103     case kpidNumSubFiles:
104     case kpidOffset:
105     case kpidLinks:
106     case kpidNumBlocks:
107     case kpidNumVolumes:
108     case kpidPhySize:
109     case kpidHeadersSize:
110     case kpidTotalSize:
111     case kpidFreeSpace:
112     case kpidClusterSize:
113     case kpidNumErrors:
114     case kpidNumStreams:
115     case kpidNumAltStreams:
116     case kpidAltStreamsSize:
117     case kpidVirtualSize:
118     case kpidUnpackSize:
119     case kpidTotalPhySize:
120     case kpidTailSize:
121     case kpidEmbeddedStubSize:
122       return true;
123   }
124   return false;
125 }
126 
127 
128 
129 /*
130 #include <stdio.h>
131 
132 UInt64 GetCpuTicks()
133 {
134     #ifdef _WIN64
135       return __rdtsc();
136     #else
137       UInt32 lowVal, highVal;
138       __asm RDTSC;
139       __asm mov lowVal, EAX;
140       __asm mov highVal, EDX;
141       return ((UInt64)highVal << 32) | lowVal;
142     #endif
143 }
144 
145 UInt32 g_NumGroups;
146 UInt64 g_start_tick;
147 UInt64 g_prev_tick;
148 DWORD g_Num_SetItemText;
149 UInt32 g_NumMessages;
150 */
151 
SetItemText(LVITEMW & item)152 LRESULT CPanel::SetItemText(LVITEMW &item)
153 {
154   if (_dontShowMode)
155     return 0;
156   UInt32 realIndex = GetRealIndex(item);
157 
158   // g_Num_SetItemText++;
159 
160   /*
161   if ((item.mask & LVIF_IMAGE) != 0)
162   {
163     bool defined  = false;
164     CComPtr<IFolderGetSystemIconIndex> folderGetSystemIconIndex;
165     _folder.QueryInterface(&folderGetSystemIconIndex);
166     if (folderGetSystemIconIndex)
167     {
168       folderGetSystemIconIndex->GetSystemIconIndex(index, &item.iImage);
169       defined = (item.iImage > 0);
170     }
171     if (!defined)
172     {
173       NCOM::CPropVariant prop;
174       _folder->GetProperty(index, kpidAttrib, &prop);
175       UINT32 attrib = 0;
176       if (prop.vt == VT_UI4)
177         attrib = prop.ulVal;
178       else if (IsItemFolder(index))
179         attrib |= FILE_ATTRIBUTE_DIRECTORY;
180       if (_currentFolderPrefix.IsEmpty())
181         throw 1;
182       else
183         item.iImage = _extToIconMap.GetIconIndex(attrib, GetSystemString(GetItemName(index)));
184     }
185     // item.iImage = 1;
186   }
187   */
188 
189   if ((item.mask & LVIF_TEXT) == 0)
190     return 0;
191 
192   LPWSTR text = item.pszText;
193 
194   if (item.cchTextMax > 0)
195     text[0] = 0;
196 
197   if (item.cchTextMax <= 1)
198     return 0;
199 
200   // item.cchTextMax > 1
201 
202   const CPropColumn &property = _visibleColumns[item.iSubItem];
203   PROPID propID = property.ID;
204 
205   if (realIndex == kParentIndex_UInt32)
206   {
207     if (propID == kpidName)
208     {
209       if (item.cchTextMax > 2)
210       {
211         text[0] = '.';
212         text[1] = '.';
213         text[2] = 0;
214       }
215     }
216     return 0;
217   }
218 
219   /*
220   // List-view in report-view in Windows 10 is slow (50+ ms) for page change.
221   // that code shows the time of page reload for items
222   // if you know how to improve the speed of list view refresh, notify 7-Zip developer
223 
224   // if (propID == 2000)
225   // if (propID == kpidName)
226   {
227     // debug column;
228     // DWORD dw = GetCpuTicks();
229     UInt64 dw = GetCpuTicks();
230     UInt64 deltaLast = dw - g_prev_tick;
231     #define conv_ticks(t) ((unsigned)((t) / 100000))
232     if (deltaLast > 1000u * 1000 * 1000)
233     {
234       UInt64 deltaFull = g_prev_tick - g_start_tick;
235       char s[128];
236       sprintf(s, "%d", conv_ticks(deltaFull));
237       OutputDebugStringA(s);
238       g_start_tick = dw;
239       g_NumGroups++;
240     }
241     g_prev_tick = dw;
242     UString u;
243     char s[128];
244     UInt64 deltaFull = dw - g_start_tick;
245     // for (int i = 0; i < 100000; i++)
246     sprintf(s, "%d %d %d-%d ", g_NumMessages, g_Num_SetItemText, g_NumGroups, conv_ticks(deltaFull));
247     // sprintf(s, "%d-%d ", g_NumGroups, conv_ticks(deltaFull));
248     u = s;
249     lstrcpyW(text, u.Ptr());
250     text += u.Len();
251 
252     // dw = GetCpuTicks();
253     // deltaFull = dw - g_prev_tick;
254     // sprintf(s, "-%d ", conv_ticks(deltaFull));
255     // u = s;
256     // lstrcpyW(text, u.Ptr());
257     // text += u.Len();
258 
259     if (propID != kpidName)
260       return 0;
261   }
262   */
263 
264 
265   if (property.IsRawProp)
266   {
267     const void *data;
268     UInt32 dataSize;
269     UInt32 propType;
270     RINOK(_folderRawProps->GetRawProp(realIndex, propID, &data, &dataSize, &propType))
271     unsigned limit = (unsigned)item.cchTextMax - 1;
272     // limit != 0
273     if (dataSize == 0)
274       return 0;
275 
276     if (propID == kpidNtReparse)
277     {
278       UString s;
279       ConvertNtReparseToString((const Byte *)data, dataSize, s);
280       if (!s.IsEmpty())
281       {
282         unsigned i;
283         for (i = 0; i < limit; i++)
284         {
285           const wchar_t c = s[i];
286           if (c == 0)
287             break;
288           text[i] = c;
289         }
290         text[i] = 0;
291         return 0;
292       }
293     }
294     else if (propID == kpidNtSecure)
295     {
296       AString s;
297       ConvertNtSecureToString((const Byte *)data, dataSize, s);
298       if (!s.IsEmpty())
299       {
300         unsigned i;
301         for (i = 0; i < limit; i++)
302         {
303           const wchar_t c = (Byte)s[i];
304           if (c == 0)
305             break;
306           text[i] = c;
307         }
308         text[i] = 0;
309         return 0;
310       }
311     }
312     {
313       const unsigned kMaxDataSize = 64;
314       if (dataSize > kMaxDataSize)
315       {
316         char temp[32];
317         MyStringCopy(temp, "data:");
318         ConvertUInt32ToString(dataSize, temp + 5);
319         unsigned i;
320         for (i = 0; i < limit; i++)
321         {
322           wchar_t c = (Byte)temp[i];
323           if (c == 0)
324             break;
325           *text++ = c;
326         }
327         *text = 0;
328       }
329       else
330       {
331         const char * const k_Hex =
332           (dataSize <= 8
333             && (propID == kpidCRC || propID == kpidChecksum))
334             ? k_Hex_Upper : k_Hex_Lower;
335         limit /= 2;
336         if (limit > dataSize)
337             limit = dataSize;
338         const Byte *data2 = (const Byte *)data;
339         do
340         {
341           const size_t b = *data2++;
342           text[0] = (Byte)k_Hex[b >> 4];
343           text[1] = (Byte)k_Hex[b & 15];
344           text += 2;
345         }
346         while (--limit);
347         *text = 0;
348       }
349     }
350     return 0;
351   }
352   /*
353   {
354     NCOM::CPropVariant prop;
355     if (propID == kpidType)
356       string = GetFileType(index);
357     else
358     {
359       HRESULT result = m_ArchiveFolder->GetProperty(index, propID, &prop);
360       if (result != S_OK)
361       {
362         // PrintMessage("GetPropertyValue error");
363         return 0;
364       }
365       string = ConvertPropertyToString(prop, propID, false);
366     }
367   }
368   */
369   // const NFind::CFileInfo &aFileInfo = m_Files[index];
370 
371   NCOM::CPropVariant prop;
372   /*
373   bool needRead = true;
374   if (propID == kpidSize)
375   {
376     CComPtr<IFolderGetItemFullSize> getItemFullSize;
377     if (_folder.QueryInterface(&getItemFullSize) == S_OK)
378     {
379       if (getItemFullSize->GetItemFullSize(index, &prop) == S_OK)
380         needRead = false;
381     }
382   }
383   if (needRead)
384   */
385 
386   if (item.cchTextMax < 32)
387     return 0;
388 
389   if (propID == kpidName)
390   {
391     if (_folderGetItemName)
392     {
393       const wchar_t *name = NULL;
394       unsigned nameLen = 0;
395       _folderGetItemName->GetItemName(realIndex, &name, &nameLen);
396 
397       if (name)
398       {
399         unsigned dest = 0;
400         const unsigned limit = (unsigned)item.cchTextMax - 1;
401 
402         for (unsigned i = 0; dest < limit;)
403         {
404           const wchar_t c = name[i++];
405           if (c == 0)
406             break;
407           text[dest++] = c;
408 
409           if (c != ' ')
410           {
411             if (c != 0x202E) // RLO
412               continue;
413             text[(size_t)dest - 1] = '_';
414             continue;
415           }
416 
417           if (name[i] != ' ')
418             continue;
419 
420           unsigned t = 1;
421           for (; name[i + t] == ' '; t++);
422 
423           if (t >= 4 && dest + 4 < limit)
424           {
425             text[dest++] = '.';
426             text[dest++] = '.';
427             text[dest++] = '.';
428             text[dest++] = ' ';
429             i += t;
430           }
431         }
432 
433         if (dest == 0)
434           text[dest++]= '_';
435 
436         #ifdef _WIN32
437         else if (text[(size_t)dest - 1] == ' ')
438         {
439           if (dest < limit)
440             text[dest++] = SPACE_TERMINATOR_CHAR;
441           else
442             text[dest - 1] = SPACE_REPLACE_CHAR;
443         }
444         #endif
445 
446         text[dest] = 0;
447         // OutputDebugStringW(text);
448         return 0;
449       }
450     }
451   }
452 
453   if (propID == kpidPrefix)
454   {
455     if (_folderGetItemName)
456     {
457       const wchar_t *name = NULL;
458       unsigned nameLen = 0;
459       _folderGetItemName->GetItemPrefix(realIndex, &name, &nameLen);
460       if (name)
461       {
462         unsigned dest = 0;
463         const unsigned limit = (unsigned)item.cchTextMax - 1;
464         for (unsigned i = 0; dest < limit;)
465         {
466           const wchar_t c = name[i++];
467           if (c == 0)
468             break;
469           text[dest++] = c;
470         }
471         text[dest] = 0;
472         return 0;
473       }
474     }
475   }
476 
477   const HRESULT res = _folder->GetProperty(realIndex, propID, &prop);
478 
479   if (res != S_OK)
480   {
481     MyStringCopy(text, L"Error: ");
482     // s = UString("Error: ") + HResultToMessage(res);
483   }
484   else if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID))
485   {
486     UInt64 v = 0;
487     ConvertPropVariantToUInt64(prop, v);
488     ConvertSizeToString(v, text);
489   }
490   else if (prop.vt == VT_BSTR)
491   {
492     const unsigned limit = (unsigned)item.cchTextMax - 1;
493     const wchar_t *src = prop.bstrVal;
494     unsigned i;
495     for (i = 0; i < limit; i++)
496     {
497       wchar_t c = src[i];
498       if (c == 0) break;
499       if (c == 0xA) c = ' ';
500       if (c == 0xD) c = ' ';
501       text[i] = c;
502     }
503     text[i] = 0;
504   }
505   else
506   {
507     char temp[64];
508     ConvertPropertyToShortString2(temp, prop, propID, _timestampLevel);
509     unsigned i;
510     const unsigned limit = (unsigned)item.cchTextMax - 1;
511     for (i = 0; i < limit; i++)
512     {
513       const wchar_t c = (Byte)temp[i];
514       if (c == 0)
515         break;
516       text[i] = c;
517     }
518     text[i] = 0;
519   }
520 
521   return 0;
522 }
523 
OnItemChanged(NMLISTVIEW * item)524 void CPanel::OnItemChanged(NMLISTVIEW *item)
525 {
526   const unsigned index = (unsigned)item->lParam;
527   if (index == kParentIndex)
528     return;
529   const bool oldSelected = (item->uOldState & LVIS_SELECTED) != 0;
530   const bool newSelected = (item->uNewState & LVIS_SELECTED) != 0;
531   // Don't change this code. It works only with such check
532   if (oldSelected != newSelected)
533     _selectedStatusVector[index] = newSelected;
534 }
535 
536 extern bool g_LVN_ITEMACTIVATE_Support;
537 
OnNotifyActivateItems()538 void CPanel::OnNotifyActivateItems()
539 {
540   bool alt = IsKeyDown(VK_MENU);
541   bool ctrl = IsKeyDown(VK_CONTROL);
542   bool shift = IsKeyDown(VK_SHIFT);
543   if (!shift && alt && !ctrl)
544     Properties();
545   else
546     OpenSelectedItems(!shift || alt || ctrl);
547 }
548 
OnNotifyList(LPNMHDR header,LRESULT & result)549 bool CPanel::OnNotifyList(LPNMHDR header, LRESULT &result)
550 {
551   switch (header->code)
552   {
553     case LVN_ITEMCHANGED:
554     {
555       if (_enableItemChangeNotify)
556       {
557         if (!_mySelectMode)
558           OnItemChanged((LPNMLISTVIEW)header);
559 
560         // Post_Refresh_StatusBar();
561         /* 9.26: we don't call Post_Refresh_StatusBar.
562            it was very slow if we select big number of files
563            and then clead slection by selecting just new file.
564            probably it called slow Refresh_StatusBar for each item deselection.
565            I hope Refresh_StatusBar still will be called for each key / mouse action.
566         */
567       }
568       return false;
569     }
570     /*
571 
572     case LVN_ODSTATECHANGED:
573       {
574       break;
575       }
576     */
577 
578     case LVN_GETDISPINFOW:
579     {
580       LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header;
581 
582       //is the sub-item information being requested?
583 
584       if ((dispInfo->item.mask & LVIF_TEXT) != 0 ||
585           (dispInfo->item.mask & LVIF_IMAGE) != 0)
586         SetItemText(dispInfo->item);
587       {
588         // 20.03:
589         result = 0;
590         return true;
591         // old 7-Zip:
592         // return false;
593       }
594     }
595     case LVN_KEYDOWN:
596     {
597       LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header);
598       bool boolResult = OnKeyDown(keyDownInfo, result);
599       switch (keyDownInfo->wVKey)
600       {
601         case VK_CONTROL:
602         case VK_SHIFT:
603         case VK_MENU:
604           break;
605         default:
606           Post_Refresh_StatusBar();
607       }
608       return boolResult;
609     }
610 
611     case LVN_COLUMNCLICK:
612       OnColumnClick(LPNMLISTVIEW(header));
613       return false;
614 
615     case LVN_ITEMACTIVATE:
616       if (g_LVN_ITEMACTIVATE_Support)
617       {
618         OnNotifyActivateItems();
619         return false;
620       }
621       break;
622     case NM_DBLCLK:
623     case NM_RETURN:
624       if (!g_LVN_ITEMACTIVATE_Support)
625       {
626         OnNotifyActivateItems();
627         return false;
628       }
629       break;
630 
631     case NM_RCLICK:
632       Post_Refresh_StatusBar();
633       break;
634 
635     /*
636       return OnRightClick((LPNMITEMACTIVATE)header, result);
637     */
638       /*
639       case NM_CLICK:
640       SendRefreshStatusBarMessage();
641       return 0;
642 
643         // TODO : Handler default action...
644         return 0;
645         case LVN_ITEMCHANGED:
646         {
647         NMLISTVIEW *pNMLV = (NMLISTVIEW *) lpnmh;
648         SelChange(pNMLV);
649         return TRUE;
650         }
651         case NM_SETFOCUS:
652         return onSetFocus(NULL);
653         case NM_KILLFOCUS:
654         return onKillFocus(NULL);
655       */
656     case NM_CLICK:
657     {
658       // we need SetFocusToList, if we drag-select items from other panel.
659       SetFocusToList();
660       Post_Refresh_StatusBar();
661       if (_mySelectMode)
662 #ifdef Z7_USE_DYN_ComCtl32Version
663         if (g_ComCtl32Version >= MAKELONG(71, 4))
664 #endif
665           OnLeftClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header);
666       return false;
667     }
668     case LVN_BEGINLABELEDITW:
669       result = OnBeginLabelEdit((LV_DISPINFOW *)header);
670       return true;
671     case LVN_ENDLABELEDITW:
672       result = OnEndLabelEdit((LV_DISPINFOW *)header);
673       return true;
674 
675     case NM_CUSTOMDRAW:
676     {
677       if (_mySelectMode || (_markDeletedItems && _thereAreDeletedItems))
678         return OnCustomDraw((LPNMLVCUSTOMDRAW)header, result);
679       break;
680     }
681     case LVN_BEGINDRAG:
682     {
683       OnDrag((LPNMLISTVIEW)header, false);
684       Post_Refresh_StatusBar();
685       break;
686     }
687     case LVN_BEGINRDRAG:
688     {
689       OnDrag((LPNMLISTVIEW)header, true);
690       Post_Refresh_StatusBar();
691       break;
692     }
693     // case LVN_BEGINRDRAG:
694   }
695   return false;
696 }
697 
OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd,LRESULT & result)698 bool CPanel::OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result)
699 {
700   switch (lplvcd->nmcd.dwDrawStage)
701   {
702   case CDDS_PREPAINT :
703     result = CDRF_NOTIFYITEMDRAW;
704     return true;
705 
706   case CDDS_ITEMPREPAINT:
707     /*
708     SelectObject(lplvcd->nmcd.hdc,
709     GetFontForItem(lplvcd->nmcd.dwItemSpec,
710     lplvcd->nmcd.lItemlParam) );
711     lplvcd->clrText = GetColorForItem(lplvcd->nmcd.dwItemSpec,
712     lplvcd->nmcd.lItemlParam);
713     lplvcd->clrTextBk = GetBkColorForItem(lplvcd->nmcd.dwItemSpec,
714     lplvcd->nmcd.lItemlParam);
715     */
716     const unsigned realIndex = (unsigned)lplvcd->nmcd.lItemlParam;
717     lplvcd->clrTextBk = _listView.GetBkColor();
718     if (_mySelectMode)
719     {
720       if (realIndex != kParentIndex && _selectedStatusVector[realIndex])
721        lplvcd->clrTextBk = RGB(255, 192, 192);
722     }
723 
724     if (_markDeletedItems && _thereAreDeletedItems)
725     {
726       if (IsItem_Deleted(realIndex))
727         lplvcd->clrText = RGB(255, 0, 0);
728     }
729     // lplvcd->clrText = RGB(0, 0, 0);
730     // result = CDRF_NEWFONT;
731     result = CDRF_NOTIFYITEMDRAW;
732     return true;
733 
734     // return false;
735     // return true;
736     /*
737     case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
738     if (lplvcd->iSubItem == 0)
739     {
740     // lplvcd->clrText = RGB(255, 0, 0);
741     lplvcd->clrTextBk = RGB(192, 192, 192);
742     }
743     else
744     {
745     lplvcd->clrText = RGB(0, 0, 0);
746     lplvcd->clrTextBk = RGB(255, 255, 255);
747     }
748     return true;
749     */
750 
751         /* At this point, you can change the background colors for the item
752         and any subitems and return CDRF_NEWFONT. If the list-view control
753         is in report mode, you can simply return CDRF_NOTIFYSUBITEMREDRAW
754         to customize the item's subitems individually */
755   }
756   return false;
757 }
758 
Refresh_StatusBar()759 void CPanel::Refresh_StatusBar()
760 {
761   /*
762   g_name_cnt++;
763   char s[256];
764   sprintf(s, "g_name_cnt = %8d", g_name_cnt);
765   OutputDebugStringA(s);
766   */
767   // DWORD dw = GetTickCount();
768 
769   CRecordVector<UInt32> indices;
770   Get_ItemIndices_Operated(indices);
771 
772   {
773     UString s;
774     s.Add_UInt32(indices.Size());
775     s += " / ";
776     s.Add_UInt32(_selectedStatusVector.Size());
777 
778     // UString s1 = MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, NumberToString(indices.Size()));
779     // UString s1 = MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size()));
780     _statusBar.SetText(0, MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, s));
781     // _statusBar.SetText(0, MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size())));
782   }
783 
784   {
785     wchar_t selectSizeString[32];
786     selectSizeString[0] = 0;
787 
788     if (!indices.IsEmpty())
789     {
790       // for (unsigned ttt = 0; ttt < 1000; ttt++) {
791       UInt64 totalSize = 0;
792       FOR_VECTOR (i, indices)
793         totalSize += GetItemSize(indices[i]);
794       ConvertSizeToString(totalSize, selectSizeString);
795       // }
796     }
797     _statusBar.SetText(1, selectSizeString);
798   }
799 
800   const int focusedItem = _listView.GetFocusedItem();
801   wchar_t sizeString[32];
802   sizeString[0] = 0;
803   wchar_t dateString[32];
804   dateString[0] = 0;
805   if (focusedItem >= 0 && _listView.GetSelectedCount() > 0)
806   {
807     const unsigned realIndex = GetRealItemIndex(focusedItem);
808     if (realIndex != kParentIndex)
809     {
810       ConvertSizeToString(GetItemSize(realIndex), sizeString);
811       NCOM::CPropVariant prop;
812       if (_folder->GetProperty(realIndex, kpidMTime, &prop) == S_OK)
813       {
814         char dateString2[64];
815         dateString2[0] = 0;
816         ConvertPropertyToShortString2(dateString2, prop, kpidMTime);
817         for (unsigned i = 0;; i++)
818         {
819           char c = dateString2[i];
820           dateString[i] = (Byte)c;
821           if (c == 0)
822             break;
823         }
824       }
825     }
826   }
827   _statusBar.SetText(2, sizeString);
828   _statusBar.SetText(3, dateString);
829 
830   // _statusBar.SetText(4, nameString);
831   // _statusBar2.SetText(1, MyFormatNew(L"{0} bytes", NumberToStringW(totalSize)));
832   // }
833   /*
834   dw = GetTickCount() - dw;
835   sprintf(s, "status = %8d ms", dw);
836   OutputDebugStringA(s);
837   */
838 }
839