[WIN32K][CONSRV]
[reactos.git] / rosapps / applications / explorer-old / taskbar / favorites.cpp
1 /*
2 * Copyright 2004, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19
20 //
21 // Explorer and Desktop clone
22 //
23 // favorites.cpp
24 //
25 // Martin Fuchs, 04.04.2004
26 //
27
28
29 #include <precomp.h>
30
31 #include "startmenu.h"
32
33
34 String DecodeURLString(const char* s)
35 {
36 TCHAR buffer[BUFFER_LEN];
37 LPTSTR o = buffer;
38
39 for(const char* p=s; *p; ++p)
40 if (*p == '%') {
41 if (!strncmp(p+1, "20", 2)) {
42 *o++ = ' ';
43 p += 2;
44 } else
45 *o++ = *p;
46 } else
47 *o++ = *p;
48
49 return String(buffer, o-buffer);
50 }
51
52
53 /// read .URL file
54 bool Bookmark::read_url(LPCTSTR path)
55 {
56 char line[BUFFER_LEN];
57
58 tifstream in(path);
59
60 while(in.good()) {
61 in.getline(line, BUFFER_LEN);
62
63 const char* p = line;
64 while(isspace(*p))
65 ++p;
66
67 const char* keyword = p;
68 const char* eq = strchr(p, '=');
69
70 if (eq) {
71 const char* cont = eq + 1;
72 while(isspace(*cont))
73 ++cont;
74
75 if (!_strnicmp(keyword, "URL", 3))
76 _url = DecodeURLString(cont);
77 else if (!_strnicmp(keyword, "IconFile", 8))
78 _icon_path = DecodeURLString(cont);
79 }
80 }
81
82 return true;
83 }
84
85 /// convert XBEL bookmark node
86 bool Bookmark::read(const_XMLPos& pos)
87 {
88 _url = pos.get("href").c_str();
89
90 if (pos.go_down("title")) {
91 _name = pos->get_content();
92 pos.back();
93 }
94
95 if (pos.go_down("desc")) {
96 _description = pos->get_content();
97 pos.back();
98 }
99
100 if (pos.go_down("info")) {
101 const_XMLChildrenFilter metadata(pos, "metadata");
102
103 for(const_XMLChildrenFilter::const_iterator it=metadata.begin(); it!=metadata.end(); ++it) {
104 const XMLNode& node = **it;
105 const_XMLPos sub_pos(&node);
106
107 if (node.get("owner") == "ros-explorer") {
108 if (sub_pos.go_down("icon")) {
109 _icon_path = sub_pos.get("path").c_str();
110 _icon_idx = XS_toi(sub_pos.get("index"));
111
112 sub_pos.back(); // </icon>
113 }
114 }
115 }
116
117 pos.back(); // </metadata>
118 pos.back(); // </info>
119 }
120
121 return !_url.empty(); // _url is mandatory.
122 }
123
124 /// write XBEL bookmark node
125 void Bookmark::write(XMLPos& pos) const
126 {
127 pos.create("bookmark");
128
129 pos["href"] = _url.c_str();
130
131 if (!_name.empty()) {
132 pos.create("title");
133 pos->set_content(_name);
134 pos.back();
135 }
136
137 if (!_description.empty()) {
138 pos.create("desc");
139 pos->set_content(_description);
140 pos.back();
141 }
142
143 if (!_icon_path.empty()) {
144 pos.create("info");
145 pos.create("metadata");
146 pos["owner"] = "ros-explorer";
147 pos.create("icon");
148 pos["path"] = _icon_path.c_str();
149 pos["index"].printf(XS_TEXT("%d"), _icon_idx);
150 pos.back(); // </icon>
151 pos.back(); // </metadata>
152 pos.back(); // </info>
153 }
154
155 pos.back();
156 }
157
158
159 /// read bookmark folder from XBEL formated XML tree
160 void BookmarkFolder::read(const_XMLPos& pos)
161 {
162 if (pos.go_down("title")) {
163 _name = pos->get_content();
164 pos.back();
165 }
166
167 if (pos.go_down("desc")) {
168 _description = pos->get_content();
169 pos.back();
170 }
171
172 _bookmarks.read(pos);
173 }
174
175 /// write bookmark folder content from XBEL formated XML tree
176 void BookmarkFolder::write(XMLPos& pos) const
177 {
178 pos.create("folder");
179
180 if (!_name.empty()) {
181 pos.create("title");
182 pos->set_content(_name);
183 pos.back();
184 }
185
186 if (!_description.empty()) {
187 pos.create("desc");
188 pos->set_content(_description);
189 pos.back();
190 }
191
192 _bookmarks.write(pos);
193 }
194
195
196 BookmarkNode::BookmarkNode()
197 : _type(BMNT_NONE)
198 {
199 _pbookmark = NULL;
200 }
201
202 BookmarkNode::BookmarkNode(const Bookmark& bm)
203 : _type(BMNT_BOOKMARK)
204 {
205 _pbookmark = new Bookmark(bm);
206 }
207
208 BookmarkNode::BookmarkNode(const BookmarkFolder& bmf)
209 : _type(BMNT_FOLDER)
210 {
211 _pfolder = new BookmarkFolder(bmf);
212 }
213
214 BookmarkNode::BookmarkNode(const BookmarkNode& other)
215 : _type(other._type)
216 {
217 if (other._type == BMNT_BOOKMARK)
218 _pbookmark = new Bookmark(*other._pbookmark);
219 else if (other._type == BMNT_FOLDER)
220 _pfolder = new BookmarkFolder(*other._pfolder);
221 else
222 _pbookmark = NULL;
223 }
224
225 BookmarkNode::~BookmarkNode()
226 {
227 if (_type == BMNT_BOOKMARK)
228 delete _pbookmark;
229 else if (_type == BMNT_FOLDER)
230 delete _pfolder;
231 }
232
233 BookmarkNode& BookmarkNode::operator=(const Bookmark& bm)
234 {
235 clear();
236
237 _pbookmark = new Bookmark(bm);
238
239 return *this;
240 }
241
242 BookmarkNode& BookmarkNode::operator=(const BookmarkFolder& bmf)
243 {
244 clear();
245
246 _pfolder = new BookmarkFolder(bmf);
247
248 return *this;
249 }
250
251 BookmarkNode& BookmarkNode::operator=(const BookmarkNode& other)
252 {
253 clear();
254
255 _type = other._type;
256
257 if (other._type == BMNT_BOOKMARK)
258 _pbookmark = new Bookmark(*other._pbookmark);
259 else if (other._type == BMNT_FOLDER)
260 _pfolder = new BookmarkFolder(*other._pfolder);
261
262 return *this;
263 }
264
265 void BookmarkNode::clear()
266 {
267 if (_type == BMNT_BOOKMARK) {
268 delete _pbookmark;
269 _pbookmark = NULL;
270 }
271 else if (_type == BMNT_FOLDER) {
272 delete _pfolder;
273 _pfolder = NULL;
274 }
275
276 _type = BMNT_NONE;
277 }
278
279
280 /// read bookmark list from XBEL formated XML tree
281 void BookmarkList::read(const_XMLPos& pos)
282 {
283 const XMLNode::Children& children = pos->get_children();
284
285 for(XMLNode::Children::const_iterator it=children.begin(); it!=children.end(); ++it) {
286 const XMLNode& node = **it;
287 const_XMLPos sub_pos(&node);
288
289 if (node == "folder") {
290 BookmarkFolder folder;
291
292 folder.read(sub_pos);
293
294 push_back(folder);
295 } else if (node == "bookmark") {
296 Bookmark bookmark;
297
298 if (bookmark.read(sub_pos))
299 push_back(bookmark);
300 }
301 }
302 }
303
304 /// write bookmark list into XBEL formated XML tree
305 void BookmarkList::write(XMLPos& pos) const
306 {
307 for(const_iterator it=begin(); it!=end(); ++it) {
308 const BookmarkNode& node = *it;
309
310 if (node._type == BookmarkNode::BMNT_FOLDER) {
311 const BookmarkFolder& folder = *node._pfolder;
312
313 folder.write(pos);
314
315 pos.back();
316 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
317 const Bookmark& bookmark = *node._pbookmark;
318
319 if (!bookmark._url.empty())
320 bookmark.write(pos);
321 }
322 }
323 }
324
325
326 /// fill treeview control with bookmark tree content
327 void BookmarkList::fill_tree(HWND hwnd, HTREEITEM parent, HIMAGELIST himagelist, HDC hdc_wnd) const
328 {
329 TV_INSERTSTRUCT tvi;
330
331 tvi.hParent = parent;
332 tvi.hInsertAfter = TVI_LAST;
333
334 TV_ITEM& tv = tvi.item;
335 tv.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
336
337 for(const_iterator it=begin(); it!=end(); ++it) {
338 const BookmarkNode& node = *it;
339
340 tv.lParam = (LPARAM)&node;
341
342 if (node._type == BookmarkNode::BMNT_FOLDER) {
343 const BookmarkFolder& folder = *node._pfolder;
344
345 tv.pszText = (LPTSTR)folder._name.c_str();
346 tv.iImage = 3; // folder
347 tv.iSelectedImage = 4; // open folder
348 HTREEITEM hitem = TreeView_InsertItem(hwnd, &tvi);
349
350 folder._bookmarks.fill_tree(hwnd, hitem, himagelist, hdc_wnd);
351 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
352 const Bookmark& bookmark = *node._pbookmark;
353
354 tv.pszText = (LPTSTR)bookmark._name.c_str();
355 tv.iImage = 1; // bookmark
356 tv.iSelectedImage = 2; // selected bookmark
357
358 if (!bookmark._icon_path.empty()) {
359 const Icon& icon = g_Globals._icon_cache.extract(bookmark._icon_path, bookmark._icon_idx);
360
361 if ((ICON_ID)icon != ICID_NONE)
362 tv.iImage = tv.iSelectedImage = icon.add_to_imagelist(himagelist, hdc_wnd);
363 }
364
365 (void)TreeView_InsertItem(hwnd, &tvi);
366 }
367 }
368 }
369
370
371 /// import Internet Explorer bookmarks from Favorites folder into bookmark list
372 void BookmarkList::import_IE_favorites(ShellDirectory& dir, HWND hwnd)
373 {
374 TCHAR path[MAX_PATH], ext[_MAX_EXT];
375
376 dir.smart_scan(SORT_NAME, SCAN_DONT_EXTRACT_ICONS);
377
378 for(Entry*entry=dir._down; entry; entry=entry->_next) {
379 if (entry->_shell_attribs & SFGAO_HIDDEN) // ignore files like "desktop.ini"
380 continue;
381
382 String name;
383
384 if (entry->_etype == ET_SHELL)
385 name = dir._folder.get_name(static_cast<ShellEntry*>(entry)->_pidl);
386 else
387 name = entry->_display_name;
388
389 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
390 BookmarkFolder new_folder;
391
392 new_folder._name = DecodeXMLString(name);
393
394 if (entry->_etype == ET_SHELL) {
395 ShellDirectory new_dir(dir._folder, static_cast<ShellEntry*>(entry)->_pidl, hwnd);
396 new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
397 } else {
398 entry->get_path(path, COUNTOF(path));
399 ShellDirectory new_dir(GetDesktopFolder(), path, hwnd);
400 new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
401 }
402
403 push_back(new_folder);
404 } else {
405 Bookmark bookmark;
406
407 bookmark._name = DecodeXMLString(name);
408
409 entry->get_path(path, COUNTOF(path));
410 _tsplitpath_s(path, NULL, 0, NULL, 0, NULL, 0, ext, COUNTOF(ext));
411
412 if (!_tcsicmp(ext, TEXT(".url"))) {
413 bookmark.read_url(path);
414 push_back(bookmark);
415 } else {
416 ///@todo read shell links
417 //assert(0);
418 }
419 }
420 }
421 }
422
423
424 /// read XBEL bookmark file
425 bool Favorites::read(LPCTSTR path)
426 {
427 XMLDoc xbel;
428
429 if (!xbel.read_file(path)) {
430 if (!xbel._errors.empty())
431 MessageBox(g_Globals._hwndDesktop, xbel._errors.str(),
432 TEXT("ROS Explorer - reading bookmark file"), MB_OK);
433 }
434
435 const_XMLPos pos(&xbel);
436
437 if (!pos.go_down("xbel"))
438 return false;
439
440 super::read(pos);
441
442 pos.back();
443
444 return true;
445 }
446
447 /// write XBEL bookmark file
448 void Favorites::write(LPCTSTR path) const
449 {
450 XMLDoc xbel;
451
452 XMLPos pos(&xbel);
453 pos.create("xbel");
454 super::write(pos);
455 pos.back();
456
457 xbel._format._doctype._name = "xbel";
458 xbel._format._doctype._public = "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML";
459 xbel._format._doctype._system = "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd";
460
461 xbel.write_file(path);
462 }
463
464 /// import Internet Explorer bookmarks from Favorites folder
465 bool Favorites::import_IE_favorites(HWND hwnd)
466 {
467 WaitCursor wait;
468
469 StartMenuShellDirs dirs;
470
471 try {
472 dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_FAVORITES, hwnd), hwnd));
473 dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_FAVORITES, hwnd), hwnd));
474 } catch(COMException&) {
475 }
476
477 for(StartMenuShellDirs::iterator it=dirs.begin(); it!=dirs.end(); ++it) {
478 StartMenuDirectory& smd = *it;
479 ShellDirectory& dir = smd._dir;
480
481 try {
482 super::import_IE_favorites(dir, hwnd);
483 } catch(COMException&) {
484 }
485 }
486
487 return true;
488 }