/* * Copyright 2004, 2006, 2010 Martin Fuchs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // // Explorer and Desktop clone // // favorites.cpp // // Martin Fuchs, 04.04.2004 // #include #include "startmenu.h" String DecodeURLString(const char* s) { TCHAR buffer[BUFFER_LEN]; LPTSTR o = buffer; for(const char* p=s; *p; ++p) if (*p == '%') { if (!strncmp(p+1, "20", 2)) { *o++ = ' '; p += 2; } else *o++ = *p; } else *o++ = *p; return String(buffer, o-buffer); } /// read .URL file bool Bookmark::read_url(LPCTSTR path) { char line[BUFFER_LEN]; tifstream in(path); while(in.good()) { in.getline(line, BUFFER_LEN); const char* p = line; while(isspace(*p)) ++p; const char* keyword = p; const char* eq = strchr(p, '='); if (eq) { const char* cont = eq + 1; while(isspace(*cont)) ++cont; if (!_strnicmp(keyword, "URL", 3)) _url = DecodeURLString(cont); else if (!_strnicmp(keyword, "IconFile", 8)) _icon_path = DecodeURLString(cont); } } return true; } /// convert XBEL bookmark node bool Bookmark::read(const_XMLPos& pos) { _url = pos.get("href").c_str(); if (pos.go_down("title")) { _name = pos->get_content(); pos.back(); } if (pos.go_down("desc")) { _description = pos->get_content(); pos.back(); } if (pos.go_down("info")) { const_XMLChildrenFilter metadata(pos, "metadata"); for(const_XMLChildrenFilter::const_iterator it=metadata.begin(); it!=metadata.end(); ++it) { const XMLNode& node = **it; const_XMLPos sub_pos(&node); if (node.get("owner") == "ros-explorer") { if (sub_pos.go_down("icon")) { _icon_path = sub_pos.get("path").c_str(); _icon_idx = XS_toi(sub_pos.get("index")); sub_pos.back(); // } } } pos.back(); // pos.back(); // } return !_url.empty(); // _url is mandatory. } /// write XBEL bookmark node void Bookmark::write(XMLPos& pos) const { pos.create("bookmark"); pos["href"] = _url.c_str(); if (!_name.empty()) { pos.create("title"); pos->set_content(_name); pos.back(); } if (!_description.empty()) { pos.create("desc"); pos->set_content(_description); pos.back(); } if (!_icon_path.empty()) { pos.create("info"); pos.create("metadata"); pos["owner"] = "ros-explorer"; pos.create("icon"); pos["path"] = _icon_path.c_str(); pos["index"].printf(XS_TEXT("%d"), _icon_idx); pos.back(); // pos.back(); // pos.back(); // } pos.back(); } /// read bookmark folder from XBEL formated XML tree void BookmarkFolder::read(const_XMLPos& pos) { if (pos.go_down("title")) { _name = pos->get_content(); pos.back(); } if (pos.go_down("desc")) { _description = pos->get_content(); pos.back(); } _bookmarks.read(pos); } /// write bookmark folder content from XBEL formated XML tree void BookmarkFolder::write(XMLPos& pos) const { pos.create("folder"); if (!_name.empty()) { pos.create("title"); pos->set_content(_name); pos.back(); } if (!_description.empty()) { pos.create("desc"); pos->set_content(_description); pos.back(); } _bookmarks.write(pos); } BookmarkNode::BookmarkNode() : _type(BMNT_NONE) { _pbookmark = NULL; } BookmarkNode::BookmarkNode(const Bookmark& bm) : _type(BMNT_BOOKMARK) { _pbookmark = new Bookmark(bm); } BookmarkNode::BookmarkNode(const BookmarkFolder& bmf) : _type(BMNT_FOLDER) { _pfolder = new BookmarkFolder(bmf); } BookmarkNode::BookmarkNode(const BookmarkNode& other) : _type(other._type) { if (other._type == BMNT_BOOKMARK) _pbookmark = new Bookmark(*other._pbookmark); else if (other._type == BMNT_FOLDER) _pfolder = new BookmarkFolder(*other._pfolder); else _pbookmark = NULL; } BookmarkNode::~BookmarkNode() { if (_type == BMNT_BOOKMARK) delete _pbookmark; else if (_type == BMNT_FOLDER) delete _pfolder; } BookmarkNode& BookmarkNode::operator=(const Bookmark& bm) { clear(); _pbookmark = new Bookmark(bm); return *this; } BookmarkNode& BookmarkNode::operator=(const BookmarkFolder& bmf) { clear(); _pfolder = new BookmarkFolder(bmf); return *this; } BookmarkNode& BookmarkNode::operator=(const BookmarkNode& other) { clear(); _type = other._type; if (other._type == BMNT_BOOKMARK) _pbookmark = new Bookmark(*other._pbookmark); else if (other._type == BMNT_FOLDER) _pfolder = new BookmarkFolder(*other._pfolder); return *this; } void BookmarkNode::clear() { if (_type == BMNT_BOOKMARK) { delete _pbookmark; _pbookmark = NULL; } else if (_type == BMNT_FOLDER) { delete _pfolder; _pfolder = NULL; } _type = BMNT_NONE; } /// read bookmark list from XBEL formated XML tree void BookmarkList::read(const_XMLPos& pos) { const XMLNode::Children& children = pos->get_children(); for(XMLNode::Children::const_iterator it=children.begin(); it!=children.end(); ++it) { const XMLNode& node = **it; const_XMLPos sub_pos(&node); if (node == "folder") { BookmarkFolder folder; folder.read(sub_pos); push_back(folder); } else if (node == "bookmark") { Bookmark bookmark; if (bookmark.read(sub_pos)) push_back(bookmark); } } } /// write bookmark list into XBEL formated XML tree void BookmarkList::write(XMLPos& pos) const { for(const_iterator it=begin(); it!=end(); ++it) { const BookmarkNode& node = *it; if (node._type == BookmarkNode::BMNT_FOLDER) { const BookmarkFolder& folder = *node._pfolder; folder.write(pos); pos.back(); } else if (node._type == BookmarkNode::BMNT_BOOKMARK) { const Bookmark& bookmark = *node._pbookmark; if (!bookmark._url.empty()) bookmark.write(pos); } } } /// fill treeview control with bookmark tree content void BookmarkList::fill_tree(HWND hwnd, HTREEITEM parent, HIMAGELIST himagelist, HDC hdc_wnd) const { TV_INSERTSTRUCT tvi; tvi.hParent = parent; tvi.hInsertAfter = TVI_LAST; TV_ITEM& tv = tvi.item; tv.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM; for(const_iterator it=begin(); it!=end(); ++it) { const BookmarkNode& node = *it; tv.lParam = (LPARAM)&node; if (node._type == BookmarkNode::BMNT_FOLDER) { const BookmarkFolder& folder = *node._pfolder; tv.pszText = (LPTSTR)folder._name.c_str(); tv.iImage = 3; // folder tv.iSelectedImage = 4; // open folder HTREEITEM hitem = TreeView_InsertItem(hwnd, &tvi); folder._bookmarks.fill_tree(hwnd, hitem, himagelist, hdc_wnd); } else if (node._type == BookmarkNode::BMNT_BOOKMARK) { const Bookmark& bookmark = *node._pbookmark; tv.pszText = (LPTSTR)bookmark._name.c_str(); tv.iImage = 1; // bookmark tv.iSelectedImage = 2; // selected bookmark if (!bookmark._icon_path.empty()) { const Icon& icon = g_Globals._icon_cache.extract(bookmark._icon_path, bookmark._icon_idx); if ((ICON_ID)icon != ICID_NONE) tv.iImage = tv.iSelectedImage = icon.add_to_imagelist(himagelist, hdc_wnd); } (void)TreeView_InsertItem(hwnd, &tvi); } } } /// import Internet Explorer bookmarks from Favorites folder into bookmark list void BookmarkList::import_IE_favorites(ShellDirectory& dir, HWND hwnd) { TCHAR path[MAX_PATH], ext[_MAX_EXT]; dir.smart_scan(SORT_NAME, SCAN_DONT_EXTRACT_ICONS); for(Entry*entry=dir._down; entry; entry=entry->_next) { if (entry->_shell_attribs & SFGAO_HIDDEN) // ignore files like "desktop.ini" continue; String name; if (entry->_etype == ET_SHELL) name = dir._folder.get_name(static_cast(entry)->_pidl); else name = entry->_display_name; if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { BookmarkFolder new_folder; new_folder._name = DecodeXMLString(name); if (entry->_etype == ET_SHELL) { ShellDirectory new_dir(dir._folder, static_cast(entry)->_pidl, hwnd); new_folder._bookmarks.import_IE_favorites(new_dir, hwnd); } else { entry->get_path(path, COUNTOF(path)); ShellDirectory new_dir(GetDesktopFolder(), path, hwnd); new_folder._bookmarks.import_IE_favorites(new_dir, hwnd); } push_back(new_folder); } else { Bookmark bookmark; bookmark._name = DecodeXMLString(name); entry->get_path(path, COUNTOF(path)); _tsplitpath_s(path, NULL, 0, NULL, 0, NULL, 0, ext, COUNTOF(ext)); if (!_tcsicmp(ext, TEXT(".url"))) { bookmark.read_url(path); push_back(bookmark); } else { ///@todo read shell links //assert(0); } } } } /// read XBEL bookmark file bool Favorites::read(LPCTSTR path) { XMLDoc xbel; if (!xbel.read_file(path)) { if (!xbel._errors.empty()) MessageBox(g_Globals._hwndDesktop, xbel._errors.str(), TEXT("ROS Explorer - reading bookmark file"), MB_OK); } const_XMLPos pos(&xbel); if (!pos.go_down("xbel")) return false; super::read(pos); pos.back(); return true; } /// write XBEL bookmark file void Favorites::write(LPCTSTR path) const { XMLDoc xbel; XMLPos pos(&xbel); pos.create("xbel"); super::write(pos); pos.back(); xbel._format._doctype._name = "xbel"; xbel._format._doctype._public = "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML"; xbel._format._doctype._system = "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd"; xbel.write_file(path); } /// import Internet Explorer bookmarks from Favorites folder bool Favorites::import_IE_favorites(HWND hwnd) { WaitCursor wait; StartMenuShellDirs dirs; try { dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_FAVORITES, hwnd), hwnd)); dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_FAVORITES, hwnd), hwnd)); } catch(COMException&) { } for(StartMenuShellDirs::iterator it=dirs.begin(); it!=dirs.end(); ++it) { StartMenuDirectory& smd = *it; ShellDirectory& dir = smd._dir; try { super::import_IE_favorites(dir, hwnd); } catch(COMException&) { } } return true; }