* created a Makefile for compiling as standalone project using MinGW
[reactos.git] / reactos / subsys / system / explorer / shell / entries.cpp
1 /*
2 * Copyright 2003 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // entries.cpp
24 //
25 // Martin Fuchs, 23.07.2003
26 //
27
28
29 #include "../utility/utility.h"
30 #include "../utility/shellclasses.h"
31 #include "../globals.h" // for _prescan_nodes
32
33 #include "entries.h"
34
35
36 // allocate and initialise a directory entry
37 Entry::Entry(ENTRY_TYPE etype)
38 : _etype(etype)
39 {
40 _up = NULL;
41 _next = NULL;
42 _down = NULL;
43 _expanded = false;
44 _scanned = false;
45 _bhfi_valid = false;
46 _level = 0;
47 _hIcon = 0;
48 }
49
50 Entry::Entry(Entry* parent)
51 : _up(parent),
52 _etype(parent->_etype)
53 {
54 _next = NULL;
55 _down = NULL;
56 _expanded = false;
57 _scanned = false;
58 _bhfi_valid = false;
59 _level = 0;
60 _hIcon = 0;
61 }
62
63 // free a directory entry
64 Entry::~Entry()
65 {
66 if (_hIcon && _hIcon!=(HICON)-1)
67 DestroyIcon(_hIcon);
68 }
69
70
71 // read directory tree and expand to the given location
72 Entry* Entry::read_tree(const void* path, SORT_ORDER sortOrder)
73 {
74 HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
75
76 Entry* entry = this;
77 Entry* next_entry = entry;
78
79 for(const void*p=path; p&&next_entry; p=entry->get_next_path_component(p)) {
80 entry = next_entry;
81
82 entry->read_directory(sortOrder);
83
84 if (entry->_down)
85 entry->_expanded = true;
86
87 next_entry = entry->find_entry(p);
88 }
89
90 SetCursor(old_cursor);
91
92 return entry;
93 }
94
95
96 void Entry::read_directory(SORT_ORDER sortOrder)
97 {
98 // call into subclass
99 read_directory();
100
101 if (g_Globals._prescan_nodes) {
102 for(Entry*entry=_down; entry; entry=entry->_next)
103 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
104 entry->read_directory();
105 entry->sort_directory(sortOrder);
106 }
107 }
108
109 sort_directory(sortOrder);
110 }
111
112
113 Root::Root()
114 {
115 memset(this, 0, sizeof(Root));
116 }
117
118 Root::~Root()
119 {
120 if (_entry)
121 _entry->free_subentries();
122 }
123
124
125 // directories first...
126 static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
127 {
128 int dir1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
129 int dir2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
130
131 return dir2==dir1? 0: dir2<dir1? -1: 1;
132 }
133
134
135 static int compareName(const void* arg1, const void* arg2)
136 {
137 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
138 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
139
140 int cmp = compareType(fd1, fd2);
141 if (cmp)
142 return cmp;
143
144 return lstrcmpi(fd1->cFileName, fd2->cFileName);
145 }
146
147 static int compareExt(const void* arg1, const void* arg2)
148 {
149 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
150 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
151 const TCHAR *name1, *name2, *ext1, *ext2;
152
153 int cmp = compareType(fd1, fd2);
154 if (cmp)
155 return cmp;
156
157 name1 = fd1->cFileName;
158 name2 = fd2->cFileName;
159
160 ext1 = _tcsrchr(name1, TEXT('.'));
161 ext2 = _tcsrchr(name2, TEXT('.'));
162
163 if (ext1)
164 ++ext1;
165 else
166 ext1 = TEXT("");
167
168 if (ext2)
169 ++ext2;
170 else
171 ext2 = TEXT("");
172
173 cmp = lstrcmpi(ext1, ext2);
174 if (cmp)
175 return cmp;
176
177 return lstrcmpi(name1, name2);
178 }
179
180 static int compareSize(const void* arg1, const void* arg2)
181 {
182 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
183 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
184
185 int cmp = compareType(fd1, fd2);
186 if (cmp)
187 return cmp;
188
189 cmp = fd2->nFileSizeHigh - fd1->nFileSizeHigh;
190
191 if (cmp < 0)
192 return -1;
193 else if (cmp > 0)
194 return 1;
195
196 cmp = fd2->nFileSizeLow - fd1->nFileSizeLow;
197
198 return cmp<0? -1: cmp>0? 1: 0;
199 }
200
201 static int compareDate(const void* arg1, const void* arg2)
202 {
203 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
204 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
205
206 int cmp = compareType(fd1, fd2);
207 if (cmp)
208 return cmp;
209
210 return CompareFileTime(&fd2->ftLastWriteTime, &fd1->ftLastWriteTime);
211 }
212
213
214 static int (*sortFunctions[])(const void* arg1, const void* arg2) = {
215 compareName, // SORT_NAME
216 compareExt, // SORT_EXT
217 compareSize, // SORT_SIZE
218 compareDate // SORT_DATE
219 };
220
221
222 void Entry::sort_directory(SORT_ORDER sortOrder)
223 {
224 Entry* entry = _down;
225 Entry** array, **p;
226 int len;
227
228 len = 0;
229 for(entry=_down; entry; entry=entry->_next)
230 ++len;
231
232 if (len) {
233 array = (Entry**) alloca(len*sizeof(Entry*));
234
235 p = array;
236 for(entry=_down; entry; entry=entry->_next)
237 *p++ = entry;
238
239 // call qsort with the appropriate compare function
240 qsort(array, len, sizeof(array[0]), sortFunctions[sortOrder]);
241
242 _down = array[0];
243
244 for(p=array; --len; p++)
245 p[0]->_next = p[1];
246
247 (*p)->_next = 0;
248 }
249 }
250
251
252 void Entry::smart_scan()
253 {
254 if (!_scanned) {
255 free_subentries();
256 read_directory(SORT_NAME); // we could use IShellFolder2::GetDefaultColumn to determine sort order
257 }
258 }
259
260
261 BOOL Entry::launch_entry(HWND hwnd, UINT nCmdShow)
262 {
263 TCHAR cmd[MAX_PATH];
264
265 get_path(cmd);
266
267 // start program, open document...
268 return launch_file(hwnd, cmd, nCmdShow);
269 }
270
271
272 // recursively free all child entries
273 void Entry::free_subentries()
274 {
275 Entry *entry, *next=_down;
276
277 if (next) {
278 _down = 0;
279
280 do {
281 entry = next;
282 next = entry->_next;
283
284 entry->free_subentries();
285 delete entry;
286 } while(next);
287 }
288 }