update for HEAD-2003091401
[reactos.git] / 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  :      _etype(parent->_etype),
52         _up(parent)
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 }