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 } 489