Implemented explorer and desktop window using shell views
[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"
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 _level = 0;
46 _hicon = 0;
47 }
48
49 Entry::Entry(Entry* parent)
50 : _etype(parent->_etype),
51 _up(parent)
52 {
53 _next = NULL;
54 _down = NULL;
55 _expanded = false;
56 _scanned = false;
57 _level = 0;
58 _hicon = 0;
59 }
60
61 // free a directory entry
62 Entry::~Entry()
63 {
64 if (_hicon && _hicon!=(HICON)-1)
65 DestroyIcon(_hicon);
66 }
67
68
69 // read directory tree and expand to the given location
70 Entry* Entry::read_tree(const void* path, SORT_ORDER sortOrder)
71 {
72 HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
73
74 Entry* entry = this;
75 Entry* next_entry = entry;
76
77 for(const void*p=path; p&&next_entry; p=entry->get_next_path_component(p)) {
78 entry = next_entry;
79
80 entry->read_directory(sortOrder);
81
82 if (entry->_down)
83 entry->_expanded = true;
84
85 next_entry = entry->find_entry(p);
86 }
87
88 SetCursor(old_cursor);
89
90 return entry;
91 }
92
93
94 void Entry::read_directory(SORT_ORDER sortOrder)
95 {
96 // call into subclass
97 read_directory();
98
99 if (g_Globals._prescan_nodes) {
100 for(Entry*entry=_down; entry; entry=entry->_next)
101 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
102 entry->read_directory();
103 entry->sort_directory(sortOrder);
104 }
105 }
106
107 sort_directory(sortOrder);
108 }
109
110
111 Root::Root()
112 {
113 memset(this, 0, sizeof(Root));
114 }
115
116 Root::~Root()
117 {
118 if (_entry)
119 _entry->free_subentries();
120 }
121
122
123 // directories first...
124 static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
125 {
126 int dir1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
127 int dir2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
128
129 return dir2==dir1? 0: dir2<dir1? -1: 1;
130 }
131
132
133 static int compareName(const void* arg1, const void* arg2)
134 {
135 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
136 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
137
138 int cmp = compareType(fd1, fd2);
139 if (cmp)
140 return cmp;
141
142 return lstrcmpi(fd1->cFileName, fd2->cFileName);
143 }
144
145 static int compareExt(const void* arg1, const void* arg2)
146 {
147 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
148 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
149 const TCHAR *name1, *name2, *ext1, *ext2;
150
151 int cmp = compareType(fd1, fd2);
152 if (cmp)
153 return cmp;
154
155 name1 = fd1->cFileName;
156 name2 = fd2->cFileName;
157
158 ext1 = _tcsrchr(name1, TEXT('.'));
159 ext2 = _tcsrchr(name2, TEXT('.'));
160
161 if (ext1)
162 ++ext1;
163 else
164 ext1 = TEXT("");
165
166 if (ext2)
167 ++ext2;
168 else
169 ext2 = TEXT("");
170
171 cmp = lstrcmpi(ext1, ext2);
172 if (cmp)
173 return cmp;
174
175 return lstrcmpi(name1, name2);
176 }
177
178 static int compareSize(const void* arg1, const void* arg2)
179 {
180 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
181 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
182
183 int cmp = compareType(fd1, fd2);
184 if (cmp)
185 return cmp;
186
187 cmp = fd2->nFileSizeHigh - fd1->nFileSizeHigh;
188
189 if (cmp < 0)
190 return -1;
191 else if (cmp > 0)
192 return 1;
193
194 cmp = fd2->nFileSizeLow - fd1->nFileSizeLow;
195
196 return cmp<0? -1: cmp>0? 1: 0;
197 }
198
199 static int compareDate(const void* arg1, const void* arg2)
200 {
201 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->_data;
202 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->_data;
203
204 int cmp = compareType(fd1, fd2);
205 if (cmp)
206 return cmp;
207
208 return CompareFileTime(&fd2->ftLastWriteTime, &fd1->ftLastWriteTime);
209 }
210
211
212 static int (*sortFunctions[])(const void* arg1, const void* arg2) = {
213 compareName, // SORT_NAME
214 compareExt, // SORT_EXT
215 compareSize, // SORT_SIZE
216 compareDate // SORT_DATE
217 };
218
219
220 void Entry::sort_directory(SORT_ORDER sortOrder)
221 {
222 Entry* entry = _down;
223 Entry** array, **p;
224 int len;
225
226 len = 0;
227 for(entry=_down; entry; entry=entry->_next)
228 ++len;
229
230 if (len) {
231 array = (Entry**) alloca(len*sizeof(Entry*));
232
233 p = array;
234 for(entry=_down; entry; entry=entry->_next)
235 *p++ = entry;
236
237 // call qsort with the appropriate compare function
238 qsort(array, len, sizeof(array[0]), sortFunctions[sortOrder]);
239
240 _down = array[0];
241
242 for(p=array; --len; p++)
243 p[0]->_next = p[1];
244
245 (*p)->_next = 0;
246 }
247 }
248
249
250 BOOL Entry::launch_entry(HWND hwnd, UINT nCmdShow)
251 {
252 TCHAR cmd[MAX_PATH];
253
254 get_path(cmd);
255
256 // start program, open document...
257 return launch_file(hwnd, cmd, nCmdShow);
258 }
259
260
261 // recursively free all child entries
262 void Entry::free_subentries()
263 {
264 Entry *entry, *next=_down;
265
266 if (next) {
267 _down = 0;
268
269 do {
270 entry = next;
271 next = entry->_next;
272
273 entry->free_subentries();
274 delete entry;
275 } while(next);
276 }
277 }