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