xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // OverwriteDialog.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/StringConvert.h"
7 
8 #include "../../../Windows/FileFind.h"
9 #include "../../../Windows/PropVariantConv.h"
10 #include "../../../Windows/ResourceString.h"
11 
12 #include "../../../Windows/Control/Static.h"
13 
14 #include "FormatUtils.h"
15 #include "LangUtils.h"
16 #include "OverwriteDialog.h"
17 
18 #include "PropertyNameRes.h"
19 
20 using namespace NWindows;
21 
22 #ifdef Z7_LANG
23 static const UInt32 kLangIDs[] =
24 {
25   IDT_OVERWRITE_HEADER,
26   IDT_OVERWRITE_QUESTION_BEGIN,
27   IDT_OVERWRITE_QUESTION_END,
28   IDB_YES_TO_ALL,
29   IDB_NO_TO_ALL,
30   IDB_AUTO_RENAME
31 };
32 #endif
33 
34 static const unsigned kCurrentFileNameSizeLimit = 72;
35 
ReduceString(UString & s)36 void COverwriteDialog::ReduceString(UString &s)
37 {
38   const unsigned size =
39 #ifdef UNDER_CE
40       !_isBig ? 30 : // kCurrentFileNameSizeLimit2
41 #endif
42       kCurrentFileNameSizeLimit;
43 
44   if (s.Len() > size)
45   {
46     s.Delete(size / 2, s.Len() - size);
47     s.Insert(size / 2, L" ... ");
48   }
49   if (!s.IsEmpty() && s.Back() == ' ')
50   {
51     // s += (wchar_t)(0x2423); // visible space
52     s.InsertAtFront(L'\"');
53     s.Add_Char('\"');
54   }
55 }
56 
57 
SetItemIcon(unsigned iconID,HICON hIcon)58 void COverwriteDialog::SetItemIcon(unsigned iconID, HICON hIcon)
59 {
60   NControl::CStatic staticContol;
61   staticContol.Attach(GetItem(iconID));
62   hIcon = staticContol.SetIcon(hIcon);
63   if (hIcon)
64     DestroyIcon(hIcon);
65 }
66 
67 void AddSizeValue(UString &s, UInt64 value);
AddSizeValue(UString & s,UInt64 value)68 void AddSizeValue(UString &s, UInt64 value)
69 {
70   {
71     wchar_t sz[32];
72     ConvertUInt64ToString(value, sz);
73     s += MyFormatNew(IDS_FILE_SIZE, sz);
74   }
75   if (value >= (1 << 10))
76   {
77     char c;
78           if (value >= ((UInt64)10 << 30)) { value >>= 30; c = 'G'; }
79     else  if (value >=         (10 << 20)) { value >>= 20; c = 'M'; }
80     else                                   { value >>= 10; c = 'K'; }
81     s += " : ";
82     s.Add_UInt64(value);
83     s.Add_Space();
84     s.Add_Char(c);
85     s += "iB";
86   }
87 }
88 
89 
SetFileInfoControl(const NOverwriteDialog::CFileInfo & fileInfo,unsigned textID,unsigned iconID,unsigned iconID_2)90 void COverwriteDialog::SetFileInfoControl(
91     const NOverwriteDialog::CFileInfo &fileInfo,
92     unsigned textID,
93     unsigned iconID,
94     unsigned iconID_2)
95 {
96   {
97     const UString &path = fileInfo.Path;
98     const int slashPos = path.ReverseFind_PathSepar();
99     UString s = path.Left((unsigned)(slashPos + 1));
100     ReduceString(s);
101     s.Add_LF();
102     {
103       UString s2 = path.Ptr((unsigned)(slashPos + 1));
104       ReduceString(s2);
105       s += s2;
106     }
107     s.Add_LF();
108     if (fileInfo.Size_IsDefined)
109       AddSizeValue(s, fileInfo.Size);
110     s.Add_LF();
111     if (fileInfo.Time_IsDefined)
112     {
113       AddLangString(s, IDS_PROP_MTIME);
114       s += ": ";
115       char t[64];
116       ConvertUtcFileTimeToString(fileInfo.Time, t);
117       s += t;
118     }
119     SetItemText(textID, s);
120   }
121 /*
122   SHGetFileInfo():
123     DOCs: If uFlags does not contain SHGFI_EXETYPE or SHGFI_SYSICONINDEX,
124           the return value is nonzero if successful, or zero otherwise.
125     We don't use SHGFI_EXETYPE or SHGFI_SYSICONINDEX here.
126   win10: we call with SHGFI_ICON flag set.
127     it returns 0: if error : (shFileInfo::*) members are not set.
128     it returns non_0, if successful, and retrieve:
129       { shFileInfo.hIcon != NULL : the handle to icon (must be destroyed by our code)
130         shFileInfo.iIcon is index of the icon image within the system image list.
131       }
132   Note:
133     If we send path to ".exe" file,
134     SHGFI_USEFILEATTRIBUTES flag is ignored, and it tries to open file.
135     and return icon from that exe file.
136     So we still need to reduce path, if want to get raw icon of exe file.
137 
138   if (name.Len() >= MAX_PATH))
139   {
140     it can return:
141       return 0.
142       return 1 and:
143         { shFileInfo.hIcon != NULL : is some default icon for file
144           shFileInfo.iIcon == 0
145         }
146     return results (0 or 1) can depend from:
147       - unicode/non-unicode
148       - (SHGFI_USEFILEATTRIBUTES) flag
149       - exact file extension (.exe).
150   }
151 */
152   int iconIndex = -1;
153   for (unsigned i = 0; i < 2; i++)
154   {
155     CSysString name = GetSystemString(fileInfo.Path);
156     if (i != 0)
157     {
158       if (!fileInfo.Is_FileSystemFile)
159         break;
160       if (name.Len() < 4 ||
161           (!StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".exe") &&
162            !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".ico")))
163         break;
164       // if path for ".exe" file is long, it returns default icon (shFileInfo.iIcon == 0).
165       // We don't want to show that default icon.
166       // But we will check for default icon later instead of MAX_PATH check here.
167       // if (name.Len() >= MAX_PATH) break; // optional
168     }
169     else
170     {
171       // we need only file extension with dot
172       const int separ = name.ReverseFind_PathSepar();
173       name.DeleteFrontal((unsigned)(separ + 1));
174       // if (name.Len() >= MAX_PATH)
175       {
176         const int dot = name.ReverseFind_Dot();
177         if (dot >= 0)
178           name.DeleteFrontal((unsigned)dot);
179         // else name.Empty(); to set default name below
180       }
181       // name.Empty(); // for debug
182     }
183 
184     if (name.IsEmpty())
185     {
186       // If we send empty name, SHGetFileInfo() returns some strange icon.
187       // So we use common dummy name without extension,
188       // and SHGetFileInfo() will return default icon (iIcon == 0)
189       name = "__file__";
190     }
191 
192     DWORD attrib = FILE_ATTRIBUTE_ARCHIVE;
193     if (fileInfo.Is_FileSystemFile)
194     {
195       NFile::NFind::CFileInfo fi;
196       if (fi.Find(us2fs(fileInfo.Path)) && !fi.IsAltStream && !fi.IsDir())
197         attrib = fi.Attrib;
198     }
199 
200     SHFILEINFO shFileInfo;
201     // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); // optional
202     shFileInfo.hIcon = NULL; // optional
203     shFileInfo.iIcon = -1;   // optional
204     // memset(&shFileInfo, 1, sizeof(shFileInfo)); // for debug
205     const DWORD_PTR res = ::SHGetFileInfo(name, attrib,
206         &shFileInfo, sizeof(shFileInfo),
207         SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SHELLICONSIZE |
208         // (i == 0 ? SHGFI_USEFILEATTRIBUTES : 0)
209         SHGFI_USEFILEATTRIBUTES
210         // we use SHGFI_USEFILEATTRIBUTES for second icon, because
211         // it still returns real icon from exe files
212         );
213     if (res && shFileInfo.hIcon)
214     {
215       // we don't show second icon, if icon index (iIcon) is same
216       // as first icon index of first shown icon (exe file without icon)
217       if (   shFileInfo.iIcon >= 0
218           && shFileInfo.iIcon != iconIndex
219           && (shFileInfo.iIcon != 0 || i == 0)) // we don't want default icon for second icon
220       {
221         iconIndex = shFileInfo.iIcon;
222         SetItemIcon(i == 0 ? iconID : iconID_2, shFileInfo.hIcon);
223       }
224       else
225         DestroyIcon(shFileInfo.hIcon);
226     }
227   }
228 }
229 
230 
231 
OnInit()232 bool COverwriteDialog::OnInit()
233 {
234   #ifdef Z7_LANG
235   LangSetWindowText(*this, IDD_OVERWRITE);
236   LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
237   #endif
238   SetFileInfoControl(OldFileInfo,
239       IDT_OVERWRITE_OLD_FILE_SIZE_TIME,
240       IDI_OVERWRITE_OLD_FILE,
241       IDI_OVERWRITE_OLD_FILE_2);
242   SetFileInfoControl(NewFileInfo,
243       IDT_OVERWRITE_NEW_FILE_SIZE_TIME,
244       IDI_OVERWRITE_NEW_FILE,
245       IDI_OVERWRITE_NEW_FILE_2);
246   NormalizePosition();
247 
248   if (!ShowExtraButtons)
249   {
250     HideItem(IDB_YES_TO_ALL);
251     HideItem(IDB_NO_TO_ALL);
252     HideItem(IDB_AUTO_RENAME);
253   }
254 
255   if (DefaultButton_is_NO)
256   {
257     PostMsg(DM_SETDEFID, IDNO);
258     HWND h = GetItem(IDNO);
259     PostMsg(WM_NEXTDLGCTL, (WPARAM)h, TRUE);
260     // ::SetFocus(h);
261   }
262 
263   return CModalDialog::OnInit();
264 }
265 
OnDestroy()266 bool COverwriteDialog::OnDestroy()
267 {
268   SetItemIcon(IDI_OVERWRITE_OLD_FILE, NULL);
269   SetItemIcon(IDI_OVERWRITE_OLD_FILE_2, NULL);
270   SetItemIcon(IDI_OVERWRITE_NEW_FILE, NULL);
271   SetItemIcon(IDI_OVERWRITE_NEW_FILE_2, NULL);
272   return false; // we return (false) to perform default dialog operation
273 }
274 
OnButtonClicked(unsigned buttonID,HWND buttonHWND)275 bool COverwriteDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
276 {
277   switch (buttonID)
278   {
279     case IDYES:
280     case IDNO:
281     case IDB_YES_TO_ALL:
282     case IDB_NO_TO_ALL:
283     case IDB_AUTO_RENAME:
284       End((INT_PTR)buttonID);
285       return true;
286   }
287   return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
288 }
289