summaryrefslogtreecommitdiff
path: root/desktop/history_global_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/history_global_core.c')
-rw-r--r--desktop/history_global_core.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/desktop/history_global_core.c b/desktop/history_global_core.c
new file mode 100644
index 000000000..b8cd9a5b0
--- /dev/null
+++ b/desktop/history_global_core.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/browser.h"
+#include "desktop/history_global_core.h"
+#include "desktop/plotters.h"
+#include "desktop/tree.h"
+#include "desktop/tree_url_node.h"
+
+#ifdef riscos
+#include "riscos/gui.h"
+#endif
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+
+#define MAXIMUM_BASE_NODES 16
+#define GLOBAL_HISTORY_RECENT_URLS 16
+#define URL_CHUNK_LENGTH 512
+
+static struct node *global_history_base_node[MAXIMUM_BASE_NODES];
+static int global_history_base_node_time[MAXIMUM_BASE_NODES];
+static int global_history_base_node_count = 0;
+
+static bool global_history_initialised;
+
+static struct tree *global_history_tree;
+static struct node *global_history_tree_root;
+
+static hlcache_handle *folder_icon;
+
+static const char *const weekday_msg_name [] =
+{
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+};
+
+/**
+ * Find an entry in the global history
+ *
+ * \param url The URL to find
+ * \return Pointer to node, or NULL if not found
+ */
+static struct node *history_global_find(const char *url)
+{
+ int i;
+ struct node *node;
+ const char *text;
+
+ for (i = 0; i < global_history_base_node_count; i++) {
+ if (!tree_node_is_deleted(global_history_base_node[i])) {
+ node = tree_node_get_child(global_history_base_node[i]);
+ for (; node != NULL; node = tree_node_get_next(node)) {
+ text = tree_url_node_get_url(node);
+ if ((text != NULL) && !strcmp(url, text))
+ return node;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Internal routine to actually perform global history addition
+ *
+ * \param url The URL to add
+ * \param data URL data associated with URL
+ * \return true (for urldb_iterate_entries)
+ */
+static bool global_history_add_internal(const char *url,
+ const struct url_data *data)
+{
+ int i, j;
+ struct node *parent = NULL;
+ struct node *link;
+ struct node *node;
+ bool before = false;
+ int visit_date;
+
+ assert((url != NULL) && (data != NULL));
+
+ visit_date = data->last_visit;
+
+ /* find parent node */
+ for (i = 0; i < global_history_base_node_count; i++) {
+ if (global_history_base_node_time[i] <= visit_date) {
+ parent = global_history_base_node[i];
+ break;
+ }
+ }
+
+ /* the entry is too old to care about */
+ if (parent == NULL)
+ return true;
+
+ if (tree_node_is_deleted(parent)) {
+ /* parent was deleted, so find place to insert it */
+ link = global_history_tree_root;
+
+ for (j = global_history_base_node_count - 1; j >= 0; j--) {
+ if (!tree_node_is_deleted(global_history_base_node[j]) &&
+ global_history_base_node_time[j] >
+ global_history_base_node_time[i]) {
+ link = global_history_base_node[j];
+ before = true;
+ break;
+ }
+ }
+
+ tree_set_node_selected(global_history_tree,
+ parent, true, false);
+ tree_set_node_expanded(global_history_tree,
+ parent, false, true, true);
+ tree_link_node(global_history_tree, link, parent, before);
+ }
+
+ /* find any previous occurance */
+ if (global_history_initialised == false) {
+ node = history_global_find(url);
+ if (node != NULL) {
+ tree_update_URL_node(global_history_tree,
+ node, url, data, true);
+ tree_delink_node(global_history_tree, node);
+ tree_link_node(global_history_tree, parent, node,
+ false);
+ return true;
+ }
+ }
+
+ /* Add the node at the bottom */
+ node = tree_create_URL_node_shared(global_history_tree,
+ parent, url, data,
+ tree_url_node_callback, NULL);
+
+ return true;
+}
+
+static node_callback_resp
+history_global_node_callback(void *user_data,
+ struct node_msg_data *msg_data)
+{
+ if (msg_data->msg == NODE_DELETE_ELEMENT_IMG)
+ return NODE_CALLBACK_HANDLED;
+ return NODE_CALLBACK_NOT_HANDLED;
+}
+
+/**
+ * Initialises a single grouping node for the global history tree.
+ *
+ * \return false on memory exhaustion, true otherwise
+ */
+static bool history_global_initialise_node(const char *title,
+ time_t base, int days_back)
+{
+ struct tm *full_time;
+ char *buffer;
+ struct node *node;
+
+ base += days_back * 60 * 60 * 24;
+ if (title == NULL) {
+ full_time = localtime(&base);
+ buffer = strdup(messages_get(weekday_msg_name[full_time->tm_wday]));
+ } else {
+ buffer = strdup(title);
+ }
+
+ if (buffer == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return false;
+ }
+
+ node = tree_create_folder_node(NULL, NULL, buffer,
+ false, true, true);
+ if (node == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ free(buffer);
+ return false;
+ }
+ if (folder_icon != NULL)
+ tree_set_node_icon(global_history_tree, node, folder_icon);
+ tree_set_node_user_callback(node, history_global_node_callback, NULL);
+
+ global_history_base_node[global_history_base_node_count] = node;
+ global_history_base_node_time[global_history_base_node_count] = base;
+ global_history_base_node_count++;
+
+ return true;
+}
+
+/**
+ * Initialises the grouping nodes(Today, Yesterday etc.) for the global history
+ * tree.
+ *
+ * \return false on memory exhaustion, true otherwise
+ */
+static bool history_global_initialise_nodes(void)
+{
+ struct tm *full_time;
+ time_t t;
+ int weekday;
+ int i;
+
+ /* get the current time */
+ t = time(NULL);
+ if (t == -1) {
+ LOG(("time info unaviable"));
+ return false;
+ }
+
+ /* get the time at the start of today */
+ full_time = localtime(&t);
+ weekday = full_time->tm_wday;
+ full_time->tm_sec = 0;
+ full_time->tm_min = 0;
+ full_time->tm_hour = 0;
+ t = mktime(full_time);
+ if (t == -1) {
+ LOG(("mktime failed"));
+ return false;
+ }
+
+ history_global_initialise_node(messages_get("DateToday"), t, 0);
+ if (weekday > 0)
+ if (!history_global_initialise_node(
+ messages_get("DateYesterday"), t, -1))
+ return false;
+ for (i = 2; i <= weekday; i++)
+ if (!history_global_initialise_node(NULL, t, -i))
+ return false;
+
+ if (!history_global_initialise_node(messages_get("Date1Week"),
+ t, -weekday - 7))
+ return false;
+ if (!history_global_initialise_node(messages_get("Date2Week"),
+ t, -weekday - 14))
+ return false;
+ if (!history_global_initialise_node(messages_get("Date3Week"),
+ t, -weekday - 21))
+ return false;
+
+ return true;
+}
+
+/**
+ * Initialises the global history tree.
+ *
+ * \param data user data for the callbacks
+ * \param start_redraw callback function called before every redraw
+ * \param end_redraw callback function called after every redraw
+ * \return true on success, false on memory exhaustion
+ */
+bool history_global_initialise(struct tree *tree)
+{
+ struct node *first;
+
+ folder_icon = tree_load_icon(tree_directory_icon_name);
+ tree_url_node_init();
+
+ if (tree == NULL)
+ return false;
+
+ global_history_tree = tree;
+ global_history_tree_root = tree_get_root(global_history_tree);
+
+ if (!history_global_initialise_nodes())
+ return false;
+
+ global_history_initialised = true;
+ urldb_iterate_entries(global_history_add_internal);
+ global_history_initialised = false;
+ tree_set_node_expanded(global_history_tree, global_history_tree_root,
+ false, true, true);
+ first = tree_node_get_child(global_history_tree_root);
+ if (first != NULL)
+ tree_set_node_expanded(global_history_tree, first,
+ true, false, false);
+
+ return true;
+}
+
+
+/**
+ * Get flags with which the global history tree should be created;
+ *
+ * \return the flags
+ */
+unsigned int history_global_get_tree_flags(void)
+{
+ return TREE_NO_FLAGS;
+}
+
+
+/**
+ * Deletes the global history tree.
+ */
+void history_global_cleanup(void)
+{
+}
+
+
+/**
+ * Adds a url to the global history.
+ *
+ * \param url the url to be added
+ */
+void global_history_add(const char *url)
+{
+ const struct url_data *data;
+
+ data = urldb_get_url_data(url);
+ if (data == NULL)
+ return;
+
+ global_history_add_internal(url, data);
+}
+
+
+/* Actions to be connected to front end specific toolbars */
+
+/**
+ * Save the global history in a human-readable form under the given location.
+ *
+ * \param path the path where the history will be saved
+ */
+bool history_global_export(const char *path)
+{
+ return tree_urlfile_save(global_history_tree, path, "NetSurf history");
+}
+
+/**
+ * Delete nodes which are currently selected.
+ */
+void history_global_delete_selected(void)
+{
+ tree_delete_selected_nodes(global_history_tree,
+ global_history_tree_root);
+}
+
+/**
+ * Delete all nodes.
+ */
+void history_global_delete_all(void)
+{
+ bool redraw_needed = tree_get_redraw(global_history_tree);
+ if (redraw_needed)
+ tree_set_redraw(global_history_tree, false);
+
+ tree_set_node_selected(global_history_tree, global_history_tree_root,
+ true, true);
+ tree_delete_selected_nodes(global_history_tree,
+ global_history_tree_root);
+
+ if (redraw_needed)
+ tree_set_redraw(global_history_tree, true);
+}
+
+/**
+ * Select all nodes in the tree.
+ */
+void history_global_select_all(void)
+{
+ tree_set_node_selected(global_history_tree, global_history_tree_root,
+ true, true);
+}
+
+/**
+ * Unselect all nodes.
+ */
+void history_global_clear_selection(void)
+{
+ tree_set_node_selected(global_history_tree, global_history_tree_root,
+ true, false);
+}
+
+/**
+ * Expand grouping folders and history entries.
+ */
+void history_global_expand_all(void)
+{
+ tree_set_node_expanded(global_history_tree, global_history_tree_root,
+ true, true, true);
+}
+
+/**
+ * Expand grouping folders only.
+ */
+void history_global_expand_directories(void)
+{
+ tree_set_node_expanded(global_history_tree, global_history_tree_root,
+ true, true, false);
+}
+
+/**
+ * Expand history entries only.
+ */
+void history_global_expand_addresses(void)
+{
+ tree_set_node_expanded(global_history_tree, global_history_tree_root,
+ true, false, true);
+}
+
+/**
+ * Collapse grouping folders and history entries.
+ */
+void history_global_collapse_all(void)
+{
+ tree_set_node_expanded(global_history_tree, global_history_tree_root,
+ false, true, true);
+}
+
+/**
+ * Collapse grouping folders only.
+ */
+void history_global_collapse_directories(void)
+{
+ tree_set_node_expanded(global_history_tree, global_history_tree_root,
+ false, true, false);
+}
+
+/**
+ * Collapse history entries only.
+ */
+void history_global_collapse_addresses(void)
+{
+ tree_set_node_expanded(global_history_tree, global_history_tree_root,
+ false, false, true);
+}
+
+/**
+ * Open the selected entries in seperate browser windows.
+ */
+void history_global_launch_selected(void)
+{
+ tree_launch_selected(global_history_tree);
+}