Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2004, 2005 Richard Wilson <info@tinct.net>
  3.  * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
  4.  *
  5.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  6.  *
  7.  * NetSurf is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; version 2 of the License.
  10.  *
  11.  * NetSurf is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  */
  19.  
  20. #include <ctype.h>
  21. #include <stdlib.h>
  22.  
  23. #include "content/content.h"
  24. #include "content/hlcache.h"
  25. #include "content/urldb.h"
  26. #include "desktop/browser.h"
  27. #include "desktop/hotlist.h"
  28. #include "desktop/plotters.h"
  29. #include "desktop/tree.h"
  30. #include "desktop/tree_url_node.h"
  31.  
  32. #include "utils/messages.h"
  33. #include "utils/utils.h"
  34. #include "utils/log.h"
  35.  
  36. #define URL_CHUNK_LENGTH 512
  37.  
  38. static struct tree *hotlist_tree;
  39. static struct node *hotlist_tree_root;
  40.  
  41. static bool creating_node;
  42. static hlcache_handle *folder_icon;
  43.  
  44. static const struct {
  45.         const char *url;
  46.         const char *msg_key;
  47. } hotlist_default_entries[] = {
  48.         { "http://www.netsurf-browser.org/", "HotlistHomepage" },
  49.         { "http://www.netsurf-browser.org/downloads/riscos/testbuilds",
  50.           "HotlistTestBuild" },
  51.         { "http://www.netsurf-browser.org/documentation",
  52.           "HotlistDocumentation" },
  53.         { "http://sourceforge.net/tracker/?atid=464312&group_id=51719",
  54.           "HotlistBugTracker" },
  55.         { "http://sourceforge.net/tracker/?atid=464315&group_id=51719",
  56.           "HotlistFeatureRequest" }
  57. };
  58. #define HOTLIST_ENTRIES_COUNT (sizeof(hotlist_default_entries) / sizeof(hotlist_default_entries[0]))
  59.  
  60. static node_callback_resp hotlist_node_callback(void *user_data,
  61.                 struct node_msg_data *msg_data)
  62. {
  63.         struct node *node = msg_data->node;
  64.         const char *text;
  65.         char *norm_text;
  66.         bool is_folder = tree_node_is_folder(node);
  67.         bool cancelled = false;
  68.  
  69.         switch (msg_data->msg) {
  70.         case NODE_ELEMENT_EDIT_CANCELLED:
  71.                 cancelled = true;
  72.                 /* fall through */
  73.         case NODE_ELEMENT_EDIT_FINISHED:
  74.                 if (creating_node && !cancelled &&
  75.                     (is_folder == false) &&
  76.                     (msg_data->flag == TREE_ELEMENT_TITLE)) {
  77.                         tree_url_node_edit_url(hotlist_tree, node);
  78.                 } else {
  79.                         creating_node = false;
  80.                 }
  81.                 return NODE_CALLBACK_HANDLED;
  82.  
  83.         case NODE_ELEMENT_EDIT_FINISHING:
  84.                 if (creating_node && (is_folder == false))
  85.                         return tree_url_node_callback(hotlist_tree, msg_data);
  86.  
  87.                 if (is_folder == true) {
  88.                         text = msg_data->data.text;
  89.                         while (isspace(*text))
  90.                                 text++;
  91.                         norm_text = strdup(text);
  92.                         if (norm_text == NULL) {
  93.                                 LOG(("malloc failed"));
  94.                                 warn_user("NoMemory", 0);
  95.                                 return NODE_CALLBACK_REJECT;
  96.                         }
  97.                         /* don't allow zero length entry text, return false */
  98.                         if (norm_text[0] == '\0') {
  99.                                 warn_user("NoNameError", 0);
  100.                                 msg_data->data.text = NULL;
  101.                                 return NODE_CALLBACK_CONTINUE;
  102.                         }
  103.                         msg_data->data.text = norm_text;
  104.                 }
  105.                 break;
  106.  
  107.         case NODE_DELETE_ELEMENT_IMG:
  108.                 return NODE_CALLBACK_HANDLED;
  109.  
  110.         default:
  111.                 if (is_folder == false)
  112.                         return tree_url_node_callback(hotlist_tree, msg_data);
  113.         }
  114.  
  115.         return NODE_CALLBACK_NOT_HANDLED;
  116. }
  117.  
  118. /* exported interface documented in hotlist.h */
  119. bool hotlist_initialise(struct tree *tree, const char *hotlist_path,
  120.                 const char* folder_icon_name)
  121. {
  122.         struct node *node;
  123.         const struct url_data *url_data;
  124.         char *name;
  125.         int hlst_loop;
  126.  
  127.         /* Either load or create a hotlist */
  128.  
  129.         creating_node = false;
  130.  
  131.         folder_icon = tree_load_icon(folder_icon_name);
  132.  
  133.         tree_url_node_init(folder_icon_name);
  134.  
  135.         if (tree == NULL)
  136.                 return false;
  137.  
  138.         hotlist_tree = tree;
  139.         hotlist_tree_root = tree_get_root(hotlist_tree);
  140.  
  141.         if (tree_urlfile_load(hotlist_path, hotlist_tree,
  142.                         hotlist_node_callback, NULL)) {
  143.                 return true;
  144.         }
  145.  
  146.  
  147.         /* failed to load hotlist file, use default list */
  148.         name = strdup("NetSurf");
  149.         if (name == NULL) {
  150.                 LOG(("malloc failed"));
  151.                 warn_user("NoMemory", 0);
  152.                 return false;
  153.         }
  154.         node = tree_create_folder_node(hotlist_tree, hotlist_tree_root,
  155.                         name, true, false, false);
  156.         if (node == NULL) {
  157.                 free(name);
  158.                 return false;
  159.         }
  160.  
  161.         tree_set_node_user_callback(node, hotlist_node_callback, NULL);
  162.         tree_set_node_icon(hotlist_tree, node, folder_icon);
  163.  
  164.         for (hlst_loop = 0; hlst_loop != HOTLIST_ENTRIES_COUNT; hlst_loop++) {
  165.                 nsurl *url;
  166.                 if (nsurl_create(hotlist_default_entries[hlst_loop].url,
  167.                                 &url) != NSERROR_OK) {
  168.                         return false;
  169.                 }
  170.                 url_data = urldb_get_url_data(url);
  171.                 if (url_data == NULL) {
  172.                         urldb_add_url(url);
  173.                         urldb_set_url_persistence(url, true);
  174.                         url_data = urldb_get_url_data(url);
  175.                 }
  176.                 if (url_data != NULL) {
  177.                         tree_create_URL_node(hotlist_tree, node, url,
  178.                                         messages_get(hotlist_default_entries[hlst_loop].msg_key),
  179.                                         hotlist_node_callback, NULL);
  180.                         tree_update_URL_node(hotlist_tree, node, url, url_data);
  181.                 }
  182.                 nsurl_unref(url);
  183.         }
  184.  
  185.         return true;
  186. }
  187.  
  188.  
  189. /**
  190.  * Get flags with which the hotlist tree should be created;
  191.  *
  192.  * \return the flags
  193.  */
  194. unsigned int hotlist_get_tree_flags(void)
  195. {
  196.         return TREE_MOVABLE;
  197. }
  198.  
  199.  
  200. /**
  201.  * Deletes the global history tree and saves the hotlist.
  202.  * \param hotlist_path the path where the hotlist should be saved
  203.  */
  204. void hotlist_cleanup(const char *hotlist_path)
  205. {
  206.         hotlist_export(hotlist_path);
  207.         hlcache_handle_release(folder_icon);
  208.         tree_url_node_cleanup();
  209. }
  210.  
  211.  
  212. /**
  213.  * Informs the hotlist that some content has been visited. Internal procedure.
  214.  *
  215.  * \param content  the content visited
  216.  * \param node     the node to update siblings and children of
  217.  */
  218. static void hotlist_visited_internal(hlcache_handle *content, struct node *node)
  219. {
  220.         struct node *child;
  221.         const char *text;
  222.         const char *url;
  223.         nsurl *nsurl;
  224.  
  225.         if (content == NULL ||
  226.             hlcache_handle_get_url(content) == NULL ||
  227.             hotlist_tree == NULL)
  228.                 return;
  229.  
  230.         nsurl = hlcache_handle_get_url(content);
  231.         url = nsurl_access(nsurl);
  232.  
  233.         for (; node; node = tree_node_get_next(node)) {
  234.                 if (!tree_node_is_folder(node)) {
  235.                         text = tree_url_node_get_url(node);
  236.                         if (strcmp(text, url) == 0) {
  237.                                 tree_update_URL_node(hotlist_tree, node,
  238.                                                 nsurl, NULL);
  239.                         }
  240.                 }
  241.                 child = tree_node_get_child(node);
  242.                 if (child != NULL) {
  243.                         hotlist_visited_internal(content, child);
  244.                 }
  245.         }
  246. }
  247.  
  248. /**
  249.  * Informs the hotlist that some content has been visited
  250.  *
  251.  * \param content  the content visited
  252.  */
  253. void hotlist_visited(hlcache_handle *content)
  254. {
  255.         if (hotlist_tree != NULL) {
  256.                 hotlist_visited_internal(content, tree_get_root(hotlist_tree));
  257.         }
  258. }
  259.  
  260. /**
  261.  * Save the hotlist in a human-readable form under the given location.
  262.  *
  263.  * \param path the path where the hotlist will be saved
  264.  */
  265. bool hotlist_export(const char *path)
  266. {
  267.         return tree_urlfile_save(hotlist_tree, path, "NetSurf hotlist");
  268. }
  269.  
  270. /**
  271.  * Edit the node which is currently selected. Works only if one node is
  272.  * selected.
  273.  */
  274. void hotlist_edit_selected(void)
  275. {
  276.         struct node *node;
  277.         struct node_element *element;
  278.  
  279.         node = tree_get_selected_node(hotlist_tree_root);
  280.  
  281.         if (node != NULL) {
  282.                 creating_node = true;
  283.                 element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
  284.                 tree_start_edit(hotlist_tree, element);
  285.         }
  286. }
  287.  
  288. /**
  289.  * Delete nodes which are currently selected.
  290.  */
  291. void hotlist_delete_selected(void)
  292. {
  293.         tree_delete_selected_nodes(hotlist_tree, hotlist_tree_root);
  294. }
  295.  
  296. /**
  297.  * Select all nodes in the tree.
  298.  */
  299. void hotlist_select_all(void)
  300. {
  301.         tree_set_node_selected(hotlist_tree, hotlist_tree_root,
  302.                                true, true);
  303. }
  304.  
  305. /**
  306.  * Unselect all nodes.
  307.  */
  308. void hotlist_clear_selection(void)
  309. {
  310.         tree_set_node_selected(hotlist_tree, hotlist_tree_root,
  311.                                true, false);
  312. }
  313.  
  314. /**
  315.  * Expand grouping folders and history entries.
  316.  */
  317. void hotlist_expand_all(void)
  318. {
  319.         tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
  320.                                true, true, true);
  321. }
  322.  
  323. /**
  324.  * Expand grouping folders only.
  325.  */
  326. void hotlist_expand_directories(void)
  327. {
  328.         tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
  329.                                true, true, false);
  330. }
  331.  
  332. /**
  333.  * Expand history entries only.
  334.  */
  335. void hotlist_expand_addresses(void)
  336. {
  337.         tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
  338.                                true, false, true);
  339. }
  340.  
  341. /**
  342.  * Collapse grouping folders and history entries.
  343.  */
  344. void hotlist_collapse_all(void)
  345. {
  346.         tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
  347.                                false, true, true);
  348. }
  349.  
  350. /**
  351.  * Collapse grouping folders only.
  352.  */
  353. void hotlist_collapse_directories(void)
  354. {
  355.         tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
  356.                                false, true, false);
  357. }
  358.  
  359. /**
  360.  * Collapse history entries only.
  361.  */
  362. void hotlist_collapse_addresses(void)
  363. {
  364.         tree_set_node_expanded(hotlist_tree,
  365.                                hotlist_tree_root, false, false, true);
  366. }
  367.  
  368. /**
  369.  * Add a folder node.
  370.  *
  371.  * \param selected create the folder in the currently-selected node
  372.  */
  373. void hotlist_add_folder(bool selected)
  374. {
  375.         struct node *node, *parent = NULL;
  376.         struct node_element *element;
  377.         char *title = strdup("Untitled");
  378.  
  379.         if (title == NULL) {
  380.                 LOG(("malloc failed"));
  381.                 warn_user("NoMemory", 0);
  382.                 return;
  383.         }
  384.         creating_node = true;
  385.  
  386.         if (selected == true) {
  387.                 parent = tree_get_selected_node(tree_get_root(hotlist_tree));
  388.                 if (parent && (tree_node_is_folder(parent) == false)) {
  389.                         parent = tree_node_get_parent(parent);
  390.                 }
  391.         }
  392.  
  393.         if (parent == NULL) {
  394.                 parent = tree_get_default_folder_node(hotlist_tree);
  395.         }
  396.  
  397.         node = tree_create_folder_node(hotlist_tree, parent, title,
  398.                                        true, false, false);
  399.         if (node == NULL) {
  400.                 free(title);
  401.                 return;
  402.         }
  403.         tree_set_node_user_callback(node, hotlist_node_callback, NULL);
  404.         tree_set_node_icon(hotlist_tree, node, folder_icon);
  405.         element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
  406.         tree_start_edit(hotlist_tree, element);
  407. }
  408.  
  409. /**
  410.  * Add an entry node.
  411.  *
  412.  * \param selected add the entry in the currently-selected node
  413.  */
  414. void hotlist_add_entry(bool selected)
  415. {
  416.         struct node *node;
  417.         struct node *parent = NULL;
  418.         nsurl *url;
  419.         creating_node = true;
  420.  
  421.         if (selected == true) {
  422.                 parent = tree_get_selected_node(tree_get_root(hotlist_tree));
  423.                 if (parent && (tree_node_is_folder(parent) == false)) {
  424.                         parent = tree_node_get_parent(parent);
  425.                 }
  426.         }
  427.  
  428.         if (parent == NULL) {
  429.                 parent = tree_get_default_folder_node(hotlist_tree);
  430.         }
  431.  
  432.         if (nsurl_create("http://netsurf-browser.org/", &url) != NSERROR_OK)
  433.                 return;
  434.         node = tree_create_URL_node(hotlist_tree, parent, url, "Untitled",
  435.                         hotlist_node_callback, NULL);
  436.  
  437.         nsurl_unref(url);
  438.  
  439.         if (node == NULL)
  440.                 return;
  441.         tree_set_node_user_callback(node, hotlist_node_callback, NULL);
  442.         tree_url_node_edit_title(hotlist_tree, node);
  443. }
  444.  
  445. /**
  446.  * Adds the currently viewed page to the hotlist
  447.  */
  448. void hotlist_add_page(const char *url)
  449. {
  450.         const struct url_data *data;
  451.         struct node *node, *parent;
  452.         nsurl *nsurl;
  453.  
  454.         if (url == NULL)
  455.                 return;
  456.  
  457.         if (nsurl_create(url, &nsurl) != NSERROR_OK)
  458.                 return;
  459.  
  460.         data = urldb_get_url_data(nsurl);
  461.         if (data == NULL)
  462.                 return;
  463.  
  464.         parent = tree_get_default_folder_node(hotlist_tree);
  465.         node = tree_create_URL_node(hotlist_tree, parent, nsurl, NULL,
  466.                         hotlist_node_callback, NULL);
  467.         tree_update_URL_node(hotlist_tree, node, nsurl, data);
  468.         nsurl_unref(nsurl);
  469. }
  470.  
  471. /**
  472.  * Adds the currently viewed page to the hotlist at the given co-ordinates
  473.  * \param url   url of the page
  474.  * \param x     X cooridinate with respect to tree origin
  475.  * \param y     Y cooridinate with respect to tree origin
  476.  */
  477. void hotlist_add_page_xy(const char *url, int x, int y)
  478. {
  479.         const struct url_data *data;
  480.         struct node *link, *node;
  481.         bool before;
  482.         nsurl *nsurl;
  483.  
  484.         if (url == NULL)
  485.                 return;
  486.  
  487.         if (nsurl_create(url, &nsurl) != NSERROR_OK)
  488.                 return;
  489.  
  490.         data = urldb_get_url_data(nsurl);
  491.         if (data == NULL) {
  492.                 urldb_add_url(nsurl);
  493.                 urldb_set_url_persistence(nsurl, true);
  494.                 data = urldb_get_url_data(nsurl);
  495.         }
  496.         if (data != NULL) {
  497.                 link = tree_get_link_details(hotlist_tree, x, y, &before);
  498.                 node = tree_create_URL_node(NULL, NULL, nsurl,
  499.                                             NULL, hotlist_node_callback, NULL);
  500.                 tree_link_node(hotlist_tree, link, node, before);
  501.         }
  502.         nsurl_unref(nsurl);
  503. }
  504.  
  505. /**
  506.  * Open the selected entries in separate browser windows.
  507.  *
  508.  * \param  tabs  open multiple entries in tabs in the new window
  509.  */
  510. void hotlist_launch_selected(bool tabs)
  511. {
  512.         tree_launch_selected(hotlist_tree, tabs);
  513. }
  514.  
  515. /**
  516.  * Set the hotlist's default folder to the selected node.
  517.  *
  518.  * \param  clear  reset the default to tree root
  519.  */
  520. bool hotlist_set_default_folder(bool clear)
  521. {
  522.         if (clear == true) {
  523.                 tree_clear_default_folder_node(hotlist_tree);
  524.                 return true;
  525.         } else {
  526.                 return tree_set_default_folder_node(hotlist_tree, NULL);
  527.         }
  528. }
  529.