ebbe7758d62f3b7cc6507bc3a1628be2ee4a9fd0
[reactos.git] / rosapps / winfile / listview.c
1 /*
2 * ReactOS winfile
3 *
4 * listview.c
5 *
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef _MSC_VER
24 #include "stdafx.h"
25 #else
26 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
27 #include <windows.h>
28 #include <commctrl.h>
29 #include <stdlib.h>
30 #include <malloc.h>
31 #include <memory.h>
32 #include <tchar.h>
33 #include <process.h>
34 #include <stdio.h>
35 #endif
36
37 #include <shellapi.h>
38 //#include <winspool.h>
39 #include <windowsx.h>
40 #include <shellapi.h>
41 #include <ctype.h>
42 #include <assert.h>
43 #define ASSERT assert
44
45 #include "main.h"
46 #include "listview.h"
47 //#include "entries.h"
48 #include "utils.h"
49
50 #include "trace.h"
51
52 // Global Variables:
53 extern HINSTANCE hInst;
54
55
56 static void init_output(HWND hWnd)
57 {
58 TCHAR b[16];
59 HFONT old_font;
60 HDC hdc = GetDC(hWnd);
61
62 if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, _T("1000"), 0, b, 16) > 4)
63 Globals.num_sep = b[1];
64 else
65 Globals.num_sep = _T('.');
66
67 old_font = SelectFont(hdc, Globals.hFont);
68 GetTextExtentPoint32(hdc, _T(" "), 1, &Globals.spaceSize);
69 SelectFont(hdc, old_font);
70 ReleaseDC(hWnd, hdc);
71 }
72
73 static void AddEntryToList(HWND hwndLV, int idx, Entry* entry)
74 {
75 LVITEM item;
76
77 item.mask = LVIF_TEXT | LVIF_PARAM;
78 item.iItem = 0;//idx;
79 item.iSubItem = 0;
80 item.state = 0;
81 item.stateMask = 0;
82 // item.pszText = entry->data.cFileName;
83 item.pszText = LPSTR_TEXTCALLBACK;
84 item.cchTextMax = strlen(entry->data.cFileName);
85 item.iImage = 0;
86 // item.iImage = I_IMAGECALLBACK;
87 item.lParam = (LPARAM)entry;
88 #if (_WIN32_IE >= 0x0300)
89 item.iIndent = 0;
90 #endif
91 ListView_InsertItem(hwndLV, &item);
92 }
93
94 // insert listctrl entries after index idx
95 static void InsertListEntries(Pane* pane, Entry* parent, int idx)
96 {
97 Entry* entry = parent;
98
99 if (!entry)
100 return;
101 ShowWindow(pane->hWnd, SW_HIDE);
102
103 if (idx == -1) {
104 }
105 idx = 0;
106
107 for(; entry; entry=entry->next) {
108 #ifndef _LEFT_FILES
109 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
110 continue;
111 #endif
112 //ListBox_InsertItemData(pane->hWnd, idx, entry);
113 AddEntryToList(pane->hWnd, idx, entry);
114 ++idx;
115 }
116 ShowWindow(pane->hWnd, SW_SHOW);
117 }
118
119 static void CreateListColumns(HWND hWndListView)
120 {
121 char szText[50];
122 int index;
123 LV_COLUMN lvC;
124
125 // Create columns.
126 lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
127 lvC.fmt = LVCFMT_LEFT;
128 lvC.cx = 175;
129 lvC.pszText = szText;
130
131 // Load the column labels from the resource file.
132 for (index = 0; index < 4; index++) {
133 lvC.iSubItem = index;
134 LoadString(hInst, IDS_LIST_COLUMN_FIRST + index, szText, sizeof(szText));
135 if (ListView_InsertColumn(hWndListView, index, &lvC) == -1) {
136 // TODO: handle failure condition...
137 break;
138 }
139 }
140 }
141
142 static HWND CreateListView(HWND hwndParent, int id)
143 {
144 RECT rcClient; // dimensions of client area
145 HWND hwndLV; // handle to list view control
146
147 // Get the dimensions of the parent window's client area, and create the list view control.
148 GetClientRect(hwndParent, &rcClient);
149 hwndLV = CreateWindowEx(0, WC_LISTVIEW, "List View",
150 // WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT | LVS_NOCOLUMNHEADER,
151 WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT,
152 // WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_LIST | LVS_NOCOLUMNHEADER,
153 0, 0, rcClient.right, rcClient.bottom,
154 hwndParent, (HMENU)id, hInst, NULL);
155
156 // Initialize the image list, and add items to the control.
157 /*
158 if (!InitListViewImageLists(hwndLV) ||
159 !InitListViewItems(hwndLV, lpszPathName)) {
160 DestroyWindow(hwndLV);
161 return FALSE;
162 }
163 */
164 ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT);
165 CreateListColumns(hwndLV);
166
167 return hwndLV;
168 }
169
170 // OnGetDispInfo - processes the LVN_GETDISPINFO
171 // notification message.
172
173 void OnGetDispInfo(NMLVDISPINFO* plvdi)
174 {
175 static char buffer[200];
176
177 // LVITEM* pItem = &(plvdi->item);
178 // Entry* entry = (Entry*)pItem->lParam;
179 Entry* entry = (Entry*)plvdi->item.lParam;
180 ASSERT(entry);
181
182 switch (plvdi->item.iSubItem) {
183 case 0:
184 plvdi->item.pszText = entry->data.cFileName;
185 // item.cchTextMax = strlen(entry->data.cFileName);
186 // plvdi->item.pszText = rgPetInfo[plvdi->item.iItem].szKind;
187 break;
188 case 1:
189 if (entry->bhfi_valid) {
190 //entry->bhfi.nFileSizeLow;
191 //entry->bhfi.nFileSizeHigh;
192
193 //entry->bhfi.ftCreationTime
194
195 wsprintf(buffer, "%u", entry->bhfi.nFileSizeLow);
196 plvdi->item.pszText = buffer;
197 } else {
198 plvdi->item.pszText = "unknown";
199 }
200 break;
201 case 2:
202 plvdi->item.pszText = "TODO:";
203 break;
204 case 3:
205 //entry->bhfi.dwFileAttributes
206 // plvdi->item.pszText = "rhsa";
207 strcpy(buffer, " ");
208 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) strcat(buffer, "a"); else strcat(buffer, " ");
209 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) strcat(buffer, "c"); else strcat(buffer, " ");
210 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) strcat(buffer, "d"); else strcat(buffer, " ");
211 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) strcat(buffer, "e"); else strcat(buffer, " ");
212 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) strcat(buffer, "h"); else strcat(buffer, " ");
213 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) strcat(buffer, "n"); else strcat(buffer, " ");
214 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) strcat(buffer, "o"); else strcat(buffer, " ");
215 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) strcat(buffer, "r"); else strcat(buffer, " ");
216 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) strcat(buffer, "p"); else strcat(buffer, " ");
217 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) strcat(buffer, "f"); else strcat(buffer, " ");
218 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) strcat(buffer, "s"); else strcat(buffer, " ");
219 if (entry->bhfi.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) strcat(buffer, "t"); else strcat(buffer, " ");
220 plvdi->item.pszText = buffer;
221 /*
222 FILE_ATTRIBUTE_ARCHIVE The file or directory is an archive file. Applications use this attribute to mark files for backup or removal.
223 FILE_ATTRIBUTE_COMPRESSED The file or directory is compressed. For a file, this means that all of the data in the file is compressed. For a directory, this means that compression is the default for newly created files and subdirectories.
224 FILE_ATTRIBUTE_DIRECTORY The handle identifies a directory.
225 FILE_ATTRIBUTE_ENCRYPTED The file or directory is encrypted. For a file, this means that all data in the file is encrypted. For a directory, this means that encryption is the default for newly created files and subdirectories.
226 FILE_ATTRIBUTE_HIDDEN The file or directory is hidden. It is not included in an ordinary directory listing.
227 FILE_ATTRIBUTE_NORMAL The file has no other attributes. This attribute is valid only if used alone.
228 FILE_ATTRIBUTE_OFFLINE The file data is not immediately available. This attribute indicates that the file data has been physically moved to offline storage. This attribute is used by Remote Storage, the hierarchical storage management software in Windows 2000. Applications should not arbitrarily change this attribute.
229 FILE_ATTRIBUTE_READONLY The file or directory is read-only. Applications can read the file but cannot write to it or delete it. In the case of a directory, applications cannot delete it.
230 FILE_ATTRIBUTE_REPARSE_POINT The file has an associated reparse point.
231 FILE_ATTRIBUTE_SPARSE_FILE The file is a sparse file.
232 FILE_ATTRIBUTE_SYSTEM The file or directory is part of the operating system or is used exclusively by the operating system.
233 FILE_ATTRIBUTE_TEMPORARY The file is being used for temporary storage. File systems attempt to keep all the data in memory for quicker access, rather than flushing the data back to mass storage. A temporary file should be deleted by the application as soon as it is no longer needed.
234 */
235 break;
236 default:
237 break;
238 }
239 }
240 /*
241 typedef struct _BY_HANDLE_FILE_INFORMATION {
242 DWORD dwFileAttributes;
243 FILETIME ftCreationTime;
244 FILETIME ftLastAccessTime;
245 FILETIME ftLastWriteTime;
246 DWORD dwVolumeSerialNumber;
247 DWORD nFileSizeHigh;
248 DWORD nFileSizeLow;
249 DWORD nNumberOfLinks;
250 DWORD nFileIndexHigh;
251 DWORD nFileIndexLow;
252 } BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION;
253 */
254
255
256 // OnEndLabelEdit - processes the LVN_ENDLABELEDIT
257 // notification message.
258 // Returns TRUE if the label is changed, or FALSE otherwise.
259
260 BOOL OnEndLabelEdit(NMLVDISPINFO* plvdi)
261 {
262 if (plvdi->item.iItem == -1)
263 return FALSE;
264
265 // Copy the new label text to the application-defined structure.
266 // lstrcpyn(rgPetInfo[plvdi->item.iItem].szKind, plvdi->item.pszText, 10);
267
268 return TRUE;
269 // To make a more robust application you should send an EM_LIMITTEXT
270 // message to the edit control to prevent the user from entering too
271 // many characters in the field.
272 }
273
274
275 ////////////////////////////////////////////////////////////////////////////////
276 static WNDPROC g_orgListWndProc;
277
278 static LRESULT CALLBACK ListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
279 {
280 ChildWnd* child = (ChildWnd*)GetWindowLong(GetParent(hWnd), GWL_USERDATA);
281 Pane* pane = (Pane*)GetWindowLong(hWnd, GWL_USERDATA);
282 ASSERT(child);
283
284 switch (message) {
285 /*
286 case WM_CREATE:
287 //CreateListView(hWnd);
288 return 0;
289 */
290 case WM_NOTIFY:
291 switch (((LPNMHDR)lParam)->code) {
292 case LVN_GETDISPINFO:
293 OnGetDispInfo((NMLVDISPINFO*)lParam);
294 break;
295 case LVN_ENDLABELEDIT:
296 return OnEndLabelEdit((NMLVDISPINFO*)lParam);
297 break;
298 }
299 break;
300 // return 0;
301
302 case WM_SETFOCUS:
303 child->nFocusPanel = pane==&child->right? 1: 0;
304 ListBox_SetSel(hWnd, TRUE, 1);
305 //TODO: check menu items
306 break;
307
308 case WM_KEYDOWN:
309 if (wParam == VK_TAB) {
310 //TODO: SetFocus(Globals.hDriveBar)
311 SetFocus(child->nFocusPanel? child->left.hWnd: child->right.hWnd);
312 }
313 }
314 return CallWindowProc(g_orgListWndProc, hWnd, message, wParam, lParam);
315 }
316
317
318 void CreateListWnd(HWND parent, Pane* pane, int id, LPSTR lpszPathName)
319 {
320 // static int s_init = 0;
321 Entry* entry = pane->root;
322
323 pane->treePane = 0;
324 #if 1
325 pane->hWnd = CreateListView(parent, id);
326 #else
327 pane->hWnd = CreateWindow(_T("ListBox"), _T(""), WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
328 LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED|LBS_NOTIFY,
329 0, 0, 0, 0, parent, (HMENU)id, Globals.hInstance, 0);
330 #endif
331 SetWindowLong(pane->hWnd, GWL_USERDATA, (LPARAM)pane);
332 g_orgListWndProc = SubclassWindow(pane->hWnd, ListWndProc);
333 SendMessage(pane->hWnd, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
334
335 // insert entries into listbox
336 if (entry)
337 InsertListEntries(pane, entry, -1);
338
339 // calculate column widths
340 // if (!s_init) {
341 // s_init = 1;
342 // init_output(pane->hWnd);
343 // }
344 // calc_widths(pane, TRUE);
345 }
346